3 * $Id: wais.cc,v 1.116 1998/08/14 09:22:43 wessels Exp $
5 * DEBUG: section 24 WAIS Relay
6 * AUTHOR: Harvest Derived
8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
9 * ----------------------------------------------------------
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 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.
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.
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.
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
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
44 const HttpHeader
*request_hdr
;
45 char request
[MAX_URL
];
48 static PF waisStateFree
;
49 static PF waisTimeout
;
50 static PF waisReadReply
;
51 static CWCB waisSendComplete
;
52 static PF waisSendRequest
;
55 waisStateFree(int fdnotused
, void *data
)
57 WaisStateData
*waisState
= data
;
58 if (waisState
== NULL
)
60 storeUnlockObject(waisState
->entry
);
61 cbdataFree(waisState
);
64 /* This will be called when socket lifetime is expired. */
66 waisTimeout(int fd
, void *data
)
68 WaisStateData
*waisState
= data
;
70 StoreEntry
*entry
= waisState
->entry
;
71 debug(24, 4) ("waisTimeout: FD %d: '%s'\n", fd
, storeUrl(entry
));
72 err
= errorCon(ERR_READ_TIMEOUT
, HTTP_GATEWAY_TIMEOUT
);
73 err
->request
= urlParse(METHOD_CONNECT
, waisState
->request
);
74 errorAppendEntry(entry
, err
);
78 /* This will be called when data is ready to be read from fd. Read until
79 * error or connection closed. */
81 waisReadReply(int fd
, void *data
)
83 WaisStateData
*waisState
= data
;
84 LOCAL_ARRAY(char, buf
, 4096);
85 StoreEntry
*entry
= waisState
->entry
;
91 delay_id delay_id
= delayMostBytesAllowed(entry
->mem_obj
);
93 if (fwdAbortFetch(entry
)) {
95 err
= errorCon(ERR_CLIENT_ABORT
, HTTP_INTERNAL_SERVER_ERROR
);
96 err
->request
= urlParse(METHOD_CONNECT
, waisState
->request
);
97 errorAppendEntry(entry
, err
);
104 read_sz
= delayBytesWanted(delay_id
, read_sz
);
107 len
= read(fd
, buf
, read_sz
);
109 fd_bytes(fd
, len
, FD_READ
);
111 delayBytesIn(delay_id
, len
);
113 kb_incr(&Counter
.server
.all
.kbytes_in
, len
);
114 kb_incr(&Counter
.server
.other
.kbytes_in
, len
);
116 debug(24, 5) ("waisReadReply: FD %d read len:%d\n", fd
, len
);
118 commSetTimeout(fd
, Config
.Timeout
.read
, NULL
, NULL
);
119 IOStats
.Wais
.reads
++;
120 for (clen
= len
- 1, bin
= 0; clen
; bin
++)
122 IOStats
.Wais
.read_hist
[bin
]++;
125 debug(50, 1) ("waisReadReply: FD %d: read failure: %s.\n",
127 if (ignoreErrno(errno
)) {
128 /* reinstall handlers */
129 /* XXX This may loop forever */
130 commSetSelect(fd
, COMM_SELECT_READ
,
131 waisReadReply
, waisState
, 0);
134 EBIT_CLR(entry
->flag
, ENTRY_CACHABLE
);
135 storeReleaseRequest(entry
);
136 err
= errorCon(ERR_READ_ERROR
, HTTP_INTERNAL_SERVER_ERROR
);
138 err
->request
= urlParse(METHOD_CONNECT
, waisState
->request
);
139 errorAppendEntry(entry
, err
);
142 } else if (len
== 0 && entry
->mem_obj
->inmem_hi
== 0) {
144 err
= errorCon(ERR_ZERO_SIZE_OBJECT
, HTTP_SERVICE_UNAVAILABLE
);
146 err
->request
= urlParse(METHOD_CONNECT
, waisState
->request
);
147 errorAppendEntry(entry
, err
);
149 } else if (len
== 0) {
150 /* Connection closed; retrieval done. */
151 entry
->expires
= squid_curtime
;
152 storeComplete(entry
);
155 storeAppend(entry
, buf
, len
);
163 /* This will be called when request write is complete. Schedule read of
166 waisSendComplete(int fd
, char *bufnotused
, size_t size
, int errflag
, void *data
)
168 WaisStateData
*waisState
= data
;
169 StoreEntry
*entry
= waisState
->entry
;
170 debug(24, 5) ("waisSendComplete: FD %d size: %d errflag: %d\n",
173 fd_bytes(fd
, size
, FD_WRITE
);
174 kb_incr(&Counter
.server
.all
.kbytes_out
, size
);
175 kb_incr(&Counter
.server
.other
.kbytes_out
, size
);
177 if (errflag
== COMM_ERR_CLOSING
)
181 err
= errorCon(ERR_CONNECT_FAIL
, HTTP_SERVICE_UNAVAILABLE
);
183 err
->host
= xstrdup(waisState
->relayhost
);
184 err
->port
= waisState
->relayport
;
185 err
->request
= urlParse(METHOD_CONNECT
, waisState
->request
);
186 errorAppendEntry(entry
, err
);
189 /* Schedule read reply. */
194 commSetDefer(fd
, fwdCheckDeferRead
, entry
);
198 /* This will be called when connect completes. Write request. */
200 waisSendRequest(int fd
, void *data
)
202 WaisStateData
*waisState
= data
;
204 const char *Method
= RequestMethodStr
[waisState
->method
];
205 debug(24, 5) ("waisSendRequest: FD %d\n", fd
);
206 memBufPrintf(&mb
, "%s %s", Method
, waisState
->request
);
207 if (waisState
->request_hdr
) {
209 packerToMemInit(&p
, &mb
);
210 httpHeaderPackInto(waisState
->request_hdr
, &p
);
213 memBufPrintf(&mb
, "\r\n");
214 debug(24, 6) ("waisSendRequest: buf: %s\n", mb
.buf
);
215 comm_write_mbuf(fd
, mb
, waisSendComplete
, waisState
);
216 if (EBIT_TEST(waisState
->entry
->flag
, ENTRY_CACHABLE
))
217 storeSetPublicKey(waisState
->entry
); /* Make it public */
221 waisStart(request_t
* request
, StoreEntry
* entry
, int fd
)
223 WaisStateData
*waisState
= NULL
;
224 const char *url
= storeUrl(entry
);
225 method_t method
= request
->method
;
226 debug(24, 3) ("waisStart: \"%s %s\"\n", RequestMethodStr
[method
], url
);
227 Counter
.server
.all
.requests
++;
228 Counter
.server
.other
.requests
++;
229 if (!Config
.Wais
.relayHost
) {
231 debug(24, 0) ("waisStart: Failed because no relay host defined!\n");
232 err
= errorCon(ERR_NO_RELAY
, HTTP_INTERNAL_SERVER_ERROR
);
233 err
->request
= urlParse(METHOD_CONNECT
, waisState
->request
);
234 errorAppendEntry(entry
, err
);
237 waisState
= xcalloc(1, sizeof(WaisStateData
));
238 cbdataAdd(waisState
, MEM_NONE
);
239 waisState
->method
= method
;
240 waisState
->relayhost
= Config
.Wais
.relayHost
;
241 waisState
->relayport
= Config
.Wais
.relayPort
;
242 waisState
->request_hdr
= &request
->header
;
244 waisState
->entry
= entry
;
245 xstrncpy(waisState
->request
, url
, MAX_URL
);
246 comm_add_close_handler(waisState
->fd
, waisStateFree
, waisState
);
247 storeLockObject(entry
);
248 commSetSelect(fd
, COMM_SELECT_WRITE
, waisSendRequest
, waisState
, 0);
249 commSetTimeout(fd
, Config
.Timeout
.read
, waisTimeout
, waisState
);