]> git.ipfire.org Git - thirdparty/squid.git/blame - src/urn.cc
- removed store_status == STORE_PENDING assertion which got triggered
[thirdparty/squid.git] / src / urn.cc
CommitLineData
85491f8d 1
2/*
ebe14c5d 3 *
41462d93 4 * $Id: urn.cc,v 1.35 1998/06/04 18:57:19 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
fa040df2 35enum {
164f7660 36 URN_FORCE_MENU
fa040df2 37};
38
cf26e54c 39typedef struct {
164f7660 40 StoreEntry *entry;
41 StoreEntry *urlres_e;
42 request_t *request;
40548fef 43 request_t *urlres_r;
164f7660 44 int flags;
cf26e54c 45} UrnState;
85491f8d 46
9ce5e3e6 47typedef struct {
48 char *url;
49 char *host;
50 int rtt;
51 struct {
52 int cached;
53 } flags;
54} url_entry;
55
56static STCB urnHandleReply;
57static url_entry *urnParseReply(const char *inbuf, method_t);
58static const char *const crlf = "\r\n";
59static QS url_entry_sort;
60
61url_entry *
62urnFindMinRtt(url_entry * urls, method_t m, int *rtt_ret)
85491f8d 63{
23d92c64 64 int min_rtt = 0;
9ce5e3e6 65 url_entry *u = NULL;
66 url_entry *min_u = NULL;
67 int i;
1caf595b 68 int urlcnt = 0;
6f6f0853 69 debug(52, 3) ("urnFindMinRtt\n");
23d92c64 70 assert(urls != NULL);
00141c96 71 for (i = 0; NULL != urls[i].url; i++)
1caf595b 72 urlcnt++;
00141c96 73 debug(0, 0) ("urnFindMinRtt: Counted %d URLs\n", i);
9ce5e3e6 74 if (1 == urlcnt) {
75 debug(52, 3) ("urnFindMinRtt: Only one URL - return it!\n");
76 return urls;
1caf595b 77 }
00141c96 78 for (i = 0; i < urlcnt; i++) {
79 u = &urls[i];
9ce5e3e6 80 debug(52, 3) ("urnFindMinRtt: %s rtt=%d\n", u->host, u->rtt);
81 if (u->rtt == 0)
23d92c64 82 continue;
9ce5e3e6 83 if (u->rtt > min_rtt && min_rtt != 0)
164f7660 84 continue;
9ce5e3e6 85 min_rtt = u->rtt;
86 min_u = u;
23d92c64 87 }
88 if (rtt_ret)
89 *rtt_ret = min_rtt;
6f6f0853 90 debug(52, 1) ("urnFindMinRtt: Returning '%s' RTT %d\n",
9ce5e3e6 91 min_u ? min_u->url : "NONE",
23d92c64 92 min_rtt);
9ce5e3e6 93 return min_u;
85491f8d 94}
95
96void
164f7660 97urnStart(request_t * r, StoreEntry * e)
85491f8d 98{
23d92c64 99 LOCAL_ARRAY(char, urlres, 4096);
23d92c64 100 request_t *urlres_r = NULL;
101 const cache_key *k;
02922e76 102 const char *t;
c6528ea4 103 char *host;
cf26e54c 104 UrnState *urnState;
105 StoreEntry *urlres_e;
0adbab7c 106 ErrorState *err;
6f6f0853 107 debug(52, 3) ("urnStart: '%s'\n", storeUrl(e));
cf26e54c 108 urnState = xcalloc(1, sizeof(UrnState));
109 urnState->entry = e;
110 urnState->request = requestLink(r);
3f6c0fb2 111 cbdataAdd(urnState, MEM_NONE);
8d709a1b 112 storeLockObject(urnState->entry);
02922e76 113 if (strncasecmp(strBuf(r->urlpath), "menu.", 5) == 0) {
114 char *new_path = xstrdup(strBuf(r->urlpath) + 5);
de28f103 115 EBIT_SET(urnState->flags, URN_FORCE_MENU);
02922e76 116 stringReset(&r->urlpath, new_path);
117 xfree(new_path);
de28f103 118 }
02922e76 119 if ((t = strChr(r->urlpath, ':')) != NULL) {
120 strSet(r->urlpath, t, '\0');
121 host = xstrdup(strBuf(r->urlpath));
122 strSet(r->urlpath, t, ':');
fa040df2 123 } else {
02922e76 124 host = xstrdup(strBuf(r->urlpath));
fa040df2 125 }
02922e76 126 snprintf(urlres, 4096, "http://%s/uri-res/N2L?urn:%s", host, strBuf(r->urlpath));
c6528ea4 127 safe_free(host);
23d92c64 128 k = storeKeyPublic(urlres, METHOD_GET);
129 urlres_r = urlParse(METHOD_GET, urlres);
0adbab7c 130 if (urlres_r == NULL) {
131 debug(52, 3) ("urnStart: Bad uri-res URL %s\n", urlres);
132 err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND);
133 err->url = xstrdup(urlres);
134 errorAppendEntry(e, err);
135 return;
136 }
99edd1c3 137#if OLD_CODE
8d709a1b 138 urlres_r->headers = xstrdup("Accept: text/plain\r\n\r\n");
23d92c64 139 urlres_r->headers_sz = strlen(urlres_r->headers);
99edd1c3 140#else
2246b732 141 httpHeaderPutStr(&urlres_r->header, HDR_ACCEPT, "text/plain");
99edd1c3 142#endif
cf26e54c 143 if ((urlres_e = storeGet(k)) == NULL) {
144 urlres_e = storeCreateEntry(urlres, urlres, 0, METHOD_GET);
145 storeClientListAdd(urlres_e, urnState);
41462d93 146 fwdStart(-1, urlres_e, urlres_r);
cf26e54c 147 } else {
164f7660 148 storeLockObject(urlres_e);
149 storeClientListAdd(urlres_e, urnState);
85491f8d 150 }
cf26e54c 151 urnState->urlres_e = urlres_e;
40548fef 152 urnState->urlres_r = requestLink(urlres_r);
cf26e54c 153 storeClientCopy(urlres_e,
154 0,
155 0,
156 4096,
7021844c 157 memAllocate(MEM_4K_BUF),
cf26e54c 158 urnHandleReply,
159 urnState);
85491f8d 160}
161
9ce5e3e6 162static int
163url_entry_sort(const void *A, const void *B)
164{
165 const url_entry *u1 = A;
166 const url_entry *u2 = B;
167 if (u2->rtt == u1->rtt)
168 return 0;
169 else if (0 == u1->rtt)
170 return 1;
171 else if (0 == u2->rtt)
00141c96 172 return -1;
9ce5e3e6 173 else
00141c96 174 return u1->rtt - u2->rtt;
9ce5e3e6 175}
176
85491f8d 177static void
23d92c64 178urnHandleReply(void *data, char *buf, ssize_t size)
85491f8d 179{
cf26e54c 180 UrnState *urnState = data;
181 StoreEntry *e = urnState->entry;
182 StoreEntry *urlres_e = urnState->urlres_e;
23d92c64 183 char *s = NULL;
2334c194 184 size_t k;
cb69b4c7 185 HttpReply *rep;
9ce5e3e6 186 url_entry *urls;
00141c96 187 url_entry *u;
9ce5e3e6 188 url_entry *min_u;
02922e76 189 MemBuf mb;
cf26e54c 190 ErrorState *err;
9ce5e3e6 191 int i;
192 int urlcnt = 0;
cf26e54c 193
6f6f0853 194 debug(52, 3) ("urnHandleReply: Called with size=%d.\n", size);
cf26e54c 195 if (urlres_e->store_status == STORE_ABORTED) {
3f6c0fb2 196 memFree(MEM_4K_BUF, buf);
23d92c64 197 return;
85491f8d 198 }
23d92c64 199 if (size == 0) {
3f6c0fb2 200 memFree(MEM_4K_BUF, buf);
23d92c64 201 return;
202 } else if (size < 0) {
3f6c0fb2 203 memFree(MEM_4K_BUF, buf);
23d92c64 204 return;
85491f8d 205 }
4b534024 206 if (urlres_e->store_status == STORE_PENDING && size < SM_PAGE_SIZE) {
cf26e54c 207 storeClientCopy(urlres_e,
208 size,
23d92c64 209 0,
210 SM_PAGE_SIZE,
211 buf,
212 urnHandleReply,
cf26e54c 213 urnState);
85491f8d 214 return;
23d92c64 215 }
216 /* we know its STORE_OK */
2334c194 217 k = headersEnd(buf, size);
218 if (0 == k) {
6f6f0853 219 debug(52, 1) ("urnHandleReply: didn't find end-of-headers for %s\n",
cf26e54c 220 storeUrl(e));
85491f8d 221 return;
85491f8d 222 }
2334c194 223 s = buf + k;
cf26e54c 224 assert(urlres_e->mem_obj->reply);
cb69b4c7 225 httpReplyParse(urlres_e->mem_obj->reply, buf);
6f6f0853 226 debug(52, 3) ("mem->reply exists, code=%d.\n",
cb69b4c7 227 urlres_e->mem_obj->reply->sline.status);
228 if (urlres_e->mem_obj->reply->sline.status != HTTP_OK) {
6f6f0853 229 debug(52, 3) ("urnHandleReply: failed.\n");
cf26e54c 230 err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND);
231 err->request = requestLink(urnState->request);
232 err->url = xstrdup(storeUrl(e));
233 errorAppendEntry(e, err);
23d92c64 234 return;
85491f8d 235 }
23d92c64 236 while (isspace(*s))
237 s++;
9ce5e3e6 238 urls = urnParseReply(s, urnState->request->method);
00141c96 239 for (i = 0; NULL != urls[i].url; i++)
9ce5e3e6 240 urlcnt++;
00141c96 241 debug(0, 0) ("urnFindMinRtt: Counted %d URLs\n", i);
164f7660 242 if (urls == NULL) { /* unkown URN error */
6f6f0853 243 debug(52, 3) ("urnTranslateDone: unknown URN %s\n", storeUrl(e));
cf26e54c 244 err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND);
245 err->request = requestLink(urnState->request);
246 err->url = xstrdup(storeUrl(e));
247 errorAppendEntry(e, err);
248 return;
164f7660 249 }
9ce5e3e6 250 min_u = urnFindMinRtt(urls, urnState->request->method, NULL);
251 qsort(urls, urlcnt, sizeof(*urls), url_entry_sort);
cf26e54c 252 storeBuffer(e);
02922e76 253 memBufDefInit(&mb);
254 memBufPrintf(&mb,
cf26e54c 255 "<TITLE>Select URL for %s</TITLE>\n"
256 "<H2>Select URL for %s</H2>\n"
2e141322 257 "<TABLE BORDER=0 WIDTH=\"100%%\">\n", storeUrl(e), storeUrl(e));
9ce5e3e6 258 for (i = 0; i < urlcnt; i++) {
00141c96 259 u = &urls[i];
260 debug(0, 0) ("URL {%s}\n", u->url);
9ce5e3e6 261 memBufPrintf(&mb,
00141c96 262 "<TR><TD><A HREF=\"%s\">%s</A></TD>", u->url, u->url);
263 if (urls[i].rtt > 0)
9ce5e3e6 264 memBufPrintf(&mb,
00141c96 265 "<TD align=right>%4d </it>ms</it></TD>", u->rtt);
164f7660 266 else
9ce5e3e6 267 memBufPrintf(&mb, "<TD align=right>Unknown</TD>");
268 memBufPrintf(&mb,
00141c96 269 "<TD>%s</TD></TR>\n", u->flags.cached ? " [cached]" : " ");
cf26e54c 270 }
02922e76 271 memBufPrintf(&mb,
2e141322 272 "</TABLE>"
cf26e54c 273 "<HR>\n"
274 "<ADDRESS>\n"
02922e76 275 "Generated by %s@%s\n"
cf26e54c 276 "</ADDRESS>\n",
02922e76 277 full_appname_string, getMyHostname());
cb69b4c7 278 rep = e->mem_obj->reply;
279 httpReplyReset(rep);
280 httpReplySetHeaders(rep, 1.0, HTTP_MOVED_TEMPORARILY, NULL,
02922e76 281 "text/html", mb.size, 0, squid_curtime);
cb69b4c7 282 if (EBIT_TEST(urnState->flags, URN_FORCE_MENU)) {
283 debug(51, 3) ("urnHandleReply: forcing menu\n");
9ce5e3e6 284 } else if (min_u) {
285 httpHeaderPutStr(&rep->header, HDR_LOCATION, min_u->url);
cb69b4c7 286 }
1afe05c5 287 httpBodySet(&rep->body, mb.buf, mb.size + 1, memBufFreeFunc(&mb));
cb69b4c7 288 httpReplySwapOut(rep, e);
cf26e54c 289 storeComplete(e);
3f6c0fb2 290 memFree(MEM_4K_BUF, buf);
9ce5e3e6 291 for (i = 0; i < urlcnt; i++) {
00141c96 292 safe_free(urls[i].url);
293 safe_free(urls[i].host);
9ce5e3e6 294 }
295 safe_free(urls);
02922e76 296 /* mb was frozen with memBufFreeFunc call, so we must not clean it */
8d709a1b 297 storeUnregister(urlres_e, urnState);
cf26e54c 298 storeUnlockObject(urlres_e);
8d709a1b 299 storeUnlockObject(urnState->entry);
300 requestUnlink(urnState->request);
40548fef 301 requestUnlink(urnState->urlres_r);
8d709a1b 302 cbdataFree(urnState);
85491f8d 303}
304
9ce5e3e6 305static url_entry *
306urnParseReply(const char *inbuf, method_t m)
85491f8d 307{
23d92c64 308 char *buf = xstrdup(inbuf);
309 char *token;
9ce5e3e6 310 char *url;
311 char *host;
312 const cache_key *key;
313 int rtt;
314 url_entry *list;
315 url_entry *old;
316 int n = 32;
317 int i = 0;
6f6f0853 318 debug(52, 3) ("urnParseReply\n");
9ce5e3e6 319 list = xcalloc(n + 1, sizeof(*list));
23d92c64 320 for (token = strtok(buf, crlf); token; token = strtok(NULL, crlf)) {
6f6f0853 321 debug(52, 3) ("urnParseReply: got '%s'\n", token);
9ce5e3e6 322 if (i == n) {
323 old = list;
324 n <<= 2;
325 list = xcalloc(n + 1, sizeof(*list));
326 xmemcpy(list, old, i * sizeof(*list));
327 safe_free(old);
328 }
329 url = xstrdup(token);
330 host = urlHostname(url);
331 if (NULL == host)
332 continue;
333 rtt = netdbHostRtt(host);
334 if (0 == rtt) {
335 debug(52, 3) ("urnParseReply: Pinging %s\n", host);
336 netdbPingSite(host);
337 }
338 key = storeKeyPublic(url, m);
00141c96 339 list[i].url = url;
340 list[i].host = xstrdup(host);
341 list[i].rtt = rtt;
342 list[i].flags.cached = storeGet(key) ? 1 : 0;
9ce5e3e6 343 i++;
85491f8d 344 }
00141c96 345 debug(0, 0) ("urnParseReply: Found %d URLs\n", i);
9ce5e3e6 346 return list;
85491f8d 347}