]> git.ipfire.org Git - thirdparty/squid.git/blame - src/urn.cc
SQUID_2_2 branch merge
[thirdparty/squid.git] / src / urn.cc
CommitLineData
85491f8d 1
2/*
ebe14c5d 3 *
b6a2f15e 4 * $Id: urn.cc,v 1.53 1999/04/15 06:16:14 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/
e25c139f 10 * ----------------------------------------------------------
85491f8d 11 *
12 * Squid is the result of efforts by numerous individuals from the
13 * Internet community. Development is led by Duane Wessels of the
e25c139f 14 * National Laboratory for Applied Network Research and funded by the
15 * National Science Foundation. Squid is Copyrighted (C) 1998 by
16 * Duane Wessels and the University of California San Diego. Please
17 * see the COPYRIGHT file for full details. Squid incorporates
18 * software developed and/or copyrighted by other sources. Please see
19 * the CREDITS file for full details.
85491f8d 20 *
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 2 of the License, or
24 * (at your option) any later version.
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
cbdec147 33 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 34 *
85491f8d 35 */
36
37#include "squid.h"
38
cf26e54c 39typedef struct {
164f7660 40 StoreEntry *entry;
41 StoreEntry *urlres_e;
42 request_t *request;
40548fef 43 request_t *urlres_r;
b515fc11 44 struct {
45 int force_menu:1;
46 } flags;
cf26e54c 47} UrnState;
85491f8d 48
9ce5e3e6 49typedef struct {
50 char *url;
51 char *host;
52 int rtt;
53 struct {
54 int cached;
55 } flags;
56} url_entry;
57
58static STCB urnHandleReply;
59static url_entry *urnParseReply(const char *inbuf, method_t);
60static const char *const crlf = "\r\n";
61static QS url_entry_sort;
62
63url_entry *
64urnFindMinRtt(url_entry * urls, method_t m, int *rtt_ret)
85491f8d 65{
23d92c64 66 int min_rtt = 0;
9ce5e3e6 67 url_entry *u = NULL;
68 url_entry *min_u = NULL;
69 int i;
1caf595b 70 int urlcnt = 0;
6f6f0853 71 debug(52, 3) ("urnFindMinRtt\n");
23d92c64 72 assert(urls != NULL);
00141c96 73 for (i = 0; NULL != urls[i].url; i++)
1caf595b 74 urlcnt++;
94934dbe 75 debug(53, 3) ("urnFindMinRtt: Counted %d URLs\n", i);
9ce5e3e6 76 if (1 == urlcnt) {
77 debug(52, 3) ("urnFindMinRtt: Only one URL - return it!\n");
78 return urls;
1caf595b 79 }
00141c96 80 for (i = 0; i < urlcnt; i++) {
81 u = &urls[i];
9ce5e3e6 82 debug(52, 3) ("urnFindMinRtt: %s rtt=%d\n", u->host, u->rtt);
83 if (u->rtt == 0)
23d92c64 84 continue;
9ce5e3e6 85 if (u->rtt > min_rtt && min_rtt != 0)
164f7660 86 continue;
9ce5e3e6 87 min_rtt = u->rtt;
88 min_u = u;
23d92c64 89 }
90 if (rtt_ret)
91 *rtt_ret = min_rtt;
6f6f0853 92 debug(52, 1) ("urnFindMinRtt: Returning '%s' RTT %d\n",
9ce5e3e6 93 min_u ? min_u->url : "NONE",
23d92c64 94 min_rtt);
9ce5e3e6 95 return min_u;
85491f8d 96}
97
98void
164f7660 99urnStart(request_t * r, StoreEntry * e)
85491f8d 100{
23d92c64 101 LOCAL_ARRAY(char, urlres, 4096);
23d92c64 102 request_t *urlres_r = NULL;
02922e76 103 const char *t;
c6528ea4 104 char *host;
cf26e54c 105 UrnState *urnState;
106 StoreEntry *urlres_e;
0adbab7c 107 ErrorState *err;
6f6f0853 108 debug(52, 3) ("urnStart: '%s'\n", storeUrl(e));
cf26e54c 109 urnState = xcalloc(1, sizeof(UrnState));
110 urnState->entry = e;
111 urnState->request = requestLink(r);
db1cd23c 112 cbdataAdd(urnState, cbdataXfree, 0);
8d709a1b 113 storeLockObject(urnState->entry);
02922e76 114 if (strncasecmp(strBuf(r->urlpath), "menu.", 5) == 0) {
115 char *new_path = xstrdup(strBuf(r->urlpath) + 5);
b515fc11 116 urnState->flags.force_menu = 1;
02922e76 117 stringReset(&r->urlpath, new_path);
118 xfree(new_path);
de28f103 119 }
02922e76 120 if ((t = strChr(r->urlpath, ':')) != NULL) {
121 strSet(r->urlpath, t, '\0');
122 host = xstrdup(strBuf(r->urlpath));
123 strSet(r->urlpath, t, ':');
fa040df2 124 } else {
02922e76 125 host = xstrdup(strBuf(r->urlpath));
fa040df2 126 }
02922e76 127 snprintf(urlres, 4096, "http://%s/uri-res/N2L?urn:%s", host, strBuf(r->urlpath));
c6528ea4 128 safe_free(host);
23d92c64 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 }
2246b732 137 httpHeaderPutStr(&urlres_r->header, HDR_ACCEPT, "text/plain");
08e5d64f 138 if ((urlres_e = storeGetPublic(urlres, METHOD_GET)) == NULL) {
92695e5e 139 urlres_e = storeCreateEntry(urlres, urlres, null_request_flags, METHOD_GET);
cf26e54c 140 storeClientListAdd(urlres_e, urnState);
ae2c08a2 141 fwdStart(-1, urlres_e, urlres_r, no_addr, no_addr);
cf26e54c 142 } else {
164f7660 143 storeLockObject(urlres_e);
144 storeClientListAdd(urlres_e, urnState);
85491f8d 145 }
cf26e54c 146 urnState->urlres_e = urlres_e;
40548fef 147 urnState->urlres_r = requestLink(urlres_r);
cf26e54c 148 storeClientCopy(urlres_e,
149 0,
150 0,
151 4096,
7021844c 152 memAllocate(MEM_4K_BUF),
cf26e54c 153 urnHandleReply,
154 urnState);
85491f8d 155}
156
9ce5e3e6 157static int
158url_entry_sort(const void *A, const void *B)
159{
160 const url_entry *u1 = A;
161 const url_entry *u2 = B;
162 if (u2->rtt == u1->rtt)
163 return 0;
164 else if (0 == u1->rtt)
165 return 1;
166 else if (0 == u2->rtt)
00141c96 167 return -1;
9ce5e3e6 168 else
00141c96 169 return u1->rtt - u2->rtt;
9ce5e3e6 170}
171
85491f8d 172static void
23d92c64 173urnHandleReply(void *data, char *buf, ssize_t size)
85491f8d 174{
cf26e54c 175 UrnState *urnState = data;
176 StoreEntry *e = urnState->entry;
177 StoreEntry *urlres_e = urnState->urlres_e;
23d92c64 178 char *s = NULL;
2334c194 179 size_t k;
cb69b4c7 180 HttpReply *rep;
9ce5e3e6 181 url_entry *urls;
00141c96 182 url_entry *u;
9ce5e3e6 183 url_entry *min_u;
02922e76 184 MemBuf mb;
cf26e54c 185 ErrorState *err;
9ce5e3e6 186 int i;
187 int urlcnt = 0;
cf26e54c 188
6f6f0853 189 debug(52, 3) ("urnHandleReply: Called with size=%d.\n", size);
b7fe0ab0 190 if (EBIT_TEST(urlres_e->flags, ENTRY_ABORTED)) {
db1cd23c 191 memFree(buf, MEM_4K_BUF);
23d92c64 192 return;
85491f8d 193 }
23d92c64 194 if (size == 0) {
db1cd23c 195 memFree(buf, MEM_4K_BUF);
23d92c64 196 return;
197 } else if (size < 0) {
db1cd23c 198 memFree(buf, MEM_4K_BUF);
23d92c64 199 return;
85491f8d 200 }
4b534024 201 if (urlres_e->store_status == STORE_PENDING && size < SM_PAGE_SIZE) {
cf26e54c 202 storeClientCopy(urlres_e,
203 size,
23d92c64 204 0,
205 SM_PAGE_SIZE,
206 buf,
207 urnHandleReply,
cf26e54c 208 urnState);
85491f8d 209 return;
23d92c64 210 }
211 /* we know its STORE_OK */
2334c194 212 k = headersEnd(buf, size);
213 if (0 == k) {
6f6f0853 214 debug(52, 1) ("urnHandleReply: didn't find end-of-headers for %s\n",
cf26e54c 215 storeUrl(e));
85491f8d 216 return;
85491f8d 217 }
2334c194 218 s = buf + k;
cf26e54c 219 assert(urlres_e->mem_obj->reply);
cb69b4c7 220 httpReplyParse(urlres_e->mem_obj->reply, buf);
6f6f0853 221 debug(52, 3) ("mem->reply exists, code=%d.\n",
cb69b4c7 222 urlres_e->mem_obj->reply->sline.status);
223 if (urlres_e->mem_obj->reply->sline.status != HTTP_OK) {
6f6f0853 224 debug(52, 3) ("urnHandleReply: failed.\n");
cf26e54c 225 err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND);
226 err->request = requestLink(urnState->request);
227 err->url = xstrdup(storeUrl(e));
228 errorAppendEntry(e, err);
23d92c64 229 return;
85491f8d 230 }
b6a2f15e 231 while (xisspace(*s))
23d92c64 232 s++;
9ce5e3e6 233 urls = urnParseReply(s, urnState->request->method);
00141c96 234 for (i = 0; NULL != urls[i].url; i++)
9ce5e3e6 235 urlcnt++;
94934dbe 236 debug(53, 3) ("urnFindMinRtt: Counted %d URLs\n", i);
164f7660 237 if (urls == NULL) { /* unkown URN error */
6f6f0853 238 debug(52, 3) ("urnTranslateDone: unknown URN %s\n", storeUrl(e));
cf26e54c 239 err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND);
240 err->request = requestLink(urnState->request);
241 err->url = xstrdup(storeUrl(e));
242 errorAppendEntry(e, err);
243 return;
164f7660 244 }
9ce5e3e6 245 min_u = urnFindMinRtt(urls, urnState->request->method, NULL);
246 qsort(urls, urlcnt, sizeof(*urls), url_entry_sort);
cf26e54c 247 storeBuffer(e);
02922e76 248 memBufDefInit(&mb);
249 memBufPrintf(&mb,
cf26e54c 250 "<TITLE>Select URL for %s</TITLE>\n"
251 "<H2>Select URL for %s</H2>\n"
2e141322 252 "<TABLE BORDER=0 WIDTH=\"100%%\">\n", storeUrl(e), storeUrl(e));
9ce5e3e6 253 for (i = 0; i < urlcnt; i++) {
00141c96 254 u = &urls[i];
94934dbe 255 debug(52, 3) ("URL {%s}\n", u->url);
9ce5e3e6 256 memBufPrintf(&mb,
00141c96 257 "<TR><TD><A HREF=\"%s\">%s</A></TD>", u->url, u->url);
258 if (urls[i].rtt > 0)
9ce5e3e6 259 memBufPrintf(&mb,
00141c96 260 "<TD align=right>%4d </it>ms</it></TD>", u->rtt);
164f7660 261 else
9ce5e3e6 262 memBufPrintf(&mb, "<TD align=right>Unknown</TD>");
263 memBufPrintf(&mb,
00141c96 264 "<TD>%s</TD></TR>\n", u->flags.cached ? " [cached]" : " ");
cf26e54c 265 }
02922e76 266 memBufPrintf(&mb,
2e141322 267 "</TABLE>"
cf26e54c 268 "<HR>\n"
269 "<ADDRESS>\n"
02922e76 270 "Generated by %s@%s\n"
cf26e54c 271 "</ADDRESS>\n",
02922e76 272 full_appname_string, getMyHostname());
cb69b4c7 273 rep = e->mem_obj->reply;
274 httpReplyReset(rep);
275 httpReplySetHeaders(rep, 1.0, HTTP_MOVED_TEMPORARILY, NULL,
02922e76 276 "text/html", mb.size, 0, squid_curtime);
b515fc11 277 if (urnState->flags.force_menu) {
cb69b4c7 278 debug(51, 3) ("urnHandleReply: forcing menu\n");
9ce5e3e6 279 } else if (min_u) {
280 httpHeaderPutStr(&rep->header, HDR_LOCATION, min_u->url);
cb69b4c7 281 }
96a5be3d 282 httpBodySet(&rep->body, &mb);
cb69b4c7 283 httpReplySwapOut(rep, e);
cf26e54c 284 storeComplete(e);
db1cd23c 285 memFree(buf, MEM_4K_BUF);
9ce5e3e6 286 for (i = 0; i < urlcnt; i++) {
00141c96 287 safe_free(urls[i].url);
288 safe_free(urls[i].host);
9ce5e3e6 289 }
290 safe_free(urls);
96a5be3d 291 /* mb was absorbed in httpBodySet call, so we must not clean it */
8d709a1b 292 storeUnregister(urlres_e, urnState);
cf26e54c 293 storeUnlockObject(urlres_e);
8d709a1b 294 storeUnlockObject(urnState->entry);
295 requestUnlink(urnState->request);
40548fef 296 requestUnlink(urnState->urlres_r);
8d709a1b 297 cbdataFree(urnState);
85491f8d 298}
299
9ce5e3e6 300static url_entry *
301urnParseReply(const char *inbuf, method_t m)
85491f8d 302{
23d92c64 303 char *buf = xstrdup(inbuf);
304 char *token;
9ce5e3e6 305 char *url;
306 char *host;
9ce5e3e6 307 int rtt;
308 url_entry *list;
309 url_entry *old;
310 int n = 32;
311 int i = 0;
6f6f0853 312 debug(52, 3) ("urnParseReply\n");
9ce5e3e6 313 list = xcalloc(n + 1, sizeof(*list));
23d92c64 314 for (token = strtok(buf, crlf); token; token = strtok(NULL, crlf)) {
6f6f0853 315 debug(52, 3) ("urnParseReply: got '%s'\n", token);
9ce5e3e6 316 if (i == n) {
317 old = list;
318 n <<= 2;
319 list = xcalloc(n + 1, sizeof(*list));
320 xmemcpy(list, old, i * sizeof(*list));
321 safe_free(old);
322 }
323 url = xstrdup(token);
324 host = urlHostname(url);
325 if (NULL == host)
326 continue;
327 rtt = netdbHostRtt(host);
328 if (0 == rtt) {
329 debug(52, 3) ("urnParseReply: Pinging %s\n", host);
330 netdbPingSite(host);
331 }
00141c96 332 list[i].url = url;
333 list[i].host = xstrdup(host);
334 list[i].rtt = rtt;
08e5d64f 335 list[i].flags.cached = storeGetPublic(url, m) ? 1 : 0;
9ce5e3e6 336 i++;
85491f8d 337 }
94934dbe 338 debug(52, 3) ("urnParseReply: Found %d URLs\n", i);
9ce5e3e6 339 return list;
85491f8d 340}