]> git.ipfire.org Git - thirdparty/squid.git/blame - src/forward.cc
update
[thirdparty/squid.git] / src / forward.cc
CommitLineData
41462d93 1
2/*
798b0889 3 * $Id: forward.cc,v 1.16 1998/07/13 21:37:15 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/
9 * --------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from the
12 * Internet community. Development is led by Duane Wessels of the
13 * National Laboratory for Applied Network Research and funded by
14 * the National Science Foundation.
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 *
30 */
31
32
33#include "squid.h"
34
41462d93 35static void fwdStartComplete(peer * p, void *data);
36static void fwdStartFail(peer * p, void *data);
6801f8a8 37static void fwdDispatch(FwdState *);
910169e5 38static void fwdConnectStart(FwdState * fwdState);
39static void fwdStateFree(FwdState * fwdState);
40static PF fwdConnectTimeout;
41static PF fwdServerClosed;
42static CNCB fwdConnectDone;
68bd6892 43static int fwdCheckRetry(FwdState * fwdState);
41462d93 44
45static void
4ca83e82 46fwdStateFree(FwdState * fwdState)
41462d93 47{
910169e5 48 FwdServer *s;
49 FwdServer *n = fwdState->servers;
f563eea9 50 StoreEntry *e = fwdState->entry;
51 ErrorState *err;
6801f8a8 52 int sfd;
53 static int loop_detect = 0;
6801f8a8 54 assert(loop_detect++ == 0);
f563eea9 55 assert(e->mem_obj);
1640c2df 56 if (e->store_status == STORE_PENDING) {
57 if (e->mem_obj->inmem_hi == 0) {
58 assert(fwdState->fail.err_code);
59 err = errorCon(fwdState->fail.err_code, fwdState->fail.http_code);
60 err->request = requestLink(fwdState->request);
61 err->xerrno = fwdState->fail.xerrno;
62 errorAppendEntry(e, err);
63 } else {
64 storeAbort(e, 0);
65 }
f563eea9 66 }
41462d93 67 while ((s = n)) {
68 n = s->next;
69 xfree(s->host);
798b0889 70 memFree(MEM_FWD_SERVER, s);
41462d93 71 }
72 fwdState->servers = NULL;
73 requestUnlink(fwdState->request);
4ca83e82 74 fwdState->request = NULL;
f563eea9 75 storeUnregisterAbort(e);
76 storeUnlockObject(e);
4ca83e82 77 fwdState->entry = NULL;
6801f8a8 78 sfd = fwdState->server_fd;
79 if (sfd > -1) {
80 comm_remove_close_handler(sfd, fwdServerClosed, fwdState);
81 fwdState->server_fd = -1;
9dbf253d 82 debug(17, 1) ("fwdStateFree: closing FD %d\n", sfd);
6801f8a8 83 comm_close(sfd);
84 }
41462d93 85 cbdataFree(fwdState);
6801f8a8 86 loop_detect--;
41462d93 87}
88
68bd6892 89static int
90fwdCheckRetry(FwdState * fwdState)
91{
1640c2df 92 if (fwdState->entry->store_status != STORE_PENDING)
93 return 0;
68bd6892 94 if (fwdState->entry->mem_obj->inmem_hi > 0)
95 return 0;
96 if (fwdState->n_tries > 10)
97 return 0;
98 if (squid_curtime - fwdState->start > 120)
99 return 0;
1d22e062 100 if (pumpMethod(fwdState->request->method))
101 if (0 == pumpRestart(fwdState->request))
102 return 0;
68bd6892 103 return 1;
104}
105
910169e5 106static void
107fwdServerClosed(int fd, void *data)
108{
4ca83e82 109 FwdState *fwdState = data;
68bd6892 110 debug(17, 3) ("fwdServerClosed: FD %d %s\n", fd, storeUrl(fwdState->entry));
6801f8a8 111 assert(fwdState->server_fd == fd);
112 fwdState->server_fd = -1;
68bd6892 113 if (fwdCheckRetry(fwdState)) {
114 debug(17, 1) ("fwdServerClosed: re-forwarding (%d tries, %d secs)\n",
9dbf253d 115 fwdState->n_tries,
116 (int) (squid_curtime - fwdState->start));
f563eea9 117 fwdConnectStart(fwdState);
118 } else {
119 fwdStateFree(fwdState);
120 }
910169e5 121}
122
41462d93 123static void
124fwdConnectDone(int server_fd, int status, void *data)
125{
126 FwdState *fwdState = data;
127 ErrorState *err;
6801f8a8 128 assert(fwdState->server_fd == server_fd);
41462d93 129 if (status == COMM_ERR_DNS) {
130 debug(17, 4) ("fwdConnectDone: Unknown host: %s\n",
131 fwdState->request->host);
132 err = errorCon(ERR_DNS_FAIL, HTTP_SERVICE_UNAVAILABLE);
133 err->dnsserver_msg = xstrdup(dns_error_message);
134 err->request = requestLink(fwdState->request);
135 errorAppendEntry(fwdState->entry, err);
136 comm_close(server_fd);
137 } else if (status != COMM_OK) {
138 err = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE);
139 err->xerrno = errno;
140 err->host = xstrdup(fwdState->servers->host);
141 err->port = fwdState->servers->port;
142 err->request = requestLink(fwdState->request);
143 errorAppendEntry(fwdState->entry, err);
144 assert(fwdState->servers);
145 if (fwdState->servers->peer)
146 peerCheckConnectStart(fwdState->servers->peer);
147 comm_close(server_fd);
148 } else {
149 fd_note(server_fd, storeUrl(fwdState->entry));
150 fd_table[server_fd].uses++;
6801f8a8 151 fwdDispatch(fwdState);
41462d93 152 }
41462d93 153}
154
155static void
156fwdConnectTimeout(int fd, void *data)
157{
158 FwdState *fwdState = data;
159 StoreEntry *entry = fwdState->entry;
160 ErrorState *err;
161 debug(17, 3) ("fwdConnectTimeout: FD %d: '%s'\n", fd, storeUrl(entry));
6801f8a8 162 assert(fd == fwdState->server_fd);
41462d93 163 if (entry->mem_obj->inmem_hi == 0) {
164 err = errorCon(ERR_READ_TIMEOUT, HTTP_GATEWAY_TIMEOUT);
165 err->request = requestLink(fwdState->request);
166 errorAppendEntry(entry, err);
167 } else {
168 storeAbort(entry, 0);
169 }
170 comm_close(fd);
171}
172
173static void
174fwdConnectStart(FwdState * fwdState)
175{
176 const char *url = storeUrl(fwdState->entry);
177 int fd;
178 ErrorState *err;
910169e5 179 FwdServer *srv = fwdState->servers;
41462d93 180 assert(srv);
cddc721b 181 assert(fwdState->server_fd == -1);
41462d93 182 debug(17, 3) ("fwdConnectStart: %s\n", url);
183 if ((fd = pconnPop(srv->host, srv->port)) >= 0) {
184 debug(17, 3) ("fwdConnectStart: reusing pconn FD %d\n", fd);
9dbf253d 185 fwdState->server_fd = fd;
910169e5 186 comm_add_close_handler(fd, fwdServerClosed, fwdState);
41462d93 187 fwdConnectDone(fd, COMM_OK, fwdState);
188 return;
189 }
190 fd = comm_open(SOCK_STREAM,
191 0,
192 Config.Addrs.tcp_outgoing,
193 0,
194 COMM_NONBLOCKING,
195 url);
196 if (fd < 0) {
197 debug(50, 4) ("fwdConnectStart: %s\n", xstrerror());
198 err = errorCon(ERR_SOCKET_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
199 err->xerrno = errno;
200 err->request = requestLink(fwdState->request);
201 errorAppendEntry(fwdState->entry, err);
910169e5 202 fwdStateFree(fwdState);
41462d93 203 return;
204 }
6801f8a8 205 fwdState->server_fd = fd;
68bd6892 206 fwdState->n_tries++;
910169e5 207 comm_add_close_handler(fd, fwdServerClosed, fwdState);
41462d93 208 commSetTimeout(fd,
209 Config.Timeout.connect,
210 fwdConnectTimeout,
211 fwdState);
212 commConnectStart(fd,
213 srv->host,
214 srv->port,
215 fwdConnectDone,
216 fwdState);
217}
218
219static void
220fwdStartComplete(peer * p, void *data)
221{
222 FwdState *fwdState = data;
910169e5 223 FwdServer *s;
798b0889 224 s = memAllocate(MEM_FWD_SERVER);
41462d93 225 if (NULL != p) {
226 s->host = xstrdup(p->host);
227 s->port = p->http_port;
228 s->peer = p;
229 } else {
230 s->host = xstrdup(fwdState->request->host);
231 s->port = fwdState->request->port;
232 }
233 fwdState->servers = s;
234 fwdConnectStart(fwdState);
235}
236
237static void
238fwdStartFail(peer * peernotused, void *data)
239{
240 FwdState *fwdState = data;
241 ErrorState *err;
41462d93 242 err = errorCon(ERR_CANNOT_FORWARD, HTTP_SERVICE_UNAVAILABLE);
243 err->request = requestLink(fwdState->request);
244 errorAppendEntry(fwdState->entry, err);
245 requestUnlink(fwdState->request);
910169e5 246 fwdStateFree(fwdState);
41462d93 247}
910169e5 248
41462d93 249static void
6801f8a8 250fwdDispatch(FwdState * fwdState)
41462d93 251{
252 peer *p;
253 request_t *request = fwdState->request;
254 StoreEntry *entry = fwdState->entry;
255 debug(17, 5) ("fwdDispatch: FD %d: Fetching '%s %s'\n",
910169e5 256 fwdState->client_fd,
41462d93 257 RequestMethodStr[request->method],
258 storeUrl(entry));
9dbf253d 259 /*assert(!EBIT_TEST(entry->flag, ENTRY_DISPATCHED)); */
41462d93 260 assert(entry->ping_status != PING_WAITING);
4ca83e82 261 assert(entry->lock_count);
41462d93 262 EBIT_SET(entry->flag, ENTRY_DISPATCHED);
263 netdbPingSite(request->host);
e0ebe27c 264 /*
265 * Assert that server_fd is set. This is to guarantee that fwdState
266 * is attached to something and will be deallocated when server_fd
267 * is closed.
268 */
269 assert(fwdState->server_fd > -1);
41462d93 270 if (fwdState->servers && (p = fwdState->servers->peer)) {
271 p->stats.fetches++;
6801f8a8 272 httpStart(fwdState, fwdState->server_fd);
41462d93 273 } else {
274 switch (request->protocol) {
275 case PROTO_HTTP:
6801f8a8 276 httpStart(fwdState, fwdState->server_fd);
41462d93 277 break;
278 case PROTO_GOPHER:
6801f8a8 279 gopherStart(entry, fwdState->server_fd);
41462d93 280 break;
281 case PROTO_FTP:
6801f8a8 282 ftpStart(request, entry, fwdState->server_fd);
41462d93 283 break;
284 case PROTO_WAIS:
6801f8a8 285 waisStart(request, entry, fwdState->server_fd);
41462d93 286 break;
287 case PROTO_CACHEOBJ:
e0ebe27c 288 case PROTO_INTERNAL:
289 fatal_dump("Should never get here");
41462d93 290 break;
291 case PROTO_URN:
292 urnStart(request, entry);
293 break;
294 case PROTO_WHOIS:
1640c2df 295 whoisStart(fwdState, fwdState->server_fd);
41462d93 296 break;
41462d93 297 default:
298 if (request->method == METHOD_CONNECT) {
299 ErrorState *err;
300 debug(17, 1) ("fwdDispatch: Cannot retrieve '%s'\n",
301 storeUrl(entry));
302 err = errorCon(ERR_UNSUP_REQ, HTTP_BAD_REQUEST);
303 err->request = requestLink(request);
304 errorAppendEntry(entry, err);
305 }
306 }
307 }
308}
309
310/* PUBLIC FUNCTIONS */
311
41462d93 312void
313fwdStart(int fd, StoreEntry * entry, request_t * request)
314{
315 FwdState *fwdState;
316 debug(17, 3) ("fwdStart: '%s'\n", storeUrl(entry));
317 entry->mem_obj->request = requestLink(request);
318 entry->mem_obj->fd = fd;
e0ebe27c 319 switch (request->protocol) {
320 /*
321 * Note, don't create fwdState for these requests
322 */
323 case PROTO_INTERNAL:
324 internalStart(request, entry);
325 return;
326 case PROTO_CACHEOBJ:
327 cachemgrStart(fd, request, entry);
328 return;
329 default:
330 break;
331 }
798b0889 332 fwdState = memAllocate(MEM_FWD_STATE);
333 cbdataAdd(fwdState, MEM_FWD_STATE);
41462d93 334 fwdState->entry = entry;
910169e5 335 fwdState->client_fd = fd;
6801f8a8 336 fwdState->server_fd = -1;
41462d93 337 fwdState->request = requestLink(request);
f563eea9 338 fwdState->start = squid_curtime;
4ca83e82 339 storeLockObject(entry);
6801f8a8 340 storeRegisterAbort(entry, fwdAbort, fwdState);
41462d93 341 peerSelect(request,
342 entry,
343 fwdStartComplete,
344 fwdStartFail,
345 fwdState);
346}
347
348/* This is called before reading data from the server side to
349 * decide if the server side should abort the fetch.
350 * XXX This probably breaks quick_abort!
351 * When to abort?
352 * - NOT if there are clients reading
353 * - YES if we don't know the content length
354 * - YES if we do know the content length and we don't have the
355 * whole object
356 */
357int
358fwdAbortFetch(StoreEntry * entry)
359{
360 MemObject *mem;
361 const HttpReply *reply;
362 if (storeClientWaiting(entry))
363 return 0;
364 mem = entry->mem_obj;
365 reply = mem->reply;
366 if (reply->content_length < 0)
367 return 1;
368 if (mem->inmem_hi < reply->content_length + reply->hdr_sz)
369 return 1;
370 return 0;
371}
372
373int
374fwdCheckDeferRead(int fdnotused, void *data)
375{
376 StoreEntry *e = data;
377 MemObject *mem = e->mem_obj;
378 if (mem == NULL)
379 return 0;
380 if (mem->inmem_hi - storeLowestMemReaderOffset(e) < READ_AHEAD_GAP)
381 return 0;
382 return 1;
383}
910169e5 384
385void
4ca83e82 386fwdFail(FwdState * fwdState, int err_code, http_status http_code, int xerrno)
910169e5 387{
4ca83e82 388 debug(17, 1) ("fwdFail: %s \"%s\"\n\t%s\n",
389 err_type_str[err_code],
390 httpStatusString(http_code),
391 storeUrl(fwdState->entry));
392 fwdState->fail.err_code = err_code;
393 fwdState->fail.http_code = http_code;
394 fwdState->fail.xerrno = xerrno;
910169e5 395}
6801f8a8 396
397/*
398 * Called when someone else calls StoreAbort() on this entry
399 */
400void
401fwdAbort(void *data)
402{
9dbf253d 403 FwdState *fwdState = data;
404 debug(17, 1) ("fwdAbort: %s\n", storeUrl(fwdState->entry));
405 fwdStateFree(fwdState);
6801f8a8 406}
0b49cd31 407
408/*
409 * Frees fwdState without closing FD or generating an abort
410 */
411void
9dbf253d 412fwdUnregister(int fd, FwdState * fwdState)
0b49cd31 413{
9dbf253d 414 debug(17, 3) ("fwdUnregister: %s\n", storeUrl(fwdState->entry));
415 assert(fd = fwdState->server_fd);
416 comm_remove_close_handler(fd, fwdServerClosed, fwdState);
417 fwdState->server_fd = -1;
418 fwdStateFree(fwdState);
0b49cd31 419}