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