]> git.ipfire.org Git - thirdparty/squid.git/blame - src/http.cc
Fix a printf type warning about long int vs int
[thirdparty/squid.git] / src / http.cc
CommitLineData
da2b3a17 1
30a4f2a8 2/*
7058745b 3 * $Id: http.cc,v 1.398 2002/10/14 08:47:47 hno 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"
e6ccf245 42#include "http.h"
43#include "authenticate.h"
44#include "Store.h"
45
46CBDATA_TYPE(HttpStateData);
47
090089c4 48
6bf8443a 49static const char *const crlf = "\r\n";
4db43fab 50
9e4ad609 51static CWCB httpSendComplete;
c3d63b2a 52static CWCB httpSendRequestEntity;
54220df8 53
c4b7a5a9 54static IOCB httpReadReply;
b6a2f15e 55static void httpSendRequest(HttpStateData *);
9e4ad609 56static PF httpStateFree;
57static PF httpTimeout;
f5b8bbc4 58static void httpCacheNegatively(StoreEntry *);
59static void httpMakePrivate(StoreEntry *);
60static void httpMakePublic(StoreEntry *);
f8309b15 61static int httpCachableReply(HttpStateData *);
f9cece6e 62static void httpMaybeRemovePublic(StoreEntry *, http_status);
b8d8561b 63
b177367b 64static void
59715b38 65httpStateFree(int fd, void *data)
f5558c95 66{
e6ccf245 67 HttpStateData *httpState = static_cast<HttpStateData *>(data);
59715b38 68#if DELAY_POOLS
69 delayClearNoDelay(fd);
70#endif
0d4d4170 71 if (httpState == NULL)
b177367b 72 return;
f88211e8 73 storeUnlockObject(httpState->entry);
0d4d4170 74 if (httpState->reply_hdr) {
db1cd23c 75 memFree(httpState->reply_hdr, MEM_8K_BUF);
0d4d4170 76 httpState->reply_hdr = NULL;
77 }
30a4f2a8 78 requestUnlink(httpState->request);
20cc1450 79 requestUnlink(httpState->orig_request);
7dd44885 80 httpState->request = NULL;
81 httpState->orig_request = NULL;
82 cbdataFree(httpState);
f5558c95 83}
84
b8d8561b 85int
75e88d56 86httpCachable(method_t method)
090089c4 87{
090089c4 88 /* GET and HEAD are cachable. Others are not. */
6eb42cae 89 if (method != METHOD_GET && method != METHOD_HEAD)
090089c4 90 return 0;
090089c4 91 /* else cachable */
92 return 1;
93}
94
b8d8561b 95static void
5c5783a2 96httpTimeout(int fd, void *data)
090089c4 97{
e6ccf245 98 HttpStateData *httpState = static_cast<HttpStateData *>(data);
593c9a75 99 StoreEntry *entry = httpState->entry;
9fb13bb6 100 debug(11, 4) ("httpTimeout: FD %d: '%s'\n", fd, storeUrl(entry));
12158bdc 101 if (entry->store_status == STORE_PENDING) {
102 if (entry->mem_obj->inmem_hi == 0) {
103 fwdFail(httpState->fwd,
104 errorCon(ERR_READ_TIMEOUT, HTTP_GATEWAY_TIMEOUT));
105 }
9b312a19 106 }
0d4d4170 107 comm_close(fd);
090089c4 108}
109
30a4f2a8 110/* This object can be cached for a long time */
b8d8561b 111static void
112httpMakePublic(StoreEntry * entry)
30a4f2a8 113{
d46a87a8 114 if (EBIT_TEST(entry->flags, ENTRY_CACHABLE))
30a4f2a8 115 storeSetPublicKey(entry);
116}
117
118/* This object should never be cached at all */
b8d8561b 119static void
120httpMakePrivate(StoreEntry * entry)
30a4f2a8 121{
30a4f2a8 122 storeExpireNow(entry);
30a4f2a8 123 storeReleaseRequest(entry); /* delete object when not used */
f3e570e9 124 /* storeReleaseRequest clears ENTRY_CACHABLE flag */
30a4f2a8 125}
126
127/* This object may be negatively cached */
b8d8561b 128static void
129httpCacheNegatively(StoreEntry * entry)
30a4f2a8 130{
79b5cc5f 131 storeNegativeCache(entry);
d46a87a8 132 if (EBIT_TEST(entry->flags, ENTRY_CACHABLE))
30a4f2a8 133 storeSetPublicKey(entry);
30a4f2a8 134}
135
f9cece6e 136static void
137httpMaybeRemovePublic(StoreEntry * e, http_status status)
138{
139 int remove = 0;
7e3ce7b9 140 int forbidden = 0;
f9cece6e 141 StoreEntry *pe;
d46a87a8 142 if (!EBIT_TEST(e->flags, KEY_PRIVATE))
9dc1202d 143 return;
f9cece6e 144 switch (status) {
145 case HTTP_OK:
146 case HTTP_NON_AUTHORITATIVE_INFORMATION:
147 case HTTP_MULTIPLE_CHOICES:
148 case HTTP_MOVED_PERMANENTLY:
149 case HTTP_MOVED_TEMPORARILY:
f9cece6e 150 case HTTP_GONE:
7e3ce7b9 151 case HTTP_NOT_FOUND:
f9cece6e 152 remove = 1;
153 break;
7e3ce7b9 154 case HTTP_FORBIDDEN:
155 case HTTP_METHOD_NOT_ALLOWED:
156 forbidden = 1;
157 break;
f9cece6e 158#if WORK_IN_PROGRESS
c8fd0193 159 case HTTP_UNAUTHORIZED:
7e3ce7b9 160 forbidden = 1;
f9cece6e 161 break;
162#endif
163 default:
7e3ce7b9 164#if QUESTIONABLE
165 /*
166 * Any 2xx response should eject previously cached entities...
167 */
168 if (status >= 200 && status < 300)
169 remove = 1;
170#endif
f9cece6e 171 break;
172 }
7e3ce7b9 173 if (!remove && !forbidden)
f9cece6e 174 return;
175 assert(e->mem_obj);
f66a9ef4 176 if (e->mem_obj->request)
177 pe = storeGetPublicByRequest(e->mem_obj->request);
178 else
179 pe = storeGetPublic(e->mem_obj->url, e->mem_obj->method);
180 if (pe != NULL) {
0856d155 181 assert(e != pe);
182 storeRelease(pe);
183 }
7e3ce7b9 184 /*
185 * Also remove any cached HEAD response in case the object has
186 * changed.
187 */
f66a9ef4 188 if (e->mem_obj->request)
189 pe = storeGetPublicByRequestMethod(e->mem_obj->request, METHOD_HEAD);
190 else
191 pe = storeGetPublic(e->mem_obj->url, METHOD_HEAD);
192 if (pe != NULL) {
7e3ce7b9 193 assert(e != pe);
194 storeRelease(pe);
195 }
196 if (forbidden)
197 return;
198 switch (e->mem_obj->method) {
199 case METHOD_PUT:
200 case METHOD_DELETE:
201 case METHOD_PROPPATCH:
202 case METHOD_MKCOL:
203 case METHOD_MOVE:
42b51993 204 case METHOD_BMOVE:
205 case METHOD_BDELETE:
7e3ce7b9 206 /*
207 * Remove any cached GET object if it is beleived that the
208 * object may have changed as a result of other methods
209 */
f66a9ef4 210 if (e->mem_obj->request)
211 pe = storeGetPublicByRequestMethod(e->mem_obj->request, METHOD_GET);
212 else
213 pe = storeGetPublic(e->mem_obj->url, METHOD_GET);
214 if (pe != NULL) {
0856d155 215 assert(e != pe);
216 storeRelease(pe);
217 }
7e3ce7b9 218 break;
c8be6d7b 219 default:
220 /* Keep GCC happy. The methods above are all mutating HTTP methods
221 */
222 break;
0856d155 223 }
f9cece6e 224}
225
f8309b15 226static int
227httpCachableReply(HttpStateData * httpState)
c54e9052 228{
d8b249ef 229 HttpReply *rep = httpState->entry->mem_obj->reply;
230 HttpHeader *hdr = &rep->header;
231 const int cc_mask = (rep->cache_control) ? rep->cache_control->mask : 0;
c68e9c6b 232 const char *v;
7faf2bdb 233 if (EBIT_TEST(cc_mask, CC_PRIVATE))
f8309b15 234 return 0;
7faf2bdb 235 if (EBIT_TEST(cc_mask, CC_NO_CACHE))
f8309b15 236 return 0;
ed2f05a1 237 if (EBIT_TEST(cc_mask, CC_NO_STORE))
238 return 0;
92695e5e 239 if (httpState->request->flags.auth) {
a6dfe2d9 240 /*
241 * Responses to requests with authorization may be cached
68aefb7d 242 * only if a Cache-Control: public reply header is present.
a6dfe2d9 243 * RFC 2068, sec 14.9.4
244 */
245 if (!EBIT_TEST(cc_mask, CC_PUBLIC))
fee0cebb 246 return 0;
a6dfe2d9 247 }
c68e9c6b 248 /* Pragma: no-cache in _replies_ is not documented in HTTP,
249 * but servers like "Active Imaging Webcast/2.0" sure do use it */
250 if (httpHeaderHas(hdr, HDR_PRAGMA)) {
251 String s = httpHeaderGetList(hdr, HDR_PRAGMA);
252 const int no_cache = strListIsMember(&s, "no-cache", ',');
253 stringClean(&s);
254 if (no_cache)
255 return 0;
256 }
257 /*
258 * The "multipart/x-mixed-replace" content type is used for
259 * continuous push replies. These are generally dynamic and
260 * probably should not be cachable
261 */
262 if ((v = httpHeaderGetStr(hdr, HDR_CONTENT_TYPE)))
263 if (!strncasecmp(v, "multipart/x-mixed-replace", 25))
264 return 0;
cb69b4c7 265 switch (httpState->entry->mem_obj->reply->sline.status) {
c54e9052 266 /* Responses that are cacheable */
19a04dac 267 case HTTP_OK:
268 case HTTP_NON_AUTHORITATIVE_INFORMATION:
269 case HTTP_MULTIPLE_CHOICES:
270 case HTTP_MOVED_PERMANENTLY:
271 case HTTP_GONE:
cfa9f1cb 272 /*
273 * Don't cache objects that need to be refreshed on next request,
274 * unless we know how to refresh it.
275 */
276 if (!refreshIsCachable(httpState->entry))
277 return 0;
1294c0fc 278 /* don't cache objects from peers w/o LMT, Date, or Expires */
cb69b4c7 279 /* check that is it enough to check headers @?@ */
d8b249ef 280 if (rep->date > -1)
c54e9052 281 return 1;
d8b249ef 282 else if (rep->last_modified > -1)
c54e9052 283 return 1;
29b8d8d6 284 else if (!httpState->_peer)
c54e9052 285 return 1;
d8b249ef 286 /* @?@ (here and 302): invalid expires header compiles to squid_curtime */
287 else if (rep->expires > -1)
c54e9052 288 return 1;
c54e9052 289 else
290 return 0;
79d39a72 291 /* NOTREACHED */
c54e9052 292 break;
293 /* Responses that only are cacheable if the server says so */
19a04dac 294 case HTTP_MOVED_TEMPORARILY:
d8b249ef 295 if (rep->expires > -1)
c54e9052 296 return 1;
297 else
298 return 0;
79d39a72 299 /* NOTREACHED */
c54e9052 300 break;
301 /* Errors can be negatively cached */
19a04dac 302 case HTTP_NO_CONTENT:
303 case HTTP_USE_PROXY:
304 case HTTP_BAD_REQUEST:
305 case HTTP_FORBIDDEN:
306 case HTTP_NOT_FOUND:
307 case HTTP_METHOD_NOT_ALLOWED:
308 case HTTP_REQUEST_URI_TOO_LARGE:
309 case HTTP_INTERNAL_SERVER_ERROR:
310 case HTTP_NOT_IMPLEMENTED:
311 case HTTP_BAD_GATEWAY:
312 case HTTP_SERVICE_UNAVAILABLE:
313 case HTTP_GATEWAY_TIMEOUT:
c54e9052 314 return -1;
79d39a72 315 /* NOTREACHED */
c54e9052 316 break;
317 /* Some responses can never be cached */
0cdcddb9 318 case HTTP_PARTIAL_CONTENT: /* Not yet supported */
19a04dac 319 case HTTP_SEE_OTHER:
320 case HTTP_NOT_MODIFIED:
321 case HTTP_UNAUTHORIZED:
322 case HTTP_PROXY_AUTHENTICATION_REQUIRED:
0cdcddb9 323 case HTTP_INVALID_HEADER: /* Squid header parsing error */
c54e9052 324 default: /* Unknown status code */
325 return 0;
79d39a72 326 /* NOTREACHED */
c54e9052 327 break;
328 }
79d39a72 329 /* NOTREACHED */
c54e9052 330}
090089c4 331
f66a9ef4 332/*
333 * For Vary, store the relevant request headers as
334 * virtual headers in the reply
335 * Returns false if the variance cannot be stored
336 */
337const char *
338httpMakeVaryMark(request_t * request, HttpReply * reply)
339{
f66a9ef4 340 String vary, hdr;
341 const char *pos = NULL;
342 const char *item;
343 const char *value;
344 int ilen;
345 static String vstr =
346 {0, 0, NULL};
347
348 stringClean(&vstr);
349 vary = httpHeaderGetList(&reply->header, HDR_VARY);
350 while (strListGetItem(&vary, ',', &item, &ilen, &pos)) {
e6ccf245 351 char *name = (char *)xmalloc(ilen + 1);
f66a9ef4 352 xstrncpy(name, item, ilen + 1);
353 Tolower(name);
354 strListAdd(&vstr, name, ',');
355 hdr = httpHeaderGetByName(&request->header, name);
356 safe_free(name);
357 value = strBuf(hdr);
358 if (value) {
70508bf5 359 value = rfc1738_escape_part(value);
f66a9ef4 360 stringAppend(&vstr, "=\"", 2);
361 stringAppend(&vstr, value, strlen(value));
362 stringAppend(&vstr, "\"", 1);
363 }
364 stringClean(&hdr);
365 }
366 stringClean(&vary);
367#if X_ACCELERATOR_VARY
368 vary = httpHeaderGetList(&reply->header, HDR_X_ACCELERATOR_VARY);
369 while (strListGetItem(&vary, ',', &item, &ilen, &pos)) {
7058745b 370 char *name = (char *)xmalloc(ilen + 1);
f66a9ef4 371 xstrncpy(name, item, ilen + 1);
372 Tolower(name);
373 strListAdd(&vstr, name, ',');
374 hdr = httpHeaderGetByName(&request->header, name);
375 safe_free(name);
376 value = strBuf(hdr);
377 if (value) {
70508bf5 378 value = rfc1738_escape_part(value);
f66a9ef4 379 stringAppend(&vstr, "=\"", 2);
380 stringAppend(&vstr, value, strlen(value));
381 stringAppend(&vstr, "\"", 1);
382 }
383 stringClean(&hdr);
384 }
385 stringClean(&vary);
386#endif
3a114cc1 387 debug(11, 3) ("httpMakeVaryMark: %s\n", strBuf(vstr));
f66a9ef4 388 return strBuf(vstr);
389}
390
cb69b4c7 391/* rewrite this later using new interfaces @?@ */
b8d8561b 392void
e6ccf245 393HttpStateData::processReplyHeader(const char *buf, int size)
f5558c95 394{
395 char *t = NULL;
d3fb4dea 396 int room;
9bc73deb 397 size_t hdr_len;
cb69b4c7 398 HttpReply *reply = entry->mem_obj->reply;
9bc73deb 399 Ctx ctx;
b6cfb65c 400 debug(11, 3) ("httpProcessReplyHeader: key '%s'\n",
e6ccf245 401 storeKeyText((const cache_key *)(entry->hash.key)));
402 if (reply_hdr == NULL)
403 reply_hdr = (char *)memAllocate(MEM_8K_BUF);
404 assert(reply_hdr_state == 0);
405 hdr_len = reply_hdr_size;
9bc73deb 406 room = 8191 - hdr_len;
e6ccf245 407 xmemcpy(reply_hdr + hdr_len, buf, room < size ? room : size);
9bc73deb 408 hdr_len += room < size ? room : size;
e6ccf245 409 reply_hdr[hdr_len] = '\0';
410 reply_hdr_size = hdr_len;
411 if (hdr_len > 4 && strncmp(reply_hdr, "HTTP/", 5)) {
412 debug(11, 3) ("httpProcessReplyHeader: Non-HTTP-compliant header: '%s'\n", reply_hdr);
413 reply_hdr_state += 2;
9bc73deb 414 reply->sline.status = HTTP_INVALID_HEADER;
e6ccf245 415 if (eof == 1) {
416 fwdComplete(fwd);
417 comm_close(fd);
418 }
9bc73deb 419 return;
f5558c95 420 }
e6ccf245 421 t = reply_hdr + hdr_len;
9bc73deb 422 /* headers can be incomplete only if object still arriving */
e6ccf245 423 if (!eof) {
424 size_t k = headersEnd(reply_hdr, 8192);
425 if (0 == k) {
426 if (eof == 1) {
427 fwdComplete(fwd);
428 comm_close(fd);
429 }
d20b1cd0 430 return; /* headers not complete */
e6ccf245 431 }
432 t = reply_hdr + k;
9bc73deb 433 }
434 *t = '\0';
e6ccf245 435 reply_hdr_state++;
436 assert(reply_hdr_state == 1);
9bc73deb 437 ctx = ctx_enter(entry->mem_obj->url);
e6ccf245 438 reply_hdr_state++;
9bc73deb 439 debug(11, 9) ("GOT HTTP REPLY HDR:\n---------\n%s\n----------\n",
e6ccf245 440 reply_hdr);
9bc73deb 441 /* Parse headers into reply structure */
442 /* what happens if we fail to parse here? */
e6ccf245 443 httpReplyParse(reply, reply_hdr, hdr_len);
9bc73deb 444 storeTimestampsSet(entry);
445 /* Check if object is cacheable or not based on reply code */
446 debug(11, 3) ("httpProcessReplyHeader: HTTP CODE: %d\n", reply->sline.status);
447 if (neighbors_do_private_keys)
448 httpMaybeRemovePublic(entry, reply->sline.status);
e6ccf245 449
450 switch (httpCachableReply(this)) {
9bc73deb 451 case 1:
f66a9ef4 452 if (httpHeaderHas(&reply->header, HDR_VARY)
453#if X_ACCELERATOR_VARY
454 || httpHeaderHas(&reply->header, HDR_X_ACCELERATOR_VARY)
455#endif
456 ) {
e6ccf245 457 const char *vary = httpMakeVaryMark(orig_request, reply);
f66a9ef4 458 if (vary) {
459 entry->mem_obj->vary_headers = xstrdup(vary);
460 /* Kill the old base object if a change in variance is detected */
461 httpMakePublic(entry);
462 } else {
463 httpMakePrivate(entry);
464 }
465 } else {
466 httpMakePublic(entry);
467 }
9bc73deb 468 break;
469 case 0:
470 httpMakePrivate(entry);
471 break;
472 case -1:
473 httpCacheNegatively(entry);
474 break;
475 default:
476 assert(0);
477 break;
478 }
479 if (reply->cache_control) {
480 if (EBIT_TEST(reply->cache_control->mask, CC_PROXY_REVALIDATE))
481 EBIT_SET(entry->flags, ENTRY_REVALIDATE);
482 else if (EBIT_TEST(reply->cache_control->mask, CC_MUST_REVALIDATE))
483 EBIT_SET(entry->flags, ENTRY_REVALIDATE);
484 }
e6ccf245 485 if (flags.keepalive)
486 if (_peer)
487 _peer->stats.n_keepalives_sent++;
9bc73deb 488 if (reply->keep_alive)
e6ccf245 489 if (_peer)
490 _peer->stats.n_keepalives_recv++;
491 if (reply->date > -1 && !_peer) {
9bc73deb 492 int skew = abs(reply->date - squid_curtime);
493 if (skew > 86400)
494 debug(11, 3) ("%s's clock is skewed by %d seconds!\n",
e6ccf245 495 request->host, skew);
f5558c95 496 }
9bc73deb 497 ctx_exit(ctx);
c3609322 498#if HEADERS_LOG
e6ccf245 499 headersLog(1, 0, request->method, reply);
c3609322 500#endif
e6ccf245 501 if (eof == 1) {
502 fwdComplete(fwd);
503 comm_close(fd);
504 }
f5558c95 505}
506
603a02fd 507static int
508httpPconnTransferDone(HttpStateData * httpState)
509{
510 /* return 1 if we got the last of the data on a persistent connection */
511 MemObject *mem = httpState->entry->mem_obj;
cb69b4c7 512 HttpReply *reply = mem->reply;
35282fbf 513 int clen;
51fdcbd5 514 debug(11, 3) ("httpPconnTransferDone: FD %d\n", httpState->fd);
978e455f 515 /*
99edd1c3 516 * If we didn't send a keep-alive request header, then this
978e455f 517 * can not be a persistent connection.
518 */
b515fc11 519 if (!httpState->flags.keepalive)
603a02fd 520 return 0;
9f5a2895 521 /*
522 * What does the reply have to say about keep-alive?
523 */
b6a2f15e 524 /*
525 * XXX BUG?
526 * If the origin server (HTTP/1.0) does not send a keep-alive
527 * header, but keeps the connection open anyway, what happens?
528 * We'll return here and http.c waits for an EOF before changing
529 * store_status to STORE_OK. Combine this with ENTRY_FWD_HDR_WAIT
530 * and an error status code, and we might have to wait until
531 * the server times out the socket.
532 */
9f5a2895 533 if (!reply->keep_alive)
534 return 0;
51fdcbd5 535 debug(11, 5) ("httpPconnTransferDone: content_length=%d\n",
d8b249ef 536 reply->content_length);
35282fbf 537 /* If we haven't seen the end of reply headers, we are not done */
978e455f 538 if (httpState->reply_hdr_state < 2)
539 return 0;
35282fbf 540 clen = httpReplyBodySize(httpState->request->method, reply);
541 /* If there is no message body, we can be persistent */
542 if (0 == clen)
a3c60429 543 return 1;
35282fbf 544 /* If the body size is unknown we must wait for EOF */
545 if (clen < 0)
603a02fd 546 return 0;
35282fbf 547 /* If the body size is known, we must wait until we've gotten all of it. */
548 if (mem->inmem_hi < reply->content_length + reply->hdr_sz)
603a02fd 549 return 0;
35282fbf 550 /* We got it all */
551 return 1;
603a02fd 552}
090089c4 553
554/* This will be called when data is ready to be read from fd. Read until
555 * error or connection closed. */
f5558c95 556/* XXX this function is too long! */
b8d8561b 557static void
c4b7a5a9 558httpReadReply(int fd, char *buf, size_t len, comm_err_t flag, int xerrno,void *data)
559{
560 HttpStateData *httpState = static_cast<HttpStateData *>(data);
561 httpState->readReply (fd, buf, len, flag, xerrno, data);
562}
563
564void
565HttpStateData::readReply (int fd, char *buf, size_t len, comm_err_t flag, int xerrno,void *data)
090089c4 566{
e6ccf245 567 HttpStateData *httpState = static_cast<HttpStateData *>(data);
bfcaf585 568 StoreEntry *entry = httpState->entry;
603a02fd 569 const request_t *request = httpState->request;
30a4f2a8 570 int bin;
090089c4 571 int clen;
c4b7a5a9 572 read_sz = SQUID_TCP_SO_RCVBUF;
573 do_next_read = 0;
447e176b 574#if DELAY_POOLS
4326a9b6 575 delay_id delayId;
59715b38 576
577 /* special "if" only for http (for nodelay proxy conns) */
578 if (delayIsNoDelay(fd))
4326a9b6 579 delayId = 0;
59715b38 580 else
4326a9b6 581 delayId = delayMostBytesAllowed(entry->mem_obj);
447e176b 582#endif
c4b7a5a9 583
584
585 assert(buf == httpState->buf);
586
587 /* Bail out early on COMM_ERR_CLOSING - close handlers will tidy up for us
588*/
589 if (flag == COMM_ERR_CLOSING) {
590 return;
591 }
592
593
594
e92e4e44 595 if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
c4b7a5a9 596 maybeReadData();
e92e4e44 597 return;
598 }
c4b7a5a9 599
1513873c 600 errno = 0;
c4b7a5a9 601 /* prepare the read size for the next read (if any) */
447e176b 602#if DELAY_POOLS
4326a9b6 603 read_sz = delayBytesWanted(delayId, 1, read_sz);
447e176b 604#endif
c4b7a5a9 605 debug(11, 5) ("httpReadReply: FD %d: len %d.\n", fd, (int)len);
606 if (flag == COMM_OK && len > 0) {
447e176b 607#if DELAY_POOLS
4326a9b6 608 delayBytesIn(delayId, len);
447e176b 609#endif
83704487 610 kb_incr(&statCounter.server.all.kbytes_in, len);
611 kb_incr(&statCounter.server.http.kbytes_in, len);
4f92c80c 612 commSetTimeout(fd, Config.Timeout.read, NULL, NULL);
4a63c85f 613 IOStats.Http.reads++;
30a4f2a8 614 for (clen = len - 1, bin = 0; clen; bin++)
615 clen >>= 1;
616 IOStats.Http.read_hist[bin]++;
617 }
c4b7a5a9 618 if (!httpState->reply_hdr && flag == COMM_OK && len > 0) {
5ede6c8f 619 /* Skip whitespace */
b6a2f15e 620 while (len > 0 && xisspace(*buf))
5ede6c8f 621 xmemmove(buf, buf + 1, len--);
622 if (len == 0) {
623 /* Continue to read... */
c4b7a5a9 624 do_next_read = 1;
625 maybeReadData();
5ede6c8f 626 return;
627 }
628 }
c4b7a5a9 629 if (flag != COMM_OK || len < 0) {
55cb44f1 630 debug(50, 2) ("httpReadReply: FD %d: read failure: %s.\n",
631 fd, xstrerror());
b224ea98 632 if (ignoreErrno(errno)) {
c4b7a5a9 633 do_next_read = 1;
910169e5 634 } else if (entry->mem_obj->inmem_hi == 0) {
ec250dfd 635 ErrorState *err;
636 err = errorCon(ERR_READ_ERROR, HTTP_INTERNAL_SERVER_ERROR);
b16e464a 637 err->request = requestLink((request_t *) request);
ec250dfd 638 err->xerrno = errno;
639 fwdFail(httpState->fwd, err);
c4b7a5a9 640 do_next_read = 0;
1afe05c5 641 comm_close(fd);
090089c4 642 } else {
c4b7a5a9 643 do_next_read = 0;
0d4d4170 644 comm_close(fd);
090089c4 645 }
c4b7a5a9 646 } else if (flag == COMM_OK && len == 0 && entry->mem_obj->inmem_hi == 0) {
ec250dfd 647 ErrorState *err;
648 err = errorCon(ERR_ZERO_SIZE_OBJECT, HTTP_SERVICE_UNAVAILABLE);
649 err->xerrno = errno;
b16e464a 650 err->request = requestLink((request_t *) request);
ec250dfd 651 fwdFail(httpState->fwd, err);
910169e5 652 httpState->eof = 1;
c4b7a5a9 653 do_next_read = 0;
910169e5 654 comm_close(fd);
c4b7a5a9 655 } else if (flag == COMM_OK && len == 0) {
090089c4 656 /* Connection closed; retrieval done. */
f86a6a46 657 httpState->eof = 1;
d1a43e28 658 if (httpState->reply_hdr_state < 2)
b34ed725 659 /*
660 * Yes Henrik, there is a point to doing this. When we
661 * called httpProcessReplyHeader() before, we didn't find
662 * the end of headers, but now we are definately at EOF, so
663 * we want to process the reply headers.
664 */
e6ccf245 665 /* doesn't return */
666 httpState->processReplyHeader(buf, len);
667 else {
668 fwdComplete(httpState->fwd);
c4b7a5a9 669 do_next_read = 0;
e6ccf245 670 comm_close(fd);
671 }
090089c4 672 } else {
7e3e1d01 673 if (httpState->reply_hdr_state < 2) {
e6ccf245 674 httpState->processReplyHeader(buf, len);
db1cd23c 675 if (httpState->reply_hdr_state == 2) {
676 http_status s = entry->mem_obj->reply->sline.status;
225644d7 677#if WIP_FWD_LOG
678 fwdStatus(httpState->fwd, s);
679#endif
b6a2f15e 680 /*
681 * If its not a reply that we will re-forward, then
682 * allow the client to get it.
db1cd23c 683 */
b6a2f15e 684 if (!fwdReforwardableStatus(s))
db1cd23c 685 EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
686 }
7e3e1d01 687 }
e6ccf245 688 httpState->processReplyData(buf, len);
689 }
690}
691
692void
693HttpStateData::processReplyData(const char *buf, int len)
694{
695 storeAppend(entry, buf, len);
696 if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
697 /*
698 * the above storeAppend() call could ABORT this entry,
699 * in that case, the server FD should already be closed.
700 * there's nothing for us to do.
701 */
702 (void) 0;
703 } else if (httpPconnTransferDone(this)) {
704 /* yes we have to clear all these! */
705 commSetDefer(fd, NULL, NULL);
706 commSetTimeout(fd, -1, NULL, NULL);
c4b7a5a9 707 do_next_read = 0;
ec603b25 708#if DELAY_POOLS
e6ccf245 709 delayClearNoDelay(fd);
ec603b25 710#endif
e6ccf245 711 comm_remove_close_handler(fd, httpStateFree, this);
712 fwdUnregister(fd, fwd);
713 pconnPush(fd, request->host, request->port);
714 fwdComplete(fwd);
715 fd = -1;
716 httpStateFree(fd, this);
717 } else {
718 /* Wait for EOF condition */
c4b7a5a9 719 do_next_read = 1;
090089c4 720 }
c4b7a5a9 721 maybeReadData();
722}
723
724void
725HttpStateData::maybeReadData()
726{
727 if (do_next_read)
728 comm_read(fd, buf, read_sz, httpReadReply, this);
090089c4 729}
730
731/* This will be called when request write is complete. Schedule read of
732 * reply. */
b8d8561b 733static void
3d7e9d7c 734httpSendComplete(int fd, char *bufnotused, size_t size, comm_err_t errflag, void *data)
090089c4 735{
e6ccf245 736 HttpStateData *httpState = static_cast<HttpStateData *>(data);
9b312a19 737 StoreEntry *entry = httpState->entry;
738 ErrorState *err;
a3d5953d 739 debug(11, 5) ("httpSendComplete: FD %d: size %d: errflag %d.\n",
ed19251a 740 fd, (int) size, errflag);
bc87dc25 741#if URL_CHECKSUM_DEBUG
742 assert(entry->mem_obj->chksum == url_checksum(entry->mem_obj->url));
743#endif
ee1679df 744 if (size > 0) {
745 fd_bytes(fd, size, FD_WRITE);
83704487 746 kb_incr(&statCounter.server.all.kbytes_out, size);
747 kb_incr(&statCounter.server.http.kbytes_out, size);
ee1679df 748 }
ea3a2a69 749 if (errflag == COMM_ERR_CLOSING)
750 return;
090089c4 751 if (errflag) {
fe40a877 752 err = errorCon(ERR_WRITE_ERROR, HTTP_INTERNAL_SERVER_ERROR);
c45ed9ad 753 err->xerrno = errno;
79a15e0a 754 err->request = requestLink(httpState->orig_request);
9b312a19 755 errorAppendEntry(entry, err);
0d4d4170 756 comm_close(fd);
090089c4 757 return;
758 } else {
759 /* Schedule read reply. */
c4b7a5a9 760 /* XXX we're not taking into account delay pools on this read! */
761 comm_read(fd, httpState->buf, SQUID_TCP_SO_RCVBUF, httpReadReply, httpState);
b6a2f15e 762 /*
763 * Set the read timeout here because it hasn't been set yet.
764 * We only set the read timeout after the request has been
765 * fully written to the server-side. If we start the timeout
766 * after connection establishment, then we are likely to hit
767 * the timeout for POST/PUT requests that have very large
768 * request bodies.
769 */
770 commSetTimeout(fd, Config.Timeout.read, httpTimeout, httpState);
41462d93 771 commSetDefer(fd, fwdCheckDeferRead, entry);
090089c4 772 }
773}
774
99edd1c3 775/*
776 * build request headers and append them to a given MemBuf
777 * used by httpBuildRequestPrefix()
778 * note: calls httpHeaderInit(), the caller is responsible for Clean()-ing
779 */
e1e72f06 780void
6bf8443a 781httpBuildRequestHeader(request_t * request,
782 request_t * orig_request,
783 StoreEntry * entry,
5999b776 784 HttpHeader * hdr_out,
b515fc11 785 http_state_flags flags)
6bf8443a 786{
99edd1c3 787 /* building buffer for complex strings */
5999b776 788#define BBUF_SZ (MAX_URL+32)
99edd1c3 789 LOCAL_ARRAY(char, bbuf, BBUF_SZ);
790 String strConnection = StringNull;
791 const HttpHeader *hdr_in = &orig_request->header;
792 const HttpHeaderEntry *e;
6bccf575 793 String strFwd;
99edd1c3 794 HttpHeaderPos pos = HttpHeaderInitPos;
2246b732 795 httpHeaderInit(hdr_out, hoRequest);
99edd1c3 796 /* append our IMS header */
9bc73deb 797 if (request->lastmod > -1 && request->method == METHOD_GET)
798 httpHeaderPutTime(hdr_out, HDR_IF_MODIFIED_SINCE, request->lastmod);
99edd1c3 799
800 strConnection = httpHeaderGetList(hdr_in, HDR_CONNECTION);
801 while ((e = httpHeaderGetEntry(hdr_in, &pos))) {
802 debug(11, 5) ("httpBuildRequestHeader: %s: %s\n",
803 strBuf(e->name), strBuf(e->value));
b7677233 804 if (!httpRequestHdrAllowed(e, &strConnection)) {
805 debug(11, 2) ("'%s' header denied by anonymize_headers configuration\n",
806 strBuf(e->name));
6bf8443a 807 continue;
b7677233 808 }
99edd1c3 809 switch (e->id) {
810 case HDR_PROXY_AUTHORIZATION:
94439e4e 811 /* Only pass on proxy authentication to peers for which
812 * authentication forwarding is explicitly enabled
813 */
814 if (request->flags.proxying && orig_request->peer_login &&
815 strcmp(orig_request->peer_login, "PASS") == 0) {
99edd1c3 816 httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
94439e4e 817 }
99edd1c3 818 break;
c68e9c6b 819 case HDR_AUTHORIZATION:
94439e4e 820 /* Pass on WWW authentication even if used locally. If this is
821 * not wanted in an accelerator then the header can be removed
822 * using the anonymization functions
823 */
824 httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
825 /* XXX Some accelerators might want to strip the header
826 * and regard the reply as cacheable, but authentication
827 * is not normally enabled for accelerators without reading
828 * the code, so there is not much use in adding logics here
829 * without first defining the concept of having authentication
830 * in the accelerator...
831 */
c68e9c6b 832 break;
99edd1c3 833 case HDR_HOST:
7e3ce7b9 834 /*
835 * Normally Squid does not copy the Host: header from
836 * a client request into the forwarded request headers.
837 * However, there is one case when we do: If the URL
838 * went through our redirector and the admin configured
839 * 'redir_rewrites_host' to be off.
840 */
841 if (request->flags.redirected)
842 if (!Config.onoff.redir_rewrites_host)
843 httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
99edd1c3 844 break;
845 case HDR_IF_MODIFIED_SINCE:
846 /* append unless we added our own;
847 * note: at most one client's ims header can pass through */
848 if (!httpHeaderHas(hdr_out, HDR_IF_MODIFIED_SINCE))
849 httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
850 break;
851 case HDR_MAX_FORWARDS:
b3b64e58 852 if (orig_request->method == METHOD_TRACE) {
99edd1c3 853 /* sacrificing efficiency over clarity, etc. */
854 const int hops = httpHeaderGetInt(hdr_in, HDR_MAX_FORWARDS);
855 if (hops > 0)
5999b776 856 httpHeaderPutInt(hdr_out, HDR_MAX_FORWARDS, hops - 1);
b3b64e58 857 }
99edd1c3 858 break;
736cb6aa 859 case HDR_VIA:
860 /* If Via is disabled then forward any received header as-is */
861 if (!Config.onoff.via)
862 httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
863 break;
99edd1c3 864 case HDR_PROXY_CONNECTION:
865 case HDR_CONNECTION:
99edd1c3 866 case HDR_X_FORWARDED_FOR:
867 case HDR_CACHE_CONTROL:
868 /* append these after the loop if needed */
869 break;
870 default:
871 /* pass on all other header fields */
872 httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e));
66f7337b 873 }
88738790 874 }
99edd1c3 875
99edd1c3 876 /* append Via */
736cb6aa 877 if (Config.onoff.via) {
878 String strVia = httpHeaderGetList(hdr_in, HDR_VIA);
879 snprintf(bbuf, BBUF_SZ, "%d.%d %s",
880 orig_request->http_ver.major,
881 orig_request->http_ver.minor, ThisCache);
882 strListAdd(&strVia, bbuf, ',');
883 httpHeaderPutStr(hdr_out, HDR_VIA, strBuf(strVia));
884 stringClean(&strVia);
885 }
99edd1c3 886 /* append X-Forwarded-For */
6bccf575 887 strFwd = httpHeaderGetList(hdr_in, HDR_X_FORWARDED_FOR);
6056ae68 888 if (opt_forwarded_for && orig_request->client_addr.s_addr != no_addr.s_addr)
889 strListAdd(&strFwd, inet_ntoa(orig_request->client_addr), ',');
890 else
891 strListAdd(&strFwd, "unknown", ',');
6bccf575 892 httpHeaderPutStr(hdr_out, HDR_X_FORWARDED_FOR, strBuf(strFwd));
893 stringClean(&strFwd);
894
99edd1c3 895 /* append Host if not there already */
896 if (!httpHeaderHas(hdr_out, HDR_HOST)) {
897 /* use port# only if not default */
898 if (orig_request->port == urlDefaultPort(orig_request->protocol)) {
899 httpHeaderPutStr(hdr_out, HDR_HOST, orig_request->host);
900 } else {
2246b732 901 httpHeaderPutStrf(hdr_out, HDR_HOST, "%s:%d",
99edd1c3 902 orig_request->host, (int) orig_request->port);
99edd1c3 903 }
6bf8443a 904 }
c68e9c6b 905 /* append Authorization if known in URL, not in header and going direct */
906 if (!httpHeaderHas(hdr_out, HDR_AUTHORIZATION)) {
907 if (!request->flags.proxying && *request->login) {
908 httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s",
909 base64_encode(request->login));
910 }
911 }
912 /* append Proxy-Authorization if configured for peer, and proxying */
c3b33cb7 913 if (request->flags.proxying && orig_request->peer_login &&
2b6662ba 914 !httpHeaderHas(hdr_out, HDR_PROXY_AUTHORIZATION) &&
915 strcmp(orig_request->peer_login, "PASS") != 0) {
c3b33cb7 916 if (*orig_request->peer_login == '*') {
917 /* Special mode, to pass the username to the upstream cache */
918 char loginbuf[256];
a2c963ae 919 const char *username = "-";
c3b33cb7 920 if (orig_request->auth_user_request)
e6ccf245 921 username = orig_request->auth_user_request->username();
2b6662ba 922 snprintf(loginbuf, sizeof(loginbuf), "%s%s", username, orig_request->peer_login + 1);
c3b33cb7 923 httpHeaderPutStrf(hdr_out, HDR_PROXY_AUTHORIZATION, "Basic %s",
924 base64_encode(loginbuf));
925 } else {
c68e9c6b 926 httpHeaderPutStrf(hdr_out, HDR_PROXY_AUTHORIZATION, "Basic %s",
1f38f50a 927 base64_encode(orig_request->peer_login));
c68e9c6b 928 }
929 }
99edd1c3 930 /* append Cache-Control, add max-age if not there already */
931 {
932 HttpHdrCc *cc = httpHeaderGetCc(hdr_in);
933 if (!cc)
934 cc = httpHdrCcCreate();
935 if (!EBIT_TEST(cc->mask, CC_MAX_AGE)) {
9b5d1d21 936 const char *url = entry ? storeUrl(entry) : urlCanonical(orig_request);
99edd1c3 937 httpHdrCcSetMaxAge(cc, getMaxAge(url));
938 if (strLen(request->urlpath))
939 assert(strstr(url, strBuf(request->urlpath)));
940 }
db1cd23c 941 if (flags.only_if_cached)
942 EBIT_SET(cc->mask, CC_ONLY_IF_CACHED);
99edd1c3 943 httpHeaderPutCc(hdr_out, cc);
944 httpHdrCcDestroy(cc);
6bf8443a 945 }
99edd1c3 946 /* maybe append Connection: keep-alive */
b515fc11 947 if (flags.keepalive) {
948 if (flags.proxying) {
99edd1c3 949 httpHeaderPutStr(hdr_out, HDR_PROXY_CONNECTION, "keep-alive");
603a02fd 950 } else {
99edd1c3 951 httpHeaderPutStr(hdr_out, HDR_CONNECTION, "keep-alive");
603a02fd 952 }
603a02fd 953 }
6bccf575 954 /* Now mangle the headers. */
955 httpHdrMangleList(hdr_out, request);
99edd1c3 956 stringClean(&strConnection);
957}
958
959/* build request prefix and append it to a given MemBuf;
960 * return the length of the prefix */
9bc73deb 961mb_size_t
99edd1c3 962httpBuildRequestPrefix(request_t * request,
963 request_t * orig_request,
964 StoreEntry * entry,
5999b776 965 MemBuf * mb,
b515fc11 966 http_state_flags flags)
99edd1c3 967{
968 const int offset = mb->size;
969 memBufPrintf(mb, "%s %s HTTP/1.0\r\n",
970 RequestMethodStr[request->method],
971 strLen(request->urlpath) ? strBuf(request->urlpath) : "/");
972 /* build and pack headers */
973 {
974 HttpHeader hdr;
975 Packer p;
6056ae68 976 httpBuildRequestHeader(request, orig_request, entry, &hdr, flags);
99edd1c3 977 packerToMemInit(&p, mb);
978 httpHeaderPackInto(&hdr, &p);
979 httpHeaderClean(&hdr);
980 packerClean(&p);
9d9d144b 981 }
99edd1c3 982 /* append header terminator */
b8890359 983 memBufAppend(mb, crlf, 2);
99edd1c3 984 return mb->size - offset;
6bf8443a 985}
090089c4 986/* This will be called when connect completes. Write request. */
b8d8561b 987static void
b6a2f15e 988httpSendRequest(HttpStateData * httpState)
090089c4 989{
99edd1c3 990 MemBuf mb;
30a4f2a8 991 request_t *req = httpState->request;
620da955 992 StoreEntry *entry = httpState->entry;
29b8d8d6 993 peer *p = httpState->_peer;
901e234d 994 CWCB *sendHeaderDone;
090089c4 995
b6a2f15e 996 debug(11, 5) ("httpSendRequest: FD %d: httpState %p.\n", httpState->fd, httpState);
090089c4 997
94439e4e 998 if (httpState->orig_request->body_connection)
c3d63b2a 999 sendHeaderDone = httpSendRequestEntity;
7db8b16d 1000 else
1001 sendHeaderDone = httpSendComplete;
54220df8 1002
1294c0fc 1003 if (p != NULL)
b515fc11 1004 httpState->flags.proxying = 1;
94439e4e 1005 else
1006 httpState->flags.proxying = 0;
efb9218c 1007 /*
99edd1c3 1008 * Is keep-alive okay for all request methods?
efb9218c 1009 */
efd900cb 1010 if (!Config.onoff.server_pconns)
1011 httpState->flags.keepalive = 0;
1012 else if (p == NULL)
b515fc11 1013 httpState->flags.keepalive = 1;
efb9218c 1014 else if (p->stats.n_keepalives_sent < 10)
b515fc11 1015 httpState->flags.keepalive = 1;
efb9218c 1016 else if ((double) p->stats.n_keepalives_recv / (double) p->stats.n_keepalives_sent > 0.50)
b515fc11 1017 httpState->flags.keepalive = 1;
29b8d8d6 1018 if (httpState->_peer)
1019 if (neighborType(httpState->_peer, httpState->request) == PEER_SIBLING &&
1020 !httpState->_peer->options.allow_miss)
db1cd23c 1021 httpState->flags.only_if_cached = 1;
99edd1c3 1022 memBufDefInit(&mb);
1023 httpBuildRequestPrefix(req,
79a15e0a 1024 httpState->orig_request,
6bf8443a 1025 entry,
99edd1c3 1026 &mb,
603a02fd 1027 httpState->flags);
b6a2f15e 1028 debug(11, 6) ("httpSendRequest: FD %d:\n%s\n", httpState->fd, mb.buf);
1029 comm_write_mbuf(httpState->fd, mb, sendHeaderDone, httpState);
090089c4 1030}
b6a2f15e 1031
910169e5 1032void
db1cd23c 1033httpStart(FwdState * fwd)
603a02fd 1034{
db1cd23c 1035 int fd = fwd->server_fd;
28c60158 1036 HttpStateData *httpState;
910169e5 1037 request_t *proxy_req;
db1cd23c 1038 request_t *orig_req = fwd->request;
910169e5 1039 debug(11, 3) ("httpStart: \"%s %s\"\n",
1040 RequestMethodStr[orig_req->method],
db1cd23c 1041 storeUrl(fwd->entry));
e6ccf245 1042 CBDATA_INIT_TYPE(HttpStateData);
72711e31 1043 httpState = cbdataAlloc(HttpStateData);
db1cd23c 1044 storeLockObject(fwd->entry);
1045 httpState->fwd = fwd;
1046 httpState->entry = fwd->entry;
9e4ad609 1047 httpState->fd = fd;
db1cd23c 1048 if (fwd->servers)
29b8d8d6 1049 httpState->_peer = fwd->servers->_peer; /* might be NULL */
1050 if (httpState->_peer) {
910169e5 1051 proxy_req = requestCreate(orig_req->method,
1052 PROTO_NONE, storeUrl(httpState->entry));
29b8d8d6 1053 xstrncpy(proxy_req->host, httpState->_peer->host, SQUIDHOSTNAMELEN);
1054 proxy_req->port = httpState->_peer->http_port;
23e8446b 1055 proxy_req->flags = orig_req->flags;
9bc73deb 1056 proxy_req->lastmod = orig_req->lastmod;
910169e5 1057 httpState->request = requestLink(proxy_req);
910169e5 1058 httpState->orig_request = requestLink(orig_req);
92695e5e 1059 proxy_req->flags.proxying = 1;
910169e5 1060 /*
1061 * This NEIGHBOR_PROXY_ONLY check probably shouldn't be here.
1062 * We might end up getting the object from somewhere else if,
1063 * for example, the request to this neighbor fails.
1064 */
29b8d8d6 1065 if (httpState->_peer->options.proxy_only)
910169e5 1066 storeReleaseRequest(httpState->entry);
95e36d02 1067#if DELAY_POOLS
59715b38 1068 assert(delayIsNoDelay(fd) == 0);
29b8d8d6 1069 if (httpState->_peer->options.no_delay)
59715b38 1070 delaySetNoDelay(fd);
95e36d02 1071#endif
603a02fd 1072 } else {
910169e5 1073 httpState->request = requestLink(orig_req);
1074 httpState->orig_request = requestLink(orig_req);
603a02fd 1075 }
910169e5 1076 /*
1077 * register the handler to free HTTP state data when the FD closes
1078 */
1079 comm_add_close_handler(fd, httpStateFree, httpState);
83704487 1080 statCounter.server.all.requests++;
1081 statCounter.server.http.requests++;
b6a2f15e 1082 httpSendRequest(httpState);
1083 /*
1084 * We used to set the read timeout here, but not any more.
1085 * Now its set in httpSendComplete() after the full request,
1086 * including request body, has been written to the server.
1087 */
090089c4 1088}
1089
54220df8 1090static void
c3d63b2a 1091httpSendRequestEntityDone(int fd, void *data)
54220df8 1092{
e6ccf245 1093 HttpStateData *httpState = static_cast<HttpStateData *>(data);
94439e4e 1094 aclCheck_t ch;
c3d63b2a 1095 debug(11, 5) ("httpSendRequestEntityDone: FD %d\n",
94439e4e 1096 fd);
1097 memset(&ch, '\0', sizeof(ch));
1098 ch.request = httpState->request;
1099 if (!Config.accessList.brokenPosts) {
c3d63b2a 1100 debug(11, 5) ("httpSendRequestEntityDone: No brokenPosts list\n");
e6ccf245 1101 httpSendComplete(fd, NULL, 0, COMM_OK, data);
94439e4e 1102 } else if (!aclCheckFast(Config.accessList.brokenPosts, &ch)) {
c3d63b2a 1103 debug(11, 5) ("httpSendRequestEntityDone: didn't match brokenPosts\n");
e6ccf245 1104 httpSendComplete(fd, NULL, 0, COMM_OK, data);
94439e4e 1105 } else {
c3d63b2a 1106 debug(11, 2) ("httpSendRequestEntityDone: matched brokenPosts\n");
94439e4e 1107 comm_write(fd, "\r\n", 2, httpSendComplete, data, NULL);
54220df8 1108 }
94439e4e 1109}
1110
1111static void
e6ccf245 1112httpRequestBodyHandler(char *buf, ssize_t size, void *data)
94439e4e 1113{
1114 HttpStateData *httpState = (HttpStateData *) data;
1115 if (size > 0) {
c3d63b2a 1116 comm_write(httpState->fd, buf, size, httpSendRequestEntity, data, memFree8K);
94439e4e 1117 } else if (size == 0) {
1118 /* End of body */
1119 memFree8K(buf);
c3d63b2a 1120 httpSendRequestEntityDone(httpState->fd, data);
94439e4e 1121 } else {
1122 /* Failed to get whole body, probably aborted */
1123 memFree8K(buf);
1124 httpSendComplete(httpState->fd, NULL, 0, COMM_ERR_CLOSING, data);
b6a2f15e 1125 }
376bb137 1126}
1127
1128static void
3d7e9d7c 1129httpSendRequestEntity(int fd, char *bufnotused, size_t size, comm_err_t errflag, void *data)
376bb137 1130{
e6ccf245 1131 HttpStateData *httpState = static_cast<HttpStateData *>(data);
376bb137 1132 StoreEntry *entry = httpState->entry;
1133 ErrorState *err;
c3d63b2a 1134 debug(11, 5) ("httpSendRequestEntity: FD %d: size %d: errflag %d.\n",
ed19251a 1135 fd, (int) size, errflag);
376bb137 1136 if (size > 0) {
1137 fd_bytes(fd, size, FD_WRITE);
83704487 1138 kb_incr(&statCounter.server.all.kbytes_out, size);
1139 kb_incr(&statCounter.server.http.kbytes_out, size);
376bb137 1140 }
1141 if (errflag == COMM_ERR_CLOSING)
1142 return;
1143 if (errflag) {
1144 err = errorCon(ERR_WRITE_ERROR, HTTP_INTERNAL_SERVER_ERROR);
1145 err->xerrno = errno;
1146 err->request = requestLink(httpState->orig_request);
1147 errorAppendEntry(entry, err);
1148 comm_close(fd);
1149 return;
1150 }
94439e4e 1151 if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
1152 comm_close(fd);
1153 return;
376bb137 1154 }
e6ccf245 1155 clientReadBody(httpState->orig_request, (char *)memAllocate(MEM_8K_BUF), 8192, httpRequestBodyHandler, httpState);
54220df8 1156}
ccf44862 1157
1158void
110eb4e5 1159httpBuildVersion(http_version_t * version, unsigned int major, unsigned int minor)
1160{
1161 version->major = major;
1162 version->minor = minor;
ccf44862 1163}