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