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