]>
Commit | Line | Data |
---|---|---|
f900607e | 1 | |
30a4f2a8 | 2 | /* |
190154cf | 3 | * $Id: wais.cc,v 1.150 2003/08/10 11:00:45 robertc Exp $ |
30a4f2a8 | 4 | * |
5 | * DEBUG: section 24 WAIS Relay | |
6 | * AUTHOR: Harvest Derived | |
7 | * | |
2b6662ba | 8 | * SQUID Web Proxy Cache http://www.squid-cache.org/ |
e25c139f | 9 | * ---------------------------------------------------------- |
30a4f2a8 | 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. | |
30a4f2a8 | 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 | * |
7528fc90 | 34 | */ |
44a47c6e | 35 | |
36 | #include "squid.h" | |
e6ccf245 | 37 | #include "Store.h" |
528b2c61 | 38 | #include "HttpRequest.h" |
b67e2c8c | 39 | #if DELAY_POOLS |
40 | #include "DelayPools.h" | |
86a2f789 | 41 | #include "MemObject.h" |
b67e2c8c | 42 | #endif |
a46d2c0e | 43 | #include "comm.h" |
ed43818f | 44 | |
62e76326 | 45 | class WaisStateData |
46 | { | |
47 | ||
528b2c61 | 48 | public: |
30a4f2a8 | 49 | int fd; |
090089c4 | 50 | StoreEntry *entry; |
7111c86a | 51 | method_t method; |
2246b732 | 52 | const HttpHeader *request_hdr; |
cadc5bae | 53 | char url[MAX_URL]; |
190154cf | 54 | HttpRequest *request; |
db1cd23c | 55 | FwdState *fwd; |
528b2c61 | 56 | char buf[BUFSIZ]; |
57 | bool dataWritten; | |
58 | }; | |
30a4f2a8 | 59 | |
582b6456 | 60 | static PF waisStateFree; |
5c5783a2 | 61 | static PF waisTimeout; |
c4b7a5a9 | 62 | static IOCB waisReadReply; |
f17936ab | 63 | static CWCB waisSendComplete; |
582b6456 | 64 | static PF waisSendRequest; |
090089c4 | 65 | |
582b6456 | 66 | static void |
79d39a72 | 67 | waisStateFree(int fdnotused, void *data) |
ba718c8f | 68 | { |
e6ccf245 | 69 | WaisStateData *waisState = (WaisStateData *)data; |
62e76326 | 70 | |
51fa90db | 71 | if (waisState == NULL) |
62e76326 | 72 | return; |
73 | ||
f88211e8 | 74 | storeUnlockObject(waisState->entry); |
62e76326 | 75 | |
cadc5bae | 76 | requestUnlink(waisState->request); |
62e76326 | 77 | |
7dd44885 | 78 | cbdataFree(waisState); |
ba718c8f | 79 | } |
80 | ||
090089c4 | 81 | /* This will be called when socket lifetime is expired. */ |
b8d8561b | 82 | static void |
5c5783a2 | 83 | waisTimeout(int fd, void *data) |
090089c4 | 84 | { |
e6ccf245 | 85 | WaisStateData *waisState = (WaisStateData *)data; |
582b6456 | 86 | StoreEntry *entry = waisState->entry; |
9fb13bb6 | 87 | debug(24, 4) ("waisTimeout: FD %d: '%s'\n", fd, storeUrl(entry)); |
62e76326 | 88 | |
e3dd531e | 89 | if (entry->store_status == STORE_PENDING) { |
62e76326 | 90 | if (!waisState->dataWritten) { |
91 | fwdFail(waisState->fwd, | |
92 | errorCon(ERR_READ_TIMEOUT, HTTP_GATEWAY_TIMEOUT)); | |
93 | } | |
e3dd531e | 94 | } |
62e76326 | 95 | |
51fa90db | 96 | comm_close(fd); |
090089c4 | 97 | } |
98 | ||
090089c4 | 99 | /* This will be called when data is ready to be read from fd. Read until |
100 | * error or connection closed. */ | |
b8d8561b | 101 | static void |
c4b7a5a9 | 102 | waisReadReply(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data) |
090089c4 | 103 | { |
e6ccf245 | 104 | WaisStateData *waisState = (WaisStateData *)data; |
582b6456 | 105 | StoreEntry *entry = waisState->entry; |
56fa4cad | 106 | int clen; |
56fa4cad | 107 | int bin; |
447e176b | 108 | size_t read_sz; |
109 | #if DELAY_POOLS | |
62e76326 | 110 | |
b67e2c8c | 111 | DelayId delayId = entry->mem_obj->mostBytesAllowed(); |
447e176b | 112 | #endif |
c4b7a5a9 | 113 | |
114 | /* Bail out early on COMM_ERR_CLOSING - close handlers will tidy up for us */ | |
62e76326 | 115 | |
c4b7a5a9 | 116 | if (flag == COMM_ERR_CLOSING) { |
117 | return; | |
118 | } | |
119 | ||
e92e4e44 | 120 | if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { |
62e76326 | 121 | comm_close(fd); |
122 | return; | |
e92e4e44 | 123 | } |
62e76326 | 124 | |
447e176b | 125 | errno = 0; |
c4b7a5a9 | 126 | read_sz = BUFSIZ; |
62e76326 | 127 | |
c4b7a5a9 | 128 | if (flag == COMM_OK && len > 0) { |
447e176b | 129 | #if DELAY_POOLS |
62e76326 | 130 | delayId.bytesIn(len); |
447e176b | 131 | #endif |
62e76326 | 132 | |
133 | kb_incr(&statCounter.server.all.kbytes_in, len); | |
134 | kb_incr(&statCounter.server.other.kbytes_in, len); | |
ee1679df | 135 | } |
62e76326 | 136 | |
c4b7a5a9 | 137 | #if DELAY_POOLS |
b67e2c8c | 138 | read_sz = delayId.bytesWanted(1, read_sz); |
62e76326 | 139 | |
c4b7a5a9 | 140 | #endif |
62e76326 | 141 | |
c4b7a5a9 | 142 | debug(24, 5) ("waisReadReply: FD %d read len:%d\n", fd, (int)len); |
62e76326 | 143 | |
c4b7a5a9 | 144 | if (flag == COMM_OK && len > 0) { |
62e76326 | 145 | commSetTimeout(fd, Config.Timeout.read, NULL, NULL); |
146 | IOStats.Wais.reads++; | |
147 | ||
148 | for (clen = len - 1, bin = 0; clen; bin++) | |
149 | clen >>= 1; | |
150 | ||
151 | IOStats.Wais.read_hist[bin]++; | |
56fa4cad | 152 | } |
62e76326 | 153 | |
c4b7a5a9 | 154 | if (flag != COMM_OK || len < 0) { |
62e76326 | 155 | debug(50, 1) ("waisReadReply: FD %d: read failure: %s.\n", |
156 | fd, xstrerror()); | |
157 | ||
158 | if (ignoreErrno(xerrno)) { | |
159 | /* reinstall handlers */ | |
160 | /* XXX This may loop forever */ | |
c4b7a5a9 | 161 | comm_read(fd, waisState->buf, read_sz, waisReadReply, waisState); |
62e76326 | 162 | } else { |
163 | ErrorState *err; | |
164 | EBIT_CLR(entry->flags, ENTRY_CACHABLE); | |
165 | storeReleaseRequest(entry); | |
166 | err = errorCon(ERR_READ_ERROR, HTTP_INTERNAL_SERVER_ERROR); | |
167 | err->xerrno = errno; | |
168 | err->request = requestLink(waisState->request); | |
169 | errorAppendEntry(entry, err); | |
170 | comm_close(fd); | |
171 | } | |
528b2c61 | 172 | } else if (flag == COMM_OK && len == 0 && !waisState->dataWritten) { |
62e76326 | 173 | ErrorState *err; |
174 | err = errorCon(ERR_ZERO_SIZE_OBJECT, HTTP_SERVICE_UNAVAILABLE); | |
175 | err->xerrno = errno; | |
176 | err->request = requestLink(waisState->request); | |
177 | errorAppendEntry(entry, err); | |
178 | comm_close(fd); | |
c4b7a5a9 | 179 | } else if (flag == COMM_OK && len == 0) { |
62e76326 | 180 | /* Connection closed; retrieval done. */ |
181 | entry->expires = squid_curtime; | |
182 | fwdComplete(waisState->fwd); | |
183 | comm_close(fd); | |
090089c4 | 184 | } else { |
62e76326 | 185 | waisState->dataWritten = 1; |
186 | storeAppend(entry, buf, len); | |
c4b7a5a9 | 187 | comm_read(fd, waisState->buf, read_sz, waisReadReply, waisState); |
090089c4 | 188 | } |
189 | } | |
190 | ||
191 | /* This will be called when request write is complete. Schedule read of | |
192 | * reply. */ | |
b8d8561b | 193 | static void |
3d7e9d7c | 194 | waisSendComplete(int fd, char *bufnotused, size_t size, comm_err_t errflag, void *data) |
090089c4 | 195 | { |
e6ccf245 | 196 | WaisStateData *waisState = (WaisStateData *)data; |
582b6456 | 197 | StoreEntry *entry = waisState->entry; |
a3d5953d | 198 | debug(24, 5) ("waisSendComplete: FD %d size: %d errflag: %d\n", |
62e76326 | 199 | fd, (int) size, errflag); |
200 | ||
ee1679df | 201 | if (size > 0) { |
62e76326 | 202 | fd_bytes(fd, size, FD_WRITE); |
203 | kb_incr(&statCounter.server.all.kbytes_out, size); | |
204 | kb_incr(&statCounter.server.other.kbytes_out, size); | |
ee1679df | 205 | } |
62e76326 | 206 | |
ea3a2a69 | 207 | if (errflag == COMM_ERR_CLOSING) |
62e76326 | 208 | return; |
209 | ||
090089c4 | 210 | if (errflag) { |
62e76326 | 211 | ErrorState *err; |
212 | err = errorCon(ERR_WRITE_ERROR, HTTP_SERVICE_UNAVAILABLE); | |
213 | err->xerrno = errno; | |
214 | err->request = requestLink(waisState->request); | |
215 | errorAppendEntry(entry, err); | |
216 | comm_close(fd); | |
090089c4 | 217 | } else { |
62e76326 | 218 | /* Schedule read reply. */ |
a46d2c0e | 219 | entry->delayAwareRead(fd, waisState->buf, BUFSIZ, waisReadReply, waisState); |
090089c4 | 220 | } |
090089c4 | 221 | } |
222 | ||
223 | /* This will be called when connect completes. Write request. */ | |
b8d8561b | 224 | static void |
582b6456 | 225 | waisSendRequest(int fd, void *data) |
090089c4 | 226 | { |
e6ccf245 | 227 | WaisStateData *waisState = (WaisStateData *)data; |
2246b732 | 228 | MemBuf mb; |
0ee4272b | 229 | const char *Method = RequestMethodStr[waisState->method]; |
a3d5953d | 230 | debug(24, 5) ("waisSendRequest: FD %d\n", fd); |
4d62b0af | 231 | memBufDefInit(&mb); |
232 | memBufPrintf(&mb, "%s %s HTTP/1.0\r\n", Method, waisState->url); | |
62e76326 | 233 | |
2246b732 | 234 | if (waisState->request_hdr) { |
62e76326 | 235 | Packer p; |
236 | packerToMemInit(&p, &mb); | |
237 | httpHeaderPackInto(waisState->request_hdr, &p); | |
238 | packerClean(&p); | |
2246b732 | 239 | } |
62e76326 | 240 | |
2246b732 | 241 | memBufPrintf(&mb, "\r\n"); |
242 | debug(24, 6) ("waisSendRequest: buf: %s\n", mb.buf); | |
d4cb310b | 243 | comm_old_write_mbuf(fd, mb, waisSendComplete, waisState); |
62e76326 | 244 | |
d46a87a8 | 245 | if (EBIT_TEST(waisState->entry->flags, ENTRY_CACHABLE)) |
62e76326 | 246 | storeSetPublicKey(waisState->entry); /* Make it public */ |
247 | ||
ec250dfd | 248 | EBIT_CLR(waisState->entry->flags, ENTRY_FWD_HDR_WAIT); |
30a4f2a8 | 249 | } |
250 | ||
28c60158 | 251 | CBDATA_TYPE(WaisStateData); |
770f051d | 252 | void |
db1cd23c | 253 | waisStart(FwdState * fwd) |
090089c4 | 254 | { |
30a4f2a8 | 255 | WaisStateData *waisState = NULL; |
190154cf | 256 | HttpRequest *request = fwd->request; |
db1cd23c | 257 | StoreEntry *entry = fwd->entry; |
258 | int fd = fwd->server_fd; | |
9fb13bb6 | 259 | const char *url = storeUrl(entry); |
f182d1c5 | 260 | method_t method = request->method; |
a3d5953d | 261 | debug(24, 3) ("waisStart: \"%s %s\"\n", RequestMethodStr[method], url); |
83704487 | 262 | statCounter.server.all.requests++; |
263 | statCounter.server.other.requests++; | |
28c60158 | 264 | CBDATA_INIT_TYPE(WaisStateData); |
72711e31 | 265 | waisState = cbdataAlloc(WaisStateData); |
30a4f2a8 | 266 | waisState->method = method; |
2246b732 | 267 | waisState->request_hdr = &request->header; |
30a4f2a8 | 268 | waisState->fd = fd; |
0a0bf5db | 269 | waisState->entry = entry; |
528b2c61 | 270 | waisState->dataWritten = 0; |
cadc5bae | 271 | xstrncpy(waisState->url, url, MAX_URL); |
272 | waisState->request = requestLink(request); | |
db1cd23c | 273 | waisState->fwd = fwd; |
bfcaf585 | 274 | comm_add_close_handler(waisState->fd, waisStateFree, waisState); |
770f051d | 275 | storeLockObject(entry); |
41462d93 | 276 | commSetTimeout(fd, Config.Timeout.read, waisTimeout, waisState); |
c4b7a5a9 | 277 | waisSendRequest(fd, waisState); |
090089c4 | 278 | } |