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