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