]> git.ipfire.org Git - thirdparty/squid.git/blame - src/HttpRequest.cc
tproxy does not spoof spliced connections
[thirdparty/squid.git] / src / HttpRequest.cc
CommitLineData
99edd1c3 1/*
4ac4a490 2 * Copyright (C) 1996-2017 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
9157915c 335 const bool ret = urlParse(method, (char *) start, *this);
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 *
5ceaee75 523HttpRequest::FromUrl(char * url, const MasterXaction::Pointer &mx, const HttpRequestMethod& method)
c21ad0f5 524{
5ceaee75 525 std::unique_ptr<HttpRequest> req(new HttpRequest(mx));
9157915c
CT
526 if (urlParse(method, url, *req))
527 return req.release();
528 return nullptr;
c21ad0f5 529}
530
c2a7cefd 531/**
610ee341 532 * Are responses to this request possible cacheable ?
533 * If false then no matter what the response must not be cached.
534 */
535bool
c2a7cefd 536HttpRequest::maybeCacheable()
610ee341 537{
2962f8b8
AJ
538 // Intercepted request with Host: header which cannot be trusted.
539 // Because it failed verification, or someone bypassed the security tests
540 // we cannot cache the reponse for sharing between clients.
541 // TODO: update cache to store for particular clients only (going to same Host: and destination IP)
0d901ef4 542 if (!flags.hostVerified && (flags.intercepted || flags.interceptTproxy))
2962f8b8
AJ
543 return false;
544
4e3f4dc7 545 switch (url.getScheme()) {
c2a7cefd 546 case AnyP::PROTO_HTTP:
2c32c73e 547 case AnyP::PROTO_HTTPS:
c2a7cefd
AJ
548 if (!method.respMaybeCacheable())
549 return false;
9e008dda 550
38041f53
GD
551 // RFC 7234 section 5.2.1.5:
552 // "cache MUST NOT store any part of either this request or any response to it"
553 //
554 // NP: refresh_pattern ignore-no-store only applies to response messages
555 // this test is handling request message CC header.
810d879f 556 if (!flags.ignoreCc && cache_control && cache_control->hasNoStore())
38041f53 557 return false;
c2a7cefd 558 break;
610ee341 559
c2a7cefd
AJ
560 case AnyP::PROTO_GOPHER:
561 if (!gopherCachable(this))
562 return false;
563 break;
610ee341 564
c2a7cefd 565 case AnyP::PROTO_CACHE_OBJECT:
60745f24 566 return false;
610ee341 567
f53969cc 568 //case AnyP::PROTO_FTP:
c2a7cefd
AJ
569 default:
570 break;
571 }
572
60745f24 573 return true;
610ee341 574}
d67acb4e 575
79c8035e
AR
576bool
577HttpRequest::conditional() const
578{
45e5102d 579 return flags.ims ||
789217a2
FC
580 header.has(Http::HdrType::IF_MATCH) ||
581 header.has(Http::HdrType::IF_NONE_MATCH);
79c8035e
AR
582}
583
d5964067 584void
4a3b98d7 585HttpRequest::recordLookup(const Dns::LookupDetails &dns)
3ff65596
AR
586{
587 if (dns.wait >= 0) { // known delay
588 if (dnsWait >= 0) // have recorded DNS wait before
589 dnsWait += dns.wait;
590 else
591 dnsWait = dns.wait;
592 }
593}
11e3fa1c
AJ
594
595int64_t
596HttpRequest::getRangeOffsetLimit()
597{
598 /* -2 is the starting value of rangeOffsetLimit.
599 * If it is -2, that means we haven't checked it yet.
600 * Otherwise, return the current value */
5e5f247c 601 if (rangeOffsetLimit != -2)
11e3fa1c
AJ
602 return rangeOffsetLimit;
603
604 rangeOffsetLimit = 0; // default value for rangeOffsetLimit
605
606 ACLFilledChecklist ch(NULL, this, NULL);
607 ch.src_addr = client_addr;
608 ch.my_addr = my_addr;
609
1328cfb7 610 for (AclSizeLimit *l = Config.rangeOffsetLimit; l; l = l -> next) {
11e3fa1c 611 /* if there is no ACL list or if the ACLs listed match use this limit value */
2efeb0b7 612 if (!l->aclList || ch.fastCheck(l->aclList) == ACCESS_ALLOWED) {
11e3fa1c
AJ
613 debugs(58, 4, HERE << "rangeOffsetLimit=" << rangeOffsetLimit);
614 rangeOffsetLimit = l->size; // may be -1
615 break;
616 }
617 }
618
619 return rangeOffsetLimit;
620}
655daa06 621
f0baf149
AR
622void
623HttpRequest::ignoreRange(const char *reason)
624{
625 if (range) {
626 debugs(73, 3, static_cast<void*>(range) << " for " << reason);
627 delete range;
628 range = NULL;
629 }
630 // Some callers also reset isRanged but it may not be safe for all callers:
631 // isRanged is used to determine whether a weak ETag comparison is allowed,
632 // and that check should not ignore the Range header if it was present.
633 // TODO: Some callers also delete HDR_RANGE, HDR_REQUEST_RANGE. Should we?
634}
635
655daa06
AR
636bool
637HttpRequest::canHandle1xx() const
638{
639 // old clients do not support 1xx unless they sent Expect: 100-continue
789217a2
FC
640 // (we reject all other Http::HdrType::EXPECT values so just check for Http::HdrType::EXPECT)
641 if (http_ver <= Http::ProtocolVersion(1,0) && !header.has(Http::HdrType::EXPECT))
655daa06
AR
642 return false;
643
644 // others must support 1xx control messages
645 return true;
646}
582c2af2
FC
647
648ConnStateData *
b0fb853f
A
649HttpRequest::pinnedConnection()
650{
582c2af2
FC
651 if (clientConnectionManager.valid() && clientConnectionManager->pinning.pinned)
652 return clientConnectionManager.get();
653 return NULL;
654}
a8a0b1c2 655
851feda6 656const SBuf
a8a0b1c2
EC
657HttpRequest::storeId()
658{
659 if (store_id.size() != 0) {
851feda6 660 debugs(73, 3, "sent back store_id: " << store_id);
d7ef451f 661 return StringToSBuf(store_id);
a8a0b1c2 662 }
851feda6
AJ
663 debugs(73, 3, "sent back effectiveRequestUrl: " << effectiveRequestUri());
664 return effectiveRequestUri();
665}
a8a0b1c2 666
851feda6
AJ
667const SBuf &
668HttpRequest::effectiveRequestUri() const
669{
6b2b6cfe 670 if (method.id() == Http::METHOD_CONNECT || url.getScheme() == AnyP::PROTO_AUTHORITY_FORM)
851feda6
AJ
671 return url.authority(true); // host:port
672 return url.absolute();
a8a0b1c2 673}
f53969cc 674
75d47340
CT
675NotePairs::Pointer
676HttpRequest::notes()
677{
678 if (!theNotes)
679 theNotes = new NotePairs;
680 return theNotes;
681}
682
683void
684UpdateRequestNotes(ConnStateData *csd, HttpRequest &request, NotePairs const &helperNotes)
685{
686 // Tag client connection if the helper responded with clt_conn_tag=tag.
687 const char *cltTag = "clt_conn_tag";
688 if (const char *connTag = helperNotes.findFirst(cltTag)) {
689 if (csd) {
690 csd->notes()->remove(cltTag);
691 csd->notes()->add(cltTag, connTag);
692 }
693 }
694 request.notes()->replaceOrAdd(&helperNotes);
695}
696
cd4a5c60
CT
697
698void
699HttpRequest::manager(const CbcPointer<ConnStateData> &aMgr, const AccessLogEntryPointer &al)
700{
701 clientConnectionManager = aMgr;
702
703 if (!clientConnectionManager.valid())
704 return;
705
706 AnyP::PortCfgPointer port = clientConnectionManager->port;
707 if (port) {
708 myportname = port->name;
709 flags.ignoreCc = port->ignore_cc;
710 }
711
712 if (auto clientConnection = clientConnectionManager->clientConnection) {
713 client_addr = clientConnection->remote; // XXX: remove request->client_addr member.
714#if FOLLOW_X_FORWARDED_FOR
715 // indirect client gets stored here because it is an HTTP header result (from X-Forwarded-For:)
716 // not details about the TCP connection itself
717 indirect_client_addr = clientConnection->remote;
718#endif /* FOLLOW_X_FORWARDED_FOR */
719 my_addr = clientConnection->local;
720
721 flags.intercepted = ((clientConnection->flags & COMM_INTERCEPTION) != 0);
722 flags.interceptTproxy = ((clientConnection->flags & COMM_TRANSPARENT) != 0 ) ;
723 const bool proxyProtocolPort = port ? port->flags.proxySurrogate : false;
724 if (flags.interceptTproxy && !proxyProtocolPort) {
725 if (Config.accessList.spoof_client_ip) {
726 ACLFilledChecklist *checklist = new ACLFilledChecklist(Config.accessList.spoof_client_ip, this, clientConnection->rfc931);
727 checklist->al = al;
728 flags.spoofClientIp = (checklist->fastCheck() == ACCESS_ALLOWED);
729 delete checklist;
730 } else
731 flags.spoofClientIp = true;
732 } else
733 flags.spoofClientIp = false;
734 }
735}