]> git.ipfire.org Git - thirdparty/squid.git/blame - src/HttpRequest.cc
Create Packable interface class
[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"
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);
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}
373
374/* packs request-line and headers, appends <crlf> terminator */
375void
5cafad19 376HttpRequest::pack(Packer * p)
a00a7c85 377{
5cafad19 378 assert(p);
a00a7c85 379 /* pack request-line */
d2a739f5
AJ
380 p->Printf(SQUIDSBUFPH " " SQUIDSTRINGPH " HTTP/%d.%d\r\n",
381 SQUIDSBUFPRINT(method.image()), SQUIDSTRINGPRINT(urlpath),
382 http_ver.major, http_ver.minor);
a00a7c85 383 /* headers */
a9925b40 384 header.packInto(p);
2246b732 385 /* trailer */
785b508d 386 p->append("\r\n", 2);
2246b732 387}
388
5cafad19 389/*
390 * A wrapper for debugObj()
391 */
2246b732 392void
5cafad19 393httpRequestPack(void *obj, Packer *p)
2246b732 394{
5cafad19 395 HttpRequest *request = static_cast<HttpRequest*>(obj);
396 request->pack(p);
99edd1c3 397}
eeb423fb 398
2246b732 399/* returns the length of request line + headers + crlf */
400int
5cafad19 401HttpRequest::prefixLen()
2246b732 402{
7f06a3d8 403 return method.image().length() + 1 +
5cafad19 404 urlpath.size() + 1 +
62e76326 405 4 + 1 + 3 + 2 +
5cafad19 406 header.len + 2;
2246b732 407}
99edd1c3 408
190154cf 409/* sync this routine when you update HttpRequest struct */
8596962e 410void
07947ad8 411HttpRequest::hdrCacheInit()
528b2c61 412{
07947ad8 413 HttpMsg::hdrCacheInit();
62e76326 414
66363092 415 assert(!range);
a9925b40 416 range = header.getRange();
528b2c61 417}
418
3ff65596 419#if ICAP_CLIENT
e1381638 420Adaptation::Icap::History::Pointer
3ff65596
AR
421HttpRequest::icapHistory() const
422{
423 if (!icapHistory_) {
38e16f92 424 if (Log::TheConfig.hasIcapToken || IcapLogfileStatus == LOG_ENABLE) {
3ff65596
AR
425 icapHistory_ = new Adaptation::Icap::History();
426 debugs(93,4, HERE << "made " << icapHistory_ << " for " << this);
427 }
428 }
429
430 return icapHistory_;
431}
432#endif
433
434#if USE_ADAPTATION
e1381638 435Adaptation::History::Pointer
a22e6cd3 436HttpRequest::adaptHistory(bool createIfNone) const
3ff65596 437{
a22e6cd3
AR
438 if (!adaptHistory_ && createIfNone) {
439 adaptHistory_ = new Adaptation::History();
440 debugs(93,4, HERE << "made " << adaptHistory_ << " for " << this);
3ff65596
AR
441 }
442
443 return adaptHistory_;
444}
a22e6cd3 445
e1381638 446Adaptation::History::Pointer
a22e6cd3
AR
447HttpRequest::adaptLogHistory() const
448{
38e16f92 449 return HttpRequest::adaptHistory(Log::TheConfig.hasAdaptToken);
a22e6cd3
AR
450}
451
aaf0559d
AR
452void
453HttpRequest::adaptHistoryImport(const HttpRequest &them)
454{
455 if (!adaptHistory_) {
456 adaptHistory_ = them.adaptHistory_; // may be nil
457 } else {
458 // check that histories did not diverge
459 Must(!them.adaptHistory_ || them.adaptHistory_ == adaptHistory_);
460 }
461}
462
3ff65596
AR
463#endif
464
528b2c61 465bool
190154cf 466HttpRequest::multipartRangeRequest() const
528b2c61 467{
9ad511b6 468 return (range && range->specs.size() > 1);
528b2c61 469}
8000a965 470
58217e94 471bool
9e008dda
AJ
472HttpRequest::bodyNibbled() const
473{
58217e94 474 return body_pipe != NULL && body_pipe->consumedSize() > 0;
475}
5f8252d2 476
64b66b76
CT
477void
478HttpRequest::detailError(err_type aType, int aDetail)
479{
480 if (errType || errDetail)
481 debugs(11, 5, HERE << "old error details: " << errType << '/' << errDetail);
482 debugs(11, 5, HERE << "current error details: " << aType << '/' << aDetail);
483 // checking type and detail separately may cause inconsistency, but
484 // may result in more details available if they only become available later
485 if (!errType)
486 errType = aType;
487 if (!errDetail)
488 errDetail = aDetail;
489}
490
129fe2a1
CT
491void
492HttpRequest::clearError()
493{
494 debugs(11, 7, HERE << "old error details: " << errType << '/' << errDetail);
495 errType = ERR_NONE;
496 errDetail = ERR_DETAIL_NONE;
497}
498
8596962e 499const char *HttpRequest::packableURI(bool full_uri) const
500{
501 if (full_uri)
502 return urlCanonical((HttpRequest*)this);
503
504 if (urlpath.size())
b4f2886c 505 return urlpath.termedBuf();
8596962e 506
507 return "/";
508}
509
510void HttpRequest::packFirstLineInto(Packer * p, bool full_uri) const
511{
512 // form HTTP request-line
d2a739f5
AJ
513 p->Printf(SQUIDSBUFPH " %s HTTP/%d.%d\r\n",
514 SQUIDSBUFPRINT(method.image()),
515 packableURI(full_uri),
516 http_ver.major, http_ver.minor);
8596962e 517}
8ddea643 518
519/*
684e9c80 520 * Indicate whether or not we would expect an entity-body
8ddea643 521 * along with this request
522 */
523bool
ced8def3 524HttpRequest::expectingBody(const HttpRequestMethod &, int64_t &theSize) const
8ddea643 525{
526 bool expectBody = false;
527
528 /*
684e9c80
HN
529 * Note: Checks for message validity is in clientIsContentLengthValid().
530 * this just checks if a entity-body is expected based on HTTP message syntax
8ddea643 531 */
684e9c80 532 if (header.chunked()) {
8ddea643 533 expectBody = true;
684e9c80
HN
534 theSize = -1;
535 } else if (content_length >= 0) {
8ddea643 536 expectBody = true;
684e9c80
HN
537 theSize = content_length;
538 } else {
8ddea643 539 expectBody = false;
684e9c80 540 // theSize undefined
8ddea643 541 }
542
543 return expectBody;
544}
c21ad0f5 545
546/*
547 * Create a Request from a URL and METHOD.
548 *
549 * If the METHOD is CONNECT, then a host:port pair is looked for instead of a URL.
550 * If the request cannot be created cleanly, NULL is returned
551 */
552HttpRequest *
60745f24 553HttpRequest::CreateFromUrlAndMethod(char * url, const HttpRequestMethod& method)
c21ad0f5 554{
555 return urlParse(method, url, NULL);
556}
557
558/*
559 * Create a Request from a URL.
560 *
561 * If the request cannot be created cleanly, NULL is returned
562 */
563HttpRequest *
564HttpRequest::CreateFromUrl(char * url)
565{
c2a7cefd 566 return urlParse(Http::METHOD_GET, url, NULL);
c21ad0f5 567}
610ee341 568
c2a7cefd 569/**
610ee341 570 * Are responses to this request possible cacheable ?
571 * If false then no matter what the response must not be cached.
572 */
573bool
c2a7cefd 574HttpRequest::maybeCacheable()
610ee341 575{
2962f8b8
AJ
576 // Intercepted request with Host: header which cannot be trusted.
577 // Because it failed verification, or someone bypassed the security tests
578 // we cannot cache the reponse for sharing between clients.
579 // TODO: update cache to store for particular clients only (going to same Host: and destination IP)
0d901ef4 580 if (!flags.hostVerified && (flags.intercepted || flags.interceptTproxy))
2962f8b8
AJ
581 return false;
582
4e3f4dc7 583 switch (url.getScheme()) {
c2a7cefd 584 case AnyP::PROTO_HTTP:
2c32c73e 585 case AnyP::PROTO_HTTPS:
c2a7cefd
AJ
586 if (!method.respMaybeCacheable())
587 return false;
9e008dda 588
c2a7cefd
AJ
589 // XXX: this would seem the correct place to detect request cache-controls
590 // no-store, private and related which block cacheability
591 break;
610ee341 592
c2a7cefd
AJ
593 case AnyP::PROTO_GOPHER:
594 if (!gopherCachable(this))
595 return false;
596 break;
610ee341 597
c2a7cefd 598 case AnyP::PROTO_CACHE_OBJECT:
60745f24 599 return false;
610ee341 600
f53969cc 601 //case AnyP::PROTO_FTP:
c2a7cefd
AJ
602 default:
603 break;
604 }
605
60745f24 606 return true;
610ee341 607}
d67acb4e 608
79c8035e
AR
609bool
610HttpRequest::conditional() const
611{
45e5102d 612 return flags.ims ||
b59e6847
A
613 header.has(HDR_IF_MATCH) ||
614 header.has(HDR_IF_NONE_MATCH);
79c8035e
AR
615}
616
d5964067 617void
4a3b98d7 618HttpRequest::recordLookup(const Dns::LookupDetails &dns)
3ff65596
AR
619{
620 if (dns.wait >= 0) { // known delay
621 if (dnsWait >= 0) // have recorded DNS wait before
622 dnsWait += dns.wait;
623 else
624 dnsWait = dns.wait;
625 }
626}
11e3fa1c
AJ
627
628int64_t
629HttpRequest::getRangeOffsetLimit()
630{
631 /* -2 is the starting value of rangeOffsetLimit.
632 * If it is -2, that means we haven't checked it yet.
633 * Otherwise, return the current value */
5e5f247c 634 if (rangeOffsetLimit != -2)
11e3fa1c
AJ
635 return rangeOffsetLimit;
636
637 rangeOffsetLimit = 0; // default value for rangeOffsetLimit
638
639 ACLFilledChecklist ch(NULL, this, NULL);
640 ch.src_addr = client_addr;
641 ch.my_addr = my_addr;
642
1328cfb7 643 for (AclSizeLimit *l = Config.rangeOffsetLimit; l; l = l -> next) {
11e3fa1c 644 /* if there is no ACL list or if the ACLs listed match use this limit value */
2efeb0b7 645 if (!l->aclList || ch.fastCheck(l->aclList) == ACCESS_ALLOWED) {
11e3fa1c
AJ
646 debugs(58, 4, HERE << "rangeOffsetLimit=" << rangeOffsetLimit);
647 rangeOffsetLimit = l->size; // may be -1
648 break;
649 }
650 }
651
652 return rangeOffsetLimit;
653}
655daa06 654
f0baf149
AR
655void
656HttpRequest::ignoreRange(const char *reason)
657{
658 if (range) {
659 debugs(73, 3, static_cast<void*>(range) << " for " << reason);
660 delete range;
661 range = NULL;
662 }
663 // Some callers also reset isRanged but it may not be safe for all callers:
664 // isRanged is used to determine whether a weak ETag comparison is allowed,
665 // and that check should not ignore the Range header if it was present.
666 // TODO: Some callers also delete HDR_RANGE, HDR_REQUEST_RANGE. Should we?
667}
668
655daa06
AR
669bool
670HttpRequest::canHandle1xx() const
671{
672 // old clients do not support 1xx unless they sent Expect: 100-continue
673 // (we reject all other HDR_EXPECT values so just check for HDR_EXPECT)
526ed14e 674 if (http_ver <= Http::ProtocolVersion(1,0) && !header.has(HDR_EXPECT))
655daa06
AR
675 return false;
676
677 // others must support 1xx control messages
678 return true;
679}
582c2af2
FC
680
681ConnStateData *
b0fb853f
A
682HttpRequest::pinnedConnection()
683{
582c2af2
FC
684 if (clientConnectionManager.valid() && clientConnectionManager->pinning.pinned)
685 return clientConnectionManager.get();
686 return NULL;
687}
a8a0b1c2
EC
688
689const char *
690HttpRequest::storeId()
691{
692 if (store_id.size() != 0) {
693 debugs(73, 3, "sent back store_id:" << store_id);
694
695 return store_id.termedBuf();
696 }
697 debugs(73, 3, "sent back canonicalUrl:" << urlCanonical(this) );
698
699 return urlCanonical(this);
700}
f53969cc 701