]>
Commit | Line | Data |
---|---|---|
41462d93 | 1 | |
2 | /* | |
190154cf | 3 | * $Id: forward.cc,v 1.109 2003/08/10 11:00:43 robertc Exp $ |
41462d93 | 4 | * |
5 | * DEBUG: section 17 Request Forwarding | |
6 | * AUTHOR: Duane Wessels | |
7 | * | |
2b6662ba | 8 | * SQUID Web Proxy Cache http://www.squid-cache.org/ |
e25c139f | 9 | * ---------------------------------------------------------- |
41462d93 | 10 | * |
2b6662ba | 11 | * Squid is the result of efforts by numerous individuals from |
12 | * the Internet community; see the CONTRIBUTORS file for full | |
13 | * details. Many organizations have provided support for Squid's | |
14 | * development; see the SPONSORS file for full details. Squid is | |
15 | * Copyrighted (C) 2001 by the Regents of the University of | |
16 | * California; see the COPYRIGHT file for full details. Squid | |
17 | * incorporates software developed and/or copyrighted by other | |
18 | * sources; see the CREDITS file for full details. | |
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" | |
e6ccf245 | 38 | #include "Store.h" |
528b2c61 | 39 | #include "HttpRequest.h" |
40 | #include "fde.h" | |
41 | #include "MemObject.h" | |
4fb35c3c | 42 | #include "ACLChecklist.h" |
8000a965 | 43 | #include "ACL.h" |
924f73bc | 44 | #include "HttpReply.h" |
41462d93 | 45 | |
db1cd23c | 46 | static PSC fwdStartComplete; |
6801f8a8 | 47 | static void fwdDispatch(FwdState *); |
ee08bdf5 | 48 | static void fwdConnectStart(void *); /* should be same as EVH */ |
910169e5 | 49 | static void fwdStateFree(FwdState * fwdState); |
50 | static PF fwdConnectTimeout; | |
51 | static PF fwdServerClosed; | |
52 | static CNCB fwdConnectDone; | |
68bd6892 | 53 | static int fwdCheckRetry(FwdState * fwdState); |
db1cd23c | 54 | static int fwdReforward(FwdState *); |
55 | static void fwdStartFail(FwdState *); | |
8ddcc35d | 56 | static void fwdLogReplyStatus(int tries, http_status status); |
57 | static OBJH fwdStats; | |
7197b20d | 58 | static STABH fwdAbort; |
c7f9eb6d | 59 | static peer *fwdStateServerPeer(FwdState *); |
8ddcc35d | 60 | |
61 | #define MAX_FWD_STATS_IDX 9 | |
9977e14b | 62 | static int FwdReplyCodes[MAX_FWD_STATS_IDX + 1][HTTP_INVALID_HEADER + 1]; |
db1cd23c | 63 | |
225644d7 | 64 | #if WIP_FWD_LOG |
65 | static void fwdLog(FwdState * fwdState); | |
66 | static Logfile *logfile = NULL; | |
67 | #endif | |
68 | ||
c7f9eb6d | 69 | static peer * |
70 | fwdStateServerPeer(FwdState * fwdState) | |
71 | { | |
72 | if (NULL == fwdState) | |
62e76326 | 73 | return NULL; |
74 | ||
c7f9eb6d | 75 | if (NULL == fwdState->servers) |
62e76326 | 76 | return NULL; |
77 | ||
29b8d8d6 | 78 | return fwdState->servers->_peer; |
c7f9eb6d | 79 | } |
80 | ||
db1cd23c | 81 | static void |
82 | fwdServerFree(FwdServer * fs) | |
83 | { | |
29b8d8d6 | 84 | cbdataReferenceDone(fs->_peer); |
db1cd23c | 85 | memFree(fs, MEM_FWD_SERVER); |
86 | } | |
87 | ||
41462d93 | 88 | static void |
4ca83e82 | 89 | fwdStateFree(FwdState * fwdState) |
41462d93 | 90 | { |
f563eea9 | 91 | StoreEntry *e = fwdState->entry; |
6801f8a8 | 92 | int sfd; |
c7f9eb6d | 93 | peer *p; |
0bdf2621 | 94 | debug(17, 3) ("fwdStateFree: %p\n", fwdState); |
f563eea9 | 95 | assert(e->mem_obj); |
bc87dc25 | 96 | #if URL_CHECKSUM_DEBUG |
62e76326 | 97 | |
528b2c61 | 98 | e->mem_obj->checkUrlChecksum(); |
225644d7 | 99 | #endif |
100 | #if WIP_FWD_LOG | |
62e76326 | 101 | |
225644d7 | 102 | fwdLog(fwdState); |
bc87dc25 | 103 | #endif |
62e76326 | 104 | |
1640c2df | 105 | if (e->store_status == STORE_PENDING) { |
62e76326 | 106 | if (e->isEmpty()) { |
107 | assert(fwdState->err); | |
108 | errorAppendEntry(e, fwdState->err); | |
109 | fwdState->err = NULL; | |
110 | } else { | |
111 | EBIT_CLR(e->flags, ENTRY_FWD_HDR_WAIT); | |
112 | e->complete(); | |
113 | storeReleaseRequest(e); | |
114 | } | |
f563eea9 | 115 | } |
62e76326 | 116 | |
8a4f6dd6 | 117 | if (storePendingNClients(e) > 0) |
62e76326 | 118 | assert(!EBIT_TEST(e->flags, ENTRY_FWD_HDR_WAIT)); |
119 | ||
c7f9eb6d | 120 | p = fwdStateServerPeer(fwdState); |
62e76326 | 121 | |
db1cd23c | 122 | fwdServersFree(&fwdState->servers); |
62e76326 | 123 | |
41462d93 | 124 | requestUnlink(fwdState->request); |
62e76326 | 125 | |
4ca83e82 | 126 | fwdState->request = NULL; |
62e76326 | 127 | |
2c450e4e | 128 | if (fwdState->err) |
62e76326 | 129 | errorStateFree(fwdState->err); |
130 | ||
f563eea9 | 131 | storeUnregisterAbort(e); |
62e76326 | 132 | |
f563eea9 | 133 | storeUnlockObject(e); |
62e76326 | 134 | |
4ca83e82 | 135 | fwdState->entry = NULL; |
62e76326 | 136 | |
6801f8a8 | 137 | sfd = fwdState->server_fd; |
62e76326 | 138 | |
6801f8a8 | 139 | if (sfd > -1) { |
62e76326 | 140 | comm_remove_close_handler(sfd, fwdServerClosed, fwdState); |
141 | fwdState->server_fd = -1; | |
142 | debug(17, 3) ("fwdStateFree: closing FD %d\n", sfd); | |
143 | comm_close(sfd); | |
144 | ||
145 | if (p) | |
146 | p->stats.conn_open--; | |
6801f8a8 | 147 | } |
62e76326 | 148 | |
41462d93 | 149 | cbdataFree(fwdState); |
150 | } | |
151 | ||
68bd6892 | 152 | static int |
153 | fwdCheckRetry(FwdState * fwdState) | |
154 | { | |
d8fd0f18 | 155 | if (shutting_down) |
62e76326 | 156 | return 0; |
157 | ||
1640c2df | 158 | if (fwdState->entry->store_status != STORE_PENDING) |
62e76326 | 159 | return 0; |
160 | ||
528b2c61 | 161 | if (!fwdState->entry->isEmpty()) |
62e76326 | 162 | return 0; |
163 | ||
68bd6892 | 164 | if (fwdState->n_tries > 10) |
62e76326 | 165 | return 0; |
166 | ||
efd900cb | 167 | if (squid_curtime - fwdState->start > Config.Timeout.connect) |
62e76326 | 168 | return 0; |
169 | ||
ee08bdf5 | 170 | if (fwdState->flags.dont_retry) |
62e76326 | 171 | return 0; |
172 | ||
94439e4e | 173 | if (fwdState->request->flags.body_sent) |
62e76326 | 174 | return 0; |
175 | ||
68bd6892 | 176 | return 1; |
177 | } | |
178 | ||
cb928909 | 179 | static int |
180 | fwdCheckRetriable(FwdState * fwdState) | |
181 | { | |
182 | /* If there is a request body then Squid can only try once | |
183 | * even if the method is indempotent | |
184 | */ | |
185 | ||
a2ac85d9 | 186 | if (fwdState->request->body_connection.getRaw() != NULL) |
cb928909 | 187 | return 0; |
188 | ||
189 | /* RFC2616 9.1 Safe and Idempotent Methods */ | |
190 | switch (fwdState->request->method) { | |
191 | /* 9.1.1 Safe Methods */ | |
192 | ||
193 | case METHOD_GET: | |
194 | ||
195 | case METHOD_HEAD: | |
196 | /* 9.1.2 Indepontent Methods */ | |
197 | ||
198 | case METHOD_PUT: | |
199 | ||
200 | case METHOD_DELETE: | |
201 | ||
202 | case METHOD_OPTIONS: | |
203 | ||
204 | case METHOD_TRACE: | |
205 | break; | |
206 | ||
207 | default: | |
208 | return 0; | |
209 | } | |
210 | ||
211 | return 1; | |
212 | } | |
213 | ||
910169e5 | 214 | static void |
215 | fwdServerClosed(int fd, void *data) | |
216 | { | |
e6ccf245 | 217 | FwdState *fwdState = (FwdState *)data; |
ec250dfd | 218 | debug(17, 2) ("fwdServerClosed: FD %d %s\n", fd, storeUrl(fwdState->entry)); |
6801f8a8 | 219 | assert(fwdState->server_fd == fd); |
220 | fwdState->server_fd = -1; | |
62e76326 | 221 | |
68bd6892 | 222 | if (fwdCheckRetry(fwdState)) { |
62e76326 | 223 | debug(17, 3) ("fwdServerClosed: re-forwarding (%d tries, %d secs)\n", |
224 | fwdState->n_tries, | |
225 | (int) (squid_curtime - fwdState->start)); | |
226 | ||
227 | if (fwdState->servers->next) { | |
228 | /* use next, or cycle if origin server isn't last */ | |
229 | FwdServer *fs = fwdState->servers; | |
230 | FwdServer **T, *T2 = NULL; | |
231 | fwdState->servers = fs->next; | |
232 | ||
233 | for (T = &fwdState->servers; *T; T2 = *T, T = &(*T)->next) | |
234 | ||
235 | ; | |
236 | if (T2 && T2->_peer) { | |
237 | /* cycle */ | |
238 | *T = fs; | |
239 | fs->next = NULL; | |
240 | } else { | |
241 | /* Use next. The last "direct" entry is retried multiple times */ | |
242 | fwdState->servers = fs->next; | |
243 | fwdServerFree(fs); | |
244 | } | |
245 | } | |
246 | ||
247 | /* use eventAdd to break potential call sequence loops */ | |
248 | eventAdd("fwdConnectStart", fwdConnectStart, fwdState, 0.0, 0); | |
249 | ||
250 | return; | |
d8fd0f18 | 251 | } |
62e76326 | 252 | |
d8fd0f18 | 253 | if (!fwdState->err && shutting_down) { |
62e76326 | 254 | fwdState->err =errorCon(ERR_SHUTTING_DOWN, HTTP_SERVICE_UNAVAILABLE); |
255 | fwdState->err->request = requestLink(fwdState->request); | |
f563eea9 | 256 | } |
62e76326 | 257 | |
d8fd0f18 | 258 | fwdStateFree(fwdState); |
910169e5 | 259 | } |
260 | ||
a7ad6e4e | 261 | #if USE_SSL |
262 | static void | |
263 | fwdNegotiateSSL(int fd, void *data) | |
264 | { | |
265 | FwdState *fwdState = (FwdState *)data; | |
266 | FwdServer *fs = fwdState->servers; | |
267 | SSL *ssl = fd_table[fd].ssl; | |
268 | int ret; | |
269 | ErrorState *err; | |
190154cf | 270 | HttpRequest *request = fwdState->request; |
62e76326 | 271 | |
a7ad6e4e | 272 | if ((ret = SSL_connect(ssl)) <= 0) { |
62e76326 | 273 | int ssl_error = SSL_get_error(ssl, ret); |
274 | ||
275 | switch (ssl_error) { | |
276 | ||
277 | case SSL_ERROR_WANT_READ: | |
278 | commSetSelect(fd, COMM_SELECT_READ, fwdNegotiateSSL, fwdState, 0); | |
279 | return; | |
280 | ||
281 | case SSL_ERROR_WANT_WRITE: | |
282 | commSetSelect(fd, COMM_SELECT_WRITE, fwdNegotiateSSL, fwdState, 0); | |
283 | return; | |
284 | ||
285 | default: | |
286 | debug(81, 1) ("fwdNegotiateSSL: Error negotiating SSL connection on FD %d: %s (%d/%d)\n", fd, ERR_error_string(ERR_get_error(), NULL), ssl_error, ret); | |
287 | err = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE); | |
a7ad6e4e | 288 | #ifdef EPROTO |
62e76326 | 289 | |
290 | err->xerrno = EPROTO; | |
a7ad6e4e | 291 | #else |
62e76326 | 292 | |
293 | err->xerrno = EACCES; | |
a7ad6e4e | 294 | #endif |
62e76326 | 295 | |
296 | if (fs->_peer) { | |
297 | err->host = xstrdup(fs->_peer->host); | |
298 | err->port = fs->_peer->http_port; | |
299 | } else { | |
300 | err->host = xstrdup(request->host); | |
301 | err->port = request->port; | |
302 | } | |
303 | ||
304 | err->request = requestLink(request); | |
305 | fwdFail(fwdState, err); | |
306 | ||
307 | if (fs->_peer) { | |
308 | peerConnectFailed(fs->_peer); | |
309 | fs->_peer->stats.conn_open--; | |
310 | } | |
311 | ||
312 | comm_close(fd); | |
313 | return; | |
314 | } | |
a7ad6e4e | 315 | } |
62e76326 | 316 | |
a7ad6e4e | 317 | fwdDispatch(fwdState); |
318 | } | |
319 | ||
320 | static void | |
321 | fwdInitiateSSL(FwdState * fwdState) | |
322 | { | |
323 | FwdServer *fs = fwdState->servers; | |
324 | int fd = fwdState->server_fd; | |
325 | SSL *ssl; | |
326 | SSL_CTX *sslContext = NULL; | |
327 | peer *peer = fs->_peer; | |
62e76326 | 328 | |
a7ad6e4e | 329 | if (peer) { |
62e76326 | 330 | assert(peer->use_ssl); |
331 | sslContext = peer->sslContext; | |
a7ad6e4e | 332 | } else { |
62e76326 | 333 | sslContext = Config.ssl_client.sslContext; |
a7ad6e4e | 334 | } |
62e76326 | 335 | |
a7ad6e4e | 336 | assert(sslContext); |
62e76326 | 337 | |
a7ad6e4e | 338 | if ((ssl = SSL_new(sslContext)) == NULL) { |
62e76326 | 339 | ErrorState *err; |
340 | debug(83, 1) ("fwdInitiateSSL: Error allocating handle: %s\n", | |
341 | ERR_error_string(ERR_get_error(), NULL)); | |
342 | err = errorCon(ERR_SOCKET_FAILURE, HTTP_INTERNAL_SERVER_ERROR); | |
343 | err->xerrno = errno; | |
344 | err->request = requestLink(fwdState->request); | |
345 | fwdFail(fwdState, err); | |
346 | fwdStateFree(fwdState); | |
347 | return; | |
a7ad6e4e | 348 | } |
62e76326 | 349 | |
a7ad6e4e | 350 | SSL_set_fd(ssl, fd); |
62e76326 | 351 | |
a7ad6e4e | 352 | if (peer) { |
62e76326 | 353 | if (peer->ssldomain) |
354 | SSL_set_ex_data(ssl, ssl_ex_index_server, peer->ssldomain); | |
355 | ||
a7ad6e4e | 356 | #if NOT_YET |
62e76326 | 357 | |
358 | else if (peer->name) | |
359 | SSL_set_ex_data(ssl, ssl_ex_index_server, peer->name); | |
360 | ||
a7ad6e4e | 361 | #endif |
62e76326 | 362 | |
363 | else | |
364 | SSL_set_ex_data(ssl, ssl_ex_index_server, peer->host); | |
a7ad6e4e | 365 | } else { |
62e76326 | 366 | SSL_set_ex_data(ssl, ssl_ex_index_server, fwdState->request->host); |
a7ad6e4e | 367 | } |
62e76326 | 368 | |
a7ad6e4e | 369 | fd_table[fd].ssl = ssl; |
370 | fd_table[fd].read_method = &ssl_read_method; | |
371 | fd_table[fd].write_method = &ssl_write_method; | |
372 | fwdNegotiateSSL(fd, fwdState); | |
373 | } | |
62e76326 | 374 | |
a7ad6e4e | 375 | #endif |
376 | ||
41462d93 | 377 | static void |
f3400a93 | 378 | fwdConnectDone(int server_fd, comm_err_t status, int xerrno, void *data) |
41462d93 | 379 | { |
e6ccf245 | 380 | FwdState *fwdState = (FwdState *)data; |
db1cd23c | 381 | FwdServer *fs = fwdState->servers; |
41462d93 | 382 | ErrorState *err; |
190154cf | 383 | HttpRequest *request = fwdState->request; |
6801f8a8 | 384 | assert(fwdState->server_fd == server_fd); |
62e76326 | 385 | |
41462d93 | 386 | if (status == COMM_ERR_DNS) { |
62e76326 | 387 | /* |
388 | * Only set the dont_retry flag if the DNS lookup fails on | |
389 | * a direct connection. If DNS lookup fails when trying | |
390 | * a neighbor cache, we may want to retry another option. | |
391 | */ | |
392 | ||
393 | if (NULL == fs->_peer) | |
394 | fwdState->flags.dont_retry = 1; | |
395 | ||
396 | debug(17, 4) ("fwdConnectDone: Unknown host: %s\n", | |
397 | request->host); | |
398 | ||
399 | err = errorCon(ERR_DNS_FAIL, HTTP_SERVICE_UNAVAILABLE); | |
400 | ||
401 | err->dnsserver_msg = xstrdup(dns_error_message); | |
402 | ||
403 | err->request = requestLink(request); | |
404 | ||
405 | fwdFail(fwdState, err); | |
406 | ||
407 | if (fs->_peer) | |
408 | fs->_peer->stats.conn_open--; | |
409 | ||
410 | comm_close(server_fd); | |
41462d93 | 411 | } else if (status != COMM_OK) { |
62e76326 | 412 | assert(fs); |
413 | err = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE); | |
f3400a93 | 414 | err->xerrno = xerrno; |
62e76326 | 415 | |
416 | if (fs->_peer) { | |
417 | err->host = xstrdup(fs->_peer->host); | |
418 | err->port = fs->_peer->http_port; | |
419 | } else { | |
420 | err->host = xstrdup(request->host); | |
421 | err->port = request->port; | |
422 | } | |
423 | ||
424 | err->request = requestLink(request); | |
425 | fwdFail(fwdState, err); | |
426 | ||
427 | if (fs->_peer) { | |
428 | peerConnectFailed(fs->_peer); | |
429 | fs->_peer->stats.conn_open--; | |
430 | } | |
431 | ||
432 | comm_close(server_fd); | |
41462d93 | 433 | } else { |
62e76326 | 434 | debug(17, 3) ("fwdConnectDone: FD %d: '%s'\n", server_fd, storeUrl(fwdState->entry)); |
435 | ||
436 | if (fs->_peer) | |
437 | peerConnectSucceded(fs->_peer); | |
438 | ||
a7ad6e4e | 439 | #if USE_SSL |
62e76326 | 440 | |
441 | if ((fs->_peer && fs->_peer->use_ssl) || | |
442 | (!fs->_peer && request->protocol == PROTO_HTTPS)) { | |
443 | fwdInitiateSSL(fwdState); | |
444 | return; | |
445 | } | |
446 | ||
a7ad6e4e | 447 | #endif |
62e76326 | 448 | fwdDispatch(fwdState); |
41462d93 | 449 | } |
41462d93 | 450 | } |
451 | ||
452 | static void | |
453 | fwdConnectTimeout(int fd, void *data) | |
454 | { | |
e6ccf245 | 455 | FwdState *fwdState = (FwdState *)data; |
41462d93 | 456 | StoreEntry *entry = fwdState->entry; |
457 | ErrorState *err; | |
c7f9eb6d | 458 | peer *p = fwdStateServerPeer(fwdState); |
ec250dfd | 459 | debug(17, 2) ("fwdConnectTimeout: FD %d: '%s'\n", fd, storeUrl(entry)); |
6801f8a8 | 460 | assert(fd == fwdState->server_fd); |
62e76326 | 461 | |
528b2c61 | 462 | if (entry->isEmpty()) { |
62e76326 | 463 | err = errorCon(ERR_CONNECT_FAIL, HTTP_GATEWAY_TIMEOUT); |
464 | err->request = requestLink(fwdState->request); | |
465 | err->xerrno = ETIMEDOUT; | |
466 | fwdFail(fwdState, err); | |
467 | /* | |
468 | * This marks the peer DOWN ... | |
469 | */ | |
470 | ||
471 | if (fwdState->servers) | |
472 | if (fwdState->servers->_peer) | |
473 | peerConnectFailed(fwdState->servers->_peer); | |
41462d93 | 474 | } |
62e76326 | 475 | |
c7f9eb6d | 476 | if (p) |
62e76326 | 477 | p->stats.conn_open--; |
478 | ||
41462d93 | 479 | comm_close(fd); |
480 | } | |
481 | ||
d6827718 | 482 | static struct in_addr |
62e76326 | 483 | aclMapAddr(acl_address * head, ACLChecklist * ch) |
d6827718 | 484 | { |
485 | acl_address *l; | |
62e76326 | 486 | |
d6827718 | 487 | struct in_addr addr; |
62e76326 | 488 | |
489 | for (l = head; l; l = l->next) | |
490 | { | |
7684c4b1 | 491 | if (ch->matchAclListFast(l->aclList)) |
62e76326 | 492 | return l->addr; |
d6827718 | 493 | } |
62e76326 | 494 | |
d6827718 | 495 | addr.s_addr = INADDR_ANY; |
496 | return addr; | |
497 | } | |
498 | ||
499 | static int | |
4fb35c3c | 500 | aclMapTOS(acl_tos * head, ACLChecklist * ch) |
d6827718 | 501 | { |
502 | acl_tos *l; | |
62e76326 | 503 | |
d6827718 | 504 | for (l = head; l; l = l->next) { |
7684c4b1 | 505 | if (ch->matchAclListFast(l->aclList)) |
62e76326 | 506 | return l->tos; |
d6827718 | 507 | } |
62e76326 | 508 | |
d6827718 | 509 | return 0; |
510 | } | |
511 | ||
512 | struct in_addr | |
190154cf | 513 | getOutgoingAddr(HttpRequest * request) |
d6827718 | 514 | { |
4fb35c3c | 515 | ACLChecklist ch; |
62e76326 | 516 | |
517 | if (request) | |
518 | { | |
519 | ch.src_addr = request->client_addr; | |
520 | ch.my_addr = request->my_addr; | |
521 | ch.my_port = request->my_port; | |
522 | ch.request = requestLink(request); | |
d6827718 | 523 | } |
62e76326 | 524 | |
d6827718 | 525 | return aclMapAddr(Config.accessList.outgoing_address, &ch); |
526 | } | |
527 | ||
528 | unsigned long | |
190154cf | 529 | getOutgoingTOS(HttpRequest * request) |
d6827718 | 530 | { |
4fb35c3c | 531 | ACLChecklist ch; |
62e76326 | 532 | |
d6827718 | 533 | if (request) { |
62e76326 | 534 | ch.src_addr = request->client_addr; |
535 | ch.my_addr = request->my_addr; | |
536 | ch.my_port = request->my_port; | |
537 | ch.request = requestLink(request); | |
d6827718 | 538 | } |
62e76326 | 539 | |
d6827718 | 540 | return aclMapTOS(Config.accessList.outgoing_tos, &ch); |
541 | } | |
542 | ||
41462d93 | 543 | static void |
ee08bdf5 | 544 | fwdConnectStart(void *data) |
41462d93 | 545 | { |
e6ccf245 | 546 | FwdState *fwdState = (FwdState *)data; |
41462d93 | 547 | const char *url = storeUrl(fwdState->entry); |
cb928909 | 548 | int fd = -1; |
41462d93 | 549 | ErrorState *err; |
db1cd23c | 550 | FwdServer *fs = fwdState->servers; |
551 | const char *host; | |
552 | unsigned short port; | |
bd0723ad | 553 | const char *domain = NULL; |
3f62decd | 554 | time_t ctimeout; |
62e76326 | 555 | |
d6827718 | 556 | struct in_addr outgoing; |
557 | unsigned short tos; | |
db1cd23c | 558 | assert(fs); |
cddc721b | 559 | assert(fwdState->server_fd == -1); |
41462d93 | 560 | debug(17, 3) ("fwdConnectStart: %s\n", url); |
62e76326 | 561 | |
29b8d8d6 | 562 | if (fs->_peer) { |
bd0723ad | 563 | host = fs->_peer->name; |
62e76326 | 564 | port = fs->_peer->http_port; |
565 | ctimeout = fs->_peer->connect_timeout > 0 ? fs->_peer->connect_timeout | |
566 | : Config.Timeout.peer_connect; | |
bd0723ad | 567 | |
1fdcd380 | 568 | if (fs->_peer->options.originserver) { |
bd0723ad | 569 | domain = fwdState->request->host; |
1fdcd380 | 570 | port = fwdState->request->port; |
571 | } | |
db1cd23c | 572 | } else { |
62e76326 | 573 | host = fwdState->request->host; |
574 | port = fwdState->request->port; | |
575 | ctimeout = Config.Timeout.connect; | |
db1cd23c | 576 | } |
62e76326 | 577 | |
cb928909 | 578 | if (fwdCheckRetriable(fwdState)) { |
bd0723ad | 579 | if ((fd = pconnPop(host, port, domain)) >= 0) { |
cb928909 | 580 | debug(17, 3) ("fwdConnectStart: reusing pconn FD %d\n", fd); |
581 | fwdState->server_fd = fd; | |
582 | fwdState->n_tries++; | |
583 | comm_add_close_handler(fd, fwdServerClosed, fwdState); | |
584 | fwdDispatch(fwdState); | |
585 | return; | |
586 | } | |
41462d93 | 587 | } |
62e76326 | 588 | |
bc87dc25 | 589 | #if URL_CHECKSUM_DEBUG |
528b2c61 | 590 | fwdState->entry->mem_obj->checkUrlChecksum(); |
62e76326 | 591 | |
bc87dc25 | 592 | #endif |
62e76326 | 593 | |
d6827718 | 594 | outgoing = getOutgoingAddr(fwdState->request); |
62e76326 | 595 | |
d6827718 | 596 | tos = getOutgoingTOS(fwdState->request); |
597 | ||
598 | debug(17, 3) ("fwdConnectStart: got addr %s, tos %d\n", | |
62e76326 | 599 | inet_ntoa(outgoing), tos); |
600 | ||
d6827718 | 601 | fd = comm_openex(SOCK_STREAM, |
bdb741f4 | 602 | IPPROTO_TCP, |
62e76326 | 603 | outgoing, |
604 | 0, | |
605 | COMM_NONBLOCKING, | |
606 | tos, | |
607 | url); | |
608 | ||
41462d93 | 609 | if (fd < 0) { |
62e76326 | 610 | debug(50, 4) ("fwdConnectStart: %s\n", xstrerror()); |
611 | err = errorCon(ERR_SOCKET_FAILURE, HTTP_INTERNAL_SERVER_ERROR); | |
612 | err->xerrno = errno; | |
613 | err->request = requestLink(fwdState->request); | |
614 | fwdFail(fwdState, err); | |
615 | fwdStateFree(fwdState); | |
616 | return; | |
41462d93 | 617 | } |
62e76326 | 618 | |
6801f8a8 | 619 | fwdState->server_fd = fd; |
68bd6892 | 620 | fwdState->n_tries++; |
c7f9eb6d | 621 | /* |
622 | * stats.conn_open is used to account for the number of | |
623 | * connections that we have open to the peer, so we can limit | |
624 | * based on the max-conn option. We need to increment here, | |
625 | * even if the connection may fail. | |
626 | */ | |
62e76326 | 627 | |
29b8d8d6 | 628 | if (fs->_peer) |
62e76326 | 629 | fs->_peer->stats.conn_open++; |
630 | ||
910169e5 | 631 | comm_add_close_handler(fd, fwdServerClosed, fwdState); |
62e76326 | 632 | |
41462d93 | 633 | commSetTimeout(fd, |
62e76326 | 634 | ctimeout, |
635 | fwdConnectTimeout, | |
636 | fwdState); | |
637 | ||
db1cd23c | 638 | commConnectStart(fd, host, port, fwdConnectDone, fwdState); |
41462d93 | 639 | } |
640 | ||
641 | static void | |
db1cd23c | 642 | fwdStartComplete(FwdServer * servers, void *data) |
41462d93 | 643 | { |
e6ccf245 | 644 | FwdState *fwdState = (FwdState *)data; |
8a4f6dd6 | 645 | debug(17, 3) ("fwdStartComplete: %s\n", storeUrl(fwdState->entry)); |
62e76326 | 646 | |
db1cd23c | 647 | if (servers != NULL) { |
62e76326 | 648 | fwdState->servers = servers; |
649 | fwdConnectStart(fwdState); | |
41462d93 | 650 | } else { |
62e76326 | 651 | fwdStartFail(fwdState); |
41462d93 | 652 | } |
41462d93 | 653 | } |
654 | ||
655 | static void | |
db1cd23c | 656 | fwdStartFail(FwdState * fwdState) |
41462d93 | 657 | { |
41462d93 | 658 | ErrorState *err; |
8a4f6dd6 | 659 | debug(17, 3) ("fwdStartFail: %s\n", storeUrl(fwdState->entry)); |
41462d93 | 660 | err = errorCon(ERR_CANNOT_FORWARD, HTTP_SERVICE_UNAVAILABLE); |
661 | err->request = requestLink(fwdState->request); | |
ec250dfd | 662 | err->xerrno = errno; |
663 | fwdFail(fwdState, err); | |
910169e5 | 664 | fwdStateFree(fwdState); |
41462d93 | 665 | } |
910169e5 | 666 | |
41462d93 | 667 | static void |
6801f8a8 | 668 | fwdDispatch(FwdState * fwdState) |
41462d93 | 669 | { |
c7f9eb6d | 670 | peer *p = NULL; |
190154cf | 671 | HttpRequest *request = fwdState->request; |
41462d93 | 672 | StoreEntry *entry = fwdState->entry; |
1f38f50a | 673 | ErrorState *err; |
a7ad6e4e | 674 | FwdServer *fs = fwdState->servers; |
675 | int server_fd = fwdState->server_fd; | |
b746bd8a | 676 | debug(17, 3) ("fwdDispatch: FD %d: Fetching '%s %s'\n", |
62e76326 | 677 | fwdState->client_fd, |
678 | RequestMethodStr[request->method], | |
679 | storeUrl(entry)); | |
e0ebe27c | 680 | /* |
681 | * Assert that server_fd is set. This is to guarantee that fwdState | |
682 | * is attached to something and will be deallocated when server_fd | |
683 | * is closed. | |
684 | */ | |
a7ad6e4e | 685 | assert(server_fd > -1); |
62e76326 | 686 | |
a7ad6e4e | 687 | if (fs->_peer) |
62e76326 | 688 | hierarchyNote(&fwdState->request->hier, fs->code, fs->_peer->host); |
a7ad6e4e | 689 | else if (Config.onoff.log_ip_on_direct) |
62e76326 | 690 | hierarchyNote(&fwdState->request->hier, fs->code, fd_table[server_fd].ipaddr); |
a7ad6e4e | 691 | else |
62e76326 | 692 | hierarchyNote(&fwdState->request->hier, fs->code, request->host); |
693 | ||
a7ad6e4e | 694 | fd_note(server_fd, storeUrl(fwdState->entry)); |
62e76326 | 695 | |
a7ad6e4e | 696 | fd_table[server_fd].uses++; |
62e76326 | 697 | |
a7ad6e4e | 698 | /*assert(!EBIT_TEST(entry->flags, ENTRY_DISPATCHED)); */ |
699 | assert(entry->ping_status != PING_WAITING); | |
62e76326 | 700 | |
a7ad6e4e | 701 | assert(entry->lock_count); |
62e76326 | 702 | |
a7ad6e4e | 703 | EBIT_SET(entry->flags, ENTRY_DISPATCHED); |
62e76326 | 704 | |
a7ad6e4e | 705 | netdbPingSite(request->host); |
62e76326 | 706 | |
29b8d8d6 | 707 | if (fwdState->servers && (p = fwdState->servers->_peer)) { |
62e76326 | 708 | p->stats.fetches++; |
709 | fwdState->request->peer_login = p->login; | |
710 | fwdState->request->peer_domain = p->domain; | |
711 | httpStart(fwdState); | |
41462d93 | 712 | } else { |
62e76326 | 713 | fwdState->request->peer_login = NULL; |
714 | fwdState->request->peer_domain = NULL; | |
715 | ||
716 | switch (request->protocol) { | |
a7ad6e4e | 717 | #if USE_SSL |
62e76326 | 718 | |
719 | case PROTO_HTTPS: | |
720 | httpStart(fwdState); | |
721 | break; | |
a7ad6e4e | 722 | #endif |
62e76326 | 723 | |
724 | case PROTO_HTTP: | |
725 | httpStart(fwdState); | |
726 | break; | |
727 | ||
728 | case PROTO_GOPHER: | |
729 | gopherStart(fwdState); | |
730 | break; | |
731 | ||
732 | case PROTO_FTP: | |
733 | ftpStart(fwdState); | |
734 | break; | |
735 | ||
736 | case PROTO_WAIS: | |
737 | waisStart(fwdState); | |
738 | break; | |
739 | ||
740 | case PROTO_CACHEOBJ: | |
741 | ||
742 | case PROTO_INTERNAL: | |
743 | ||
744 | case PROTO_URN: | |
745 | fatal_dump("Should never get here"); | |
746 | break; | |
747 | ||
748 | case PROTO_WHOIS: | |
749 | whoisStart(fwdState); | |
750 | break; | |
751 | ||
752 | default: | |
753 | debug(17, 1) ("fwdDispatch: Cannot retrieve '%s'\n", | |
754 | storeUrl(entry)); | |
755 | err = errorCon(ERR_UNSUP_REQ, HTTP_BAD_REQUEST); | |
756 | err->request = requestLink(request); | |
757 | fwdFail(fwdState, err); | |
758 | /* | |
759 | * Force a persistent connection to be closed because | |
760 | * some Netscape browsers have a bug that sends CONNECT | |
761 | * requests as GET's over persistent connections. | |
762 | */ | |
763 | request->flags.proxy_keepalive = 0; | |
764 | /* | |
765 | * Set the dont_retry flag becuase this is not a | |
766 | * transient (network) error; its a bug. | |
767 | */ | |
768 | fwdState->flags.dont_retry = 1; | |
769 | /* | |
770 | * this assertion exists because if we are connected to | |
771 | * a peer, then we need to decrement p->stats.conn_open. | |
772 | */ | |
773 | assert(NULL == p); | |
774 | comm_close(fwdState->server_fd); | |
775 | break; | |
776 | } | |
41462d93 | 777 | } |
778 | } | |
779 | ||
db1cd23c | 780 | static int |
781 | fwdReforward(FwdState * fwdState) | |
782 | { | |
783 | StoreEntry *e = fwdState->entry; | |
784 | FwdServer *fs = fwdState->servers; | |
785 | http_status s; | |
786 | assert(e->store_status == STORE_PENDING); | |
787 | assert(e->mem_obj); | |
bc87dc25 | 788 | #if URL_CHECKSUM_DEBUG |
62e76326 | 789 | |
528b2c61 | 790 | e->mem_obj->checkUrlChecksum(); |
bc87dc25 | 791 | #endif |
62e76326 | 792 | |
b746bd8a | 793 | debug(17, 3) ("fwdReforward: %s?\n", storeUrl(e)); |
62e76326 | 794 | |
d6eb18d6 | 795 | if (!EBIT_TEST(e->flags, ENTRY_FWD_HDR_WAIT)) { |
62e76326 | 796 | debug(17, 3) ("fwdReforward: No, ENTRY_FWD_HDR_WAIT isn't set\n"); |
797 | return 0; | |
d6eb18d6 | 798 | } |
62e76326 | 799 | |
db1cd23c | 800 | if (fwdState->n_tries > 9) |
62e76326 | 801 | return 0; |
802 | ||
94439e4e | 803 | if (fwdState->request->flags.body_sent) |
62e76326 | 804 | return 0; |
805 | ||
db1cd23c | 806 | assert(fs); |
62e76326 | 807 | |
db1cd23c | 808 | fwdState->servers = fs->next; |
62e76326 | 809 | |
db1cd23c | 810 | fwdServerFree(fs); |
62e76326 | 811 | |
db1cd23c | 812 | if (fwdState->servers == NULL) { |
62e76326 | 813 | debug(17, 3) ("fwdReforward: No forward-servers left\n"); |
814 | return 0; | |
db1cd23c | 815 | } |
62e76326 | 816 | |
528b2c61 | 817 | s = e->getReply()->sline.status; |
db1cd23c | 818 | debug(17, 3) ("fwdReforward: status %d\n", (int) s); |
b6a2f15e | 819 | return fwdReforwardableStatus(s); |
db1cd23c | 820 | } |
821 | ||
41462d93 | 822 | /* PUBLIC FUNCTIONS */ |
823 | ||
64d8034e | 824 | void |
825 | fwdServersFree(FwdServer ** FS) | |
826 | { | |
827 | FwdServer *fs; | |
62e76326 | 828 | |
64d8034e | 829 | while ((fs = *FS)) { |
62e76326 | 830 | *FS = fs->next; |
831 | fwdServerFree(fs); | |
64d8034e | 832 | } |
833 | } | |
834 | ||
41462d93 | 835 | void |
190154cf | 836 | fwdStart(int fd, StoreEntry * e, HttpRequest * r) |
41462d93 | 837 | { |
838 | FwdState *fwdState; | |
d1061d2b | 839 | int answer; |
840 | ErrorState *err; | |
5843eb62 | 841 | /* |
db1cd23c | 842 | * client_addr == no_addr indicates this is an "internal" request |
5843eb62 | 843 | * from peer_digest.c, asn.c, netdb.c, etc and should always |
844 | * be allowed. yuck, I know. | |
d1061d2b | 845 | */ |
62e76326 | 846 | |
7e3ce7b9 | 847 | if (r->client_addr.s_addr != no_addr.s_addr) { |
62e76326 | 848 | /* |
849 | * Check if this host is allowed to fetch MISSES from us (miss_access) | |
850 | */ | |
851 | ACLChecklist ch; | |
852 | ch.src_addr = r->client_addr; | |
853 | ch.my_addr = r->my_addr; | |
854 | ch.my_port = r->my_port; | |
855 | ch.request = requestLink(r); | |
856 | answer = aclCheckFast(Config.accessList.miss, &ch); | |
857 | ||
858 | if (answer == 0) { | |
859 | err = errorCon(ERR_FORWARDING_DENIED, HTTP_FORBIDDEN); | |
860 | err->request = requestLink(r); | |
861 | err->src_addr = r->client_addr; | |
862 | errorAppendEntry(e, err); | |
863 | return; | |
864 | } | |
d1061d2b | 865 | } |
62e76326 | 866 | |
7197b20d | 867 | debug(17, 3) ("fwdStart: '%s'\n", storeUrl(e)); |
868 | e->mem_obj->request = requestLink(r); | |
bc87dc25 | 869 | #if URL_CHECKSUM_DEBUG |
62e76326 | 870 | |
528b2c61 | 871 | e->mem_obj->checkUrlChecksum(); |
bc87dc25 | 872 | #endif |
62e76326 | 873 | |
05b744f3 | 874 | if (shutting_down) { |
62e76326 | 875 | /* more yuck */ |
876 | err = errorCon(ERR_SHUTTING_DOWN, HTTP_SERVICE_UNAVAILABLE); | |
877 | err->request = requestLink(r); | |
878 | errorAppendEntry(e, err); | |
879 | return; | |
05b744f3 | 880 | } |
62e76326 | 881 | |
d1061d2b | 882 | switch (r->protocol) { |
62e76326 | 883 | /* |
884 | * Note, don't create fwdState for these requests | |
885 | */ | |
886 | ||
e0ebe27c | 887 | case PROTO_INTERNAL: |
62e76326 | 888 | internalStart(r, e); |
889 | return; | |
890 | ||
e0ebe27c | 891 | case PROTO_CACHEOBJ: |
62e76326 | 892 | cachemgrStart(fd, r, e); |
893 | return; | |
894 | ||
ae0b4725 | 895 | case PROTO_URN: |
62e76326 | 896 | urnStart(r, e); |
897 | return; | |
898 | ||
e0ebe27c | 899 | default: |
62e76326 | 900 | break; |
e0ebe27c | 901 | } |
62e76326 | 902 | |
72711e31 | 903 | fwdState = cbdataAlloc(FwdState); |
d1061d2b | 904 | fwdState->entry = e; |
910169e5 | 905 | fwdState->client_fd = fd; |
6801f8a8 | 906 | fwdState->server_fd = -1; |
d1061d2b | 907 | fwdState->request = requestLink(r); |
f563eea9 | 908 | fwdState->start = squid_curtime; |
d1061d2b | 909 | storeLockObject(e); |
ec250dfd | 910 | EBIT_SET(e->flags, ENTRY_FWD_HDR_WAIT); |
7197b20d | 911 | storeRegisterAbort(e, fwdAbort, fwdState); |
db1cd23c | 912 | peerSelect(r, e, fwdStartComplete, fwdState); |
41462d93 | 913 | } |
914 | ||
910169e5 | 915 | void |
b8890359 | 916 | fwdFail(FwdState * fwdState, ErrorState * errorState) |
910169e5 | 917 | { |
d46a87a8 | 918 | assert(EBIT_TEST(fwdState->entry->flags, ENTRY_FWD_HDR_WAIT)); |
32b2931b | 919 | debug(17, 3) ("fwdFail: %s \"%s\"\n\t%s\n", |
62e76326 | 920 | err_type_str[errorState->type], |
921 | httpStatusString(errorState->httpStatus), | |
922 | storeUrl(fwdState->entry)); | |
923 | ||
ec250dfd | 924 | if (fwdState->err) |
62e76326 | 925 | errorStateFree(fwdState->err); |
926 | ||
ec250dfd | 927 | fwdState->err = errorState; |
910169e5 | 928 | } |
6801f8a8 | 929 | |
7197b20d | 930 | /* |
931 | * Called when someone else calls StoreAbort() on this entry | |
932 | */ | |
9bc73deb | 933 | static void |
7197b20d | 934 | fwdAbort(void *data) |
935 | { | |
e6ccf245 | 936 | FwdState *fwdState = (FwdState *)data; |
ec250dfd | 937 | debug(17, 2) ("fwdAbort: %s\n", storeUrl(fwdState->entry)); |
7197b20d | 938 | fwdStateFree(fwdState); |
939 | } | |
940 | ||
0b49cd31 | 941 | /* |
942 | * Frees fwdState without closing FD or generating an abort | |
943 | */ | |
944 | void | |
9dbf253d | 945 | fwdUnregister(int fd, FwdState * fwdState) |
0b49cd31 | 946 | { |
9dbf253d | 947 | debug(17, 3) ("fwdUnregister: %s\n", storeUrl(fwdState->entry)); |
7f646cdb | 948 | assert(fd == fwdState->server_fd); |
b7fe0ab0 | 949 | assert(fd > -1); |
9dbf253d | 950 | comm_remove_close_handler(fd, fwdServerClosed, fwdState); |
951 | fwdState->server_fd = -1; | |
0b49cd31 | 952 | } |
db1cd23c | 953 | |
954 | /* | |
955 | * server-side modules call fwdComplete() when they are done | |
956 | * downloading an object. Then, we either 1) re-forward the | |
957 | * request somewhere else if needed, or 2) call storeComplete() | |
958 | * to finish it off | |
959 | */ | |
960 | void | |
961 | fwdComplete(FwdState * fwdState) | |
962 | { | |
963 | StoreEntry *e = fwdState->entry; | |
964 | assert(e->store_status == STORE_PENDING); | |
8a28f65f | 965 | debug(17, 3) ("fwdComplete: %s\n\tstatus %d\n", storeUrl(e), |
62e76326 | 966 | e->getReply()->sline.status); |
bc87dc25 | 967 | #if URL_CHECKSUM_DEBUG |
62e76326 | 968 | |
528b2c61 | 969 | e->mem_obj->checkUrlChecksum(); |
bc87dc25 | 970 | #endif |
62e76326 | 971 | |
528b2c61 | 972 | fwdLogReplyStatus(fwdState->n_tries, e->getReply()->sline.status); |
62e76326 | 973 | |
d6eb18d6 | 974 | if (fwdReforward(fwdState)) { |
62e76326 | 975 | debug(17, 3) ("fwdComplete: re-forwarding %d %s\n", |
976 | e->getReply()->sline.status, | |
977 | storeUrl(e)); | |
978 | ||
979 | if (fwdState->server_fd > -1) | |
980 | fwdUnregister(fwdState->server_fd, fwdState); | |
981 | ||
982 | storeEntryReset(e); | |
983 | ||
984 | fwdStartComplete(fwdState->servers, fwdState); | |
db1cd23c | 985 | } else { |
62e76326 | 986 | debug(17, 3) ("fwdComplete: not re-forwarding status %d\n", |
987 | e->getReply()->sline.status); | |
988 | EBIT_CLR(e->flags, ENTRY_FWD_HDR_WAIT); | |
989 | e->complete(); | |
990 | /* | |
991 | * If fwdState isn't associated with a server FD, it | |
992 | * won't get freed unless we do it here. | |
993 | */ | |
994 | ||
995 | if (fwdState->server_fd < 0) | |
996 | fwdStateFree(fwdState); | |
db1cd23c | 997 | } |
998 | } | |
8ddcc35d | 999 | |
1000 | void | |
1001 | fwdInit(void) | |
1002 | { | |
9977e14b | 1003 | cachemgrRegister("forward", |
62e76326 | 1004 | "Request Forwarding Statistics", |
1005 | fwdStats, 0, 1); | |
225644d7 | 1006 | #if WIP_FWD_LOG |
62e76326 | 1007 | |
225644d7 | 1008 | if (logfile) |
62e76326 | 1009 | (void) 0; |
225644d7 | 1010 | else if (NULL == Config.Log.forward) |
62e76326 | 1011 | (void) 0; |
225644d7 | 1012 | else |
62e76326 | 1013 | logfile = logfileOpen(Config.Log.forward, 0, 1); |
1014 | ||
225644d7 | 1015 | #endif |
8ddcc35d | 1016 | } |
1017 | ||
1018 | static void | |
1019 | fwdLogReplyStatus(int tries, http_status status) | |
1020 | { | |
1021 | if (status > HTTP_INVALID_HEADER) | |
62e76326 | 1022 | return; |
1023 | ||
8ddcc35d | 1024 | assert(tries); |
62e76326 | 1025 | |
8ddcc35d | 1026 | tries--; |
62e76326 | 1027 | |
8ddcc35d | 1028 | if (tries > MAX_FWD_STATS_IDX) |
62e76326 | 1029 | tries = MAX_FWD_STATS_IDX; |
1030 | ||
8ddcc35d | 1031 | FwdReplyCodes[tries][status]++; |
1032 | } | |
1033 | ||
1034 | static void | |
9977e14b | 1035 | fwdStats(StoreEntry * s) |
8ddcc35d | 1036 | { |
9977e14b | 1037 | int i; |
1038 | int j; | |
1039 | storeAppendPrintf(s, "Status"); | |
62e76326 | 1040 | |
9977e14b | 1041 | for (j = 0; j <= MAX_FWD_STATS_IDX; j++) { |
62e76326 | 1042 | storeAppendPrintf(s, "\ttry#%d", j + 1); |
9977e14b | 1043 | } |
62e76326 | 1044 | |
9977e14b | 1045 | storeAppendPrintf(s, "\n"); |
62e76326 | 1046 | |
9977e14b | 1047 | for (i = 0; i <= (int) HTTP_INVALID_HEADER; i++) { |
62e76326 | 1048 | if (FwdReplyCodes[0][i] == 0) |
1049 | continue; | |
1050 | ||
1051 | storeAppendPrintf(s, "%3d", i); | |
1052 | ||
1053 | for (j = 0; j <= MAX_FWD_STATS_IDX; j++) { | |
1054 | storeAppendPrintf(s, "\t%d", FwdReplyCodes[j][i]); | |
1055 | } | |
1056 | ||
1057 | storeAppendPrintf(s, "\n"); | |
9977e14b | 1058 | } |
8ddcc35d | 1059 | } |
b6a2f15e | 1060 | |
1061 | int | |
1062 | fwdReforwardableStatus(http_status s) | |
1063 | { | |
1064 | switch (s) { | |
62e76326 | 1065 | |
b6a2f15e | 1066 | case HTTP_FORBIDDEN: |
62e76326 | 1067 | |
b6a2f15e | 1068 | case HTTP_INTERNAL_SERVER_ERROR: |
62e76326 | 1069 | |
b6a2f15e | 1070 | case HTTP_NOT_IMPLEMENTED: |
62e76326 | 1071 | |
b6a2f15e | 1072 | case HTTP_BAD_GATEWAY: |
62e76326 | 1073 | |
b6a2f15e | 1074 | case HTTP_SERVICE_UNAVAILABLE: |
62e76326 | 1075 | |
b6a2f15e | 1076 | case HTTP_GATEWAY_TIMEOUT: |
62e76326 | 1077 | return 1; |
1078 | ||
b6a2f15e | 1079 | default: |
62e76326 | 1080 | return 0; |
b6a2f15e | 1081 | } |
62e76326 | 1082 | |
b6a2f15e | 1083 | /* NOTREACHED */ |
1084 | } | |
225644d7 | 1085 | |
1086 | #if WIP_FWD_LOG | |
1087 | void | |
1088 | fwdUninit(void) | |
1089 | { | |
dab0cec3 | 1090 | if (NULL == logfile) |
62e76326 | 1091 | return; |
1092 | ||
225644d7 | 1093 | logfileClose(logfile); |
62e76326 | 1094 | |
225644d7 | 1095 | logfile = NULL; |
1096 | } | |
1097 | ||
1098 | void | |
1099 | fwdLogRotate(void) | |
1100 | { | |
1101 | if (logfile) | |
62e76326 | 1102 | logfileRotate(logfile); |
225644d7 | 1103 | } |
1104 | ||
1105 | static void | |
1106 | fwdLog(FwdState * fwdState) | |
1107 | { | |
1108 | if (NULL == logfile) | |
62e76326 | 1109 | return; |
1110 | ||
225644d7 | 1111 | logfilePrintf(logfile, "%9d.%03d %03d %s %s\n", |
62e76326 | 1112 | (int) current_time.tv_sec, |
1113 | (int) current_time.tv_usec / 1000, | |
1114 | fwdState->last_status, | |
1115 | RequestMethodStr[fwdState->request->method], | |
1116 | fwdState->request->canonical); | |
225644d7 | 1117 | } |
1118 | ||
1119 | void | |
1120 | fwdStatus(FwdState * fwdState, http_status s) | |
1121 | { | |
1122 | fwdState->last_status = s; | |
1123 | } | |
1124 | ||
1125 | #endif |