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