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