]>
Commit | Line | Data |
---|---|---|
41462d93 | 1 | |
2 | /* | |
d2946396 | 3 | * $Id: forward.cc,v 1.40 1998/12/29 22:51:11 wessels Exp $ |
41462d93 | 4 | * |
5 | * DEBUG: section 17 Request Forwarding | |
6 | * AUTHOR: Duane Wessels | |
7 | * | |
8 | * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ | |
e25c139f | 9 | * ---------------------------------------------------------- |
41462d93 | 10 | * |
11 | * Squid is the result of efforts by numerous individuals from the | |
12 | * Internet community. Development is led by Duane Wessels of the | |
e25c139f | 13 | * National Laboratory for Applied Network Research and funded by the |
14 | * National Science Foundation. Squid is Copyrighted (C) 1998 by | |
15 | * Duane Wessels and the University of California San Diego. Please | |
16 | * see the COPYRIGHT file for full details. Squid incorporates | |
17 | * software developed and/or copyrighted by other sources. Please see | |
18 | * the CREDITS file for full details. | |
41462d93 | 19 | * |
20 | * This program is free software; you can redistribute it and/or modify | |
21 | * it under the terms of the GNU General Public License as published by | |
22 | * the Free Software Foundation; either version 2 of the License, or | |
23 | * (at your option) any later version. | |
24 | * | |
25 | * This program is distributed in the hope that it will be useful, | |
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
28 | * GNU General Public License for more details. | |
29 | * | |
30 | * You should have received a copy of the GNU General Public License | |
31 | * along with this program; if not, write to the Free Software | |
cbdec147 | 32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. |
e25c139f | 33 | * |
41462d93 | 34 | */ |
35 | ||
36 | ||
37 | #include "squid.h" | |
38 | ||
db1cd23c | 39 | static PSC fwdStartComplete; |
6801f8a8 | 40 | static void fwdDispatch(FwdState *); |
910169e5 | 41 | static void fwdConnectStart(FwdState * fwdState); |
42 | static void fwdStateFree(FwdState * fwdState); | |
43 | static PF fwdConnectTimeout; | |
44 | static PF fwdServerClosed; | |
45 | static CNCB fwdConnectDone; | |
68bd6892 | 46 | static int fwdCheckRetry(FwdState * fwdState); |
db1cd23c | 47 | static int fwdReforward(FwdState *); |
48 | static void fwdStartFail(FwdState *); | |
8ddcc35d | 49 | static void fwdLogReplyStatus(int tries, http_status status); |
50 | static OBJH fwdStats; | |
51 | ||
52 | #define MAX_FWD_STATS_IDX 9 | |
9977e14b | 53 | static int FwdReplyCodes[MAX_FWD_STATS_IDX + 1][HTTP_INVALID_HEADER + 1]; |
db1cd23c | 54 | |
55 | static void | |
56 | fwdServerFree(FwdServer * fs) | |
57 | { | |
58 | if (fs->peer) | |
59 | cbdataUnlock(fs->peer); | |
60 | memFree(fs, MEM_FWD_SERVER); | |
61 | } | |
62 | ||
63 | static void | |
64 | fwdServersFree(FwdServer ** FS) | |
65 | { | |
66 | FwdServer *fs; | |
67 | while ((fs = *FS)) { | |
68 | *FS = fs->next; | |
69 | fwdServerFree(fs); | |
70 | } | |
71 | } | |
41462d93 | 72 | |
73 | static void | |
4ca83e82 | 74 | fwdStateFree(FwdState * fwdState) |
41462d93 | 75 | { |
f563eea9 | 76 | StoreEntry *e = fwdState->entry; |
77 | ErrorState *err; | |
6801f8a8 | 78 | int sfd; |
79 | static int loop_detect = 0; | |
0bdf2621 | 80 | debug(17, 3) ("fwdStateFree: %p\n", fwdState); |
6801f8a8 | 81 | assert(loop_detect++ == 0); |
f563eea9 | 82 | assert(e->mem_obj); |
1640c2df | 83 | if (e->store_status == STORE_PENDING) { |
84 | if (e->mem_obj->inmem_hi == 0) { | |
85 | assert(fwdState->fail.err_code); | |
86 | err = errorCon(fwdState->fail.err_code, fwdState->fail.http_code); | |
87 | err->request = requestLink(fwdState->request); | |
88 | err->xerrno = fwdState->fail.xerrno; | |
89 | errorAppendEntry(e, err); | |
90 | } else { | |
91 | storeAbort(e, 0); | |
92 | } | |
f563eea9 | 93 | } |
db1cd23c | 94 | fwdServersFree(&fwdState->servers); |
41462d93 | 95 | requestUnlink(fwdState->request); |
4ca83e82 | 96 | fwdState->request = NULL; |
f563eea9 | 97 | storeUnregisterAbort(e); |
98 | storeUnlockObject(e); | |
4ca83e82 | 99 | fwdState->entry = NULL; |
6801f8a8 | 100 | sfd = fwdState->server_fd; |
101 | if (sfd > -1) { | |
102 | comm_remove_close_handler(sfd, fwdServerClosed, fwdState); | |
103 | fwdState->server_fd = -1; | |
32b2931b | 104 | debug(17, 3) ("fwdStateFree: closing FD %d\n", sfd); |
6801f8a8 | 105 | comm_close(sfd); |
106 | } | |
41462d93 | 107 | cbdataFree(fwdState); |
6801f8a8 | 108 | loop_detect--; |
41462d93 | 109 | } |
110 | ||
68bd6892 | 111 | static int |
112 | fwdCheckRetry(FwdState * fwdState) | |
113 | { | |
1640c2df | 114 | if (fwdState->entry->store_status != STORE_PENDING) |
115 | return 0; | |
68bd6892 | 116 | if (fwdState->entry->mem_obj->inmem_hi > 0) |
117 | return 0; | |
118 | if (fwdState->n_tries > 10) | |
119 | return 0; | |
120 | if (squid_curtime - fwdState->start > 120) | |
121 | return 0; | |
1d22e062 | 122 | if (pumpMethod(fwdState->request->method)) |
123 | if (0 == pumpRestart(fwdState->request)) | |
124 | return 0; | |
68bd6892 | 125 | return 1; |
126 | } | |
127 | ||
910169e5 | 128 | static void |
129 | fwdServerClosed(int fd, void *data) | |
130 | { | |
4ca83e82 | 131 | FwdState *fwdState = data; |
68bd6892 | 132 | debug(17, 3) ("fwdServerClosed: FD %d %s\n", fd, storeUrl(fwdState->entry)); |
6801f8a8 | 133 | assert(fwdState->server_fd == fd); |
134 | fwdState->server_fd = -1; | |
68bd6892 | 135 | if (fwdCheckRetry(fwdState)) { |
32b2931b | 136 | debug(17, 3) ("fwdServerClosed: re-forwarding (%d tries, %d secs)\n", |
9dbf253d | 137 | fwdState->n_tries, |
138 | (int) (squid_curtime - fwdState->start)); | |
f563eea9 | 139 | fwdConnectStart(fwdState); |
140 | } else { | |
141 | fwdStateFree(fwdState); | |
142 | } | |
910169e5 | 143 | } |
144 | ||
41462d93 | 145 | static void |
146 | fwdConnectDone(int server_fd, int status, void *data) | |
147 | { | |
148 | FwdState *fwdState = data; | |
db1cd23c | 149 | FwdServer *fs = fwdState->servers; |
41462d93 | 150 | ErrorState *err; |
db1cd23c | 151 | request_t *request = fwdState->request; |
6801f8a8 | 152 | assert(fwdState->server_fd == server_fd); |
41462d93 | 153 | if (status == COMM_ERR_DNS) { |
154 | debug(17, 4) ("fwdConnectDone: Unknown host: %s\n", | |
db1cd23c | 155 | request->host); |
41462d93 | 156 | err = errorCon(ERR_DNS_FAIL, HTTP_SERVICE_UNAVAILABLE); |
157 | err->dnsserver_msg = xstrdup(dns_error_message); | |
db1cd23c | 158 | err->request = requestLink(request); |
41462d93 | 159 | errorAppendEntry(fwdState->entry, err); |
160 | comm_close(server_fd); | |
161 | } else if (status != COMM_OK) { | |
db1cd23c | 162 | assert(fs); |
41462d93 | 163 | err = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE); |
164 | err->xerrno = errno; | |
db1cd23c | 165 | if (fs->peer) { |
166 | err->host = xstrdup(fs->peer->host); | |
167 | err->port = fs->peer->http_port; | |
168 | } else { | |
169 | err->host = xstrdup(request->host); | |
170 | err->port = request->port; | |
171 | } | |
172 | err->request = requestLink(request); | |
41462d93 | 173 | errorAppendEntry(fwdState->entry, err); |
db1cd23c | 174 | if (fs->peer) |
175 | peerCheckConnectStart(fs->peer); | |
41462d93 | 176 | comm_close(server_fd); |
177 | } else { | |
178 | fd_note(server_fd, storeUrl(fwdState->entry)); | |
179 | fd_table[server_fd].uses++; | |
6801f8a8 | 180 | fwdDispatch(fwdState); |
41462d93 | 181 | } |
41462d93 | 182 | } |
183 | ||
184 | static void | |
185 | fwdConnectTimeout(int fd, void *data) | |
186 | { | |
187 | FwdState *fwdState = data; | |
188 | StoreEntry *entry = fwdState->entry; | |
189 | ErrorState *err; | |
190 | debug(17, 3) ("fwdConnectTimeout: FD %d: '%s'\n", fd, storeUrl(entry)); | |
6801f8a8 | 191 | assert(fd == fwdState->server_fd); |
41462d93 | 192 | if (entry->mem_obj->inmem_hi == 0) { |
193 | err = errorCon(ERR_READ_TIMEOUT, HTTP_GATEWAY_TIMEOUT); | |
194 | err->request = requestLink(fwdState->request); | |
195 | errorAppendEntry(entry, err); | |
196 | } else { | |
197 | storeAbort(entry, 0); | |
198 | } | |
199 | comm_close(fd); | |
200 | } | |
201 | ||
202 | static void | |
203 | fwdConnectStart(FwdState * fwdState) | |
204 | { | |
205 | const char *url = storeUrl(fwdState->entry); | |
206 | int fd; | |
207 | ErrorState *err; | |
db1cd23c | 208 | FwdServer *fs = fwdState->servers; |
209 | const char *host; | |
210 | unsigned short port; | |
211 | assert(fs); | |
cddc721b | 212 | assert(fwdState->server_fd == -1); |
41462d93 | 213 | debug(17, 3) ("fwdConnectStart: %s\n", url); |
db1cd23c | 214 | if (fs->peer) { |
215 | host = fs->peer->host; | |
216 | port = fs->peer->http_port; | |
217 | } else { | |
218 | host = fwdState->request->host; | |
219 | port = fwdState->request->port; | |
220 | } | |
0bdf2621 | 221 | hierarchyNote(&fwdState->request->hier, fs->code, host); |
db1cd23c | 222 | if ((fd = pconnPop(host, port)) >= 0) { |
41462d93 | 223 | debug(17, 3) ("fwdConnectStart: reusing pconn FD %d\n", fd); |
9dbf253d | 224 | fwdState->server_fd = fd; |
9977e14b | 225 | fwdState->n_tries++; |
910169e5 | 226 | comm_add_close_handler(fd, fwdServerClosed, fwdState); |
41462d93 | 227 | fwdConnectDone(fd, COMM_OK, fwdState); |
228 | return; | |
229 | } | |
230 | fd = comm_open(SOCK_STREAM, | |
231 | 0, | |
232 | Config.Addrs.tcp_outgoing, | |
233 | 0, | |
234 | COMM_NONBLOCKING, | |
235 | url); | |
236 | if (fd < 0) { | |
237 | debug(50, 4) ("fwdConnectStart: %s\n", xstrerror()); | |
238 | err = errorCon(ERR_SOCKET_FAILURE, HTTP_INTERNAL_SERVER_ERROR); | |
239 | err->xerrno = errno; | |
240 | err->request = requestLink(fwdState->request); | |
241 | errorAppendEntry(fwdState->entry, err); | |
910169e5 | 242 | fwdStateFree(fwdState); |
41462d93 | 243 | return; |
244 | } | |
6801f8a8 | 245 | fwdState->server_fd = fd; |
68bd6892 | 246 | fwdState->n_tries++; |
910169e5 | 247 | comm_add_close_handler(fd, fwdServerClosed, fwdState); |
41462d93 | 248 | commSetTimeout(fd, |
249 | Config.Timeout.connect, | |
250 | fwdConnectTimeout, | |
251 | fwdState); | |
db1cd23c | 252 | commConnectStart(fd, host, port, fwdConnectDone, fwdState); |
41462d93 | 253 | } |
254 | ||
255 | static void | |
db1cd23c | 256 | fwdStartComplete(FwdServer * servers, void *data) |
41462d93 | 257 | { |
258 | FwdState *fwdState = data; | |
db1cd23c | 259 | if (servers != NULL) { |
260 | fwdState->servers = servers; | |
261 | fwdConnectStart(fwdState); | |
41462d93 | 262 | } else { |
db1cd23c | 263 | fwdStartFail(fwdState); |
41462d93 | 264 | } |
41462d93 | 265 | } |
266 | ||
267 | static void | |
db1cd23c | 268 | fwdStartFail(FwdState * fwdState) |
41462d93 | 269 | { |
41462d93 | 270 | ErrorState *err; |
41462d93 | 271 | err = errorCon(ERR_CANNOT_FORWARD, HTTP_SERVICE_UNAVAILABLE); |
272 | err->request = requestLink(fwdState->request); | |
273 | errorAppendEntry(fwdState->entry, err); | |
910169e5 | 274 | fwdStateFree(fwdState); |
41462d93 | 275 | } |
910169e5 | 276 | |
41462d93 | 277 | static void |
6801f8a8 | 278 | fwdDispatch(FwdState * fwdState) |
41462d93 | 279 | { |
280 | peer *p; | |
281 | request_t *request = fwdState->request; | |
282 | StoreEntry *entry = fwdState->entry; | |
283 | debug(17, 5) ("fwdDispatch: FD %d: Fetching '%s %s'\n", | |
910169e5 | 284 | fwdState->client_fd, |
41462d93 | 285 | RequestMethodStr[request->method], |
286 | storeUrl(entry)); | |
d46a87a8 | 287 | /*assert(!EBIT_TEST(entry->flags, ENTRY_DISPATCHED)); */ |
41462d93 | 288 | assert(entry->ping_status != PING_WAITING); |
4ca83e82 | 289 | assert(entry->lock_count); |
d46a87a8 | 290 | EBIT_SET(entry->flags, ENTRY_DISPATCHED); |
41462d93 | 291 | netdbPingSite(request->host); |
e0ebe27c | 292 | /* |
293 | * Assert that server_fd is set. This is to guarantee that fwdState | |
294 | * is attached to something and will be deallocated when server_fd | |
295 | * is closed. | |
296 | */ | |
297 | assert(fwdState->server_fd > -1); | |
41462d93 | 298 | if (fwdState->servers && (p = fwdState->servers->peer)) { |
299 | p->stats.fetches++; | |
db1cd23c | 300 | httpStart(fwdState); |
41462d93 | 301 | } else { |
302 | switch (request->protocol) { | |
303 | case PROTO_HTTP: | |
db1cd23c | 304 | httpStart(fwdState); |
41462d93 | 305 | break; |
306 | case PROTO_GOPHER: | |
db1cd23c | 307 | gopherStart(fwdState); |
41462d93 | 308 | break; |
309 | case PROTO_FTP: | |
db1cd23c | 310 | ftpStart(fwdState); |
41462d93 | 311 | break; |
312 | case PROTO_WAIS: | |
db1cd23c | 313 | waisStart(fwdState); |
41462d93 | 314 | break; |
315 | case PROTO_CACHEOBJ: | |
e0ebe27c | 316 | case PROTO_INTERNAL: |
41462d93 | 317 | case PROTO_URN: |
ae0b4725 | 318 | fatal_dump("Should never get here"); |
41462d93 | 319 | break; |
320 | case PROTO_WHOIS: | |
db1cd23c | 321 | whoisStart(fwdState); |
41462d93 | 322 | break; |
41462d93 | 323 | default: |
ce45d320 | 324 | debug(17, 1) ("fwdDispatch: Cannot retrieve '%s'\n", |
325 | storeUrl(entry)); | |
c68e9c6b | 326 | fwdFail(fwdState, ERR_UNSUP_REQ, HTTP_BAD_REQUEST, -1); |
327 | comm_close(fwdState->server_fd); | |
ce45d320 | 328 | break; |
41462d93 | 329 | } |
330 | } | |
331 | } | |
332 | ||
db1cd23c | 333 | static int |
334 | fwdReforward(FwdState * fwdState) | |
335 | { | |
336 | StoreEntry *e = fwdState->entry; | |
337 | FwdServer *fs = fwdState->servers; | |
338 | http_status s; | |
339 | assert(e->store_status == STORE_PENDING); | |
340 | assert(e->mem_obj); | |
d6eb18d6 | 341 | if (!EBIT_TEST(e->flags, ENTRY_FWD_HDR_WAIT)) { |
342 | debug(17, 3) ("fwdReforward: No, ENTRY_FWD_HDR_WAIT isn't set\n"); | |
343 | return 0; | |
344 | } | |
db1cd23c | 345 | if (fwdState->n_tries > 9) |
346 | return 0; | |
d2946396 | 347 | if (pumpMethod(fwdState->request->method)) |
348 | if (0 == pumpRestart(fwdState->request)) | |
349 | return 0; | |
db1cd23c | 350 | assert(fs); |
351 | fwdState->servers = fs->next; | |
352 | fwdServerFree(fs); | |
353 | if (fwdState->servers == NULL) { | |
354 | debug(17, 3) ("fwdReforward: No forward-servers left\n"); | |
355 | return 0; | |
356 | } | |
357 | s = e->mem_obj->reply->sline.status; | |
358 | debug(17, 3) ("fwdReforward: status %d\n", (int) s); | |
359 | switch (s) { | |
360 | case HTTP_FORBIDDEN: | |
361 | case HTTP_INTERNAL_SERVER_ERROR: | |
362 | case HTTP_NOT_IMPLEMENTED: | |
363 | case HTTP_BAD_GATEWAY: | |
364 | case HTTP_SERVICE_UNAVAILABLE: | |
365 | case HTTP_GATEWAY_TIMEOUT: | |
366 | return 1; | |
367 | default: | |
368 | return 0; | |
369 | } | |
370 | /* NOTREACHED */ | |
371 | } | |
372 | ||
41462d93 | 373 | /* PUBLIC FUNCTIONS */ |
374 | ||
41462d93 | 375 | void |
db1cd23c | 376 | fwdStart(int fd, StoreEntry * e, request_t * r, struct in_addr client_addr) |
41462d93 | 377 | { |
378 | FwdState *fwdState; | |
d1061d2b | 379 | aclCheck_t ch; |
380 | int answer; | |
381 | ErrorState *err; | |
5843eb62 | 382 | /* |
db1cd23c | 383 | * client_addr == no_addr indicates this is an "internal" request |
5843eb62 | 384 | * from peer_digest.c, asn.c, netdb.c, etc and should always |
385 | * be allowed. yuck, I know. | |
d1061d2b | 386 | */ |
db1cd23c | 387 | if (client_addr.s_addr != no_addr.s_addr) { |
5843eb62 | 388 | /* |
389 | * Check if this host is allowed to fetch MISSES from us (miss_access) | |
390 | */ | |
391 | memset(&ch, '\0', sizeof(aclCheck_t)); | |
db1cd23c | 392 | ch.src_addr = client_addr; |
5843eb62 | 393 | ch.request = r; |
394 | answer = aclCheckFast(Config.accessList.miss, &ch); | |
395 | if (answer == 0) { | |
396 | err = errorCon(ERR_FORWARDING_DENIED, HTTP_FORBIDDEN); | |
397 | err->request = requestLink(r); | |
db1cd23c | 398 | err->src_addr = client_addr; |
5843eb62 | 399 | errorAppendEntry(e, err); |
400 | return; | |
401 | } | |
d1061d2b | 402 | } |
403 | debug(17, 3) ("fwdStart: '%s'\n", storeUrl(e)); | |
404 | e->mem_obj->request = requestLink(r); | |
405 | e->mem_obj->fd = fd; | |
406 | switch (r->protocol) { | |
0cdcddb9 | 407 | /* |
408 | * Note, don't create fwdState for these requests | |
409 | */ | |
e0ebe27c | 410 | case PROTO_INTERNAL: |
d1061d2b | 411 | internalStart(r, e); |
e0ebe27c | 412 | return; |
413 | case PROTO_CACHEOBJ: | |
d1061d2b | 414 | cachemgrStart(fd, r, e); |
e0ebe27c | 415 | return; |
ae0b4725 | 416 | case PROTO_URN: |
417 | urnStart(r, e); | |
418 | return; | |
e0ebe27c | 419 | default: |
420 | break; | |
421 | } | |
798b0889 | 422 | fwdState = memAllocate(MEM_FWD_STATE); |
db1cd23c | 423 | cbdataAdd(fwdState, memFree, MEM_FWD_STATE); |
d1061d2b | 424 | fwdState->entry = e; |
910169e5 | 425 | fwdState->client_fd = fd; |
6801f8a8 | 426 | fwdState->server_fd = -1; |
d1061d2b | 427 | fwdState->request = requestLink(r); |
f563eea9 | 428 | fwdState->start = squid_curtime; |
d1061d2b | 429 | storeLockObject(e); |
430 | storeRegisterAbort(e, fwdAbort, fwdState); | |
db1cd23c | 431 | peerSelect(r, e, fwdStartComplete, fwdState); |
41462d93 | 432 | } |
433 | ||
41462d93 | 434 | int |
435 | fwdCheckDeferRead(int fdnotused, void *data) | |
436 | { | |
437 | StoreEntry *e = data; | |
438 | MemObject *mem = e->mem_obj; | |
439 | if (mem == NULL) | |
440 | return 0; | |
447e176b | 441 | #if DELAY_POOLS |
442 | if (delayMostBytesWanted(mem, 1) == 0) | |
443 | return 1; | |
444 | #endif | |
41462d93 | 445 | if (mem->inmem_hi - storeLowestMemReaderOffset(e) < READ_AHEAD_GAP) |
446 | return 0; | |
447 | return 1; | |
448 | } | |
910169e5 | 449 | |
450 | void | |
4ca83e82 | 451 | fwdFail(FwdState * fwdState, int err_code, http_status http_code, int xerrno) |
910169e5 | 452 | { |
d46a87a8 | 453 | assert(EBIT_TEST(fwdState->entry->flags, ENTRY_FWD_HDR_WAIT)); |
32b2931b | 454 | debug(17, 3) ("fwdFail: %s \"%s\"\n\t%s\n", |
4ca83e82 | 455 | err_type_str[err_code], |
456 | httpStatusString(http_code), | |
457 | storeUrl(fwdState->entry)); | |
458 | fwdState->fail.err_code = err_code; | |
459 | fwdState->fail.http_code = http_code; | |
460 | fwdState->fail.xerrno = xerrno; | |
910169e5 | 461 | } |
6801f8a8 | 462 | |
463 | /* | |
464 | * Called when someone else calls StoreAbort() on this entry | |
465 | */ | |
466 | void | |
467 | fwdAbort(void *data) | |
468 | { | |
9dbf253d | 469 | FwdState *fwdState = data; |
32b2931b | 470 | debug(17, 3) ("fwdAbort: %s\n", storeUrl(fwdState->entry)); |
9dbf253d | 471 | fwdStateFree(fwdState); |
6801f8a8 | 472 | } |
0b49cd31 | 473 | |
474 | /* | |
475 | * Frees fwdState without closing FD or generating an abort | |
476 | */ | |
477 | void | |
9dbf253d | 478 | fwdUnregister(int fd, FwdState * fwdState) |
0b49cd31 | 479 | { |
9dbf253d | 480 | debug(17, 3) ("fwdUnregister: %s\n", storeUrl(fwdState->entry)); |
481 | assert(fd = fwdState->server_fd); | |
482 | comm_remove_close_handler(fd, fwdServerClosed, fwdState); | |
483 | fwdState->server_fd = -1; | |
0b49cd31 | 484 | } |
db1cd23c | 485 | |
486 | /* | |
487 | * server-side modules call fwdComplete() when they are done | |
488 | * downloading an object. Then, we either 1) re-forward the | |
489 | * request somewhere else if needed, or 2) call storeComplete() | |
490 | * to finish it off | |
491 | */ | |
492 | void | |
493 | fwdComplete(FwdState * fwdState) | |
494 | { | |
495 | StoreEntry *e = fwdState->entry; | |
496 | assert(e->store_status == STORE_PENDING); | |
8a28f65f | 497 | debug(17, 3) ("fwdComplete: %s\n\tstatus %d\n", storeUrl(e), |
db1cd23c | 498 | e->mem_obj->reply->sline.status); |
9977e14b | 499 | fwdLogReplyStatus(fwdState->n_tries, e->mem_obj->reply->sline.status); |
d6eb18d6 | 500 | if (fwdReforward(fwdState)) { |
501 | debug(17, 1) ("fwdComplete: re-forwarding %d %s\n", | |
0bdf2621 | 502 | e->mem_obj->reply->sline.status, |
503 | storeUrl(e)); | |
8a28f65f | 504 | if (fwdState->server_fd > -1) |
0bdf2621 | 505 | fwdUnregister(fwdState->server_fd, fwdState); |
db1cd23c | 506 | storeEntryReset(e); |
507 | fwdStartComplete(fwdState->servers, fwdState); | |
508 | } else { | |
d6eb18d6 | 509 | debug(17, 3) ("fwdComplete: not re-forwarding status %d\n", |
510 | e->mem_obj->reply->sline.status); | |
db1cd23c | 511 | EBIT_CLR(e->flags, ENTRY_FWD_HDR_WAIT); |
512 | storeComplete(e); | |
d6eb18d6 | 513 | /* |
514 | * If fwdState isn't associated with a server FD, it | |
515 | * won't get freed unless we do it here. | |
516 | */ | |
517 | if (fwdState->server_fd < 0) | |
518 | fwdStateFree(fwdState); | |
db1cd23c | 519 | } |
520 | } | |
8ddcc35d | 521 | |
522 | void | |
523 | fwdInit(void) | |
524 | { | |
9977e14b | 525 | cachemgrRegister("forward", |
526 | "Request Forwarding Statistics", | |
527 | fwdStats, 0, 1); | |
8ddcc35d | 528 | } |
529 | ||
530 | static void | |
531 | fwdLogReplyStatus(int tries, http_status status) | |
532 | { | |
533 | if (status > HTTP_INVALID_HEADER) | |
534 | return; | |
535 | assert(tries); | |
536 | tries--; | |
537 | if (tries > MAX_FWD_STATS_IDX) | |
538 | tries = MAX_FWD_STATS_IDX; | |
539 | FwdReplyCodes[tries][status]++; | |
540 | } | |
541 | ||
542 | static void | |
9977e14b | 543 | fwdStats(StoreEntry * s) |
8ddcc35d | 544 | { |
9977e14b | 545 | int i; |
546 | int j; | |
547 | storeAppendPrintf(s, "Status"); | |
548 | for (j = 0; j <= MAX_FWD_STATS_IDX; j++) { | |
549 | storeAppendPrintf(s, "\ttry#%d", j + 1); | |
550 | } | |
551 | storeAppendPrintf(s, "\n"); | |
552 | for (i = 0; i <= (int) HTTP_INVALID_HEADER; i++) { | |
553 | if (FwdReplyCodes[0][i] == 0) | |
554 | continue; | |
555 | storeAppendPrintf(s, "%3d", i); | |
556 | for (j = 0; j <= MAX_FWD_STATS_IDX; j++) { | |
557 | storeAppendPrintf(s, "\t%d", FwdReplyCodes[j][i]); | |
8ddcc35d | 558 | } |
9977e14b | 559 | storeAppendPrintf(s, "\n"); |
560 | } | |
8ddcc35d | 561 | } |