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