]> git.ipfire.org Git - thirdparty/squid.git/blame - src/HttpRequest.cc
Supply AccessLogEntry (ALE) for more fast ACL checks. (#182)
[thirdparty/squid.git] / src / HttpRequest.cc
CommitLineData
99edd1c3 1/*
5b74111a 2 * Copyright (C) 1996-2018 The Squid Software Foundation and contributors
99edd1c3 3 *
bbc27441
AJ
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
99edd1c3 7 */
8
bbc27441
AJ
9/* DEBUG: section 73 HTTP Request */
10
582c2af2 11#include "squid.h"
f4698e0b 12#include "AccessLogEntry.h"
1328cfb7 13#include "acl/AclSizeLimit.h"
582c2af2
FC
14#include "acl/FilledChecklist.h"
15#include "client_side.h"
cd4a5c60 16#include "client_side_request.h"
4a3b98d7 17#include "dns/LookupDetails.h"
cda7024f 18#include "Downloader.h"
582c2af2 19#include "err_detail_type.h"
67679543 20#include "globals.h"
d05c079c 21#include "gopher.h"
5c0c642e 22#include "http.h"
c99510dd 23#include "http/one/RequestParser.h"
d3dddfb5 24#include "http/Stream.h"
7ebe76de 25#include "HttpHdrCc.h"
528b2c61 26#include "HttpHeaderRange.h"
582c2af2 27#include "HttpRequest.h"
38e16f92 28#include "log/Config.h"
0eb49b6d 29#include "MemBuf.h"
ac38abee 30#include "sbuf/StringConvert.h"
4d5904f7 31#include "SquidConfig.h"
25b6a907 32#include "Store.h"
b1bd952a 33#include "URL.h"
582c2af2
FC
34
35#if USE_AUTH
36#include "auth/UserRequest.h"
37#endif
3ff65596
AR
38#if ICAP_CLIENT
39#include "adaptation/icap/icap_log.h"
40#endif
528b2c61 41
5ceaee75
CT
42HttpRequest::HttpRequest(const MasterXaction::Pointer &mx) :
43 Http::Message(hoRequest),
44 masterXaction(mx)
75faaa7a 45{
5ceaee75 46 assert(mx);
5cafad19 47 init();
48}
49
5ceaee75
CT
50HttpRequest::HttpRequest(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *aSchemeImg, const char *aUrlpath, const MasterXaction::Pointer &mx) :
51 Http::Message(hoRequest),
52 masterXaction(mx)
5cafad19 53{
5ceaee75 54 assert(mx);
5dfc3258
AR
55 static unsigned int id = 1;
56 debugs(93,7, HERE << "constructed, this=" << this << " id=" << ++id);
5cafad19 57 init();
d31d59d8 58 initHTTP(aMethod, aProtocol, aSchemeImg, aUrlpath);
5cafad19 59}
60
61HttpRequest::~HttpRequest()
62{
5cafad19 63 clean();
5dfc3258 64 debugs(93,7, HERE << "destructed, this=" << this);
5cafad19 65}
66
67void
d31d59d8 68HttpRequest::initHTTP(const HttpRequestMethod& aMethod, AnyP::ProtocolType aProtocol, const char *aSchemeImg, const char *aUrlpath)
5cafad19 69{
70 method = aMethod;
d31d59d8 71 url.setScheme(aProtocol, aSchemeImg);
51b5dcf5 72 url.path(aUrlpath);
5cafad19 73}
74
75void
76HttpRequest::init()
77{
c2a7cefd 78 method = Http::METHOD_NONE;
4e3f4dc7 79 url.clear();
2f1431ea 80#if USE_AUTH
a3f28359 81 auth_user_request = NULL;
2f1431ea 82#endif
a3f28359 83 memset(&flags, '\0', sizeof(flags));
84 range = NULL;
85 ims = -1;
86 imslen = 0;
5cafad19 87 lastmod = -1;
4dd643d5
AJ
88 client_addr.setEmpty();
89 my_addr.setEmpty();
5f8252d2 90 body_pipe = NULL;
a3f28359 91 // hier
3ff65596 92 dnsWait = -1;
a3f28359 93 errType = ERR_NONE;
64b66b76 94 errDetail = ERR_DETAIL_NONE;
f53969cc
SM
95 peer_login = NULL; // not allocated/deallocated by this class
96 peer_domain = NULL; // not allocated/deallocated by this class
593d3cdb 97 peer_host = NULL;
90ab8f20 98 vary_headers = SBuf();
35fb56c9 99 myportname = null_string;
5cafad19 100 tag = null_string;
2f1431ea 101#if USE_AUTH
5cafad19 102 extacl_user = null_string;
103 extacl_passwd = null_string;
2f1431ea 104#endif
5cafad19 105 extacl_log = null_string;
8c93a598 106 extacl_message = null_string;
fb654382 107 pstate = Http::Message::psReadyToParseStartLine;
3d674977 108#if FOLLOW_X_FORWARDED_FOR
4dd643d5 109 indirect_client_addr.setEmpty();
3d674977 110#endif /* FOLLOW_X_FORWARDED_FOR */
3ff65596
AR
111#if USE_ADAPTATION
112 adaptHistory_ = NULL;
113#endif
114#if ICAP_CLIENT
115 icapHistory_ = NULL;
116#endif
11e3fa1c 117 rangeOffsetLimit = -2; //a value of -2 means not checked yet
ec69bdb2 118 forcedBodyContinuation = false;
8596962e 119}
120
99edd1c3 121void
5cafad19 122HttpRequest::clean()
99edd1c3 123{
9e008dda 124 // we used to assert that the pipe is NULL, but now the request only
5f8252d2 125 // points to a pipe that is owned and initiated by another object.
9e008dda 126 body_pipe = NULL;
2f1431ea 127#if USE_AUTH
a33a428a 128 auth_user_request = NULL;
2f1431ea 129#endif
90ab8f20 130 vary_headers.clear();
4e3f4dc7 131 url.clear();
62e76326 132
519e0948 133 header.clean();
62e76326 134
07947ad8 135 if (cache_control) {
3d7782c1 136 delete cache_control;
07947ad8 137 cache_control = NULL;
138 }
62e76326 139
5cafad19 140 if (range) {
8596962e 141 delete range;
5cafad19 142 range = NULL;
143 }
62e76326 144
35fb56c9
AJ
145 myportname.clean();
146
75d47340 147 theNotes = nullptr;
d06e17ea 148
30abd221 149 tag.clean();
2f1431ea 150#if USE_AUTH
30abd221 151 extacl_user.clean();
30abd221 152 extacl_passwd.clean();
2f1431ea 153#endif
30abd221 154 extacl_log.clean();
3ff65596 155
8c93a598
HN
156 extacl_message.clean();
157
46017fdd
CT
158 etag.clean();
159
3ff65596
AR
160#if USE_ADAPTATION
161 adaptHistory_ = NULL;
162#endif
163#if ICAP_CLIENT
164 icapHistory_ = NULL;
165#endif
8596962e 166}
4a972fa2 167
5cafad19 168void
169HttpRequest::reset()
170{
171 clean();
172 init();
173}
174
fa0e6114
AR
175HttpRequest *
176HttpRequest::clone() const
177{
5ceaee75 178 HttpRequest *copy = new HttpRequest(masterXaction);
51b5dcf5 179 copy->method = method;
fa0e6114
AR
180 // TODO: move common cloning clone to Msg::copyTo() or copy ctor
181 copy->header.append(&header);
182 copy->hdrCacheInit();
183 copy->hdr_sz = hdr_sz;
184 copy->http_ver = http_ver;
185 copy->pstate = pstate; // TODO: should we assert a specific state here?
186 copy->body_pipe = body_pipe;
187
d31d59d8 188 copy->url = url;
fa0e6114 189
66363092 190 // range handled in hdrCacheInit()
9e008dda
AJ
191 copy->ims = ims;
192 copy->imslen = imslen;
fa0e6114
AR
193 copy->hier = hier; // Is it safe to copy? Should we?
194
195 copy->errType = errType;
196
197 // XXX: what to do with copy->peer_login?
198
9e008dda 199 copy->lastmod = lastmod;
46017fdd 200 copy->etag = etag;
90ab8f20 201 copy->vary_headers = vary_headers;
fa0e6114
AR
202 // XXX: what to do with copy->peer_domain?
203
204 copy->tag = tag;
fa0e6114 205 copy->extacl_log = extacl_log;
8c93a598 206 copy->extacl_message = extacl_message;
fa0e6114 207
fbc1c5a6
AJ
208 const bool inheritWorked = copy->inheritProperties(this);
209 assert(inheritWorked);
3ff65596 210
fa0e6114
AR
211 return copy;
212}
213
d5964067 214bool
63df1d28 215HttpRequest::inheritProperties(const Http::Message *aMsg)
d5964067
AJ
216{
217 const HttpRequest* aReq = dynamic_cast<const HttpRequest*>(aMsg);
218 if (!aReq)
219 return false;
220
221 client_addr = aReq->client_addr;
222#if FOLLOW_X_FORWARDED_FOR
223 indirect_client_addr = aReq->indirect_client_addr;
d5964067
AJ
224#endif
225 my_addr = aReq->my_addr;
226
227 dnsWait = aReq->dnsWait;
228
229#if USE_ADAPTATION
230 adaptHistory_ = aReq->adaptHistory();
231#endif
232#if ICAP_CLIENT
233 icapHistory_ = aReq->icapHistory();
234#endif
235
236 // This may be too conservative for the 204 No Content case
237 // may eventually need cloneNullAdaptationImmune() for that.
238 flags = aReq->flags.cloneAdaptationImmune();
239
240 errType = aReq->errType;
241 errDetail = aReq->errDetail;
242#if USE_AUTH
243 auth_user_request = aReq->auth_user_request;
f4f6ab06
AJ
244 extacl_user = aReq->extacl_user;
245 extacl_passwd = aReq->extacl_passwd;
d5964067 246#endif
983983ce 247
20fb3571
AJ
248 myportname = aReq->myportname;
249
ec69bdb2
CT
250 forcedBodyContinuation = aReq->forcedBodyContinuation;
251
983983ce 252 // main property is which connection the request was received on (if any)
d5964067 253 clientConnectionManager = aReq->clientConnectionManager;
f4698e0b 254
cda7024f
CT
255 downloader = aReq->downloader;
256
75d47340 257 theNotes = aReq->theNotes;
88df846b
CT
258
259 sources = aReq->sources;
d5964067
AJ
260 return true;
261}
262
96ee497f
AJ
263/**
264 * Checks the first line of an HTTP request is valid
265 * currently just checks the request method is present.
266 *
267 * NP: Other errors are left for detection later in the parse.
268 */
c21ad0f5 269bool
84ae6223 270HttpRequest::sanityCheckStartLine(const char *buf, const size_t hdr_len, Http::StatusCode *error)
8596962e 271{
96ee497f
AJ
272 // content is long enough to possibly hold a reply
273 // 2 being magic size of a 1-byte request method plus space delimiter
84ae6223 274 if (hdr_len < 2) {
96ee497f
AJ
275 // this is ony a real error if the headers apparently complete.
276 if (hdr_len > 0) {
0246f6b8 277 debugs(58, 3, HERE << "Too large request header (" << hdr_len << " bytes)");
955394ce 278 *error = Http::scInvalidHeader;
96ee497f
AJ
279 }
280 return false;
281 }
8596962e 282
f9688132
AJ
283 /* See if the request buffer starts with a non-whitespace HTTP request 'method'. */
284 HttpRequestMethod m;
84ae6223 285 m.HttpRequestMethodXXX(buf);
f9688132 286 if (m == Http::METHOD_NONE) {
bf8fe701 287 debugs(73, 3, "HttpRequest::sanityCheckStartLine: did not find HTTP request method");
955394ce 288 *error = Http::scInvalidHeader;
8596962e 289 return false;
290 }
291
292 return true;
293}
294
c21ad0f5 295bool
296HttpRequest::parseFirstLine(const char *start, const char *end)
8596962e 297{
f9688132 298 method.HttpRequestMethodXXX(start);
863d85ee 299
c2a7cefd 300 if (method == Http::METHOD_NONE)
863d85ee 301 return false;
302
f9688132
AJ
303 // XXX: performance regression, strcspn() over the method bytes a second time.
304 // cheaper than allocate+copy+deallocate cycle to SBuf convert a piece of start.
305 const char *t = start + strcspn(start, w_space);
306
307 start = t + strspn(t, w_space); // skip w_space after method
863d85ee 308
309 const char *ver = findTrailingHTTPVersion(start, end);
310
311 if (ver) {
312 end = ver - 1;
313
314 while (xisspace(*end)) // find prev non-space
5e263176 315 --end;
863d85ee 316
95dc7ff4 317 ++end; // back to space
863d85ee 318
319 if (2 != sscanf(ver + 5, "%d.%d", &http_ver.major, &http_ver.minor)) {
e0236918 320 debugs(73, DBG_IMPORTANT, "parseRequestLine: Invalid HTTP identifier.");
863d85ee 321 return false;
322 }
323 } else {
324 http_ver.major = 0;
325 http_ver.minor = 9;
326 }
327
328 if (end < start) // missing URI
329 return false;
330
331 char save = *end;
332
333 * (char *) end = '\0'; // temp terminate URI, XXX dangerous?
334
8babada0 335 const bool ret = url.parse(method, start);
863d85ee 336
337 * (char *) end = save;
338
9157915c 339 return ret;
99edd1c3 340}
341
a00a7c85 342/* swaps out request using httpRequestPack */
99edd1c3 343void
5cafad19 344HttpRequest::swapOut(StoreEntry * e)
99edd1c3 345{
5cafad19 346 assert(e);
15179984
AJ
347 e->buffer();
348 pack(e);
691ad095 349 e->flush();
a00a7c85 350}
351
352/* packs request-line and headers, appends <crlf> terminator */
353void
1f28a150 354HttpRequest::pack(Packable * p) const
a00a7c85 355{
5cafad19 356 assert(p);
a00a7c85 357 /* pack request-line */
51b5dcf5
AJ
358 p->appendf(SQUIDSBUFPH " " SQUIDSBUFPH " HTTP/%d.%d\r\n",
359 SQUIDSBUFPRINT(method.image()), SQUIDSBUFPRINT(url.path()),
4391cd15 360 http_ver.major, http_ver.minor);
a00a7c85 361 /* headers */
a9925b40 362 header.packInto(p);
2246b732 363 /* trailer */
785b508d 364 p->append("\r\n", 2);
2246b732 365}
366
5cafad19 367/*
368 * A wrapper for debugObj()
369 */
2246b732 370void
17802cf1 371httpRequestPack(void *obj, Packable *p)
2246b732 372{
5cafad19 373 HttpRequest *request = static_cast<HttpRequest*>(obj);
374 request->pack(p);
99edd1c3 375}
eeb423fb 376
2246b732 377/* returns the length of request line + headers + crlf */
378int
51b5dcf5 379HttpRequest::prefixLen() const
2246b732 380{
7f06a3d8 381 return method.image().length() + 1 +
51b5dcf5 382 url.path().length() + 1 +
62e76326 383 4 + 1 + 3 + 2 +
5cafad19 384 header.len + 2;
2246b732 385}
99edd1c3 386
190154cf 387/* sync this routine when you update HttpRequest struct */
8596962e 388void
07947ad8 389HttpRequest::hdrCacheInit()
528b2c61 390{
63df1d28 391 Http::Message::hdrCacheInit();
62e76326 392
66363092 393 assert(!range);
a9925b40 394 range = header.getRange();
528b2c61 395}
396
3ff65596 397#if ICAP_CLIENT
e1381638 398Adaptation::Icap::History::Pointer
3ff65596
AR
399HttpRequest::icapHistory() const
400{
401 if (!icapHistory_) {
38e16f92 402 if (Log::TheConfig.hasIcapToken || IcapLogfileStatus == LOG_ENABLE) {
3ff65596
AR
403 icapHistory_ = new Adaptation::Icap::History();
404 debugs(93,4, HERE << "made " << icapHistory_ << " for " << this);
405 }
406 }
407
408 return icapHistory_;
409}
410#endif
411
412#if USE_ADAPTATION
e1381638 413Adaptation::History::Pointer
a22e6cd3 414HttpRequest::adaptHistory(bool createIfNone) const
3ff65596 415{
a22e6cd3
AR
416 if (!adaptHistory_ && createIfNone) {
417 adaptHistory_ = new Adaptation::History();
418 debugs(93,4, HERE << "made " << adaptHistory_ << " for " << this);
3ff65596
AR
419 }
420
421 return adaptHistory_;
422}
a22e6cd3 423
e1381638 424Adaptation::History::Pointer
a22e6cd3
AR
425HttpRequest::adaptLogHistory() const
426{
38e16f92 427 return HttpRequest::adaptHistory(Log::TheConfig.hasAdaptToken);
a22e6cd3
AR
428}
429
aaf0559d
AR
430void
431HttpRequest::adaptHistoryImport(const HttpRequest &them)
432{
433 if (!adaptHistory_) {
434 adaptHistory_ = them.adaptHistory_; // may be nil
435 } else {
436 // check that histories did not diverge
437 Must(!them.adaptHistory_ || them.adaptHistory_ == adaptHistory_);
438 }
439}
440
3ff65596
AR
441#endif
442
528b2c61 443bool
190154cf 444HttpRequest::multipartRangeRequest() const
528b2c61 445{
9ad511b6 446 return (range && range->specs.size() > 1);
528b2c61 447}
8000a965 448
58217e94 449bool
9e008dda
AJ
450HttpRequest::bodyNibbled() const
451{
58217e94 452 return body_pipe != NULL && body_pipe->consumedSize() > 0;
453}
5f8252d2 454
64b66b76
CT
455void
456HttpRequest::detailError(err_type aType, int aDetail)
457{
458 if (errType || errDetail)
459 debugs(11, 5, HERE << "old error details: " << errType << '/' << errDetail);
460 debugs(11, 5, HERE << "current error details: " << aType << '/' << aDetail);
461 // checking type and detail separately may cause inconsistency, but
462 // may result in more details available if they only become available later
463 if (!errType)
464 errType = aType;
465 if (!errDetail)
466 errDetail = aDetail;
467}
468
129fe2a1
CT
469void
470HttpRequest::clearError()
471{
472 debugs(11, 7, HERE << "old error details: " << errType << '/' << errDetail);
473 errType = ERR_NONE;
474 errDetail = ERR_DETAIL_NONE;
475}
476
51b5dcf5
AJ
477void
478HttpRequest::packFirstLineInto(Packable * p, bool full_uri) const
8596962e 479{
851feda6 480 const SBuf tmp(full_uri ? effectiveRequestUri() : url.path());
8596962e 481
8596962e 482 // form HTTP request-line
51b5dcf5 483 p->appendf(SQUIDSBUFPH " " SQUIDSBUFPH " HTTP/%d.%d\r\n",
4391cd15 484 SQUIDSBUFPRINT(method.image()),
51b5dcf5 485 SQUIDSBUFPRINT(tmp),
4391cd15 486 http_ver.major, http_ver.minor);
8596962e 487}
8ddea643 488
489/*
684e9c80 490 * Indicate whether or not we would expect an entity-body
8ddea643 491 * along with this request
492 */
493bool
ced8def3 494HttpRequest::expectingBody(const HttpRequestMethod &, int64_t &theSize) const
8ddea643 495{
496 bool expectBody = false;
497
498 /*
684e9c80
HN
499 * Note: Checks for message validity is in clientIsContentLengthValid().
500 * this just checks if a entity-body is expected based on HTTP message syntax
8ddea643 501 */
684e9c80 502 if (header.chunked()) {
8ddea643 503 expectBody = true;
684e9c80
HN
504 theSize = -1;
505 } else if (content_length >= 0) {
8ddea643 506 expectBody = true;
684e9c80
HN
507 theSize = content_length;
508 } else {
8ddea643 509 expectBody = false;
684e9c80 510 // theSize undefined
8ddea643 511 }
512
513 return expectBody;
514}
c21ad0f5 515
516/*
517 * Create a Request from a URL and METHOD.
518 *
519 * If the METHOD is CONNECT, then a host:port pair is looked for instead of a URL.
520 * If the request cannot be created cleanly, NULL is returned
521 */
522HttpRequest *
8babada0 523HttpRequest::FromUrl(const char * url, const MasterXaction::Pointer &mx, const HttpRequestMethod& method)
c21ad0f5 524{
5ceaee75 525 std::unique_ptr<HttpRequest> req(new HttpRequest(mx));
91489e45
AJ
526 if (req->url.parse(method, url)) {
527 req->method = method;
9157915c 528 return req.release();
91489e45 529 }
9157915c 530 return nullptr;
c21ad0f5 531}
532
c2a7cefd 533/**
610ee341 534 * Are responses to this request possible cacheable ?
535 * If false then no matter what the response must not be cached.
536 */
537bool
c2a7cefd 538HttpRequest::maybeCacheable()
610ee341 539{
2962f8b8
AJ
540 // Intercepted request with Host: header which cannot be trusted.
541 // Because it failed verification, or someone bypassed the security tests
542 // we cannot cache the reponse for sharing between clients.
543 // TODO: update cache to store for particular clients only (going to same Host: and destination IP)
0d901ef4 544 if (!flags.hostVerified && (flags.intercepted || flags.interceptTproxy))
2962f8b8
AJ
545 return false;
546
4e3f4dc7 547 switch (url.getScheme()) {
c2a7cefd 548 case AnyP::PROTO_HTTP:
2c32c73e 549 case AnyP::PROTO_HTTPS:
c2a7cefd
AJ
550 if (!method.respMaybeCacheable())
551 return false;
9e008dda 552
38041f53
GD
553 // RFC 7234 section 5.2.1.5:
554 // "cache MUST NOT store any part of either this request or any response to it"
555 //
556 // NP: refresh_pattern ignore-no-store only applies to response messages
557 // this test is handling request message CC header.
810d879f 558 if (!flags.ignoreCc && cache_control && cache_control->hasNoStore())
38041f53 559 return false;
c2a7cefd 560 break;
610ee341 561
c2a7cefd
AJ
562 case AnyP::PROTO_GOPHER:
563 if (!gopherCachable(this))
564 return false;
565 break;
610ee341 566
c2a7cefd 567 case AnyP::PROTO_CACHE_OBJECT:
60745f24 568 return false;
610ee341 569
f53969cc 570 //case AnyP::PROTO_FTP:
c2a7cefd
AJ
571 default:
572 break;
573 }
574
60745f24 575 return true;
610ee341 576}
d67acb4e 577
79c8035e
AR
578bool
579HttpRequest::conditional() const
580{
45e5102d 581 return flags.ims ||
789217a2
FC
582 header.has(Http::HdrType::IF_MATCH) ||
583 header.has(Http::HdrType::IF_NONE_MATCH);
79c8035e
AR
584}
585
d5964067 586void
4a3b98d7 587HttpRequest::recordLookup(const Dns::LookupDetails &dns)
3ff65596
AR
588{
589 if (dns.wait >= 0) { // known delay
fd9c47d1
AR
590 if (dnsWait >= 0) { // have recorded DNS wait before
591 debugs(78, 7, this << " " << dnsWait << " += " << dns);
3ff65596 592 dnsWait += dns.wait;
fd9c47d1
AR
593 } else {
594 debugs(78, 7, this << " " << dns);
3ff65596 595 dnsWait = dns.wait;
fd9c47d1 596 }
3ff65596
AR
597 }
598}
11e3fa1c
AJ
599
600int64_t
601HttpRequest::getRangeOffsetLimit()
602{
603 /* -2 is the starting value of rangeOffsetLimit.
604 * If it is -2, that means we haven't checked it yet.
605 * Otherwise, return the current value */
5e5f247c 606 if (rangeOffsetLimit != -2)
11e3fa1c
AJ
607 return rangeOffsetLimit;
608
609 rangeOffsetLimit = 0; // default value for rangeOffsetLimit
610
611 ACLFilledChecklist ch(NULL, this, NULL);
612 ch.src_addr = client_addr;
613 ch.my_addr = my_addr;
614
1328cfb7 615 for (AclSizeLimit *l = Config.rangeOffsetLimit; l; l = l -> next) {
11e3fa1c 616 /* if there is no ACL list or if the ACLs listed match use this limit value */
06bf5384 617 if (!l->aclList || ch.fastCheck(l->aclList).allowed()) {
11e3fa1c
AJ
618 debugs(58, 4, HERE << "rangeOffsetLimit=" << rangeOffsetLimit);
619 rangeOffsetLimit = l->size; // may be -1
620 break;
621 }
622 }
623
624 return rangeOffsetLimit;
625}
655daa06 626
f0baf149
AR
627void
628HttpRequest::ignoreRange(const char *reason)
629{
630 if (range) {
631 debugs(73, 3, static_cast<void*>(range) << " for " << reason);
632 delete range;
633 range = NULL;
634 }
635 // Some callers also reset isRanged but it may not be safe for all callers:
636 // isRanged is used to determine whether a weak ETag comparison is allowed,
637 // and that check should not ignore the Range header if it was present.
638 // TODO: Some callers also delete HDR_RANGE, HDR_REQUEST_RANGE. Should we?
639}
640
655daa06
AR
641bool
642HttpRequest::canHandle1xx() const
643{
644 // old clients do not support 1xx unless they sent Expect: 100-continue
789217a2
FC
645 // (we reject all other Http::HdrType::EXPECT values so just check for Http::HdrType::EXPECT)
646 if (http_ver <= Http::ProtocolVersion(1,0) && !header.has(Http::HdrType::EXPECT))
655daa06
AR
647 return false;
648
649 // others must support 1xx control messages
650 return true;
651}
582c2af2
FC
652
653ConnStateData *
b0fb853f
A
654HttpRequest::pinnedConnection()
655{
582c2af2
FC
656 if (clientConnectionManager.valid() && clientConnectionManager->pinning.pinned)
657 return clientConnectionManager.get();
658 return NULL;
659}
a8a0b1c2 660
851feda6 661const SBuf
a8a0b1c2
EC
662HttpRequest::storeId()
663{
664 if (store_id.size() != 0) {
851feda6 665 debugs(73, 3, "sent back store_id: " << store_id);
d7ef451f 666 return StringToSBuf(store_id);
a8a0b1c2 667 }
851feda6
AJ
668 debugs(73, 3, "sent back effectiveRequestUrl: " << effectiveRequestUri());
669 return effectiveRequestUri();
670}
a8a0b1c2 671
851feda6
AJ
672const SBuf &
673HttpRequest::effectiveRequestUri() const
674{
6b2b6cfe 675 if (method.id() == Http::METHOD_CONNECT || url.getScheme() == AnyP::PROTO_AUTHORITY_FORM)
851feda6
AJ
676 return url.authority(true); // host:port
677 return url.absolute();
a8a0b1c2 678}
f53969cc 679
75d47340
CT
680NotePairs::Pointer
681HttpRequest::notes()
682{
683 if (!theNotes)
684 theNotes = new NotePairs;
685 return theNotes;
686}
687
688void
689UpdateRequestNotes(ConnStateData *csd, HttpRequest &request, NotePairs const &helperNotes)
690{
691 // Tag client connection if the helper responded with clt_conn_tag=tag.
692 const char *cltTag = "clt_conn_tag";
693 if (const char *connTag = helperNotes.findFirst(cltTag)) {
694 if (csd) {
695 csd->notes()->remove(cltTag);
696 csd->notes()->add(cltTag, connTag);
697 }
698 }
699 request.notes()->replaceOrAdd(&helperNotes);
700}
701
cd4a5c60
CT
702void
703HttpRequest::manager(const CbcPointer<ConnStateData> &aMgr, const AccessLogEntryPointer &al)
704{
705 clientConnectionManager = aMgr;
706
707 if (!clientConnectionManager.valid())
708 return;
709
710 AnyP::PortCfgPointer port = clientConnectionManager->port;
711 if (port) {
712 myportname = port->name;
713 flags.ignoreCc = port->ignore_cc;
714 }
715
716 if (auto clientConnection = clientConnectionManager->clientConnection) {
717 client_addr = clientConnection->remote; // XXX: remove request->client_addr member.
718#if FOLLOW_X_FORWARDED_FOR
719 // indirect client gets stored here because it is an HTTP header result (from X-Forwarded-For:)
720 // not details about the TCP connection itself
721 indirect_client_addr = clientConnection->remote;
722#endif /* FOLLOW_X_FORWARDED_FOR */
723 my_addr = clientConnection->local;
b6307671 724
cd4a5c60
CT
725 flags.intercepted = ((clientConnection->flags & COMM_INTERCEPTION) != 0);
726 flags.interceptTproxy = ((clientConnection->flags & COMM_TRANSPARENT) != 0 ) ;
727 const bool proxyProtocolPort = port ? port->flags.proxySurrogate : false;
728 if (flags.interceptTproxy && !proxyProtocolPort) {
729 if (Config.accessList.spoof_client_ip) {
730 ACLFilledChecklist *checklist = new ACLFilledChecklist(Config.accessList.spoof_client_ip, this, clientConnection->rfc931);
731 checklist->al = al;
cb365059 732 checklist->syncAle(this, nullptr);
06bf5384 733 flags.spoofClientIp = checklist->fastCheck().allowed();
cd4a5c60
CT
734 delete checklist;
735 } else
736 flags.spoofClientIp = true;
737 } else
738 flags.spoofClientIp = false;
739 }
740}
b6307671 741