]> git.ipfire.org Git - thirdparty/squid.git/blame - src/http.cc
Bug #1479: wrong timezone declaration for 64 bit Irix
[thirdparty/squid.git] / src / http.cc
CommitLineData
da2b3a17 1
30a4f2a8 2/*
5cafad19 3 * $Id: http.cc,v 1.482 2006/01/19 18:40:28 wessels Exp $
30a4f2a8 4 *
5 * DEBUG: section 11 Hypertext Transfer Protocol (HTTP)
6 * AUTHOR: Harvest Derived
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 9 * ----------------------------------------------------------
30a4f2a8 10 *
2b6662ba 11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
30a4f2a8 19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
cbdec147 32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 33 *
30a4f2a8 34 */
019dd986 35
4a83b852 36/*
37 * Anonymizing patch by lutz@as-node.jena.thur.de
de3bdb4c 38 * have a look into http-anon.c to get more informations.
4a83b852 39 */
40
44a47c6e 41#include "squid.h"
0eb49b6d 42#include "MemBuf.h"
e6ccf245 43#include "http.h"
f5691f9c 44#include "AuthUserRequest.h"
e6ccf245 45#include "Store.h"
528b2c61 46#include "HttpReply.h"
47#include "HttpRequest.h"
48#include "MemObject.h"
49#include "HttpHdrContRange.h"
4fb35c3c 50#include "ACLChecklist.h"
21b92762 51#include "fde.h"
b67e2c8c 52#if DELAY_POOLS
53#include "DelayPools.h"
54#endif
2afaba07 55#if ICAP_CLIENT
56#include "ICAP/ICAPClientRespmodPrecache.h"
57#include "ICAP/ICAPConfig.h"
ab7ac359 58extern ICAPConfig TheICAPConfig;
2afaba07 59#endif
e6ccf245 60
2afaba07 61CBDATA_CLASS_INIT(HttpStateData);
090089c4 62
6bf8443a 63static const char *const crlf = "\r\n";
4db43fab 64
9e4ad609 65static PF httpStateFree;
66static PF httpTimeout;
f5b8bbc4 67static void httpCacheNegatively(StoreEntry *);
68static void httpMakePrivate(StoreEntry *);
69static void httpMakePublic(StoreEntry *);
f9cece6e 70static void httpMaybeRemovePublic(StoreEntry *, http_status);
190154cf 71static void copyOneHeaderFromClientsideRequestToUpstreamRequest(const HttpHeaderEntry *e, String strConnection, HttpRequest * request, HttpRequest * orig_request,
62e76326 72 HttpHeader * hdr_out, int we_do_ranges, http_state_flags);
2afaba07 73#if ICAP_CLIENT
74static void icapAclCheckDoneWrapper(ICAPServiceRep::Pointer service, void *data);
75#endif
528b2c61 76
a3d50c30 77HttpStateData::HttpStateData(FwdState *theFwdState)
2bb867b5 78{
79 debugs(11,5,HERE << "HttpStateData " << this << " created");
a3d50c30 80 ignoreCacheControl = false;
81 surrogateNoStore = false;
82 fwd = theFwdState;
83 entry = fwd->entry;
84 storeLockObject(entry);
85 fd = fwd->server_fd;
86 readBuf = new MemBuf;
87 readBuf->init(4096, SQUID_TCP_SO_RCVBUF);
88 orig_request = requestLink(fwd->request);
89
90 if (fwd->servers)
91 _peer = fwd->servers->_peer; /* might be NULL */
92
93 if (_peer) {
94 const char *url;
95
96 if (_peer->options.originserver)
97 url = orig_request->urlpath.buf();
98 else
99 url = storeUrl(entry);
100
5cafad19 101 HttpRequest * proxy_req = new HttpRequest(orig_request->method,
102 orig_request->protocol, url);
a3d50c30 103
104 xstrncpy(proxy_req->host, _peer->host, SQUIDHOSTNAMELEN);
105
106 proxy_req->port = _peer->http_port;
107
108 proxy_req->flags = orig_request->flags;
109
110 proxy_req->lastmod = orig_request->lastmod;
111
112 proxy_req->flags.proxying = 1;
113
114 request = requestLink(proxy_req);
115
116 /*
117 * This NEIGHBOR_PROXY_ONLY check probably shouldn't be here.
118 * We might end up getting the object from somewhere else if,
119 * for example, the request to this neighbor fails.
120 */
121 if (_peer->options.proxy_only)
122 storeReleaseRequest(entry);
123
124#if DELAY_POOLS
125
126 entry->setNoDelay(_peer->options.no_delay);
127
128#endif
129
130 } else {
131 request = requestLink(orig_request);
132 }
133
134 /*
135 * register the handler to free HTTP state data when the FD closes
136 */
137 comm_add_close_handler(fd, httpStateFree, this);
2bb867b5 138}
b8d8561b 139
2afaba07 140HttpStateData::~HttpStateData()
f5558c95 141{
2afaba07 142 if (request_body_buf) {
143 if (orig_request->body_connection.getRaw()) {
144 clientAbortBody(orig_request);
9ea12fca 145 }
21b92762 146
2afaba07 147 if (request_body_buf) {
148 memFree(request_body_buf, MEM_8K_BUF);
149 request_body_buf = NULL;
21b92762 150 }
151 }
152
2afaba07 153 storeUnlockObject(entry);
154
155 if (!readBuf->isNull())
156 readBuf->clean();
62e76326 157
2afaba07 158 delete readBuf;
159
160 requestUnlink(request);
161
162 requestUnlink(orig_request);
163
164 request = NULL;
165
166 orig_request = NULL;
167
b6b6f466 168 fwd = NULL; // refcounted
169
2afaba07 170 if (reply)
171 delete reply;
172
173#if ICAP_CLIENT
174
175 if (icap) {
176 delete icap;
177 cbdataReferenceDone(icap);
0d4d4170 178 }
62e76326 179
2afaba07 180#endif
2bb867b5 181 debugs(11,5,HERE << "HttpStateData " << this << " destroyed");
2afaba07 182}
183
184static void
185httpStateFree(int fd, void *data)
186{
187 HttpStateData *httpState = static_cast<HttpStateData *>(data);
188 debug(11,5)("httpStateFree: FD %d, httpState=%p\n", fd, data);
189
190 if (httpState)
191 delete httpState;
f5558c95 192}
193
b8d8561b 194int
75e88d56 195httpCachable(method_t method)
090089c4 196{
090089c4 197 /* GET and HEAD are cachable. Others are not. */
62e76326 198
6eb42cae 199 if (method != METHOD_GET && method != METHOD_HEAD)
62e76326 200 return 0;
201
090089c4 202 /* else cachable */
203 return 1;
204}
205
b8d8561b 206static void
5c5783a2 207httpTimeout(int fd, void *data)
090089c4 208{
e6ccf245 209 HttpStateData *httpState = static_cast<HttpStateData *>(data);
593c9a75 210 StoreEntry *entry = httpState->entry;
9fb13bb6 211 debug(11, 4) ("httpTimeout: FD %d: '%s'\n", fd, storeUrl(entry));
62e76326 212
12158bdc 213 if (entry->store_status == STORE_PENDING) {
b6b6f466 214 httpState->fwd->fail(errorCon(ERR_READ_TIMEOUT, HTTP_GATEWAY_TIMEOUT));
9b312a19 215 }
62e76326 216
0d4d4170 217 comm_close(fd);
090089c4 218}
219
30a4f2a8 220/* This object can be cached for a long time */
b8d8561b 221static void
222httpMakePublic(StoreEntry * entry)
30a4f2a8 223{
d46a87a8 224 if (EBIT_TEST(entry->flags, ENTRY_CACHABLE))
62e76326 225 storeSetPublicKey(entry);
30a4f2a8 226}
227
228/* This object should never be cached at all */
b8d8561b 229static void
230httpMakePrivate(StoreEntry * entry)
30a4f2a8 231{
30a4f2a8 232 storeExpireNow(entry);
30a4f2a8 233 storeReleaseRequest(entry); /* delete object when not used */
f3e570e9 234 /* storeReleaseRequest clears ENTRY_CACHABLE flag */
30a4f2a8 235}
236
237/* This object may be negatively cached */
b8d8561b 238static void
239httpCacheNegatively(StoreEntry * entry)
30a4f2a8 240{
79b5cc5f 241 storeNegativeCache(entry);
62e76326 242
d46a87a8 243 if (EBIT_TEST(entry->flags, ENTRY_CACHABLE))
62e76326 244 storeSetPublicKey(entry);
30a4f2a8 245}
246
f9cece6e 247static void
248httpMaybeRemovePublic(StoreEntry * e, http_status status)
249{
62e76326 250
251 int remove
252 = 0;
253
7e3ce7b9 254 int forbidden = 0;
62e76326 255
f9cece6e 256 StoreEntry *pe;
62e76326 257
d46a87a8 258 if (!EBIT_TEST(e->flags, KEY_PRIVATE))
62e76326 259 return;
260
f9cece6e 261 switch (status) {
62e76326 262
f9cece6e 263 case HTTP_OK:
62e76326 264
f9cece6e 265 case HTTP_NON_AUTHORITATIVE_INFORMATION:
62e76326 266
f9cece6e 267 case HTTP_MULTIPLE_CHOICES:
62e76326 268
f9cece6e 269 case HTTP_MOVED_PERMANENTLY:
62e76326 270
f9cece6e 271 case HTTP_MOVED_TEMPORARILY:
62e76326 272
f9cece6e 273 case HTTP_GONE:
62e76326 274
7e3ce7b9 275 case HTTP_NOT_FOUND:
62e76326 276
277 remove
278 = 1;
279
280 break;
281
7e3ce7b9 282 case HTTP_FORBIDDEN:
62e76326 283
7e3ce7b9 284 case HTTP_METHOD_NOT_ALLOWED:
62e76326 285 forbidden = 1;
286
287 break;
288
f9cece6e 289#if WORK_IN_PROGRESS
62e76326 290
c8fd0193 291 case HTTP_UNAUTHORIZED:
62e76326 292 forbidden = 1;
293
294 break;
295
f9cece6e 296#endif
62e76326 297
f9cece6e 298 default:
7e3ce7b9 299#if QUESTIONABLE
62e76326 300 /*
301 * Any 2xx response should eject previously cached entities...
302 */
abb929f0 303
62e76326 304 if (status >= 200 && status < 300)
305 remove
306 = 1;
307
7e3ce7b9 308#endif
62e76326 309
310 break;
f9cece6e 311 }
62e76326 312
313 if (!remove
314 && !forbidden)
315 return;
316
f9cece6e 317 assert(e->mem_obj);
62e76326 318
f66a9ef4 319 if (e->mem_obj->request)
62e76326 320 pe = storeGetPublicByRequest(e->mem_obj->request);
f66a9ef4 321 else
62e76326 322 pe = storeGetPublic(e->mem_obj->url, e->mem_obj->method);
323
f66a9ef4 324 if (pe != NULL) {
62e76326 325 assert(e != pe);
326 storeRelease(pe);
0856d155 327 }
62e76326 328
7e3ce7b9 329 /*
330 * Also remove any cached HEAD response in case the object has
331 * changed.
332 */
f66a9ef4 333 if (e->mem_obj->request)
62e76326 334 pe = storeGetPublicByRequestMethod(e->mem_obj->request, METHOD_HEAD);
f66a9ef4 335 else
62e76326 336 pe = storeGetPublic(e->mem_obj->url, METHOD_HEAD);
337
f66a9ef4 338 if (pe != NULL) {
62e76326 339 assert(e != pe);
340 storeRelease(pe);
7e3ce7b9 341 }
62e76326 342
7e3ce7b9 343 if (forbidden)
62e76326 344 return;
345
7e3ce7b9 346 switch (e->mem_obj->method) {
62e76326 347
7e3ce7b9 348 case METHOD_PUT:
62e76326 349
7e3ce7b9 350 case METHOD_DELETE:
62e76326 351
7e3ce7b9 352 case METHOD_PROPPATCH:
62e76326 353
7e3ce7b9 354 case METHOD_MKCOL:
62e76326 355
7e3ce7b9 356 case METHOD_MOVE:
62e76326 357
42b51993 358 case METHOD_BMOVE:
62e76326 359
42b51993 360 case METHOD_BDELETE:
62e76326 361 /*
362 * Remove any cached GET object if it is beleived that the
363 * object may have changed as a result of other methods
364 */
365
366 if (e->mem_obj->request)
367 pe = storeGetPublicByRequestMethod(e->mem_obj->request, METHOD_GET);
368 else
369 pe = storeGetPublic(e->mem_obj->url, METHOD_GET);
370
371 if (pe != NULL) {
372 assert(e != pe);
373 storeRelease(pe);
374 }
375
376 break;
377
c8be6d7b 378 default:
62e76326 379 /* Keep GCC happy. The methods above are all mutating HTTP methods
380 */
381 break;
0856d155 382 }
f9cece6e 383}
384
43ae1d95 385void
386HttpStateData::processSurrogateControl(HttpReply *reply)
387{
388#if ESI
389
390 if (request->flags.accelerated && reply->surrogate_control) {
391 HttpHdrScTarget *sctusable =
392 httpHdrScGetMergedTarget(reply->surrogate_control,
393 Config.Accel.surrogate_id);
394
395 if (sctusable) {
396 if (EBIT_TEST(sctusable->mask, SC_NO_STORE) ||
397 (Config.onoff.surrogate_is_remote
398 && EBIT_TEST(sctusable->mask, SC_NO_STORE_REMOTE))) {
399 surrogateNoStore = true;
400 httpMakePrivate(entry);
401 }
402
403 /* The HttpHeader logic cannot tell if the header it's parsing is a reply to an
404 * accelerated request or not...
405 * Still, this is an abtraction breach. - RC
406 */
407 if (sctusable->max_age != -1) {
408 if (sctusable->max_age < sctusable->max_stale)
409 reply->expires = reply->date + sctusable->max_age;
410 else
411 reply->expires = reply->date + sctusable->max_stale;
412
413 /* And update the timestamps */
414 storeTimestampsSet(entry);
415 }
416
417 /* We ignore cache-control directives as per the Surrogate specification */
418 ignoreCacheControl = true;
419
420 httpHdrScTargetDestroy(sctusable);
421 }
422 }
423
424#endif
425}
426
924f73bc 427int
428HttpStateData::cacheableReply()
c54e9052 429{
2afaba07 430 HttpReply const *rep = getReply();
528b2c61 431 HttpHeader const *hdr = &rep->header;
d8b249ef 432 const int cc_mask = (rep->cache_control) ? rep->cache_control->mask : 0;
c68e9c6b 433 const char *v;
38f9c547 434#if HTTP_VIOLATIONS
62e76326 435
38f9c547 436 const refresh_t *R = NULL;
437#endif
43ae1d95 438
38f9c547 439 if (surrogateNoStore)
62e76326 440 return 0;
441
924f73bc 442 if (!ignoreCacheControl) {
38f9c547 443 if (EBIT_TEST(cc_mask, CC_PRIVATE)) {
444#if HTTP_VIOLATIONS
43ae1d95 445
38f9c547 446 if (!R)
447 R = refreshLimits(entry->mem_obj->url);
43ae1d95 448
38f9c547 449 if (R && !R->flags.ignore_private)
450#endif
451
452 return 0;
453 }
454
455 if (EBIT_TEST(cc_mask, CC_NO_CACHE)) {
456#if HTTP_VIOLATIONS
457
458 if (!R)
459 R = refreshLimits(entry->mem_obj->url);
460
461 if (R && !R->flags.ignore_no_cache)
462#endif
463
464 return 0;
465 }
466
467 if (EBIT_TEST(cc_mask, CC_NO_STORE)) {
468#if HTTP_VIOLATIONS
469
470 if (!R)
471 R = refreshLimits(entry->mem_obj->url);
472
473 if (R && !R->flags.ignore_no_store)
474#endif
475
476 return 0;
477 }
43ae1d95 478 }
479
924f73bc 480 if (request->flags.auth) {
62e76326 481 /*
482 * Responses to requests with authorization may be cached
483 * only if a Cache-Control: public reply header is present.
484 * RFC 2068, sec 14.9.4
485 */
486
38f9c547 487 if (!EBIT_TEST(cc_mask, CC_PUBLIC)) {
488#if HTTP_VIOLATIONS
489
490 if (!R)
491 R = refreshLimits(entry->mem_obj->url);
492
493 if (R && !R->flags.ignore_auth)
494#endif
495
496 return 0;
497 }
a6dfe2d9 498 }
62e76326 499
c68e9c6b 500 /* Pragma: no-cache in _replies_ is not documented in HTTP,
501 * but servers like "Active Imaging Webcast/2.0" sure do use it */
502 if (httpHeaderHas(hdr, HDR_PRAGMA)) {
62e76326 503 String s = httpHeaderGetList(hdr, HDR_PRAGMA);
504 const int no_cache = strListIsMember(&s, "no-cache", ',');
505 s.clean();
506
38f9c547 507 if (no_cache) {
508#if HTTP_VIOLATIONS
509
510 if (!R)
511 R = refreshLimits(entry->mem_obj->url);
512
513 if (R && !R->flags.ignore_no_cache)
514#endif
515
516 return 0;
517 }
c68e9c6b 518 }
62e76326 519
c68e9c6b 520 /*
521 * The "multipart/x-mixed-replace" content type is used for
522 * continuous push replies. These are generally dynamic and
523 * probably should not be cachable
524 */
525 if ((v = httpHeaderGetStr(hdr, HDR_CONTENT_TYPE)))
62e76326 526 if (!strncasecmp(v, "multipart/x-mixed-replace", 25))
527 return 0;
528
2afaba07 529 switch (getReply()->sline.status) {
62e76326 530 /* Responses that are cacheable */
531
19a04dac 532 case HTTP_OK:
62e76326 533
19a04dac 534 case HTTP_NON_AUTHORITATIVE_INFORMATION:
62e76326 535
19a04dac 536 case HTTP_MULTIPLE_CHOICES:
62e76326 537
19a04dac 538 case HTTP_MOVED_PERMANENTLY:
62e76326 539
19a04dac 540 case HTTP_GONE:
62e76326 541 /*
542 * Don't cache objects that need to be refreshed on next request,
543 * unless we know how to refresh it.
544 */
545
924f73bc 546 if (!refreshIsCachable(entry))
62e76326 547 return 0;
548
549 /* don't cache objects from peers w/o LMT, Date, or Expires */
550 /* check that is it enough to check headers @?@ */
551 if (rep->date > -1)
552 return 1;
553 else if (rep->last_modified > -1)
554 return 1;
924f73bc 555 else if (!_peer)
62e76326 556 return 1;
557
558 /* @?@ (here and 302): invalid expires header compiles to squid_curtime */
559 else if (rep->expires > -1)
560 return 1;
561 else
562 return 0;
563
564 /* NOTREACHED */
565 break;
566
567 /* Responses that only are cacheable if the server says so */
568
19a04dac 569 case HTTP_MOVED_TEMPORARILY:
62e76326 570 if (rep->expires > -1)
571 return 1;
572 else
573 return 0;
574
575 /* NOTREACHED */
576 break;
577
578 /* Errors can be negatively cached */
579
19a04dac 580 case HTTP_NO_CONTENT:
62e76326 581
19a04dac 582 case HTTP_USE_PROXY:
62e76326 583
19a04dac 584 case HTTP_BAD_REQUEST:
62e76326 585
19a04dac 586 case HTTP_FORBIDDEN:
62e76326 587
19a04dac 588 case HTTP_NOT_FOUND:
62e76326 589
19a04dac 590 case HTTP_METHOD_NOT_ALLOWED:
62e76326 591
19a04dac 592 case HTTP_REQUEST_URI_TOO_LARGE:
62e76326 593
19a04dac 594 case HTTP_INTERNAL_SERVER_ERROR:
62e76326 595
19a04dac 596 case HTTP_NOT_IMPLEMENTED:
62e76326 597
19a04dac 598 case HTTP_BAD_GATEWAY:
62e76326 599
19a04dac 600 case HTTP_SERVICE_UNAVAILABLE:
62e76326 601
19a04dac 602 case HTTP_GATEWAY_TIMEOUT:
62e76326 603 return -1;
604
605 /* NOTREACHED */
606 break;
607
608 /* Some responses can never be cached */
609
0cdcddb9 610 case HTTP_PARTIAL_CONTENT: /* Not yet supported */
62e76326 611
19a04dac 612 case HTTP_SEE_OTHER:
62e76326 613
19a04dac 614 case HTTP_NOT_MODIFIED:
62e76326 615
19a04dac 616 case HTTP_UNAUTHORIZED:
62e76326 617
19a04dac 618 case HTTP_PROXY_AUTHENTICATION_REQUIRED:
62e76326 619
0cdcddb9 620 case HTTP_INVALID_HEADER: /* Squid header parsing error */
4eb368f9 621
622 case HTTP_HEADER_TOO_LARGE:
62e76326 623 return 0;
624
c54e9052 625 default: /* Unknown status code */
924f73bc 626 debug (11,0)("HttpStateData::cacheableReply: unknown http status code in reply\n");
62e76326 627
628 return 0;
629
630 /* NOTREACHED */
631 break;
c54e9052 632 }
62e76326 633
79d39a72 634 /* NOTREACHED */
c54e9052 635}
090089c4 636
f66a9ef4 637/*
638 * For Vary, store the relevant request headers as
639 * virtual headers in the reply
640 * Returns false if the variance cannot be stored
641 */
642const char *
190154cf 643httpMakeVaryMark(HttpRequest * request, HttpReply const * reply)
f66a9ef4 644{
f66a9ef4 645 String vary, hdr;
646 const char *pos = NULL;
647 const char *item;
648 const char *value;
649 int ilen;
528b2c61 650 static String vstr;
f66a9ef4 651
528b2c61 652 vstr.clean();
f66a9ef4 653 vary = httpHeaderGetList(&reply->header, HDR_VARY);
62e76326 654
f66a9ef4 655 while (strListGetItem(&vary, ',', &item, &ilen, &pos)) {
62e76326 656 char *name = (char *)xmalloc(ilen + 1);
657 xstrncpy(name, item, ilen + 1);
658 Tolower(name);
9776e3cc 659
660 if (strcmp(name, "*") == 0) {
661 /* Can not handle "Vary: *" withtout ETag support */
662 safe_free(name);
663 vstr.clean();
664 break;
665 }
666
62e76326 667 strListAdd(&vstr, name, ',');
668 hdr = httpHeaderGetByName(&request->header, name);
669 safe_free(name);
670 value = hdr.buf();
671
672 if (value) {
673 value = rfc1738_escape_part(value);
674 vstr.append("=\"", 2);
675 vstr.append(value);
676 vstr.append("\"", 1);
677 }
678
679 hdr.clean();
f66a9ef4 680 }
62e76326 681
528b2c61 682 vary.clean();
f66a9ef4 683#if X_ACCELERATOR_VARY
62e76326 684
aa38be4a 685 pos = NULL;
f66a9ef4 686 vary = httpHeaderGetList(&reply->header, HDR_X_ACCELERATOR_VARY);
62e76326 687
f66a9ef4 688 while (strListGetItem(&vary, ',', &item, &ilen, &pos)) {
62e76326 689 char *name = (char *)xmalloc(ilen + 1);
690 xstrncpy(name, item, ilen + 1);
691 Tolower(name);
692 strListAdd(&vstr, name, ',');
693 hdr = httpHeaderGetByName(&request->header, name);
694 safe_free(name);
695 value = hdr.buf();
696
697 if (value) {
698 value = rfc1738_escape_part(value);
699 vstr.append("=\"", 2);
700 vstr.append(value);
701 vstr.append("\"", 1);
702 }
703
704 hdr.clean();
f66a9ef4 705 }
62e76326 706
528b2c61 707 vary.clean();
f66a9ef4 708#endif
62e76326 709
528b2c61 710 debug(11, 3) ("httpMakeVaryMark: %s\n", vstr.buf());
711 return vstr.buf();
f66a9ef4 712}
713
4eb368f9 714void
715HttpStateData::failReply(HttpReply *reply, http_status const & status)
716{
717 reply->sline.version = HttpVersion(1, 0);
718 reply->sline.status = status;
719 storeEntryReplaceObject (entry, reply);
720
721 if (eof == 1) {
2afaba07 722 transactionComplete();
4eb368f9 723 }
724}
725
2afaba07 726void
727HttpStateData::keepaliveAccounting(HttpReply *reply)
728{
729 if (flags.keepalive)
730 if (_peer)
731 _peer->stats.n_keepalives_sent++;
732
733 if (reply->keep_alive) {
734 if (_peer)
735 _peer->stats.n_keepalives_recv++;
736
737 if (Config.onoff.detect_broken_server_pconns && reply->bodySize(request->method) == -1) {
738 debug(11, 1) ("keepaliveAccounting: Impossible keep-alive header from '%s'\n", storeUrl(entry));
739 // debug(11, 2) ("GOT HTTP REPLY HDR:\n---------\n%s\n----------\n", readBuf->content());
740 flags.keepalive_broken = 1;
741 }
742 }
743}
744
745void
746HttpStateData::checkDateSkew(HttpReply *reply)
747{
748 if (reply->date > -1 && !_peer) {
749 int skew = abs((int)(reply->date - squid_curtime));
750
751 if (skew > 86400)
752 debug(11, 3) ("%s's clock is skewed by %d seconds!\n",
753 request->host, skew);
754 }
755}
756
757/*
4eb368f9 758 * This creates the error page itself.. its likely
759 * that the forward ported reply header max size patch
760 * generates non http conformant error pages - in which
761 * case the errors where should be 'BAD_GATEWAY' etc
762 */
b8d8561b 763void
2afaba07 764HttpStateData::processReplyHeader()
f5558c95 765{
528b2c61 766 /* Creates a blank header. If this routine is made incremental, this will
767 * not do
768 */
2afaba07 769 reply = new HttpReply;
82384411 770 Ctx ctx = ctx_enter(entry->mem_obj->url);
2afaba07 771 debug(11, 3) ("processReplyHeader: key '%s'\n", entry->getMD5Text());
62e76326 772
1a98175f 773 assert(!flags.headers_parsed);
62e76326 774
2afaba07 775 http_status error = HTTP_STATUS_NONE;
62e76326 776
2afaba07 777 const bool parsed = reply->parse(readBuf, eof, &error);
62e76326 778
2afaba07 779 if (!parsed && error > 0) { // unrecoverable parsing error
780 debugs(11, 3, "processReplyHeader: Non-HTTP-compliant header: '" << readBuf->content() << "'");
1a98175f 781 flags.headers_parsed = 1;
2afaba07 782 // negated result yields http_status
783 failReply (reply, error); // consumes reply
784 reply = NULL;
82384411 785 ctx_exit(ctx);
4eb368f9 786 return;
787 }
62e76326 788
2afaba07 789 if (!parsed) { // need more data
790 assert(!error);
791 assert(!eof);
792 delete reply;
793 reply = NULL;
82384411 794 ctx_exit(ctx);
62e76326 795 return;
f5558c95 796 }
62e76326 797
9bc73deb 798 debug(11, 9) ("GOT HTTP REPLY HDR:\n---------\n%s\n----------\n",
2afaba07 799 readBuf->content());
4eb368f9 800
6965ab28 801 readBuf->consume(headersEnd(readBuf->content(), readBuf->contentSize()));
802 flags.headers_parsed = 1;
803
2afaba07 804 keepaliveAccounting(reply);
47ac2ebe 805
2afaba07 806 checkDateSkew(reply);
47ac2ebe 807
43ae1d95 808 processSurrogateControl (reply);
528b2c61 809
810 /* TODO: IF the reply is a 1.0 reply, AND it has a Connection: Header
811 * Parse the header and remove all referenced headers
812 */
813
2afaba07 814#if ICAP_CLIENT
815
ab7ac359 816 if (TheICAPConfig.onoff) {
2afaba07 817 ICAPAccessCheck *icap_access_check =
818 new ICAPAccessCheck(ICAP::methodRespmod, ICAP::pointPreCache, request, reply, icapAclCheckDoneWrapper, this);
819
820 icapAccessCheckPending = true;
821 icap_access_check->check(); // will eventually delete self
822 ctx_exit(ctx);
823 return;
824 }
ab7ac359 825
2afaba07 826#endif
827
528b2c61 828 storeEntryReplaceObject(entry, reply);
2afaba07 829
830 /* Note storeEntryReplaceObject() consumes reply, so we cannot use it */
528b2c61 831 reply = NULL;
832
2afaba07 833 haveParsedReplyHeaders();
834
835 if (eof == 1) {
836 transactionComplete();
837 }
838
839 ctx_exit(ctx);
840}
841
842/*
843 * This function used to be joined with processReplyHeader(), but
844 * we split it for ICAP.
845 */
846void
847HttpStateData::haveParsedReplyHeaders()
848{
849 Ctx ctx = ctx_enter(entry->mem_obj->url);
850
851 if (getReply()->sline.status == HTTP_PARTIAL_CONTENT &&
852 getReply()->content_range)
853 currentOffset = getReply()->content_range->spec.offset;
62e76326 854
9bc73deb 855 storeTimestampsSet(entry);
62e76326 856
9bc73deb 857 /* Check if object is cacheable or not based on reply code */
2afaba07 858 debug(11, 3) ("haveParsedReplyHeaders: HTTP CODE: %d\n", getReply()->sline.status);
62e76326 859
9bc73deb 860 if (neighbors_do_private_keys)
2afaba07 861 httpMaybeRemovePublic(entry, getReply()->sline.status);
e6ccf245 862
2afaba07 863 if (httpHeaderHas(&getReply()->header, HDR_VARY)
f66a9ef4 864#if X_ACCELERATOR_VARY
2afaba07 865 || httpHeaderHas(&getReply()->header, HDR_X_ACCELERATOR_VARY)
f66a9ef4 866#endif
4b44c907 867 ) {
2afaba07 868 const char *vary = httpMakeVaryMark(orig_request, getReply());
4b44c907 869
870 if (!vary) {
871 httpMakePrivate(entry);
872 goto no_cache;
873
62e76326 874 }
875
4b44c907 876 entry->mem_obj->vary_headers = xstrdup(vary);
877 }
878
2afaba07 879#if WIP_FWD_LOG
880 fwdStatus(fwd, s);
881
882#endif
883 /*
884 * If its not a reply that we will re-forward, then
885 * allow the client to get it.
886 */
b6b6f466 887 if (!fwd->reforwardableStatus(getReply()->sline.status))
2afaba07 888 EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
889
4b44c907 890 switch (cacheableReply()) {
891
892 case 1:
893 httpMakePublic(entry);
62e76326 894 break;
895
9bc73deb 896 case 0:
62e76326 897 httpMakePrivate(entry);
898 break;
899
9bc73deb 900 case -1:
4b44c907 901
902 if (Config.negativeTtl > 0)
903 httpCacheNegatively(entry);
904 else
905 httpMakePrivate(entry);
906
62e76326 907 break;
908
9bc73deb 909 default:
62e76326 910 assert(0);
4b44c907 911
62e76326 912 break;
9bc73deb 913 }
62e76326 914
4b44c907 915no_cache:
916
2afaba07 917 if (!ignoreCacheControl && getReply()->cache_control) {
918 if (EBIT_TEST(getReply()->cache_control->mask, CC_PROXY_REVALIDATE))
62e76326 919 EBIT_SET(entry->flags, ENTRY_REVALIDATE);
2afaba07 920 else if (EBIT_TEST(getReply()->cache_control->mask, CC_MUST_REVALIDATE))
62e76326 921 EBIT_SET(entry->flags, ENTRY_REVALIDATE);
9bc73deb 922 }
62e76326 923
9bc73deb 924 ctx_exit(ctx);
c3609322 925#if HEADERS_LOG
62e76326 926
2afaba07 927 headersLog(1, 0, request->method, getReply());
c3609322 928#endif
f5558c95 929}
930
528b2c61 931HttpStateData::ConnectionStatus
932HttpStateData::statusIfComplete() const
603a02fd 933{
2afaba07 934 HttpReply const *rep = getReply();
528b2c61 935 /* If the reply wants to close the connection, it takes precedence */
62e76326 936
2afaba07 937 if (httpHeaderHasConnDir(&rep->header, "close"))
62e76326 938 return COMPLETE_NONPERSISTENT_MSG;
939
528b2c61 940 /* If we didn't send a keep-alive request header, then this
978e455f 941 * can not be a persistent connection.
942 */
528b2c61 943 if (!flags.keepalive)
62e76326 944 return COMPLETE_NONPERSISTENT_MSG;
945
72b63f06 946 /*
947 * If we haven't sent the whole request then this can not be a persistent
948 * connection.
949 */
950 if (!flags.request_sent) {
2afdbf48 951 debug(11, 1) ("statusIfComplete: Request not yet fully sent \"%s %s\"\n",
72b63f06 952 RequestMethodStr[orig_request->method],
953 storeUrl(entry));
954 return COMPLETE_NONPERSISTENT_MSG;
955 }
956
9f5a2895 957 /*
958 * What does the reply have to say about keep-alive?
959 */
b6a2f15e 960 /*
961 * XXX BUG?
962 * If the origin server (HTTP/1.0) does not send a keep-alive
963 * header, but keeps the connection open anyway, what happens?
964 * We'll return here and http.c waits for an EOF before changing
965 * store_status to STORE_OK. Combine this with ENTRY_FWD_HDR_WAIT
966 * and an error status code, and we might have to wait until
967 * the server times out the socket.
968 */
2afaba07 969 if (!rep->keep_alive)
528b2c61 970 return COMPLETE_NONPERSISTENT_MSG;
62e76326 971
528b2c61 972 return COMPLETE_PERSISTENT_MSG;
973}
974
975HttpStateData::ConnectionStatus
976HttpStateData::persistentConnStatus() const
977{
2afaba07 978 HttpReply const *reply = getReply();
528b2c61 979 int clen;
2afaba07 980 debug(11, 3) ("persistentConnStatus: FD %d\n", fd);
528b2c61 981 ConnectionStatus result = statusIfComplete();
2afaba07 982 debug(11, 5) ("persistentConnStatus: content_length=%d\n",
62e76326 983 reply->content_length);
35282fbf 984 /* If we haven't seen the end of reply headers, we are not done */
62e76326 985
2afaba07 986 debug(11,5)("persistentConnStatus: flags.headers_parsed=%d\n", flags.headers_parsed);
987
1a98175f 988 if (!flags.headers_parsed)
62e76326 989 return INCOMPLETE_MSG;
990
06a5ae20 991 clen = reply->bodySize(request->method);
62e76326 992
2afaba07 993 debug(11,5)("persistentConnStatus: clen=%d\n", clen);
994
35282fbf 995 /* If there is no message body, we can be persistent */
996 if (0 == clen)
62e76326 997 return result;
998
35282fbf 999 /* If the body size is unknown we must wait for EOF */
1000 if (clen < 0)
62e76326 1001 return INCOMPLETE_MSG;
1002
35282fbf 1003 /* If the body size is known, we must wait until we've gotten all of it. */
2afaba07 1004 /* old technique:
1005 * if (entry->mem_obj->endOffset() < reply->content_length + reply->hdr_sz) */
1006 debug(11,5)("persistentConnStatus: body_bytes_read=%d, content_length=%d\n",
1007 body_bytes_read, reply->content_length);
1008
1009 if (body_bytes_read < reply->content_length)
62e76326 1010 return INCOMPLETE_MSG;
1011
35282fbf 1012 /* We got it all */
528b2c61 1013 return result;
603a02fd 1014}
090089c4 1015
2afaba07 1016/*
1017 * This is the callback after some data has been read from the network
1018 */
e5ee81f0 1019void
1020HttpStateData::ReadReplyWrapper(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
c4b7a5a9 1021{
1022 HttpStateData *httpState = static_cast<HttpStateData *>(data);
7194987f 1023 assert (fd == httpState->fd);
2afaba07 1024 // assert(buf == readBuf->content());
1d5161bd 1025 PROF_start(HttpStateData_readReply);
2afaba07 1026 httpState->readReply (len, flag, xerrno);
1d5161bd 1027 PROF_stop(HttpStateData_readReply);
c4b7a5a9 1028}
1029
2afdbf48 1030/* XXX this function is too long! */
c4b7a5a9 1031void
2afaba07 1032HttpStateData::readReply (size_t len, comm_err_t flag, int xerrno)
090089c4 1033{
30a4f2a8 1034 int bin;
090089c4 1035 int clen;
f61f0107 1036 flags.do_next_read = 0;
c4b7a5a9 1037
2afaba07 1038 /*
1039 * Bail out early on COMM_ERR_CLOSING - close handlers will tidy up for us
1040 */
62e76326 1041
c4b7a5a9 1042 if (flag == COMM_ERR_CLOSING) {
d09176e1 1043 debug (11,3)("http socket closing\n");
c4b7a5a9 1044 return;
1045 }
1046
e92e4e44 1047 if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
62e76326 1048 maybeReadData();
1049 return;
e92e4e44 1050 }
c4b7a5a9 1051
1513873c 1052 errno = 0;
c4b7a5a9 1053 /* prepare the read size for the next read (if any) */
62e76326 1054
c4b7a5a9 1055 debug(11, 5) ("httpReadReply: FD %d: len %d.\n", fd, (int)len);
62e76326 1056
c4b7a5a9 1057 if (flag == COMM_OK && len > 0) {
2afaba07 1058 readBuf->appended(len);
447e176b 1059#if DELAY_POOLS
2afaba07 1060
1061 DelayId delayId = entry->mem_obj->mostBytesAllowed();
62e76326 1062 delayId.bytesIn(len);
447e176b 1063#endif
62e76326 1064
1065 kb_incr(&statCounter.server.all.kbytes_in, len);
1066 kb_incr(&statCounter.server.http.kbytes_in, len);
62e76326 1067 IOStats.Http.reads++;
1068
1069 for (clen = len - 1, bin = 0; clen; bin++)
1070 clen >>= 1;
1071
1072 IOStats.Http.read_hist[bin]++;
30a4f2a8 1073 }
62e76326 1074
5fa061b8 1075 /* here the RFC says we should ignore whitespace between replies, but we can't as
1076 * doing so breaks HTTP/0.9 replies beginning with witespace, and in addition
1077 * the response splitting countermeasures is extremely likely to trigger on this,
1078 * not allowing connection reuse in the first place.
1079 */
1080#if DONT_DO_THIS
1a98175f 1081 if (!flags.headers_parsed && flag == COMM_OK && len > 0 && fd_table[fd].uses > 1) {
5fa061b8 1082 /* Skip whitespace between replies */
62e76326 1083
5fa061b8 1084 while (len > 0 && isspace(*buf))
62e76326 1085 xmemmove(buf, buf + 1, len--);
1086
1087 if (len == 0) {
1088 /* Continue to read... */
21b92762 1089 /* Timeout NOT increased. This whitespace was from previous reply */
f61f0107 1090 flags.do_next_read = 1;
62e76326 1091 maybeReadData();
1092 return;
1093 }
5ede6c8f 1094 }
62e76326 1095
5fa061b8 1096#endif
1097
c4b7a5a9 1098 if (flag != COMM_OK || len < 0) {
62e76326 1099 debug(50, 2) ("httpReadReply: FD %d: read failure: %s.\n",
1100 fd, xstrerror());
1101
1102 if (ignoreErrno(errno)) {
f61f0107 1103 flags.do_next_read = 1;
6cae5db1 1104 } else {
62e76326 1105 ErrorState *err;
4eb368f9 1106 err = errorCon(ERR_READ_ERROR, HTTP_BAD_GATEWAY);
62e76326 1107 err->xerrno = errno;
b6b6f466 1108 fwd->fail(err);
f61f0107 1109 flags.do_next_read = 0;
62e76326 1110 comm_close(fd);
62e76326 1111 }
2afaba07 1112 } else if (flag == COMM_OK && len == 0 && !flags.headers_parsed) {
b6b6f466 1113 fwd->fail(errorCon(ERR_ZERO_SIZE_OBJECT, HTTP_BAD_GATEWAY));
62e76326 1114 eof = 1;
f61f0107 1115 flags.do_next_read = 0;
62e76326 1116 comm_close(fd);
c4b7a5a9 1117 } else if (flag == COMM_OK && len == 0) {
62e76326 1118 /* Connection closed; retrieval done. */
1119 eof = 1;
1120
1a98175f 1121 if (!flags.headers_parsed)
62e76326 1122 /*
3f7d66c7 1123 * When we called processReplyHeader() before, we
1a98175f 1124 * didn't find the end of headers, but now we are
1125 * definately at EOF, so we want to process the reply
1126 * headers.
62e76326 1127 */
2afaba07 1128 processReplyHeader();
1129 else if (getReply()->sline.status == HTTP_INVALID_HEADER && HttpVersion(0,9) != getReply()->sline.version) {
b6b6f466 1130 fwd->fail(errorCon(ERR_INVALID_RESP, HTTP_BAD_GATEWAY));
f61f0107 1131 flags.do_next_read = 0;
47ac2ebe 1132 } else {
4eb368f9 1133 if (entry->mem_obj->getReply()->sline.status == HTTP_HEADER_TOO_LARGE) {
4eb368f9 1134 storeEntryReset(entry);
b6b6f466 1135 fwd->fail( errorCon(ERR_TOO_BIG, HTTP_BAD_GATEWAY));
1136 fwd->dontRetry(true);
2afaba07 1137 flags.do_next_read = 0;
1138 comm_close(fd);
4eb368f9 1139 } else {
2afaba07 1140 transactionComplete();
4eb368f9 1141 }
62e76326 1142 }
090089c4 1143 } else {
1a98175f 1144 if (!flags.headers_parsed) {
2afaba07 1145 processReplyHeader();
62e76326 1146
1a98175f 1147 if (flags.headers_parsed) {
2afaba07 1148 http_status s = getReply()->sline.status;
1149 HttpVersion httpver = getReply()->sline.version;
47ac2ebe 1150
b735b90c 1151 if (s == HTTP_INVALID_HEADER && httpver != HttpVersion(0,9)) {
47ac2ebe 1152 storeEntryReset(entry);
b6b6f466 1153 fwd->fail( errorCon(ERR_INVALID_RESP, HTTP_BAD_GATEWAY));
47ac2ebe 1154 comm_close(fd);
1155 return;
1156 }
1157
2afaba07 1158 }
1159 }
1160
1161 PROF_start(HttpStateData_processReplyBody);
1162 processReplyBody();
1163 PROF_stop(HttpStateData_processReplyBody);
1164 }
1165}
1166
1167/*
1168 * Call this when there is data from the origin server
1169 * which should be sent to either StoreEntry, or to ICAP...
1170 */
1171void
1172HttpStateData::writeReplyBody(const char *data, int len)
1173{
1174#if ICAP_CLIENT
62e76326 1175
2afaba07 1176 if (icap) {
1177 icap->sendMoreData (StoreIOBuffer(len, 0, (char*)data));
1178 return;
1179 }
47ac2ebe 1180
225644d7 1181#endif
62e76326 1182
2afaba07 1183 entry->write (StoreIOBuffer(len, currentOffset, (char*)data));
62e76326 1184
2afaba07 1185 currentOffset += len;
e6ccf245 1186}
1187
2afaba07 1188/*
1189 * processReplyBody has two purposes:
1190 * 1 - take the reply body data, if any, and put it into either
1191 * the StoreEntry, or give it over to ICAP.
1192 * 2 - see if we made it to the end of the response (persistent
1193 * connections and such)
1194 */
e6ccf245 1195void
2afaba07 1196HttpStateData::processReplyBody()
e6ccf245 1197{
1a98175f 1198 if (!flags.headers_parsed) {
f61f0107 1199 flags.do_next_read = 1;
62e76326 1200 maybeReadData();
1201 return;
528b2c61 1202 }
62e76326 1203
2afaba07 1204#if ICAP_CLIENT
1205 if (icapAccessCheckPending)
1206 return;
62e76326 1207
2afaba07 1208#endif
62e76326 1209
2afaba07 1210 /*
1211 * At this point the reply headers have been parsed and consumed.
1212 * That means header content has been removed from readBuf and
1213 * it contains only body data.
1214 */
1215 writeReplyBody(readBuf->content(), readBuf->contentSize());
62e76326 1216
2afaba07 1217 body_bytes_read += readBuf->contentSize();
1218
1219 readBuf->consume(readBuf->contentSize());
528b2c61 1220
e6ccf245 1221 if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
62e76326 1222 /*
2afaba07 1223 * the above writeReplyBody() call could ABORT this entry,
62e76326 1224 * in that case, the server FD should already be closed.
1225 * there's nothing for us to do.
1226 */
1227 (void) 0;
1228 } else
1229 switch (persistentConnStatus()) {
1230
1231 case INCOMPLETE_MSG:
2afaba07 1232 debug(11,5)("processReplyBody: INCOMPLETE_MSG\n");
21b92762 1233 /* Wait for more data or EOF condition */
1234
1235 if (flags.keepalive_broken) {
1236 commSetTimeout(fd, 10, NULL, NULL);
1237 } else {
1238 commSetTimeout(fd, Config.Timeout.read, NULL, NULL);
1239 }
1240
f61f0107 1241 flags.do_next_read = 1;
62e76326 1242 break;
1243
1244 case COMPLETE_PERSISTENT_MSG:
2afaba07 1245 debug(11,5)("processReplyBody: COMPLETE_PERSISTENT_MSG\n");
62e76326 1246 /* yes we have to clear all these! */
62e76326 1247 commSetTimeout(fd, -1, NULL, NULL);
f61f0107 1248 flags.do_next_read = 0;
62e76326 1249
1250 comm_remove_close_handler(fd, httpStateFree, this);
b6b6f466 1251 fwd->unregister(fd);
bd0723ad 1252
1253 if (_peer) {
1254 if (_peer->options.originserver)
b6b6f466 1255 fwd->pconnPush(fd, _peer->name, orig_request->port, orig_request->host);
bd0723ad 1256 else
b6b6f466 1257 fwd->pconnPush(fd, _peer->name, _peer->http_port, NULL);
bd0723ad 1258 } else {
b6b6f466 1259 fwd->pconnPush(fd, request->host, request->port, NULL);
bd0723ad 1260 }
1261
62e76326 1262 fd = -1;
2afaba07 1263
1264 transactionComplete();
62e76326 1265 return;
1266
1267 case COMPLETE_NONPERSISTENT_MSG:
2afaba07 1268 debug(11,5)("processReplyBody: COMPLETE_NONPERSISTENT_MSG\n");
1269 transactionComplete();
62e76326 1270 return;
1271 }
1272
c4b7a5a9 1273 maybeReadData();
1274}
1275
1276void
1277HttpStateData::maybeReadData()
1278{
2afaba07 1279 int read_sz = readBuf->spaceSize();
1280#if ICAP_CLIENT
1281
1282 if (icap) {
1283 /*
1284 * Our ICAP message pipes have a finite size limit. We
1285 * should not read more data from the network than will fit
1286 * into the pipe buffer. If totally full, don't register
1287 * the read handler at all. The ICAP side will call our
1288 * icapSpaceAvailable() method when it has free space again.
1289 */
1290 int icap_space = icap->potentialSpaceSize();
1291
1292 debugs(11,9, "HttpStateData may read up to min(" << icap_space <<
1293 ", " << read_sz << ") bytes");
1294
1295 if (icap_space < read_sz)
1296 read_sz = icap_space;
1297 }
1298
1299#endif
1300
1301 debugs(11,9, "HttpStateData may read up to " << read_sz << " bytes");
1302
1303 /*
1304 * why <2? Because delayAwareRead() won't actually read if
1305 * you ask it to read 1 byte. The delayed read request
1306 * just gets re-queued until the client side drains, then
1307 * the I/O thread hangs. Better to not register any read
1308 * handler until we get a notification from someone that
1309 * its okay to read again.
1310 */
1311 if (read_sz < 2)
1312 return;
1313
f61f0107 1314 if (flags.do_next_read) {
1315 flags.do_next_read = 0;
e5ee81f0 1316 entry->delayAwareRead(fd, readBuf->space(), read_sz, ReadReplyWrapper, this);
528b2c61 1317 }
090089c4 1318}
1319
2afaba07 1320/*
1321 * This will be called when request write is complete.
1322 */
d576a6a6 1323void
1324HttpStateData::SendComplete(int fd, char *bufnotused, size_t size, comm_err_t errflag, void *data)
090089c4 1325{
e6ccf245 1326 HttpStateData *httpState = static_cast<HttpStateData *>(data);
a3d5953d 1327 debug(11, 5) ("httpSendComplete: FD %d: size %d: errflag %d.\n",
62e76326 1328 fd, (int) size, errflag);
bc87dc25 1329#if URL_CHECKSUM_DEBUG
62e76326 1330
528b2c61 1331 entry->mem_obj->checkUrlChecksum();
bc87dc25 1332#endif
62e76326 1333
ee1679df 1334 if (size > 0) {
62e76326 1335 fd_bytes(fd, size, FD_WRITE);
1336 kb_incr(&statCounter.server.all.kbytes_out, size);
1337 kb_incr(&statCounter.server.http.kbytes_out, size);
ee1679df 1338 }
62e76326 1339
ea3a2a69 1340 if (errflag == COMM_ERR_CLOSING)
62e76326 1341 return;
1342
090089c4 1343 if (errflag) {
6cae5db1 1344 ErrorState *err;
4eb368f9 1345 err = errorCon(ERR_WRITE_ERROR, HTTP_BAD_GATEWAY);
62e76326 1346 err->xerrno = errno;
b6b6f466 1347 httpState->fwd->fail(err);
62e76326 1348 comm_close(fd);
1349 return;
090089c4 1350 }
72b63f06 1351
2afaba07 1352 /*
1353 * Set the read timeout here because it hasn't been set yet.
1354 * We only set the read timeout after the request has been
1355 * fully written to the server-side. If we start the timeout
1356 * after connection establishment, then we are likely to hit
1357 * the timeout for POST/PUT requests that have very large
1358 * request bodies.
1359 */
1360 commSetTimeout(fd, Config.Timeout.read, httpTimeout, httpState);
1361
72b63f06 1362 httpState->flags.request_sent = 1;
090089c4 1363}
1364
2afaba07 1365/*
1366 * Calling this function marks the end of the HTTP transaction.
1367 * i.e., done talking to the HTTP server. With ICAP, however, that
1368 * does not mean that we're done with HttpStateData and the StoreEntry.
1369 * We'll be expecting adapted data to come back from the ICAP
1370 * routines.
1371 */
1372void
1373HttpStateData::transactionComplete()
1374{
2bb867b5 1375 debugs(11,5,HERE << "transactionComplete FD " << fd << " this " << this);
1376
2afaba07 1377 if (fd >= 0) {
b6b6f466 1378 fwd->unregister(fd);
2afaba07 1379 comm_remove_close_handler(fd, httpStateFree, this);
1380 comm_close(fd);
1381 fd = -1;
1382 }
1383
1384#if ICAP_CLIENT
1385 if (icap) {
1386 icap->doneSending();
30398be3 1387 return;
1388 }
2afaba07 1389
1390#endif
1391
b6b6f466 1392 fwd->complete();
2afaba07 1393
30398be3 1394 httpStateFree(-1, this);
2afaba07 1395}
1396
99edd1c3 1397/*
1398 * build request headers and append them to a given MemBuf
e5ee81f0 1399 * used by buildRequestPrefix()
818c6c9e 1400 * note: initialised the HttpHeader, the caller is responsible for Clean()-ing
99edd1c3 1401 */
e1e72f06 1402void
e5ee81f0 1403HttpStateData::httpBuildRequestHeader(HttpRequest * request,
1404 HttpRequest * orig_request,
1405 StoreEntry * entry,
1406 HttpHeader * hdr_out,
1407 http_state_flags flags)
6bf8443a 1408{
99edd1c3 1409 /* building buffer for complex strings */
5999b776 1410#define BBUF_SZ (MAX_URL+32)
99edd1c3 1411 LOCAL_ARRAY(char, bbuf, BBUF_SZ);
99edd1c3 1412 const HttpHeader *hdr_in = &orig_request->header;
1413 const HttpHeaderEntry *e;
6bccf575 1414 String strFwd;
99edd1c3 1415 HttpHeaderPos pos = HttpHeaderInitPos;
75faaa7a 1416 assert (hdr_out->owner == hoRequest);
99edd1c3 1417 /* append our IMS header */
62e76326 1418
fa3e249f 1419 if (request->lastmod > -1)
62e76326 1420 httpHeaderPutTime(hdr_out, HDR_IF_MODIFIED_SINCE, request->lastmod);
99edd1c3 1421
528b2c61 1422 bool we_do_ranges = decideIfWeDoRanges (orig_request);
1423
650c4b88 1424 String strConnection (httpHeaderGetList(hdr_in, HDR_CONNECTION));
62e76326 1425
528b2c61 1426 while ((e = httpHeaderGetEntry(hdr_in, &pos)))
62e76326 1427 copyOneHeaderFromClientsideRequestToUpstreamRequest(e, strConnection, request, orig_request, hdr_out, we_do_ranges, flags);
528b2c61 1428
43ae1d95 1429 /* Abstraction break: We should interpret multipart/byterange responses
528b2c61 1430 * into offset-length data, and this works around our inability to do so.
1431 */
62e76326 1432 if (!we_do_ranges && orig_request->multipartRangeRequest()) {
1433 /* don't cache the result */
1434 orig_request->flags.cachable = 0;
1435 /* pretend it's not a range request */
00d77d6b 1436 delete orig_request->range;
62e76326 1437 orig_request->range = NULL;
1438 orig_request->flags.range = 0;
1439 }
528b2c61 1440
99edd1c3 1441 /* append Via */
736cb6aa 1442 if (Config.onoff.via) {
43ae1d95 1443 String strVia;
1444 strVia = httpHeaderGetList(hdr_in, HDR_VIA);
62e76326 1445 snprintf(bbuf, BBUF_SZ, "%d.%d %s",
1446 orig_request->http_ver.major,
1447 orig_request->http_ver.minor, ThisCache);
1448 strListAdd(&strVia, bbuf, ',');
1449 httpHeaderPutStr(hdr_out, HDR_VIA, strVia.buf());
1450 strVia.clean();
736cb6aa 1451 }
62e76326 1452
43ae1d95 1453#if ESI
1454 {
1455 /* Append Surrogate-Capabilities */
1456 String strSurrogate (httpHeaderGetList(hdr_in, HDR_SURROGATE_CAPABILITY));
ec43ae0e 1457 snprintf(bbuf, BBUF_SZ, "%s=\"Surrogate/1.0 ESI/1.0\"",
43ae1d95 1458 Config.Accel.surrogate_id);
1459 strListAdd(&strSurrogate, bbuf, ',');
1460 httpHeaderPutStr(hdr_out, HDR_SURROGATE_CAPABILITY, strSurrogate.buf());
1461 }
1462#endif
1463
99edd1c3 1464 /* append X-Forwarded-For */
6bccf575 1465 strFwd = httpHeaderGetList(hdr_in, HDR_X_FORWARDED_FOR);
62e76326 1466
6056ae68 1467 if (opt_forwarded_for && orig_request->client_addr.s_addr != no_addr.s_addr)
62e76326 1468 strListAdd(&strFwd, inet_ntoa(orig_request->client_addr), ',');
6056ae68 1469 else
62e76326 1470 strListAdd(&strFwd, "unknown", ',');
1471
528b2c61 1472 httpHeaderPutStr(hdr_out, HDR_X_FORWARDED_FOR, strFwd.buf());
62e76326 1473
528b2c61 1474 strFwd.clean();
6bccf575 1475
99edd1c3 1476 /* append Host if not there already */
1477 if (!httpHeaderHas(hdr_out, HDR_HOST)) {
62e76326 1478 if (orig_request->peer_domain) {
1479 httpHeaderPutStr(hdr_out, HDR_HOST, orig_request->peer_domain);
1480 } else if (orig_request->port == urlDefaultPort(orig_request->protocol)) {
1481 /* use port# only if not default */
1482 httpHeaderPutStr(hdr_out, HDR_HOST, orig_request->host);
1483 } else {
1484 httpHeaderPutStrf(hdr_out, HDR_HOST, "%s:%d",
1485 orig_request->host, (int) orig_request->port);
1486 }
6bf8443a 1487 }
62e76326 1488
c68e9c6b 1489 /* append Authorization if known in URL, not in header and going direct */
1490 if (!httpHeaderHas(hdr_out, HDR_AUTHORIZATION)) {
62e76326 1491 if (!request->flags.proxying && *request->login) {
1492 httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s",
1493 base64_encode(request->login));
1494 }
c68e9c6b 1495 }
62e76326 1496
c68e9c6b 1497 /* append Proxy-Authorization if configured for peer, and proxying */
c3b33cb7 1498 if (request->flags.proxying && orig_request->peer_login &&
62e76326 1499 !httpHeaderHas(hdr_out, HDR_PROXY_AUTHORIZATION)) {
1500 if (*orig_request->peer_login == '*') {
1501 /* Special mode, to pass the username to the upstream cache */
1502 char loginbuf[256];
1503 const char *username = "-";
1504
1505 if (orig_request->auth_user_request)
1506 username = orig_request->auth_user_request->username();
abb929f0 1507 else if (orig_request->extacl_user.size())
1508 username = orig_request->extacl_user.buf();
62e76326 1509
1510 snprintf(loginbuf, sizeof(loginbuf), "%s%s", username, orig_request->peer_login + 1);
1511
1512 httpHeaderPutStrf(hdr_out, HDR_PROXY_AUTHORIZATION, "Basic %s",
1513 base64_encode(loginbuf));
1514 } else if (strcmp(orig_request->peer_login, "PASS") == 0) {
abb929f0 1515 if (orig_request->extacl_user.size() && orig_request->extacl_passwd.size()) {
1516 char loginbuf[256];
1517 snprintf(loginbuf, sizeof(loginbuf), "%s:%s", orig_request->extacl_user.buf(), orig_request->extacl_passwd.buf());
1518 httpHeaderPutStrf(hdr_out, HDR_PROXY_AUTHORIZATION, "Basic %s",
1519 base64_encode(loginbuf));
1520 }
62e76326 1521 } else if (strcmp(orig_request->peer_login, "PROXYPASS") == 0) {
1522 /* Nothing to do */
1523 } else {
1524 httpHeaderPutStrf(hdr_out, HDR_PROXY_AUTHORIZATION, "Basic %s",
1525 base64_encode(orig_request->peer_login));
1526 }
c68e9c6b 1527 }
62e76326 1528
be753325 1529 /* append WWW-Authorization if configured for peer */
1530 if (flags.originpeer && orig_request->peer_login &&
62e76326 1531 !httpHeaderHas(hdr_out, HDR_AUTHORIZATION)) {
1532 if (strcmp(orig_request->peer_login, "PASS") == 0) {
1533 /* No credentials to forward.. (should have been done above if available) */
1534 } else if (strcmp(orig_request->peer_login, "PROXYPASS") == 0) {
1535 /* Special mode, convert proxy authentication to WWW authentication
abb929f0 1536 * (also applies to authentication provided by external acl)
62e76326 1537 */
1538 const char *auth = httpHeaderGetStr(hdr_in, HDR_PROXY_AUTHORIZATION);
1539
1540 if (auth && strncasecmp(auth, "basic ", 6) == 0) {
1541 httpHeaderPutStr(hdr_out, HDR_AUTHORIZATION, auth);
abb929f0 1542 } else if (orig_request->extacl_user.size() && orig_request->extacl_passwd.size()) {
1543 char loginbuf[256];
1544 snprintf(loginbuf, sizeof(loginbuf), "%s:%s", orig_request->extacl_user.buf(), orig_request->extacl_passwd.buf());
1545 httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s",
1546 base64_encode(loginbuf));
62e76326 1547 }
1548 } else if (*orig_request->peer_login == '*') {
1549 /* Special mode, to pass the username to the upstream cache */
1550 char loginbuf[256];
1551 const char *username = "-";
1552
1553 if (orig_request->auth_user_request)
f5691f9c 1554 username = orig_request->auth_user_request->username();
abb929f0 1555 else if (orig_request->extacl_user.size())
1556 username = orig_request->extacl_user.buf();
62e76326 1557
1558 snprintf(loginbuf, sizeof(loginbuf), "%s%s", username, orig_request->peer_login + 1);
1559
1560 httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s",
1561 base64_encode(loginbuf));
1562 } else {
1563 /* Fixed login string */
1564 httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s",
1565 base64_encode(orig_request->peer_login));
1566 }
be753325 1567 }
62e76326 1568
abb929f0 1569 /* append Cache-Control, add max-age if not there already */ {
62e76326 1570 HttpHdrCc *cc = httpHeaderGetCc(hdr_in);
1571
1572 if (!cc)
1573 cc = httpHdrCcCreate();
1574
1575 if (!EBIT_TEST(cc->mask, CC_MAX_AGE)) {
43ae1d95 1576 const char *url =
1577 entry ? storeUrl(entry) : urlCanonical(orig_request);
62e76326 1578 httpHdrCcSetMaxAge(cc, getMaxAge(url));
1579
1580 if (request->urlpath.size())
1581 assert(strstr(url, request->urlpath.buf()));
1582 }
1583
ce2d6441 1584 /* Set no-cache if determined needed but not found */
1585 if (orig_request->flags.nocache && !httpHeaderHas(hdr_in, HDR_PRAGMA))
1586 EBIT_SET(cc->mask, CC_NO_CACHE);
1587
1588 /* Enforce sibling relations */
62e76326 1589 if (flags.only_if_cached)
1590 EBIT_SET(cc->mask, CC_ONLY_IF_CACHED);
1591
1592 httpHeaderPutCc(hdr_out, cc);
1593
1594 httpHdrCcDestroy(cc);
6bf8443a 1595 }
62e76326 1596
99edd1c3 1597 /* maybe append Connection: keep-alive */
b515fc11 1598 if (flags.keepalive) {
62e76326 1599 if (flags.proxying) {
1600 httpHeaderPutStr(hdr_out, HDR_PROXY_CONNECTION, "keep-alive");
1601 } else {
1602 httpHeaderPutStr(hdr_out, HDR_CONNECTION, "keep-alive");
1603 }
603a02fd 1604 }
62e76326 1605
a7ad6e4e 1606 /* append Front-End-Https */
1607 if (flags.front_end_https) {
62e76326 1608 if (flags.front_end_https == 1 || request->protocol == PROTO_HTTPS)
1609 httpHeaderPutStr(hdr_out, HDR_FRONT_END_HTTPS, "On");
a7ad6e4e 1610 }
1611
6bccf575 1612 /* Now mangle the headers. */
4f56514c 1613 if (Config2.onoff.mangle_request_headers)
5967c0bf 1614 httpHdrMangleList(hdr_out, request, ROR_REQUEST);
62e76326 1615
528b2c61 1616 strConnection.clean();
99edd1c3 1617}
1618
528b2c61 1619void
190154cf 1620copyOneHeaderFromClientsideRequestToUpstreamRequest(const HttpHeaderEntry *e, String strConnection, HttpRequest * request, HttpRequest * orig_request, HttpHeader * hdr_out, int we_do_ranges, http_state_flags flags)
528b2c61 1621{
1622 debug(11, 5) ("httpBuildRequestHeader: %s: %s\n",
62e76326 1623 e->name.buf(), e->value.buf());
1624
528b2c61 1625 if (!httpRequestHdrAllowed(e, &strConnection)) {
62e76326 1626 debug(11, 2) ("'%s' header denied by anonymize_headers configuration\n",+ e->name.buf());
1627 return;
528b2c61 1628 }
62e76326 1629
528b2c61 1630 switch (e->id) {
62e76326 1631
be753325 1632 case HDR_PROXY_AUTHORIZATION:
62e76326 1633 /* Only pass on proxy authentication to peers for which
1634 * authentication forwarding is explicitly enabled
1635 */
1636
1637 if (flags.proxying && orig_request->peer_login &&
abb929f0 1638 (strcmp(orig_request->peer_login, "PASS") == 0 ||
1639 strcmp(orig_request->peer_login, "PROXYPASS") == 0)) {
62e76326 1640 httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
1641 }
1642
1643 break;
1644
be753325 1645 case HDR_AUTHORIZATION:
62e76326 1646 /* Pass on WWW authentication */
1647
1648 if (!flags.originpeer) {
1649 httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
1650 } else {
1651 /* In accelerators, only forward authentication if enabled
1652 * (see also below for proxy->server authentication)
1653 */
1654
abb929f0 1655 if (orig_request->peer_login &&
1656 (strcmp(orig_request->peer_login, "PASS") == 0 ||
1657 strcmp(orig_request->peer_login, "PROXYPASS") == 0)) {
62e76326 1658 httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
1659 }
1660 }
1661
1662 break;
1663
be753325 1664 case HDR_HOST:
62e76326 1665 /*
b883b594 1666 * Normally Squid rewrites the Host: header.
1667 * However, there is one case when we don't: If the URL
62e76326 1668 * went through our redirector and the admin configured
1669 * 'redir_rewrites_host' to be off.
1670 */
1671
b883b594 1672 if (request->flags.redirected && !Config.onoff.redir_rewrites_host)
1673 httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
1674 else {
1675 /* use port# only if not default */
1676
1677 if (orig_request->port == urlDefaultPort(orig_request->protocol)) {
1678 httpHeaderPutStr(hdr_out, HDR_HOST, orig_request->host);
1679 } else {
1680 httpHeaderPutStrf(hdr_out, HDR_HOST, "%s:%d",
1681 orig_request->host, (int) orig_request->port);
1682 }
1683 }
62e76326 1684
1685 break;
1686
be753325 1687 case HDR_IF_MODIFIED_SINCE:
62e76326 1688 /* append unless we added our own;
1689 * note: at most one client's ims header can pass through */
b883b594 1690
62e76326 1691 if (!httpHeaderHas(hdr_out, HDR_IF_MODIFIED_SINCE))
1692 httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
1693
1694 break;
1695
be753325 1696 case HDR_MAX_FORWARDS:
62e76326 1697 if (orig_request->method == METHOD_TRACE) {
1698 const int hops = httpHeaderEntryGetInt(e);
1699
1700 if (hops > 0)
1701 httpHeaderPutInt(hdr_out, HDR_MAX_FORWARDS, hops - 1);
1702 }
1703
1704 break;
1705
be753325 1706 case HDR_VIA:
62e76326 1707 /* If Via is disabled then forward any received header as-is */
1708
1709 if (!Config.onoff.via)
1710 httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
1711
1712 break;
1713
be753325 1714 case HDR_RANGE:
62e76326 1715
be753325 1716 case HDR_IF_RANGE:
62e76326 1717
be753325 1718 case HDR_REQUEST_RANGE:
62e76326 1719 if (!we_do_ranges)
1720 httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
1721
1722 break;
1723
be753325 1724 case HDR_PROXY_CONNECTION:
62e76326 1725
be753325 1726 case HDR_CONNECTION:
62e76326 1727
be753325 1728 case HDR_X_FORWARDED_FOR:
62e76326 1729
be753325 1730 case HDR_CACHE_CONTROL:
62e76326 1731 /* append these after the loop if needed */
1732 break;
1733
be753325 1734 case HDR_FRONT_END_HTTPS:
62e76326 1735 if (!flags.front_end_https)
1736 httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
1737
1738 break;
1739
be753325 1740 default:
62e76326 1741 /* pass on all other header fields */
1742 httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
528b2c61 1743 }
1744}
1745
e5ee81f0 1746bool
1747HttpStateData::decideIfWeDoRanges (HttpRequest * orig_request)
528b2c61 1748{
e5ee81f0 1749 bool result = true;
62e76326 1750 /* decide if we want to do Ranges ourselves
1751 * and fetch the whole object now)
1752 * We want to handle Ranges ourselves iff
1753 * - we can actually parse client Range specs
1754 * - the specs are expected to be simple enough (e.g. no out-of-order ranges)
1755 * - reply will be cachable
1756 * (If the reply will be uncachable we have to throw it away after
1757 * serving this request, so it is better to forward ranges to
1758 * the server and fetch only the requested content)
1759 */
1760
1761 if (NULL == orig_request->range || !orig_request->flags.cachable
1762 || orig_request->range->offsetLimitExceeded())
e5ee81f0 1763 result = false;
62e76326 1764
1765 debug(11, 8) ("decideIfWeDoRanges: range specs: %p, cachable: %d; we_do_ranges: %d\n",
1766 orig_request->range, orig_request->flags.cachable, result);
1767
1768 return result;
528b2c61 1769}
1770
62e76326 1771/* build request prefix and append it to a given MemBuf;
99edd1c3 1772 * return the length of the prefix */
9bc73deb 1773mb_size_t
e5ee81f0 1774HttpStateData::buildRequestPrefix(HttpRequest * request,
1775 HttpRequest * orig_request,
1776 StoreEntry * entry,
1777 MemBuf * mb,
1778 http_state_flags flags)
99edd1c3 1779{
1780 const int offset = mb->size;
450e0c10 1781 HttpVersion httpver(1, 0);
2fe7eff9 1782 mb->Printf("%s %s HTTP/%d.%d\r\n",
1783 RequestMethodStr[request->method],
1784 request->urlpath.size() ? request->urlpath.buf() : "/",
1785 httpver.major,httpver.minor);
99edd1c3 1786 /* build and pack headers */
1787 {
75faaa7a 1788 HttpHeader hdr(hoRequest);
62e76326 1789 Packer p;
1790 httpBuildRequestHeader(request, orig_request, entry, &hdr, flags);
1791 packerToMemInit(&p, mb);
1792 httpHeaderPackInto(&hdr, &p);
1793 httpHeaderClean(&hdr);
1794 packerClean(&p);
9d9d144b 1795 }
99edd1c3 1796 /* append header terminator */
2fe7eff9 1797 mb->append(crlf, 2);
99edd1c3 1798 return mb->size - offset;
6bf8443a 1799}
62e76326 1800
090089c4 1801/* This will be called when connect completes. Write request. */
2bb867b5 1802void
1803HttpStateData::sendRequest()
090089c4 1804{
99edd1c3 1805 MemBuf mb;
901e234d 1806 CWCB *sendHeaderDone;
090089c4 1807
2bb867b5 1808 debug(11, 5) ("httpSendRequest: FD %d: this %p.\n", fd, this);
090089c4 1809
2bb867b5 1810 commSetTimeout(fd, Config.Timeout.lifetime, httpTimeout, this);
1811 flags.do_next_read = 1;
1812 maybeReadData();
21b92762 1813
2bb867b5 1814 if (orig_request->body_connection.getRaw() != NULL)
1815 sendHeaderDone = HttpStateData::SendRequestEntityWrapper;
7db8b16d 1816 else
62e76326 1817 sendHeaderDone = HttpStateData::SendComplete;
54220df8 1818
2bb867b5 1819 if (_peer != NULL) {
1820 if (_peer->options.originserver) {
1821 flags.proxying = 0;
1822 flags.originpeer = 1;
62e76326 1823 } else {
2bb867b5 1824 flags.proxying = 1;
1825 flags.originpeer = 0;
62e76326 1826 }
be753325 1827 } else {
2bb867b5 1828 flags.proxying = 0;
1829 flags.originpeer = 0;
be753325 1830 }
62e76326 1831
efb9218c 1832 /*
99edd1c3 1833 * Is keep-alive okay for all request methods?
efb9218c 1834 */
efd900cb 1835 if (!Config.onoff.server_pconns)
2bb867b5 1836 flags.keepalive = 0;
1837 else if (_peer == NULL)
1838 flags.keepalive = 1;
1839 else if (_peer->stats.n_keepalives_sent < 10)
1840 flags.keepalive = 1;
1841 else if ((double) _peer->stats.n_keepalives_recv /
1842 (double) _peer->stats.n_keepalives_sent > 0.50)
1843 flags.keepalive = 1;
1844
1845 if (_peer) {
1846 if (neighborType(_peer, request) == PEER_SIBLING &&
1847 !_peer->options.allow_miss)
1848 flags.only_if_cached = 1;
1849
1850 flags.front_end_https = _peer->front_end_https;
a7ad6e4e 1851 }
62e76326 1852
2fe7eff9 1853 mb.init();
e5ee81f0 1854 buildRequestPrefix(request, orig_request, entry, &mb, flags);
21b92762 1855 debug(11, 6) ("httpSendRequest: FD %d:\n%s\n", fd, mb.buf);
2bb867b5 1856 comm_old_write_mbuf(fd, &mb, sendHeaderDone, this);
090089c4 1857}
b6a2f15e 1858
910169e5 1859void
b6b6f466 1860httpStart(FwdState *fwd)
603a02fd 1861{
910169e5 1862 debug(11, 3) ("httpStart: \"%s %s\"\n",
a3d50c30 1863 RequestMethodStr[fwd->request->method],
62e76326 1864 storeUrl(fwd->entry));
a3d50c30 1865 HttpStateData *httpState = new HttpStateData(fwd);
62e76326 1866
83704487 1867 statCounter.server.all.requests++;
62e76326 1868
83704487 1869 statCounter.server.http.requests++;
62e76326 1870
2bb867b5 1871 httpState->sendRequest();
62e76326 1872
b6a2f15e 1873 /*
1874 * We used to set the read timeout here, but not any more.
1875 * Now its set in httpSendComplete() after the full request,
1876 * including request body, has been written to the server.
1877 */
090089c4 1878}
1879
2bb867b5 1880void
1881HttpStateData::SendRequestEntityDoneWrapper(int fd, void *data)
54220df8 1882{
e6ccf245 1883 HttpStateData *httpState = static_cast<HttpStateData *>(data);
2bb867b5 1884 httpState->sendRequestEntityDone(fd);
1885}
1886
1887void
1888HttpStateData::sendRequestEntityDone(int fd)
1889{
4fb35c3c 1890 ACLChecklist ch;
43ae1d95 1891 debug(11, 5) ("httpSendRequestEntityDone: FD %d\n", fd);
2bb867b5 1892 ch.request = requestLink(request);
506768d9 1893
1894 if (Config.accessList.brokenPosts)
1895 ch.accessList = cbdataReference(Config.accessList.brokenPosts);
62e76326 1896
108d65b2 1897 /* cbdataReferenceDone() happens in either fastCheck() or ~ACLCheckList */
1898
94439e4e 1899 if (!Config.accessList.brokenPosts) {
62e76326 1900 debug(11, 5) ("httpSendRequestEntityDone: No brokenPosts list\n");
2bb867b5 1901 HttpStateData::SendComplete(fd, NULL, 0, COMM_OK, this);
b448c119 1902 } else if (!ch.fastCheck()) {
62e76326 1903 debug(11, 5) ("httpSendRequestEntityDone: didn't match brokenPosts\n");
2bb867b5 1904 HttpStateData::SendComplete(fd, NULL, 0, COMM_OK, this);
94439e4e 1905 } else {
62e76326 1906 debug(11, 2) ("httpSendRequestEntityDone: matched brokenPosts\n");
2bb867b5 1907 comm_old_write(fd, "\r\n", 2, HttpStateData::SendComplete, this, NULL);
54220df8 1908 }
94439e4e 1909}
1910
2bb867b5 1911void
1912HttpStateData::RequestBodyHandlerWrapper(char *buf, ssize_t size, void *data)
94439e4e 1913{
9ed57c61 1914 HttpStateData *httpState = static_cast<HttpStateData *>(data);
2bb867b5 1915 httpState->requestBodyHandler(buf, size);
1916}
1917
1918void
1919HttpStateData::requestBodyHandler(char *buf, ssize_t size)
1920{
1921 request_body_buf = NULL;
1922
1923 if (eof || fd < 0) {
1924 debugs(11, 1, HERE << "Transaction aborted while reading HTTP body");
1925 memFree8K(buf);
1926 return;
1927 }
62e76326 1928
94439e4e 1929 if (size > 0) {
2bb867b5 1930 if (flags.headers_parsed && !flags.abuse_detected) {
1931 flags.abuse_detected = 1;
21b92762 1932 debug(11, 1) ("httpSendRequestEntryDone: Likely proxy abuse detected '%s' -> '%s'\n",
2bb867b5 1933 inet_ntoa(orig_request->client_addr),
1934 storeUrl(entry));
21b92762 1935
2bb867b5 1936 if (getReply()->sline.status == HTTP_INVALID_HEADER) {
21b92762 1937 memFree8K(buf);
2bb867b5 1938 comm_close(fd);
21b92762 1939 return;
1940 }
1941 }
1942
2bb867b5 1943 comm_old_write(fd, buf, size, SendRequestEntityWrapper, this, memFree8K);
94439e4e 1944 } else if (size == 0) {
62e76326 1945 /* End of body */
1946 memFree8K(buf);
2bb867b5 1947 sendRequestEntityDone(fd);
94439e4e 1948 } else {
62e76326 1949 /* Failed to get whole body, probably aborted */
1950 memFree8K(buf);
2bb867b5 1951 HttpStateData::SendComplete(fd, NULL, 0, COMM_ERR_CLOSING, this);
b6a2f15e 1952 }
376bb137 1953}
1954
2bb867b5 1955void
1956HttpStateData::SendRequestEntityWrapper(int fd, char *bufnotused, size_t size, comm_err_t errflag, void *data)
376bb137 1957{
e6ccf245 1958 HttpStateData *httpState = static_cast<HttpStateData *>(data);
2bb867b5 1959 httpState->sendRequestEntity(fd, size, errflag);
1960}
1961
1962void
1963HttpStateData::sendRequestEntity(int fd, size_t size, comm_err_t errflag)
1964{
c3d63b2a 1965 debug(11, 5) ("httpSendRequestEntity: FD %d: size %d: errflag %d.\n",
62e76326 1966 fd, (int) size, errflag);
1967
376bb137 1968 if (size > 0) {
62e76326 1969 fd_bytes(fd, size, FD_WRITE);
1970 kb_incr(&statCounter.server.all.kbytes_out, size);
1971 kb_incr(&statCounter.server.http.kbytes_out, size);
376bb137 1972 }
62e76326 1973
376bb137 1974 if (errflag == COMM_ERR_CLOSING)
62e76326 1975 return;
1976
376bb137 1977 if (errflag) {
6cae5db1 1978 ErrorState *err;
4eb368f9 1979 err = errorCon(ERR_WRITE_ERROR, HTTP_BAD_GATEWAY);
62e76326 1980 err->xerrno = errno;
2bb867b5 1981 fwd->fail(err);
62e76326 1982 comm_close(fd);
1983 return;
376bb137 1984 }
62e76326 1985
94439e4e 1986 if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
62e76326 1987 comm_close(fd);
1988 return;
376bb137 1989 }
62e76326 1990
2bb867b5 1991 request_body_buf = (char *)memAllocate(MEM_8K_BUF);
1992 clientReadBody(orig_request, request_body_buf, 8192, RequestBodyHandlerWrapper, this);
54220df8 1993}
ccf44862 1994
1995void
450e0c10 1996httpBuildVersion(HttpVersion * version, unsigned int major, unsigned int minor)
110eb4e5 1997{
1998 version->major = major;
1999 version->minor = minor;
ccf44862 2000}
2afaba07 2001
2002#if ICAP_CLIENT
2003
2004static void
2005icapAclCheckDoneWrapper(ICAPServiceRep::Pointer service, void *data)
2006{
2007 HttpStateData *http = (HttpStateData *)data;
2008 http->icapAclCheckDone(service);
2009}
2010
2011void
2012HttpStateData::icapAclCheckDone(ICAPServiceRep::Pointer service)
2013{
2014 icapAccessCheckPending = false;
2015
2016 if (service == NULL) {
2017 // handle case where no service is selected;
2018 storeEntryReplaceObject(entry, reply);
2019
2020 /* Note storeEntryReplaceObject() consumes reply, so we cannot use it */
2021 reply = NULL;
2022
2023 haveParsedReplyHeaders();
2024 processReplyBody();
2025
2026 if (eof == 1)
2027 transactionComplete();
2028
2029 return;
2030 }
2031
2032 if (doIcap(service) < 0) {
2033 /*
2034 * XXX Maybe instead of an error page we should
2035 * handle the reply normally (without ICAP).
2036 */
2037 ErrorState *err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
2038 err->xerrno = errno;
2039 err->request = requestLink(orig_request);
2040 errorAppendEntry(entry, err);
2041 comm_close(fd);
2042 return;
2043 }
2044
2045 icap->startRespMod(this, request, reply);
2046 processReplyBody();
2047}
2048
2049/*
2050 * Initiate an ICAP transaction. Return 0 if all is well, or -1 upon error.
2051 * Caller will handle error condition by generating a Squid error message
2052 * or take other action.
2053 */
2054int
2055HttpStateData::doIcap(ICAPServiceRep::Pointer service)
2056{
2057 debug(11,5)("HttpStateData::doIcap() called\n");
2058 assert(NULL == icap);
2059 icap = new ICAPClientRespmodPrecache(service);
2060 (void) cbdataReference(icap);
2061 return 0;
2062}
2063
2064/*
2065 * Called by ICAPClientRespmodPrecache when it has space available for us.
2066 */
2067void
2068HttpStateData::icapSpaceAvailable()
2069{
2070 debug(11,5)("HttpStateData::icapSpaceAvailable() called\n");
2071 maybeReadData();
2072}
2073
2074void
2075HttpStateData::takeAdaptedHeaders(HttpReply *rep)
2076{
2077 debug(11,5)("HttpStateData::takeAdaptedHeaders() called\n");
2078
2079 if (!entry->isAccepting()) {
2080 debug(11,5)("\toops, entry is not Accepting!\n");
2081 icap->ownerAbort();
2082 return;
2083 }
2084
b559db5d 2085 assert (rep);
2afaba07 2086 storeEntryReplaceObject(entry, rep);
2087
2088 /*
2089 * After calling storeEntryReplaceObject() we give up control
2090 * of the rep and this->reply pointers.
2091 */
2092 rep = NULL;
2093
2094 haveParsedReplyHeaders();
2095
2096 debug(11,5)("HttpStateData::takeAdaptedHeaders() finished\n");
2097}
2098
2099void
2100HttpStateData::takeAdaptedBody(MemBuf *buf)
2101{
2102 debug(11,5)("HttpStateData::takeAdaptedBody() called\n");
1dd6edf2 2103 debug(11,5)("\t%d bytes\n", (int) buf->contentSize());
2afaba07 2104 debug(11,5)("\t%d is current offset\n", (int)currentOffset);
2105
2106 if (!entry->isAccepting()) {
2107 debug(11,5)("\toops, entry is not Accepting!\n");
2108 icap->ownerAbort();
2109 return;
2110 }
2111
2112 entry->write(StoreIOBuffer(buf, currentOffset)); // write everything
2113 currentOffset += buf->contentSize();
2114 buf->consume(buf->contentSize()); // consume everything written
2115}
2116
2117void
2118HttpStateData::doneAdapting()
2119{
2120 debug(11,5)("HttpStateData::doneAdapting() called\n");
2121
2122 if (!entry->isAccepting()) {
2123 debug(11,5)("\toops, entry is not Accepting!\n");
2124 icap->ownerAbort();
2125 } else {
b6b6f466 2126 fwd->complete();
2afaba07 2127 }
2128
6965ab28 2129 /*
2130 * ICAP is done, so we don't need this any more.
2131 */
2132 delete icap;
2133
2134 cbdataReferenceDone(icap);
2135
b559db5d 2136 if (fd >= 0)
2137 comm_close(fd);
2138 else
2139 httpStateFree(fd, this);
2afaba07 2140}
2141
2142void
2143HttpStateData::abortAdapting()
2144{
2145 debug(11,5)("HttpStateData::abortAdapting() called\n");
2146
b559db5d 2147 /*
2148 * ICAP has given up, we're done with it too
2149 */
2150 delete icap;
2151 cbdataReferenceDone(icap);
2152
2afaba07 2153 if (entry->isEmpty()) {
2154 ErrorState *err;
2155 err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
2156 err->request = requestLink((HttpRequest *) request);
2157 err->xerrno = errno;
b6b6f466 2158 fwd->fail( err);
2159 fwd->dontRetry(true);
2afaba07 2160 flags.do_next_read = 0;
2161 }
2162
6c2d6c93 2163 if (fd >= 0) {
2164 comm_close(fd);
2165 } else {
2166 httpStateFree(-1, this); // deletes this
2167 }
2afaba07 2168}
2169
2170#endif