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