]>
Commit | Line | Data |
---|---|---|
85491f8d | 1 | |
2 | /* | |
ebe14c5d | 3 | * |
40548fef | 4 | * $Id: urn.cc,v 1.27 1998/04/09 17:54:23 wessels Exp $ |
ebe14c5d | 5 | * |
6f6f0853 | 6 | * DEBUG: section 52 URN Parsing |
85491f8d | 7 | * AUTHOR: Kostas Anagnostakis |
8 | * | |
9 | * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ | |
10 | * -------------------------------------------------------- | |
11 | * | |
12 | * Squid is the result of efforts by numerous individuals from the | |
13 | * Internet community. Development is led by Duane Wessels of the | |
14 | * National Laboratory for Applied Network Research and funded by | |
15 | * the National Science Foundation. | |
16 | * | |
17 | * This program is free software; you can redistribute it and/or modify | |
18 | * it under the terms of the GNU General Public License as published by | |
19 | * the Free Software Foundation; either version 2 of the License, or | |
20 | * (at your option) any later version. | |
21 | * | |
22 | * This program is distributed in the hope that it will be useful, | |
23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
25 | * GNU General Public License for more details. | |
26 | * | |
27 | * You should have received a copy of the GNU General Public License | |
28 | * along with this program; if not, write to the Free Software | |
29 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
30 | * | |
31 | */ | |
32 | ||
33 | #include "squid.h" | |
34 | ||
23d92c64 | 35 | static STCB urnHandleReply; |
d017efc3 | 36 | static wordlist *urnParseReply(const char *inbuf); |
23d92c64 | 37 | static const char *const crlf = "\r\n"; |
cf26e54c | 38 | |
fa040df2 | 39 | enum { |
164f7660 | 40 | URN_FORCE_MENU |
fa040df2 | 41 | }; |
42 | ||
cf26e54c | 43 | typedef struct { |
164f7660 | 44 | StoreEntry *entry; |
45 | StoreEntry *urlres_e; | |
46 | request_t *request; | |
40548fef | 47 | request_t *urlres_r; |
164f7660 | 48 | int flags; |
cf26e54c | 49 | } UrnState; |
85491f8d | 50 | |
23d92c64 | 51 | wordlist * |
52 | urnFindMinRtt(wordlist * urls, method_t m, int *rtt_ret) | |
85491f8d | 53 | { |
23d92c64 | 54 | int min_rtt = 0; |
55 | request_t *r; | |
56 | int rtt; | |
57 | wordlist *w; | |
58 | wordlist *min_w = NULL; | |
6f6f0853 | 59 | debug(52, 3) ("urnFindMinRtt\n"); |
23d92c64 | 60 | assert(urls != NULL); |
61 | for (w = urls; w; w = w->next) { | |
62 | r = urlParse(m, w->key); | |
63 | if (r == NULL) | |
64 | continue; | |
6f6f0853 | 65 | debug(52, 3) ("Parsed %s\n", w->key); |
23d92c64 | 66 | rtt = netdbHostRtt(r->host); |
67 | if (rtt == 0) { | |
6f6f0853 | 68 | debug(52, 3) ("Pinging %s\n", r->host); |
23d92c64 | 69 | netdbPingSite(r->host); |
02922e76 | 70 | stringClean(&r->urlpath); |
3f6c0fb2 | 71 | memFree(MEM_REQUEST_T, r); |
23d92c64 | 72 | continue; |
85491f8d | 73 | } |
6f6f0853 | 74 | debug(52, 3) ("%s rtt=%d\n", r->host, rtt); |
23d92c64 | 75 | if (rtt == 0) |
164f7660 | 76 | continue; |
23d92c64 | 77 | if (rtt > min_rtt && min_rtt != 0) |
164f7660 | 78 | continue; |
23d92c64 | 79 | min_rtt = rtt; |
80 | min_w = w; | |
02922e76 | 81 | stringClean(&r->urlpath); |
3f6c0fb2 | 82 | memFree(MEM_REQUEST_T, r); |
23d92c64 | 83 | } |
84 | if (rtt_ret) | |
85 | *rtt_ret = min_rtt; | |
6f6f0853 | 86 | debug(52, 1) ("urnFindMinRtt: Returning '%s' RTT %d\n", |
23d92c64 | 87 | min_w ? min_w->key : "NONE", |
88 | min_rtt); | |
89 | return min_w; | |
85491f8d | 90 | } |
91 | ||
92 | void | |
164f7660 | 93 | urnStart(request_t * r, StoreEntry * e) |
85491f8d | 94 | { |
23d92c64 | 95 | LOCAL_ARRAY(char, urlres, 4096); |
23d92c64 | 96 | request_t *urlres_r = NULL; |
97 | const cache_key *k; | |
02922e76 | 98 | const char *t; |
c6528ea4 | 99 | char *host; |
cf26e54c | 100 | UrnState *urnState; |
101 | StoreEntry *urlres_e; | |
0adbab7c | 102 | ErrorState *err; |
6f6f0853 | 103 | debug(52, 3) ("urnStart: '%s'\n", storeUrl(e)); |
cf26e54c | 104 | urnState = xcalloc(1, sizeof(UrnState)); |
105 | urnState->entry = e; | |
106 | urnState->request = requestLink(r); | |
3f6c0fb2 | 107 | cbdataAdd(urnState, MEM_NONE); |
8d709a1b | 108 | storeLockObject(urnState->entry); |
02922e76 | 109 | if (strncasecmp(strBuf(r->urlpath), "menu.", 5) == 0) { |
110 | char *new_path = xstrdup(strBuf(r->urlpath) + 5); | |
de28f103 | 111 | EBIT_SET(urnState->flags, URN_FORCE_MENU); |
02922e76 | 112 | #if OLD_CODE |
113 | t = xstrdup(strBuf(r->urlpath) + 5); | |
de28f103 | 114 | xstrncpy(r->urlpath, t, MAX_URL); |
115 | xfree(t); | |
02922e76 | 116 | #else |
117 | stringReset(&r->urlpath, new_path); | |
118 | xfree(new_path); | |
119 | #endif | |
de28f103 | 120 | } |
02922e76 | 121 | if ((t = strChr(r->urlpath, ':')) != NULL) { |
122 | strSet(r->urlpath, t, '\0'); | |
123 | host = xstrdup(strBuf(r->urlpath)); | |
124 | strSet(r->urlpath, t, ':'); | |
fa040df2 | 125 | } else { |
02922e76 | 126 | host = xstrdup(strBuf(r->urlpath)); |
fa040df2 | 127 | } |
02922e76 | 128 | snprintf(urlres, 4096, "http://%s/uri-res/N2L?urn:%s", host, strBuf(r->urlpath)); |
c6528ea4 | 129 | safe_free(host); |
23d92c64 | 130 | k = storeKeyPublic(urlres, METHOD_GET); |
131 | urlres_r = urlParse(METHOD_GET, urlres); | |
0adbab7c | 132 | if (urlres_r == NULL) { |
133 | debug(52, 3) ("urnStart: Bad uri-res URL %s\n", urlres); | |
134 | err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND); | |
135 | err->url = xstrdup(urlres); | |
136 | errorAppendEntry(e, err); | |
137 | return; | |
138 | } | |
8d709a1b | 139 | urlres_r->headers = xstrdup("Accept: text/plain\r\n\r\n"); |
23d92c64 | 140 | urlres_r->headers_sz = strlen(urlres_r->headers); |
cf26e54c | 141 | if ((urlres_e = storeGet(k)) == NULL) { |
142 | urlres_e = storeCreateEntry(urlres, urlres, 0, METHOD_GET); | |
143 | storeClientListAdd(urlres_e, urnState); | |
144 | protoDispatch(0, urlres_e, urlres_r); | |
145 | } else { | |
164f7660 | 146 | storeLockObject(urlres_e); |
147 | storeClientListAdd(urlres_e, urnState); | |
85491f8d | 148 | } |
cf26e54c | 149 | urnState->urlres_e = urlres_e; |
40548fef | 150 | urnState->urlres_r = requestLink(urlres_r); |
cf26e54c | 151 | storeClientCopy(urlres_e, |
152 | 0, | |
153 | 0, | |
154 | 4096, | |
7021844c | 155 | memAllocate(MEM_4K_BUF), |
cf26e54c | 156 | urnHandleReply, |
157 | urnState); | |
85491f8d | 158 | } |
159 | ||
160 | static void | |
23d92c64 | 161 | urnHandleReply(void *data, char *buf, ssize_t size) |
85491f8d | 162 | { |
cf26e54c | 163 | UrnState *urnState = data; |
164 | StoreEntry *e = urnState->entry; | |
165 | StoreEntry *urlres_e = urnState->urlres_e; | |
23d92c64 | 166 | char *s = NULL; |
2334c194 | 167 | size_t k; |
cb69b4c7 | 168 | HttpReply *rep; |
cf26e54c | 169 | wordlist *w; |
170 | wordlist *urls; | |
171 | wordlist *min_w; | |
02922e76 | 172 | MemBuf mb; |
cf26e54c | 173 | ErrorState *err; |
164f7660 | 174 | double tmprtt; |
175 | StoreEntry *tmpentry; | |
cf26e54c | 176 | |
6f6f0853 | 177 | debug(52, 3) ("urnHandleReply: Called with size=%d.\n", size); |
cf26e54c | 178 | if (urlres_e->store_status == STORE_ABORTED) { |
3f6c0fb2 | 179 | memFree(MEM_4K_BUF, buf); |
23d92c64 | 180 | return; |
85491f8d | 181 | } |
23d92c64 | 182 | if (size == 0) { |
3f6c0fb2 | 183 | memFree(MEM_4K_BUF, buf); |
23d92c64 | 184 | return; |
185 | } else if (size < 0) { | |
3f6c0fb2 | 186 | memFree(MEM_4K_BUF, buf); |
23d92c64 | 187 | return; |
85491f8d | 188 | } |
4b534024 | 189 | if (urlres_e->store_status == STORE_PENDING && size < SM_PAGE_SIZE) { |
cf26e54c | 190 | storeClientCopy(urlres_e, |
191 | size, | |
23d92c64 | 192 | 0, |
193 | SM_PAGE_SIZE, | |
194 | buf, | |
195 | urnHandleReply, | |
cf26e54c | 196 | urnState); |
85491f8d | 197 | return; |
23d92c64 | 198 | } |
199 | /* we know its STORE_OK */ | |
2334c194 | 200 | k = headersEnd(buf, size); |
201 | if (0 == k) { | |
6f6f0853 | 202 | debug(52, 1) ("urnHandleReply: didn't find end-of-headers for %s\n", |
cf26e54c | 203 | storeUrl(e)); |
85491f8d | 204 | return; |
85491f8d | 205 | } |
2334c194 | 206 | s = buf + k; |
cf26e54c | 207 | assert(urlres_e->mem_obj->reply); |
cb69b4c7 | 208 | httpReplyParse(urlres_e->mem_obj->reply, buf); |
6f6f0853 | 209 | debug(52, 3) ("mem->reply exists, code=%d.\n", |
cb69b4c7 | 210 | urlres_e->mem_obj->reply->sline.status); |
211 | if (urlres_e->mem_obj->reply->sline.status != HTTP_OK) { | |
6f6f0853 | 212 | debug(52, 3) ("urnHandleReply: failed.\n"); |
cf26e54c | 213 | err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND); |
214 | err->request = requestLink(urnState->request); | |
215 | err->url = xstrdup(storeUrl(e)); | |
216 | errorAppendEntry(e, err); | |
23d92c64 | 217 | return; |
85491f8d | 218 | } |
23d92c64 | 219 | while (isspace(*s)) |
220 | s++; | |
d017efc3 | 221 | urls = urnParseReply(s); |
164f7660 | 222 | if (urls == NULL) { /* unkown URN error */ |
6f6f0853 | 223 | debug(52, 3) ("urnTranslateDone: unknown URN %s\n", storeUrl(e)); |
cf26e54c | 224 | err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND); |
225 | err->request = requestLink(urnState->request); | |
226 | err->url = xstrdup(storeUrl(e)); | |
227 | errorAppendEntry(e, err); | |
228 | return; | |
164f7660 | 229 | } |
230 | min_w = urnFindMinRtt(urls, urnState->request->method, NULL); | |
cf26e54c | 231 | storeBuffer(e); |
02922e76 | 232 | memBufDefInit(&mb); |
233 | memBufPrintf(&mb, | |
cf26e54c | 234 | "<TITLE>Select URL for %s</TITLE>\n" |
235 | "<H2>Select URL for %s</H2>\n" | |
2e141322 | 236 | "<TABLE BORDER=0 WIDTH=\"100%%\">\n", storeUrl(e), storeUrl(e)); |
cf26e54c | 237 | for (w = urls; w; w = w->next) { |
164f7660 | 238 | request_t *tmpr = urlParse(urnState->request->method, w->key); |
239 | const cache_key *tmpk = storeKeyPublic(w->key, urnState->request->method); | |
240 | tmpentry = storeGet(tmpk); | |
241 | if (tmpr && tmpr->host && (tmprtt = netdbHostRtt(tmpr->host))) | |
02922e76 | 242 | memBufPrintf(&mb, "<TR><TD><A HREF=\"%s\">%s</A></TD><TD align=right>%4.0f </it>ms</it></TD><TD>%s</TD></TR>\n", |
164f7660 | 243 | w->key, w->key, tmprtt, tmpentry ? " [cached]" : " "); |
244 | else | |
02922e76 | 245 | memBufPrintf(&mb, "<TR><TD><A HREF=\"%s\">%s</A></TD></TR>", w->key, w->key); |
cf26e54c | 246 | } |
02922e76 | 247 | memBufPrintf(&mb, |
2e141322 | 248 | "</TABLE>" |
cf26e54c | 249 | "<HR>\n" |
250 | "<ADDRESS>\n" | |
02922e76 | 251 | "Generated by %s@%s\n" |
cf26e54c | 252 | "</ADDRESS>\n", |
02922e76 | 253 | full_appname_string, getMyHostname()); |
cb69b4c7 | 254 | rep = e->mem_obj->reply; |
255 | httpReplyReset(rep); | |
256 | httpReplySetHeaders(rep, 1.0, HTTP_MOVED_TEMPORARILY, NULL, | |
02922e76 | 257 | "text/html", mb.size, 0, squid_curtime); |
cb69b4c7 | 258 | if (EBIT_TEST(urnState->flags, URN_FORCE_MENU)) { |
259 | debug(51, 3) ("urnHandleReply: forcing menu\n"); | |
2ac76861 | 260 | } else if (min_w) { |
d8b249ef | 261 | httpHeaderPutStr(&rep->header, HDR_LOCATION, min_w->key); |
cb69b4c7 | 262 | } |
1afe05c5 | 263 | httpBodySet(&rep->body, mb.buf, mb.size + 1, memBufFreeFunc(&mb)); |
cb69b4c7 | 264 | httpReplySwapOut(rep, e); |
cf26e54c | 265 | storeComplete(e); |
3f6c0fb2 | 266 | memFree(MEM_4K_BUF, buf); |
d017efc3 | 267 | wordlistDestroy(&urls); |
02922e76 | 268 | /* mb was frozen with memBufFreeFunc call, so we must not clean it */ |
8d709a1b | 269 | storeUnregister(urlres_e, urnState); |
cf26e54c | 270 | storeUnlockObject(urlres_e); |
8d709a1b | 271 | storeUnlockObject(urnState->entry); |
272 | requestUnlink(urnState->request); | |
40548fef | 273 | requestUnlink(urnState->urlres_r); |
8d709a1b | 274 | cbdataFree(urnState); |
85491f8d | 275 | } |
276 | ||
23d92c64 | 277 | static wordlist * |
d017efc3 | 278 | urnParseReply(const char *inbuf) |
85491f8d | 279 | { |
23d92c64 | 280 | char *buf = xstrdup(inbuf); |
281 | char *token; | |
282 | wordlist *u; | |
283 | wordlist *head = NULL; | |
284 | wordlist **last = &head; | |
6f6f0853 | 285 | debug(52, 3) ("urnParseReply\n"); |
23d92c64 | 286 | for (token = strtok(buf, crlf); token; token = strtok(NULL, crlf)) { |
6f6f0853 | 287 | debug(52, 3) ("urnParseReply: got '%s'\n", token); |
23d92c64 | 288 | u = xmalloc(sizeof(wordlist)); |
289 | u->key = xstrdup(token); | |
290 | u->next = NULL; | |
291 | *last = u; | |
292 | last = &u->next; | |
85491f8d | 293 | } |
d017efc3 | 294 | safe_free(buf); |
23d92c64 | 295 | return head; |
85491f8d | 296 | } |