]> git.ipfire.org Git - thirdparty/squid.git/blame - src/http.cc
dont call aclCheck if no direct access lists
[thirdparty/squid.git] / src / http.cc
CommitLineData
30a4f2a8 1/*
b6c0e933 2 * $Id: http.cc,v 1.152 1997/02/28 21:33:37 wessels Exp $
30a4f2a8 3 *
4 * DEBUG: section 11 Hypertext Transfer Protocol (HTTP)
5 * AUTHOR: Harvest Derived
6 *
42c04c16 7 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
30a4f2a8 8 * --------------------------------------------------------
9 *
10 * Squid is the result of efforts by numerous individuals from the
11 * Internet community. Development is led by Duane Wessels of the
12 * National Laboratory for Applied Network Research and funded by
13 * the National Science Foundation.
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 *
29 */
019dd986 30
31/*
30a4f2a8 32 * Copyright (c) 1994, 1995. All rights reserved.
33 *
34 * The Harvest software was developed by the Internet Research Task
35 * Force Research Group on Resource Discovery (IRTF-RD):
36 *
37 * Mic Bowman of Transarc Corporation.
38 * Peter Danzig of the University of Southern California.
39 * Darren R. Hardy of the University of Colorado at Boulder.
40 * Udi Manber of the University of Arizona.
41 * Michael F. Schwartz of the University of Colorado at Boulder.
42 * Duane Wessels of the University of Colorado at Boulder.
43 *
44 * This copyright notice applies to software in the Harvest
45 * ``src/'' directory only. Users should consult the individual
46 * copyright notices in the ``components/'' subdirectories for
47 * copyright information about other software bundled with the
48 * Harvest source code distribution.
49 *
50 * TERMS OF USE
51 *
52 * The Harvest software may be used and re-distributed without
53 * charge, provided that the software origin and research team are
54 * cited in any use of the system. Most commonly this is
55 * accomplished by including a link to the Harvest Home Page
56 * (http://harvest.cs.colorado.edu/) from the query page of any
57 * Broker you deploy, as well as in the query result pages. These
58 * links are generated automatically by the standard Broker
59 * software distribution.
60 *
61 * The Harvest software is provided ``as is'', without express or
62 * implied warranty, and with no support nor obligation to assist
63 * in its use, correction, modification or enhancement. We assume
64 * no liability with respect to the infringement of copyrights,
65 * trade secrets, or any patents, and are not responsible for
66 * consequential damages. Proper use of the Harvest software is
67 * entirely the responsibility of the user.
68 *
69 * DERIVATIVE WORKS
70 *
71 * Users may make derivative works from the Harvest software, subject
72 * to the following constraints:
73 *
74 * - You must include the above copyright notice and these
75 * accompanying paragraphs in all forms of derivative works,
76 * and any documentation and other materials related to such
77 * distribution and use acknowledge that the software was
78 * developed at the above institutions.
79 *
80 * - You must notify IRTF-RD regarding your distribution of
81 * the derivative work.
82 *
83 * - You must clearly notify users that your are distributing
84 * a modified version and not the original Harvest software.
85 *
86 * - Any derivative product is also subject to these copyright
87 * and use restrictions.
88 *
89 * Note that the Harvest software is NOT in the public domain. We
90 * retain copyright, as specified above.
91 *
92 * HISTORY OF FREE SOFTWARE STATUS
93 *
94 * Originally we required sites to license the software in cases
95 * where they were going to build commercial products/services
96 * around Harvest. In June 1995 we changed this policy. We now
97 * allow people to use the core Harvest software (the code found in
98 * the Harvest ``src/'' directory) for free. We made this change
99 * in the interest of encouraging the widest possible deployment of
100 * the technology. The Harvest software is really a reference
101 * implementation of a set of protocols and formats, some of which
102 * we intend to standardize. We encourage commercial
103 * re-implementations of code complying to this set of standards.
019dd986 104 */
44a47c6e 105
4a83b852 106/*
107 * Anonymizing patch by lutz@as-node.jena.thur.de
de3bdb4c 108 * have a look into http-anon.c to get more informations.
4a83b852 109 */
110
44a47c6e 111#include "squid.h"
090089c4 112
234967c9 113#define HTTP_DELETE_GAP (1<<18)
090089c4 114
4db43fab 115static const char *const w_space = " \t\n\r";
6bf8443a 116static const char *const crlf = "\r\n";
4db43fab 117
6fb52f6c 118typedef enum {
119 SCC_PUBLIC,
120 SCC_PRIVATE,
121 SCC_NOCACHE,
122 SCC_NOSTORE,
123 SCC_NOTRANSFORM,
124 SCC_MUSTREVALIDATE,
125 SCC_PROXYREVALIDATE,
126 SCC_MAXAGE,
127 SCC_ENUM_END
128} http_server_cc_t;
129
6bf8443a 130enum {
6fb52f6c 131 CCC_NOCACHE,
132 CCC_NOSTORE,
133 CCC_MAXAGE,
134 CCC_MAXSTALE,
135 CCC_MINFRESH,
136 CCC_ONLYIFCACHED,
137 CCC_ENUM_END
6bf8443a 138};
139
151a0b6d 140typedef enum {
141 HDR_ACCEPT,
142 HDR_AGE,
143 HDR_CONTENT_LENGTH,
144 HDR_CONTENT_MD5,
145 HDR_CONTENT_TYPE,
146 HDR_DATE,
147 HDR_ETAG,
148 HDR_EXPIRES,
6bf8443a 149 HDR_HOST,
151a0b6d 150 HDR_IMS,
151 HDR_LAST_MODIFIED,
152 HDR_MAX_FORWARDS,
153 HDR_PUBLIC,
154 HDR_RETRY_AFTER,
155 HDR_SET_COOKIE,
156 HDR_UPGRADE,
157 HDR_WARNING,
158 HDR_MISC_END
159} http_hdr_misc_t;
6fb52f6c 160
0a0bf5db 161typedef struct proxy_ctrl_t {
162 int sock;
0a0bf5db 163 request_t *orig_request;
164 StoreEntry *entry;
165 peer *e;
166} proxy_ctrl_t;
167
168typedef struct http_ctrl_t {
169 int sock;
170 request_t *request;
171 char *req_hdr;
172 int req_hdr_sz;
173 StoreEntry *entry;
174} http_ctrl_t;
175
6fb52f6c 176char *HttpServerCCStr[] =
177{
178 "public",
179 "private",
180 "no-cache",
181 "no-store",
182 "no-transform",
183 "must-revalidate",
184 "proxy-revalidate",
185 "max-age",
186 "NONE"
187};
188
151a0b6d 189static char *HttpHdrMiscStr[] =
190{
191 "Accept",
192 "Age",
193 "Content-Length",
194 "Content-MD5",
195 "Content-Type",
196 "Date",
197 "Etag",
198 "Expires",
199 "Host",
200 "If-Modified-Since",
201 "Last-Modified",
202 "Max-Forwards",
203 "Public",
204 "Retry-After",
205 "Set-Cookie",
206 "Upgrade",
207 "Warning",
208 "NONE"
209};
210
24382924 211static struct {
30a4f2a8 212 int parsed;
151a0b6d 213 int misc[HDR_MISC_END];
6fb52f6c 214 int cc[SCC_ENUM_END];
30a4f2a8 215} ReplyHeaderStats;
090089c4 216
b177367b 217static void httpStateFree _PARAMS((int fd, void *));
218static void httpReadReplyTimeout _PARAMS((int fd, void *));
219static void httpLifetimeExpire _PARAMS((int fd, void *));
67508012 220static void httpMakePublic _PARAMS((StoreEntry *));
221static void httpMakePrivate _PARAMS((StoreEntry *));
222static void httpCacheNegatively _PARAMS((StoreEntry *));
b177367b 223static void httpReadReply _PARAMS((int fd, void *));
67508012 224static void httpSendComplete _PARAMS((int fd, char *, int, int, void *));
0a0bf5db 225static void proxyhttpStartComplete _PARAMS((void *, int));
226static void httpStartComplete _PARAMS((void *, int));
b177367b 227static void httpSendRequest _PARAMS((int fd, void *));
0ee4272b 228static void httpConnect _PARAMS((int fd, const ipcache_addrs *, void *));
e5f6c5c2 229static void httpConnectDone _PARAMS((int fd, int status, void *data));
6bf8443a 230static void httpAppendRequestHeader _PARAMS((char *hdr, const char *line, size_t * sz, size_t max));
231
b8d8561b 232
b177367b 233static void
234httpStateFree(int fd, void *data)
f5558c95 235{
b177367b 236 HttpStateData *httpState = data;
0d4d4170 237 if (httpState == NULL)
b177367b 238 return;
30a4f2a8 239 storeUnlockObject(httpState->entry);
0d4d4170 240 if (httpState->reply_hdr) {
241 put_free_8k_page(httpState->reply_hdr);
242 httpState->reply_hdr = NULL;
243 }
30a4f2a8 244 requestUnlink(httpState->request);
20cc1450 245 requestUnlink(httpState->orig_request);
0d4d4170 246 xfree(httpState);
f5558c95 247}
248
b8d8561b 249int
75e88d56 250httpCachable(method_t method)
090089c4 251{
090089c4 252 /* GET and HEAD are cachable. Others are not. */
6eb42cae 253 if (method != METHOD_GET && method != METHOD_HEAD)
090089c4 254 return 0;
090089c4 255 /* else cachable */
256 return 1;
257}
258
259/* This will be called when timeout on read. */
b8d8561b 260static void
b177367b 261httpReadReplyTimeout(int fd, void *data)
090089c4 262{
b177367b 263 HttpStateData *httpState = data;
090089c4 264 StoreEntry *entry = NULL;
30a4f2a8 265 entry = httpState->entry;
593c9a75 266 debug(11, 4, "httpReadReplyTimeout: FD %d: '%s'\n", fd, entry->url);
b8de7ebe 267 squid_error_entry(entry, ERR_READ_TIMEOUT, NULL);
b177367b 268 commSetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0);
0d4d4170 269 comm_close(fd);
090089c4 270}
271
272/* This will be called when socket lifetime is expired. */
b8d8561b 273static void
b177367b 274httpLifetimeExpire(int fd, void *data)
090089c4 275{
b177367b 276 HttpStateData *httpState = data;
593c9a75 277 StoreEntry *entry = httpState->entry;
278 debug(11, 4, "httpLifeTimeExpire: FD %d: '%s'\n", fd, entry->url);
ce49f524 279 squid_error_entry(entry, ERR_LIFETIME_EXP, NULL);
b177367b 280 commSetSelect(fd, COMM_SELECT_READ | COMM_SELECT_WRITE, NULL, NULL, 0);
0d4d4170 281 comm_close(fd);
090089c4 282}
283
30a4f2a8 284/* This object can be cached for a long time */
b8d8561b 285static void
286httpMakePublic(StoreEntry * entry)
30a4f2a8 287{
1c481e00 288 if (BIT_TEST(entry->flag, ENTRY_CACHABLE))
30a4f2a8 289 storeSetPublicKey(entry);
290}
291
292/* This object should never be cached at all */
b8d8561b 293static void
294httpMakePrivate(StoreEntry * entry)
30a4f2a8 295{
30a4f2a8 296 storeExpireNow(entry);
1c481e00 297 BIT_RESET(entry->flag, ENTRY_CACHABLE);
30a4f2a8 298 storeReleaseRequest(entry); /* delete object when not used */
299}
300
301/* This object may be negatively cached */
b8d8561b 302static void
303httpCacheNegatively(StoreEntry * entry)
30a4f2a8 304{
79b5cc5f 305 storeNegativeCache(entry);
1c481e00 306 if (BIT_TEST(entry->flag, ENTRY_CACHABLE))
30a4f2a8 307 storeSetPublicKey(entry);
30a4f2a8 308}
309
310
311/* Build a reply structure from HTTP reply headers */
b8d8561b 312void
48f44632 313httpParseReplyHeaders(const char *buf, struct _http_reply *reply)
30a4f2a8 314{
33b589ff 315 char *headers = get_free_4k_page();
ca85027a 316 char *line;
33b589ff 317 char *end;
30a4f2a8 318 char *s = NULL;
33b589ff 319 char *t;
ca98227c 320 time_t delta;
321 size_t l;
30a4f2a8 322
f1494beb 323 reply->code = 600;
30a4f2a8 324 ReplyHeaderStats.parsed++;
33b589ff 325 xstrncpy(headers, buf, 4096);
326 end = mime_headers_end(headers);
ca85027a 327 if (end == NULL) {
328 t = headers;
e2ad7f85 329 if (!strncasecmp(t, "HTTP/", 5)) {
330 reply->version = atof(t + 5);
331 if ((t = strchr(t, ' ')))
332 reply->code = atoi(++t);
ca85027a 333 }
e2ad7f85 334 put_free_4k_page(headers);
335 return;
ca85027a 336 }
337 reply->hdr_sz = end - headers;
338 line = get_free_4k_page();
33b589ff 339 for (s = headers; s < end; s += strcspn(s, crlf), s += strspn(s, crlf)) {
340 l = strcspn(s, crlf) + 1;
341 if (l > 4096)
342 l = 4096;
343 xstrncpy(line, s, l);
344 t = line;
345 debug(11, 3, "httpParseReplyHeaders: %s\n", t);
346 if (!strncasecmp(t, "HTTP/", 5)) {
e2ad7f85 347 reply->version = atof(t + 5);
33b589ff 348 if ((t = strchr(t, ' ')))
349 reply->code = atoi(++t);
30a4f2a8 350 } else if (!strncasecmp(t, "Content-type:", 13)) {
33b589ff 351 for (t += 13; isspace(*t); t++);
e91b56e5 352 if ((l = strcspn(t, ";\t ")) > 0)
353 *(t + l) = '\0';
33b589ff 354 xstrncpy(reply->content_type, t, HTTP_REPLY_FIELD_SZ);
151a0b6d 355 ReplyHeaderStats.misc[HDR_CONTENT_TYPE]++;
30a4f2a8 356 } else if (!strncasecmp(t, "Content-length:", 15)) {
33b589ff 357 for (t += 15; isspace(*t); t++);
33b589ff 358 reply->content_length = atoi(t);
151a0b6d 359 ReplyHeaderStats.misc[HDR_CONTENT_LENGTH]++;
30a4f2a8 360 } else if (!strncasecmp(t, "Date:", 5)) {
33b589ff 361 for (t += 5; isspace(*t); t++);
362 reply->date = parse_rfc1123(t);
151a0b6d 363 ReplyHeaderStats.misc[HDR_DATE]++;
30a4f2a8 364 } else if (!strncasecmp(t, "Expires:", 8)) {
33b589ff 365 for (t += 8; isspace(*t); t++);
366 reply->expires = parse_rfc1123(t);
367 /*
368 * The HTTP/1.0 specs says that robust implementations
369 * should consider bad or malformed Expires header as
370 * equivalent to "expires immediately."
371 */
372 if (reply->expires == -1)
373 reply->expires = squid_curtime;
151a0b6d 374 ReplyHeaderStats.misc[HDR_EXPIRES]++;
30a4f2a8 375 } else if (!strncasecmp(t, "Last-Modified:", 14)) {
33b589ff 376 for (t += 14; isspace(*t); t++);
377 reply->last_modified = parse_rfc1123(t);
151a0b6d 378 ReplyHeaderStats.misc[HDR_LAST_MODIFIED]++;
379 } else if (!strncasecmp(t, "Accept:", 7)) {
380 ReplyHeaderStats.misc[HDR_ACCEPT]++;
381 } else if (!strncasecmp(t, "Age:", 4)) {
382 ReplyHeaderStats.misc[HDR_AGE]++;
383 } else if (!strncasecmp(t, "Content-MD5:", 12)) {
384 ReplyHeaderStats.misc[HDR_CONTENT_MD5]++;
385 } else if (!strncasecmp(t, "ETag:", 5)) {
386 ReplyHeaderStats.misc[HDR_ETAG]++;
387 } else if (!strncasecmp(t, "Max-Forwards:", 13)) {
388 ReplyHeaderStats.misc[HDR_MAX_FORWARDS]++;
389 } else if (!strncasecmp(t, "Public:", 7)) {
390 ReplyHeaderStats.misc[HDR_PUBLIC]++;
391 } else if (!strncasecmp(t, "Retry-After:", 12)) {
392 ReplyHeaderStats.misc[HDR_RETRY_AFTER]++;
393 } else if (!strncasecmp(t, "Upgrade:", 8)) {
394 ReplyHeaderStats.misc[HDR_UPGRADE]++;
395 } else if (!strncasecmp(t, "Warning:", 8)) {
396 ReplyHeaderStats.misc[HDR_WARNING]++;
caebbe00 397 } else if (!strncasecmp(t, "Cache-Control:", 14)) {
33b589ff 398 for (t += 14; isspace(*t); t++);
4db43fab 399 if (!strncasecmp(t, "public", 6)) {
400 EBIT_SET(reply->cache_control, SCC_PUBLIC);
401 ReplyHeaderStats.cc[SCC_PUBLIC]++;
402 } else if (!strncasecmp(t, "private", 7)) {
403 EBIT_SET(reply->cache_control, SCC_PRIVATE);
404 ReplyHeaderStats.cc[SCC_PRIVATE]++;
405 } else if (!strncasecmp(t, "no-cache", 8)) {
406 EBIT_SET(reply->cache_control, SCC_NOCACHE);
407 ReplyHeaderStats.cc[SCC_NOCACHE]++;
c1764328 408 } else if (!strncasecmp(t, "no-store", 8)) {
409 EBIT_SET(reply->cache_control, SCC_NOSTORE);
410 ReplyHeaderStats.cc[SCC_NOSTORE]++;
411 } else if (!strncasecmp(t, "no-transform", 12)) {
412 EBIT_SET(reply->cache_control, SCC_NOTRANSFORM);
413 ReplyHeaderStats.cc[SCC_NOTRANSFORM]++;
414 } else if (!strncasecmp(t, "must-revalidate", 15)) {
415 EBIT_SET(reply->cache_control, SCC_MUSTREVALIDATE);
416 ReplyHeaderStats.cc[SCC_MUSTREVALIDATE]++;
417 } else if (!strncasecmp(t, "proxy-revalidate", 16)) {
418 EBIT_SET(reply->cache_control, SCC_PROXYREVALIDATE);
419 ReplyHeaderStats.cc[SCC_PROXYREVALIDATE]++;
4db43fab 420 } else if (!strncasecmp(t, "max-age", 7)) {
421 if ((t = strchr(t, '='))) {
ca98227c 422 delta = (time_t) atoi(++t);
423 reply->expires = squid_curtime + delta;
4db43fab 424 EBIT_SET(reply->cache_control, SCC_MAXAGE);
425 ReplyHeaderStats.cc[SCC_MAXAGE]++;
5df61230 426 }
caebbe00 427 }
df3ac7c0 428 } else if (!strncasecmp(t, "Set-Cookie:", 11)) {
429 EBIT_SET(reply->misc_headers, HDR_SET_COOKIE);
58202be7 430 ReplyHeaderStats.misc[HDR_SET_COOKIE]++;
30a4f2a8 431 }
30a4f2a8 432 }
33b589ff 433 put_free_4k_page(headers);
434 put_free_4k_page(line);
30a4f2a8 435}
436
090089c4 437
b8d8561b 438void
0ee4272b 439httpProcessReplyHeader(HttpStateData * httpState, const char *buf, int size)
f5558c95 440{
441 char *t = NULL;
30a4f2a8 442 StoreEntry *entry = httpState->entry;
d3fb4dea 443 int room;
444 int hdr_len;
33b589ff 445 struct _http_reply *reply = entry->mem_obj->reply;
d3fb4dea 446
ed85b771 447 debug(11, 3, "httpProcessReplyHeader: key '%s'\n", entry->key);
f5558c95 448
30a4f2a8 449 if (httpState->reply_hdr == NULL) {
450 httpState->reply_hdr = get_free_8k_page();
451 memset(httpState->reply_hdr, '\0', 8192);
f5558c95 452 }
30a4f2a8 453 if (httpState->reply_hdr_state == 0) {
454 hdr_len = strlen(httpState->reply_hdr);
ed85b771 455 room = 8191 - hdr_len;
30a4f2a8 456 strncat(httpState->reply_hdr, buf, room < size ? room : size);
d3fb4dea 457 hdr_len += room < size ? room : size;
30a4f2a8 458 if (hdr_len > 4 && strncmp(httpState->reply_hdr, "HTTP/", 5)) {
60bf30cb 459 debug(11, 3, "httpProcessReplyHeader: Non-HTTP-compliant header: '%s'\n", entry->key);
30a4f2a8 460 httpState->reply_hdr_state += 2;
33b589ff 461 reply->code = 555;
ed85b771 462 return;
d3fb4dea 463 }
d1a43e28 464 t = httpState->reply_hdr + hdr_len;
465 /* headers can be incomplete only if object still arriving */
f86a6a46 466 if (!httpState->eof)
d1a43e28 467 if ((t = mime_headers_end(httpState->reply_hdr)) == NULL)
468 return; /* headers not complete */
2285407f 469 *t = '\0';
30a4f2a8 470 httpState->reply_hdr_state++;
f5558c95 471 }
30a4f2a8 472 if (httpState->reply_hdr_state == 1) {
473 httpState->reply_hdr_state++;
019dd986 474 debug(11, 9, "GOT HTTP REPLY HDR:\n---------\n%s\n----------\n",
30a4f2a8 475 httpState->reply_hdr);
476 /* Parse headers into reply structure */
48f44632 477 httpParseReplyHeaders(httpState->reply_hdr, reply);
ca98227c 478 storeTimestampsSet(entry);
30a4f2a8 479 /* Check if object is cacheable or not based on reply code */
cb24292d 480 debug(11, 3, "httpProcessReplyHeader: HTTP CODE: %d\n", reply->code);
2285407f 481 switch (reply->code) {
30a4f2a8 482 /* Responses that are cacheable */
f5558c95 483 case 200: /* OK */
4e38e700 484 case 203: /* Non-Authoritative Information */
485 case 300: /* Multiple Choices */
f5558c95 486 case 301: /* Moved Permanently */
4e38e700 487 case 410: /* Gone */
30a4f2a8 488 /* don't cache objects from neighbors w/o LMT, Date, or Expires */
6fb52f6c 489 if (EBIT_TEST(reply->cache_control, SCC_PRIVATE))
caebbe00 490 httpMakePrivate(entry);
6fb52f6c 491 else if (EBIT_TEST(reply->cache_control, SCC_NOCACHE))
caebbe00 492 httpMakePrivate(entry);
e2ad7f85 493 /*
494 * Dealing with cookies is quite a bit more complicated
495 * than this. Ideally we should strip the cookie
496 * header from the reply but still cache the reply body.
497 * More confusion at draft-ietf-http-state-mgmt-05.txt.
498 */
df3ac7c0 499 else if (EBIT_TEST(reply->misc_headers, HDR_SET_COOKIE))
500 httpMakePrivate(entry);
ca98227c 501 else if (reply->date > -1)
30a4f2a8 502 httpMakePublic(entry);
ca98227c 503 else if (reply->last_modified > -1)
30a4f2a8 504 httpMakePublic(entry);
505 else if (!httpState->neighbor)
506 httpMakePublic(entry);
ca98227c 507 else if (reply->expires > -1)
30a4f2a8 508 httpMakePublic(entry);
af00901c 509 else if (entry->mem_obj->request->protocol != PROTO_HTTP)
510 /* XXX Remove this check after a while. DW 8/21/96
511 * We won't keep some FTP objects from neighbors running
512 * 1.0.8 or earlier because their ftpget's don't
513 * add a Date: field */
514 httpMakePublic(entry);
30a4f2a8 515 else
516 httpMakePrivate(entry);
517 break;
518 /* Responses that only are cacheable if the server says so */
519 case 302: /* Moved temporarily */
ca98227c 520 if (reply->expires > -1)
30a4f2a8 521 httpMakePublic(entry);
522 else
523 httpMakePrivate(entry);
f5558c95 524 break;
30a4f2a8 525 /* Errors can be negatively cached */
526 case 204: /* No Content */
527 case 305: /* Use Proxy (proxy redirect) */
528 case 400: /* Bad Request */
529 case 403: /* Forbidden */
530 case 404: /* Not Found */
531 case 405: /* Method Now Allowed */
532 case 414: /* Request-URI Too Long */
533 case 500: /* Internal Server Error */
534 case 501: /* Not Implemented */
535 case 502: /* Bad Gateway */
536 case 503: /* Service Unavailable */
537 case 504: /* Gateway Timeout */
851eeef7 538 httpCacheNegatively(entry);
30a4f2a8 539 break;
540 /* Some responses can never be cached */
541 case 303: /* See Other */
234967c9 542 case 304: /* Not Modified */
4e38e700 543 case 401: /* Unauthorized */
544 case 407: /* Proxy Authentication Required */
f1494beb 545 case 600: /* Squid header parsing error */
30a4f2a8 546 default: /* Unknown status code */
547 httpMakePrivate(entry);
4e38e700 548 break;
f5558c95 549 }
550 }
551}
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
b177367b 558httpReadReply(int fd, void *data)
090089c4 559{
b177367b 560 HttpStateData *httpState = data;
95d659f0 561 LOCAL_ARRAY(char, buf, SQUID_TCP_SO_RCVBUF);
090089c4 562 int len;
30a4f2a8 563 int bin;
090089c4 564 int clen;
565 int off;
566 StoreEntry *entry = NULL;
567
30a4f2a8 568 entry = httpState->entry;
234967c9 569 if (entry->flag & DELETE_BEHIND && !storeClientWaiting(entry)) {
570 /* we can terminate connection right now */
571 squid_error_entry(entry, ERR_NO_CLIENTS_BIG_OBJ, NULL);
572 comm_close(fd);
573 return;
574 }
575 /* check if we want to defer reading */
576 clen = entry->mem_obj->e_current_len;
577 off = storeGetLowestReaderOffset(entry);
578 if ((clen - off) > HTTP_DELETE_GAP) {
30a4f2a8 579 if (entry->flag & CLIENT_ABORT_REQUEST) {
580 squid_error_entry(entry, ERR_CLIENT_ABORT, NULL);
581 comm_close(fd);
582 return;
583 }
584 IOStats.Http.reads_deferred++;
234967c9 585 debug(11, 3, "httpReadReply: Read deferred for Object: %s\n",
586 entry->url);
587 debug(11, 3, " Current Gap: %d bytes\n", clen - off);
588 /* reschedule, so it will be automatically reactivated
589 * when Gap is big enough. */
b177367b 590 commSetSelect(fd,
234967c9 591 COMM_SELECT_READ,
b177367b 592 httpReadReply,
593 (void *) httpState, 0);
30a4f2a8 594 /* disable read timeout until we are below the GAP */
b177367b 595 commSetSelect(fd,
234967c9 596 COMM_SELECT_TIMEOUT,
b177367b 597 NULL,
234967c9 598 (void *) NULL,
599 (time_t) 0);
56fa4cad 600 if (!BIT_TEST(entry->flag, READ_DEFERRED)) {
601 comm_set_fd_lifetime(fd, 3600); /* limit during deferring */
602 BIT_SET(entry->flag, READ_DEFERRED);
603 }
234967c9 604 /* dont try reading again for a while */
b6f794d6 605 comm_set_stall(fd, Config.stallDelay);
234967c9 606 return;
56fa4cad 607 } else {
608 BIT_RESET(entry->flag, READ_DEFERRED);
090089c4 609 }
1513873c 610 errno = 0;
30a4f2a8 611 len = read(fd, buf, SQUID_TCP_SO_RCVBUF);
019dd986 612 debug(11, 5, "httpReadReply: FD %d: len %d.\n", fd, len);
30a4f2a8 613 comm_set_fd_lifetime(fd, 86400); /* extend after good read */
614 if (len > 0) {
4a63c85f 615 IOStats.Http.reads++;
30a4f2a8 616 for (clen = len - 1, bin = 0; clen; bin++)
617 clen >>= 1;
618 IOStats.Http.read_hist[bin]++;
619 }
ba718c8f 620 if (len < 0) {
0a0bf5db 621 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
1513873c 622 /* reinstall handlers */
6fe6313d 623 /* XXX This may loop forever */
b177367b 624 commSetSelect(fd, COMM_SELECT_READ,
625 httpReadReply, (void *) httpState, 0);
626 commSetSelect(fd, COMM_SELECT_TIMEOUT,
627 httpReadReplyTimeout, (void *) httpState, Config.readTimeout);
090089c4 628 } else {
1c481e00 629 BIT_RESET(entry->flag, ENTRY_CACHABLE);
2daae136 630 storeReleaseRequest(entry);
b8de7ebe 631 squid_error_entry(entry, ERR_READ_ERROR, xstrerror());
0d4d4170 632 comm_close(fd);
090089c4 633 }
0a0bf5db 634 debug(50, 2, "httpReadReply: FD %d: read failure: %s.\n",
635 fd, xstrerror());
ba718c8f 636 } else if (len == 0 && entry->mem_obj->e_current_len == 0) {
f86a6a46 637 httpState->eof = 1;
b8de7ebe 638 squid_error_entry(entry,
ba718c8f 639 ERR_ZERO_SIZE_OBJECT,
640 errno ? xstrerror() : NULL);
0d4d4170 641 comm_close(fd);
090089c4 642 } else if (len == 0) {
643 /* Connection closed; retrieval done. */
f86a6a46 644 httpState->eof = 1;
d1a43e28 645 if (httpState->reply_hdr_state < 2)
646 httpProcessReplyHeader(httpState, buf, len);
647 storeAppend(entry, buf, len); /* invoke handlers! */
648 storeComplete(entry); /* deallocates mem_obj->request */
0d4d4170 649 comm_close(fd);
090089c4 650 } else if (entry->flag & CLIENT_ABORT_REQUEST) {
651 /* append the last bit of info we get */
652 storeAppend(entry, buf, len);
b8de7ebe 653 squid_error_entry(entry, ERR_CLIENT_ABORT, NULL);
0d4d4170 654 comm_close(fd);
090089c4 655 } else {
d1a43e28 656 if (httpState->reply_hdr_state < 2)
30a4f2a8 657 httpProcessReplyHeader(httpState, buf, len);
620da955 658 storeAppend(entry, buf, len);
b177367b 659 commSetSelect(fd,
ba718c8f 660 COMM_SELECT_TIMEOUT,
b177367b 661 httpReadReplyTimeout,
30a4f2a8 662 (void *) httpState,
b6f794d6 663 Config.readTimeout);
0a0bf5db 664 commSetSelect(fd,
665 COMM_SELECT_READ,
666 httpReadReply,
667 (void *) httpState, 0);
090089c4 668 }
669}
670
671/* This will be called when request write is complete. Schedule read of
672 * reply. */
b8d8561b 673static void
674httpSendComplete(int fd, char *buf, int size, int errflag, void *data)
090089c4 675{
30a4f2a8 676 HttpStateData *httpState = data;
090089c4 677 StoreEntry *entry = NULL;
678
30a4f2a8 679 entry = httpState->entry;
019dd986 680 debug(11, 5, "httpSendComplete: FD %d: size %d: errflag %d.\n",
090089c4 681 fd, size, errflag);
682
090089c4 683 if (errflag) {
b8de7ebe 684 squid_error_entry(entry, ERR_CONNECT_FAIL, xstrerror());
0d4d4170 685 comm_close(fd);
090089c4 686 return;
687 } else {
688 /* Schedule read reply. */
b177367b 689 commSetSelect(fd,
019dd986 690 COMM_SELECT_READ,
b177367b 691 httpReadReply,
692 (void *) httpState, 0);
693 commSetSelect(fd,
019dd986 694 COMM_SELECT_TIMEOUT,
b177367b 695 httpReadReplyTimeout,
30a4f2a8 696 (void *) httpState,
b6f794d6 697 Config.readTimeout);
30a4f2a8 698 comm_set_fd_lifetime(fd, 86400); /* extend lifetime */
090089c4 699 }
700}
701
6bf8443a 702static void
703httpAppendRequestHeader(char *hdr, const char *line, size_t * sz, size_t max)
704{
705 size_t n = *sz + strlen(line) + 2;
706 if (n >= max)
707 return;
fa562c67 708 if (Config.Options.anonymizer == ANONYMIZER_PARANOID) {
bba6fa8f 709 if (!httpAnonAllowed(line))
fa562c67 710 return;
711 } else if (Config.Options.anonymizer == ANONYMIZER_STANDARD) {
bba6fa8f 712 if (httpAnonDenied(line))
fa562c67 713 return;
4a83b852 714 }
4a83b852 715 /* allowed header, explicitly known to be not dangerous */
6bf8443a 716 debug(11, 5, "httpAppendRequestHeader: %s\n", line);
929545fe 717 strcpy(hdr + (*sz), line);
6bf8443a 718 strcat(hdr + (*sz), crlf);
719 *sz = n;
720}
721
722size_t
723httpBuildRequestHeader(request_t * request,
724 request_t * orig_request,
725 StoreEntry * entry,
726 char *hdr_in,
727 size_t * in_len,
728 char *hdr_out,
729 size_t out_sz,
730 int cfd)
731{
732 char *xbuf = get_free_4k_page();
872b720f 733 char *ybuf = get_free_8k_page();
6bf8443a 734 char *viabuf = get_free_4k_page();
735 char *fwdbuf = get_free_4k_page();
736 char *t = NULL;
737 char *s = NULL;
738 char *end = NULL;
739 size_t len = 0;
740 size_t hdr_len = 0;
741 size_t in_sz;
6bf8443a 742 size_t l;
743 int hdr_flags = 0;
151a0b6d 744 int cc_flags = 0;
b3b64e58 745 int n;
6bf8443a 746 const char *url = NULL;
747
748 debug(11, 3, "httpBuildRequestHeader: INPUT:\n%s\n", hdr_in);
749 xstrncpy(fwdbuf, "X-Forwarded-For: ", 4096);
750 xstrncpy(viabuf, "Via: ", 4096);
751 sprintf(ybuf, "%s %s HTTP/1.0",
752 RequestMethodStr[request->method],
753 *request->urlpath ? request->urlpath : "/");
754 httpAppendRequestHeader(hdr_out, ybuf, &len, out_sz);
755 /* Add IMS header */
756 if (entry && entry->lastmod && request->method == METHOD_GET) {
757 sprintf(ybuf, "If-Modified-Since: %s", mkrfc1123(entry->lastmod));
758 httpAppendRequestHeader(hdr_out, ybuf, &len, out_sz);
759 EBIT_SET(hdr_flags, HDR_IMS);
760 }
00c59270 761 end = mime_headers_end(hdr_in);
6bf8443a 762 in_sz = strlen(hdr_in);
763 for (t = hdr_in; t < end; t += strcspn(t, crlf), t += strspn(t, crlf)) {
764 hdr_len = t - hdr_in;
6bf8443a 765 l = strcspn(t, crlf) + 1;
766 if (l > 4096)
767 l = 4096;
768 xstrncpy(xbuf, t, l);
a7011ca4 769 debug(11, 5, "httpBuildRequestHeader: %s\n", xbuf);
6bf8443a 770 if (strncasecmp(xbuf, "Proxy-Connection:", 17) == 0)
771 continue;
772 if (strncasecmp(xbuf, "Connection:", 11) == 0)
773 continue;
66f7337b 774 if (strncasecmp(xbuf, "Host:", 5) == 0) {
6bf8443a 775 EBIT_SET(hdr_flags, HDR_HOST);
66f7337b 776 } else if (strncasecmp(xbuf, "Cache-Control:", 14) == 0) {
6bf8443a 777 for (s = xbuf + 14; *s && isspace(*s); s++);
778 if (strncasecmp(s, "Max-age=", 8) == 0)
151a0b6d 779 EBIT_SET(cc_flags, CCC_MAXAGE);
66f7337b 780 } else if (strncasecmp(xbuf, "Via:", 4) == 0) {
6bf8443a 781 for (s = xbuf + 4; *s && isspace(*s); s++);
782 if (strlen(viabuf) + strlen(s) < 4000)
783 strcat(viabuf, s);
784 strcat(viabuf, ", ");
785 continue;
66f7337b 786 } else if (strncasecmp(xbuf, "X-Forwarded-For:", 16) == 0) {
6bf8443a 787 for (s = xbuf + 16; *s && isspace(*s); s++);
788 if (strlen(fwdbuf) + strlen(s) < 4000)
789 strcat(fwdbuf, s);
790 strcat(fwdbuf, ", ");
791 continue;
66f7337b 792 } else if (strncasecmp(xbuf, "If-Modified-Since:", 18) == 0) {
6bf8443a 793 if (EBIT_TEST(hdr_flags, HDR_IMS))
794 continue;
b3b64e58 795 } else if (strncasecmp(xbuf, "Max-Forwards:", 13) == 0) {
796 if (orig_request->method == METHOD_TRACE) {
797 for (s = xbuf + 13; *s && isspace(*s); s++);
798 n = atoi(s);
799 sprintf(xbuf, "Max-Forwards: %d", n - 1);
800 }
66f7337b 801 }
6bf8443a 802 httpAppendRequestHeader(hdr_out, xbuf, &len, out_sz - 512);
803 }
804 hdr_len = t - hdr_in;
805 /* Append Via: */
43f1c650 806 sprintf(ybuf, "%3.1f %s", orig_request->http_ver, ThisCache);
6bf8443a 807 strcat(viabuf, ybuf);
808 httpAppendRequestHeader(hdr_out, viabuf, &len, out_sz);
809 /* Append to X-Forwarded-For: */
a08307eb 810 strcat(fwdbuf, cfd < 0 ? "unknown" : fd_table[cfd].ipaddr);
6bf8443a 811 httpAppendRequestHeader(hdr_out, fwdbuf, &len, out_sz);
812 if (!EBIT_TEST(hdr_flags, HDR_HOST)) {
813 sprintf(ybuf, "Host: %s", orig_request->host);
814 httpAppendRequestHeader(hdr_out, ybuf, &len, out_sz);
815 }
151a0b6d 816 if (!EBIT_TEST(cc_flags, CCC_MAXAGE)) {
6bf8443a 817 url = entry ? entry->url : urlCanonical(orig_request, NULL);
818 sprintf(ybuf, "Cache-control: Max-age=%d", (int) getMaxAge(url));
819 httpAppendRequestHeader(hdr_out, ybuf, &len, out_sz);
820 }
821 httpAppendRequestHeader(hdr_out, null_string, &len, out_sz);
822 put_free_4k_page(xbuf);
872b720f 823 put_free_8k_page(ybuf);
6bf8443a 824 put_free_4k_page(viabuf);
825 put_free_4k_page(fwdbuf);
826 if (in_len)
827 *in_len = hdr_len;
9d9d144b 828 if ((l = strlen(hdr_out)) != len) {
829 debug_trap("httpBuildRequestHeader: size mismatch");
830 len = l;
831 }
6bf8443a 832 debug(11, 3, "httpBuildRequestHeader: OUTPUT:\n%s\n", hdr_out);
833 return len;
834}
835
090089c4 836/* This will be called when connect completes. Write request. */
b8d8561b 837static void
b177367b 838httpSendRequest(int fd, void *data)
090089c4 839{
b177367b 840 HttpStateData *httpState = data;
090089c4 841 char *buf = NULL;
090089c4 842 int len = 0;
843 int buflen;
30a4f2a8 844 request_t *req = httpState->request;
9864ee44 845 int buftype = 0;
620da955 846 StoreEntry *entry = httpState->entry;
2a26c096 847 int cfd;
090089c4 848
30a4f2a8 849 debug(11, 5, "httpSendRequest: FD %d: httpState %p.\n", fd, httpState);
6bf8443a 850 buflen = strlen(req->urlpath);
30a4f2a8 851 if (httpState->req_hdr)
4768dbe0 852 buflen += httpState->req_hdr_sz + 1;
090089c4 853 buflen += 512; /* lots of extra */
854
78657218 855 if ((req->method == METHOD_POST || req->method == METHOD_PUT)) {
856 debug_trap("httpSendRequest: should not be handling POST/PUT request");
857 return;
090089c4 858 }
30a4f2a8 859 if (buflen < DISK_PAGE_SIZE) {
9864ee44 860 buf = get_free_8k_page();
861 memset(buf, '\0', buflen);
862 buftype = BUF_TYPE_8K;
6bf8443a 863 buflen = DISK_PAGE_SIZE;
30a4f2a8 864 } else {
9864ee44 865 buf = xcalloc(buflen, 1);
866 buftype = BUF_TYPE_MALLOC;
090089c4 867 }
2a26c096 868 if (!opt_forwarded_for)
6bf8443a 869 cfd = -1;
2a26c096 870 else if (entry->mem_obj == NULL)
6bf8443a 871 cfd = -1;
2a26c096 872 else
6bf8443a 873 cfd = storeFirstClientFD(entry->mem_obj);
874 len = httpBuildRequestHeader(req,
875 httpState->orig_request ? httpState->orig_request : req,
876 entry,
877 httpState->req_hdr,
878 NULL,
879 buf,
880 buflen,
881 cfd);
67508012 882 debug(11, 6, "httpSendRequest: FD %d:\n%s\n", fd, buf);
30a4f2a8 883 comm_write(fd,
14e59844 884 buf,
885 len,
886 30,
887 httpSendComplete,
9864ee44 888 httpState,
889 buftype == BUF_TYPE_8K ? put_free_8k_page : xfree);
20cc1450 890 requestUnlink(httpState->orig_request);
891 httpState->orig_request = NULL;
090089c4 892}
893
b8d8561b 894int
75e88d56 895proxyhttpStart(request_t * orig_request,
20cc1450 896 StoreEntry * entry,
deb79f06 897 peer * e)
090089c4 898{
0a0bf5db 899 proxy_ctrl_t *ctrlp;
f5558c95 900 int sock;
7111c86a 901 debug(11, 3, "proxyhttpStart: \"%s %s\"\n",
75e88d56 902 RequestMethodStr[orig_request->method], entry->url);
019dd986 903 debug(11, 10, "proxyhttpStart: HTTP request header:\n%s\n",
22e4fa85 904 entry->mem_obj->mime_hdr);
30a4f2a8 905 if (e->options & NEIGHBOR_PROXY_ONLY)
090089c4 906 storeStartDeleteBehind(entry);
090089c4 907 /* Create socket. */
16b204c4 908 sock = comm_open(SOCK_STREAM,
909 0,
910 Config.Addrs.tcp_outgoing,
911 0,
912 COMM_NONBLOCKING,
75e88d56 913 entry->url);
090089c4 914 if (sock == COMM_ERROR) {
019dd986 915 debug(11, 4, "proxyhttpStart: Failed because we're out of sockets.\n");
b8de7ebe 916 squid_error_entry(entry, ERR_NO_FDS, xstrerror());
090089c4 917 return COMM_ERROR;
918 }
0a0bf5db 919 ctrlp = xmalloc(sizeof(proxy_ctrl_t));
920 ctrlp->sock = sock;
0a0bf5db 921 ctrlp->orig_request = orig_request;
922 ctrlp->entry = entry;
923 ctrlp->e = e;
924 storeLockObject(entry, proxyhttpStartComplete, ctrlp);
925 return COMM_OK;
926}
927
928
929static void
930proxyhttpStartComplete(void *data, int status)
931{
75e88d56 932 proxy_ctrl_t *ctrlp = data;
933 int sock = ctrlp->sock;
934 request_t *orig_request = ctrlp->orig_request;
935 StoreEntry *entry = ctrlp->entry;
936 peer *e = ctrlp->e;
937 char *url = entry->url;
0a0bf5db 938 HttpStateData *httpState = NULL;
939 request_t *request = NULL;
0a0bf5db 940 xfree(ctrlp);
30a4f2a8 941 httpState = xcalloc(1, sizeof(HttpStateData));
0a0bf5db 942 httpState->entry = entry;
30a4f2a8 943 httpState->req_hdr = entry->mem_obj->mime_hdr;
4768dbe0 944 httpState->req_hdr_sz = entry->mem_obj->mime_hdr_sz;
30a4f2a8 945 request = get_free_request_t();
946 httpState->request = requestLink(request);
947 httpState->neighbor = e;
20cc1450 948 httpState->orig_request = requestLink(orig_request);
0d4d4170 949 /* register the handler to free HTTP state data when the FD closes */
30a4f2a8 950 comm_add_close_handler(sock,
b177367b 951 httpStateFree,
30a4f2a8 952 (void *) httpState);
2cc3f720 953 request->method = orig_request->method;
d5aa0e3b 954 xstrncpy(request->host, e->host, SQUIDHOSTNAMELEN);
30a4f2a8 955 request->port = e->http_port;
d5aa0e3b 956 xstrncpy(request->urlpath, url, MAX_URL);
313c1c28 957 BIT_SET(request->flags, REQ_PROXYING);
a13d9042 958 ipcache_nbgethostbyname(request->host,
959 sock,
b15fe823 960 httpConnect,
a13d9042 961 httpState);
0a0bf5db 962 return;
a13d9042 963}
964
b15fe823 965static void
fe4e214f 966httpConnect(int fd, const ipcache_addrs * ia, void *data)
a13d9042 967{
968 HttpStateData *httpState = data;
969 request_t *request = httpState->request;
970 StoreEntry *entry = httpState->entry;
e5f6c5c2 971 if (ia == NULL) {
a13d9042 972 debug(11, 4, "httpConnect: Unknown host: %s\n", request->host);
b8de7ebe 973 squid_error_entry(entry, ERR_DNS_FAIL, dns_error_message);
a13d9042 974 comm_close(fd);
b15fe823 975 return;
090089c4 976 }
977 /* Open connection. */
e5f6c5c2 978 httpState->connectState.fd = fd;
979 httpState->connectState.host = request->host;
980 httpState->connectState.port = request->port;
981 httpState->connectState.handler = httpConnectDone;
982 httpState->connectState.data = httpState;
983 comm_nbconnect(fd, &httpState->connectState);
984}
985
986static void
987httpConnectDone(int fd, int status, void *data)
988{
989 HttpStateData *httpState = data;
990 request_t *request = httpState->request;
991 StoreEntry *entry = httpState->entry;
deb79f06 992 peer *e = NULL;
e5f6c5c2 993 if (status != COMM_OK) {
5269d0bd 994 if ((e = httpState->neighbor))
e5f6c5c2 995 e->last_fail_time = squid_curtime;
e5f6c5c2 996 squid_error_entry(entry, ERR_CONNECT_FAIL, xstrerror());
997 comm_close(fd);
998 } else {
999 /* Install connection complete handler. */
1000 if (opt_no_ipcache)
1001 ipcacheInvalidate(request->host);
1002 fd_note(fd, entry->url);
b177367b 1003 commSetSelect(fd, COMM_SELECT_LIFETIME,
1004 httpLifetimeExpire, (void *) httpState, 0);
1005 commSetSelect(fd, COMM_SELECT_WRITE,
1006 httpSendRequest, (void *) httpState, 0);
9d4b2981 1007 if (vizSock > -1)
ef2d27ff 1008 vizHackSendPkt(&httpState->connectState.S, 2);
090089c4 1009 }
090089c4 1010}
1011
b8d8561b 1012int
75e88d56 1013httpStart(request_t * request,
4768dbe0 1014 char *req_hdr,
1015 int req_hdr_sz,
1016 StoreEntry * entry)
090089c4 1017{
0a0bf5db 1018 http_ctrl_t *ctrlp;
a13d9042 1019 int sock;
7111c86a 1020 debug(11, 3, "httpStart: \"%s %s\"\n",
75e88d56 1021 RequestMethodStr[request->method], entry->url);
019dd986 1022 debug(11, 10, "httpStart: req_hdr '%s'\n", req_hdr);
090089c4 1023 /* Create socket. */
16b204c4 1024 sock = comm_open(SOCK_STREAM,
1025 0,
1026 Config.Addrs.tcp_outgoing,
1027 0,
1028 COMM_NONBLOCKING,
75e88d56 1029 entry->url);
090089c4 1030 if (sock == COMM_ERROR) {
019dd986 1031 debug(11, 4, "httpStart: Failed because we're out of sockets.\n");
b8de7ebe 1032 squid_error_entry(entry, ERR_NO_FDS, xstrerror());
090089c4 1033 return COMM_ERROR;
1034 }
0a0bf5db 1035 ctrlp = xmalloc(sizeof(http_ctrl_t));
1036 ctrlp->sock = sock;
1037 ctrlp->request = request;
1038 ctrlp->req_hdr = req_hdr;
1039 ctrlp->req_hdr_sz = req_hdr_sz;
1040 ctrlp->entry = entry;
1041 storeLockObject(entry, httpStartComplete, ctrlp);
1042 return COMM_OK;
1043}
1044
1045
1046static void
1047httpStartComplete(void *data, int status)
1048{
1049 http_ctrl_t *ctrlp = (http_ctrl_t *) data;
1050 HttpStateData *httpState = NULL;
1051 int sock;
1052 request_t *request;
1053 char *req_hdr;
1054 int req_hdr_sz;
1055 StoreEntry *entry;
1056
1057 sock = ctrlp->sock;
1058 request = ctrlp->request;
1059 req_hdr = ctrlp->req_hdr;
1060 req_hdr_sz = ctrlp->req_hdr_sz;
1061 entry = ctrlp->entry;
1062 xfree(ctrlp);
1063
30a4f2a8 1064 httpState = xcalloc(1, sizeof(HttpStateData));
0a0bf5db 1065 httpState->entry = entry;
1066
30a4f2a8 1067 httpState->req_hdr = req_hdr;
4768dbe0 1068 httpState->req_hdr_sz = req_hdr_sz;
30a4f2a8 1069 httpState->request = requestLink(request);
1070 comm_add_close_handler(sock,
b177367b 1071 httpStateFree,
30a4f2a8 1072 (void *) httpState);
a13d9042 1073 ipcache_nbgethostbyname(request->host,
1074 sock,
1075 httpConnect,
1076 httpState);
090089c4 1077}
30a4f2a8 1078
b8d8561b 1079void
1080httpReplyHeaderStats(StoreEntry * entry)
30a4f2a8 1081{
6fb52f6c 1082 http_server_cc_t i;
151a0b6d 1083 http_hdr_misc_t j;
30a4f2a8 1084 storeAppendPrintf(entry, open_bracket);
6fb52f6c 1085 storeAppendPrintf(entry, "{HTTP Reply Headers:}\n");
1086 storeAppendPrintf(entry, "{ Headers parsed: %d}\n",
30a4f2a8 1087 ReplyHeaderStats.parsed);
151a0b6d 1088 for (j = HDR_AGE; j < HDR_MISC_END; j++)
1089 storeAppendPrintf(entry, "{%21.21s: %d}\n",
1090 HttpHdrMiscStr[j],
1091 ReplyHeaderStats.misc[j]);
4db43fab 1092 for (i = SCC_PUBLIC; i < SCC_ENUM_END; i++)
884011a1 1093 storeAppendPrintf(entry, "{Cache-Control %s: %d}\n",
6fb52f6c 1094 HttpServerCCStr[i],
1095 ReplyHeaderStats.cc[i]);
30a4f2a8 1096 storeAppendPrintf(entry, close_bracket);
1097}