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