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