]> git.ipfire.org Git - thirdparty/squid.git/blame - src/urn.cc
Fix "access_log none" (and "forward_log none")
[thirdparty/squid.git] / src / urn.cc
CommitLineData
85491f8d 1
2/*
ed19251a 3 * $Id: urn.cc,v 1.68 2001/10/24 08:19:09 hno Exp $
ebe14c5d 4 *
6f6f0853 5 * DEBUG: section 52 URN Parsing
85491f8d 6 * AUTHOR: Kostas Anagnostakis
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 9 * ----------------------------------------------------------
85491f8d 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.
85491f8d 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 *
85491f8d 34 */
35
36#include "squid.h"
37
cf26e54c 38typedef struct {
164f7660 39 StoreEntry *entry;
06d2839d 40 store_client *sc;
164f7660 41 StoreEntry *urlres_e;
42 request_t *request;
40548fef 43 request_t *urlres_r;
b515fc11 44 struct {
1810dde6 45 unsigned int force_menu:1;
b515fc11 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
48ebcb22 63static url_entry *
9ce5e3e6 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
28c60158 98CBDATA_TYPE(UrnState);
85491f8d 99void
164f7660 100urnStart(request_t * r, StoreEntry * e)
85491f8d 101{
23d92c64 102 LOCAL_ARRAY(char, urlres, 4096);
23d92c64 103 request_t *urlres_r = NULL;
02922e76 104 const char *t;
c6528ea4 105 char *host;
cf26e54c 106 UrnState *urnState;
107 StoreEntry *urlres_e;
0adbab7c 108 ErrorState *err;
6f6f0853 109 debug(52, 3) ("urnStart: '%s'\n", storeUrl(e));
28c60158 110 CBDATA_INIT_TYPE(UrnState);
72711e31 111 urnState = cbdataAlloc(UrnState);
cf26e54c 112 urnState->entry = e;
113 urnState->request = requestLink(r);
8d709a1b 114 storeLockObject(urnState->entry);
02922e76 115 if (strncasecmp(strBuf(r->urlpath), "menu.", 5) == 0) {
116 char *new_path = xstrdup(strBuf(r->urlpath) + 5);
b515fc11 117 urnState->flags.force_menu = 1;
02922e76 118 stringReset(&r->urlpath, new_path);
119 xfree(new_path);
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 urlres_r = urlParse(METHOD_GET, urlres);
0adbab7c 131 if (urlres_r == NULL) {
132 debug(52, 3) ("urnStart: Bad uri-res URL %s\n", urlres);
133 err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND);
134 err->url = xstrdup(urlres);
135 errorAppendEntry(e, err);
136 return;
137 }
2246b732 138 httpHeaderPutStr(&urlres_r->header, HDR_ACCEPT, "text/plain");
08e5d64f 139 if ((urlres_e = storeGetPublic(urlres, METHOD_GET)) == NULL) {
92695e5e 140 urlres_e = storeCreateEntry(urlres, urlres, null_request_flags, METHOD_GET);
06d2839d 141 urnState->sc = storeClientListAdd(urlres_e, urnState);
7e3ce7b9 142 fwdStart(-1, urlres_e, urlres_r);
cf26e54c 143 } else {
164f7660 144 storeLockObject(urlres_e);
06d2839d 145 urnState->sc = storeClientListAdd(urlres_e, urnState);
85491f8d 146 }
cf26e54c 147 urnState->urlres_e = urlres_e;
40548fef 148 urnState->urlres_r = requestLink(urlres_r);
06d2839d 149 storeClientCopy(urnState->sc, urlres_e,
cf26e54c 150 0,
151 0,
152 4096,
7021844c 153 memAllocate(MEM_4K_BUF),
cf26e54c 154 urnHandleReply,
155 urnState);
85491f8d 156}
157
9ce5e3e6 158static int
159url_entry_sort(const void *A, const void *B)
160{
161 const url_entry *u1 = A;
162 const url_entry *u2 = B;
163 if (u2->rtt == u1->rtt)
164 return 0;
165 else if (0 == u1->rtt)
166 return 1;
167 else if (0 == u2->rtt)
00141c96 168 return -1;
9ce5e3e6 169 else
00141c96 170 return u1->rtt - u2->rtt;
9ce5e3e6 171}
172
85491f8d 173static void
23d92c64 174urnHandleReply(void *data, char *buf, ssize_t size)
85491f8d 175{
cf26e54c 176 UrnState *urnState = data;
177 StoreEntry *e = urnState->entry;
178 StoreEntry *urlres_e = urnState->urlres_e;
23d92c64 179 char *s = NULL;
2334c194 180 size_t k;
cb69b4c7 181 HttpReply *rep;
9ce5e3e6 182 url_entry *urls;
00141c96 183 url_entry *u;
9ce5e3e6 184 url_entry *min_u;
02922e76 185 MemBuf mb;
cf26e54c 186 ErrorState *err;
9ce5e3e6 187 int i;
188 int urlcnt = 0;
ccf44862 189 http_version_t version;
cf26e54c 190
ed19251a 191 debug(52, 3) ("urnHandleReply: Called with size=%d.\n", (int) size);
b7fe0ab0 192 if (EBIT_TEST(urlres_e->flags, ENTRY_ABORTED)) {
db1cd23c 193 memFree(buf, MEM_4K_BUF);
23d92c64 194 return;
85491f8d 195 }
23d92c64 196 if (size == 0) {
db1cd23c 197 memFree(buf, MEM_4K_BUF);
23d92c64 198 return;
199 } else if (size < 0) {
db1cd23c 200 memFree(buf, MEM_4K_BUF);
23d92c64 201 return;
85491f8d 202 }
4b534024 203 if (urlres_e->store_status == STORE_PENDING && size < SM_PAGE_SIZE) {
06d2839d 204 storeClientCopy(urnState->sc, urlres_e,
cf26e54c 205 size,
23d92c64 206 0,
207 SM_PAGE_SIZE,
208 buf,
209 urnHandleReply,
cf26e54c 210 urnState);
85491f8d 211 return;
23d92c64 212 }
213 /* we know its STORE_OK */
2334c194 214 k = headersEnd(buf, size);
215 if (0 == k) {
6f6f0853 216 debug(52, 1) ("urnHandleReply: didn't find end-of-headers for %s\n",
cf26e54c 217 storeUrl(e));
85491f8d 218 return;
85491f8d 219 }
2334c194 220 s = buf + k;
cf26e54c 221 assert(urlres_e->mem_obj->reply);
9bc73deb 222 httpReplyParse(urlres_e->mem_obj->reply, buf, k);
6f6f0853 223 debug(52, 3) ("mem->reply exists, code=%d.\n",
cb69b4c7 224 urlres_e->mem_obj->reply->sline.status);
225 if (urlres_e->mem_obj->reply->sline.status != HTTP_OK) {
6f6f0853 226 debug(52, 3) ("urnHandleReply: failed.\n");
cf26e54c 227 err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND);
228 err->request = requestLink(urnState->request);
229 err->url = xstrdup(storeUrl(e));
230 errorAppendEntry(e, err);
23d92c64 231 return;
85491f8d 232 }
b6a2f15e 233 while (xisspace(*s))
23d92c64 234 s++;
9ce5e3e6 235 urls = urnParseReply(s, urnState->request->method);
00141c96 236 for (i = 0; NULL != urls[i].url; i++)
9ce5e3e6 237 urlcnt++;
94934dbe 238 debug(53, 3) ("urnFindMinRtt: Counted %d URLs\n", i);
164f7660 239 if (urls == NULL) { /* unkown URN error */
6f6f0853 240 debug(52, 3) ("urnTranslateDone: unknown URN %s\n", storeUrl(e));
cf26e54c 241 err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND);
242 err->request = requestLink(urnState->request);
243 err->url = xstrdup(storeUrl(e));
244 errorAppendEntry(e, err);
245 return;
164f7660 246 }
9ce5e3e6 247 min_u = urnFindMinRtt(urls, urnState->request->method, NULL);
248 qsort(urls, urlcnt, sizeof(*urls), url_entry_sort);
cf26e54c 249 storeBuffer(e);
02922e76 250 memBufDefInit(&mb);
251 memBufPrintf(&mb,
cf26e54c 252 "<TITLE>Select URL for %s</TITLE>\n"
253 "<H2>Select URL for %s</H2>\n"
2e141322 254 "<TABLE BORDER=0 WIDTH=\"100%%\">\n", storeUrl(e), storeUrl(e));
9ce5e3e6 255 for (i = 0; i < urlcnt; i++) {
00141c96 256 u = &urls[i];
94934dbe 257 debug(52, 3) ("URL {%s}\n", u->url);
9ce5e3e6 258 memBufPrintf(&mb,
00141c96 259 "<TR><TD><A HREF=\"%s\">%s</A></TD>", u->url, u->url);
260 if (urls[i].rtt > 0)
9ce5e3e6 261 memBufPrintf(&mb,
00141c96 262 "<TD align=right>%4d </it>ms</it></TD>", u->rtt);
164f7660 263 else
9ce5e3e6 264 memBufPrintf(&mb, "<TD align=right>Unknown</TD>");
265 memBufPrintf(&mb,
00141c96 266 "<TD>%s</TD></TR>\n", u->flags.cached ? " [cached]" : " ");
cf26e54c 267 }
02922e76 268 memBufPrintf(&mb,
2e141322 269 "</TABLE>"
cf26e54c 270 "<HR>\n"
271 "<ADDRESS>\n"
02922e76 272 "Generated by %s@%s\n"
cf26e54c 273 "</ADDRESS>\n",
02922e76 274 full_appname_string, getMyHostname());
cb69b4c7 275 rep = e->mem_obj->reply;
276 httpReplyReset(rep);
bffee5af 277 httpBuildVersion(&version, 1, 0);
ccf44862 278 httpReplySetHeaders(rep, version, HTTP_MOVED_TEMPORARILY, NULL,
02922e76 279 "text/html", mb.size, 0, squid_curtime);
b515fc11 280 if (urnState->flags.force_menu) {
cb69b4c7 281 debug(51, 3) ("urnHandleReply: forcing menu\n");
9ce5e3e6 282 } else if (min_u) {
283 httpHeaderPutStr(&rep->header, HDR_LOCATION, min_u->url);
cb69b4c7 284 }
96a5be3d 285 httpBodySet(&rep->body, &mb);
cb69b4c7 286 httpReplySwapOut(rep, e);
cf26e54c 287 storeComplete(e);
db1cd23c 288 memFree(buf, MEM_4K_BUF);
9ce5e3e6 289 for (i = 0; i < urlcnt; i++) {
00141c96 290 safe_free(urls[i].url);
291 safe_free(urls[i].host);
9ce5e3e6 292 }
293 safe_free(urls);
96a5be3d 294 /* mb was absorbed in httpBodySet call, so we must not clean it */
06d2839d 295 storeUnregister(urnState->sc, urlres_e, urnState);
cf26e54c 296 storeUnlockObject(urlres_e);
8d709a1b 297 storeUnlockObject(urnState->entry);
298 requestUnlink(urnState->request);
40548fef 299 requestUnlink(urnState->urlres_r);
8d709a1b 300 cbdataFree(urnState);
85491f8d 301}
302
9ce5e3e6 303static url_entry *
304urnParseReply(const char *inbuf, method_t m)
85491f8d 305{
23d92c64 306 char *buf = xstrdup(inbuf);
307 char *token;
9ce5e3e6 308 char *url;
309 char *host;
9ce5e3e6 310 int rtt;
311 url_entry *list;
312 url_entry *old;
313 int n = 32;
314 int i = 0;
6f6f0853 315 debug(52, 3) ("urnParseReply\n");
9ce5e3e6 316 list = xcalloc(n + 1, sizeof(*list));
23d92c64 317 for (token = strtok(buf, crlf); token; token = strtok(NULL, crlf)) {
6f6f0853 318 debug(52, 3) ("urnParseReply: got '%s'\n", token);
9ce5e3e6 319 if (i == n) {
320 old = list;
321 n <<= 2;
322 list = xcalloc(n + 1, sizeof(*list));
323 xmemcpy(list, old, i * sizeof(*list));
324 safe_free(old);
325 }
326 url = xstrdup(token);
327 host = urlHostname(url);
328 if (NULL == host)
329 continue;
330 rtt = netdbHostRtt(host);
331 if (0 == rtt) {
332 debug(52, 3) ("urnParseReply: Pinging %s\n", host);
333 netdbPingSite(host);
334 }
00141c96 335 list[i].url = url;
336 list[i].host = xstrdup(host);
337 list[i].rtt = rtt;
08e5d64f 338 list[i].flags.cached = storeGetPublic(url, m) ? 1 : 0;
9ce5e3e6 339 i++;
85491f8d 340 }
94934dbe 341 debug(52, 3) ("urnParseReply: Found %d URLs\n", i);
9ce5e3e6 342 return list;
85491f8d 343}