]> git.ipfire.org Git - thirdparty/squid.git/blame - src/urn.cc
Fix diskd debugging to print the correct unlink function name, either
[thirdparty/squid.git] / src / urn.cc
CommitLineData
85491f8d 1
2/*
a9925b40 3 * $Id: urn.cc,v 1.98 2006/05/06 22:13:18 wessels 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"
c8be6d7b 37#include "StoreClient.h"
e6ccf245 38#include "Store.h"
528b2c61 39#include "HttpReply.h"
40#include "HttpRequest.h"
0eb49b6d 41#include "MemBuf.h"
b6b6f466 42#include "forward.h"
85491f8d 43
add2192d 44#define URN_REQBUF_SZ 4096
45
62e76326 46class UrnState : public StoreClient
47{
48
e6ccf245 49public:
3b13a8fd 50 void created (StoreEntry *newEntry);
06096e82 51 void *operator new (size_t byteCount);
e6ccf245 52 void operator delete (void *address);
190154cf 53 void start (HttpRequest *, StoreEntry *);
e6ccf245 54 char *getHost (String &urlpath);
190154cf 55 void setUriResFromRequest(HttpRequest *);
56 bool RequestNeedsMenu(HttpRequest *r);
57 void updateRequestURL(HttpRequest *r, char const *newPath);
e6ccf245 58 void createUriResRequest (String &uri);
59
60 virtual ~UrnState();
62e76326 61
62
164f7660 63 StoreEntry *entry;
06d2839d 64 store_client *sc;
164f7660 65 StoreEntry *urlres_e;
190154cf 66 HttpRequest *request;
67 HttpRequest *urlres_r;
62e76326 68
69 struct
70 {
71
72unsigned int force_menu:
73 1;
74 }
75
76 flags;
add2192d 77 char reqbuf[URN_REQBUF_SZ];
78 int reqofs;
62e76326 79
e6ccf245 80private:
81 char *urlres;
82};
85491f8d 83
62e76326 84typedef struct
85{
9ce5e3e6 86 char *url;
87 char *host;
88 int rtt;
62e76326 89
90 struct
91 {
92 int cached;
93 }
94
95 flags;
96}
97
98url_entry;
9ce5e3e6 99
100static STCB urnHandleReply;
101static url_entry *urnParseReply(const char *inbuf, method_t);
102static const char *const crlf = "\r\n";
103static QS url_entry_sort;
104
e6ccf245 105CBDATA_TYPE(UrnState);
106void *
06096e82 107UrnState::operator new (size_t byteCount)
e6ccf245 108{
62e76326 109 /* derived classes with different sizes must implement their own new */
e6ccf245 110 assert (byteCount == sizeof (UrnState));
111 CBDATA_INIT_TYPE(UrnState);
112 return cbdataAlloc(UrnState);
62e76326 113
e6ccf245 114}
115
116void
117UrnState::operator delete (void *address)
118{
1f1ae50a 119 UrnState * tmp = (UrnState *)address;
120 cbdataFree (tmp);
e6ccf245 121}
122
123UrnState::~UrnState ()
124{
125 safe_free(urlres);
126}
127
48ebcb22 128static url_entry *
9ce5e3e6 129urnFindMinRtt(url_entry * urls, method_t m, int *rtt_ret)
85491f8d 130{
23d92c64 131 int min_rtt = 0;
9ce5e3e6 132 url_entry *u = NULL;
133 url_entry *min_u = NULL;
134 int i;
1caf595b 135 int urlcnt = 0;
6f6f0853 136 debug(52, 3) ("urnFindMinRtt\n");
23d92c64 137 assert(urls != NULL);
62e76326 138
00141c96 139 for (i = 0; NULL != urls[i].url; i++)
62e76326 140 urlcnt++;
141
94934dbe 142 debug(53, 3) ("urnFindMinRtt: Counted %d URLs\n", i);
62e76326 143
9ce5e3e6 144 if (1 == urlcnt) {
62e76326 145 debug(52, 3) ("urnFindMinRtt: Only one URL - return it!\n");
146 return urls;
1caf595b 147 }
62e76326 148
00141c96 149 for (i = 0; i < urlcnt; i++) {
62e76326 150 u = &urls[i];
151 debug(52, 3) ("urnFindMinRtt: %s rtt=%d\n", u->host, u->rtt);
152
153 if (u->rtt == 0)
154 continue;
155
156 if (u->rtt > min_rtt && min_rtt != 0)
157 continue;
158
159 min_rtt = u->rtt;
160
161 min_u = u;
23d92c64 162 }
62e76326 163
23d92c64 164 if (rtt_ret)
62e76326 165 *rtt_ret = min_rtt;
166
6f6f0853 167 debug(52, 1) ("urnFindMinRtt: Returning '%s' RTT %d\n",
62e76326 168 min_u ? min_u->url : "NONE",
169 min_rtt);
170
9ce5e3e6 171 return min_u;
85491f8d 172}
173
e6ccf245 174char *
175UrnState::getHost (String &urlpath)
85491f8d 176{
e6ccf245 177 char * result;
178 char const *t;
62e76326 179
650c4b88 180 if ((t = urlpath.pos(':')) != NULL) {
181 urlpath.set(t, '\0');
62e76326 182 result = xstrdup(urlpath.buf());
650c4b88 183 urlpath.set(t, ':');
fa040df2 184 } else {
62e76326 185 result = xstrdup(urlpath.buf());
fa040df2 186 }
62e76326 187
e6ccf245 188 return result;
189}
190
191bool
190154cf 192UrnState::RequestNeedsMenu(HttpRequest *r)
e6ccf245 193{
528b2c61 194 return strncasecmp(r->urlpath.buf(), "menu.", 5) == 0;
e6ccf245 195}
196
197void
190154cf 198UrnState::updateRequestURL(HttpRequest *r, char const *newPath)
e6ccf245 199{
62e76326 200 char *new_path = xstrdup (newPath);
201 r->urlpath = new_path;
202 xfree(new_path);
e6ccf245 203}
204
205void
206UrnState::createUriResRequest (String &uri)
207{
208 LOCAL_ARRAY(char, local_urlres, 4096);
209 char *host = getHost (uri);
528b2c61 210 snprintf(local_urlres, 4096, "http://%s/uri-res/N2L?urn:%s", host, uri.buf());
e6ccf245 211 safe_free (host);
212 safe_free (urlres);
213 urlres = xstrdup (local_urlres);
c21ad0f5 214 urlres_r = HttpRequest::CreateFromUrl(urlres);
e6ccf245 215}
216
217void
190154cf 218UrnState::setUriResFromRequest(HttpRequest *r)
e6ccf245 219{
220 if (RequestNeedsMenu(r)) {
62e76326 221 updateRequestURL(r, r->urlpath.buf() + 5);
222 flags.force_menu = 1;
e6ccf245 223 }
62e76326 224
e6ccf245 225 createUriResRequest (r->urlpath);
62e76326 226
0adbab7c 227 if (urlres_r == NULL) {
62e76326 228 debug(52, 3) ("urnStart: Bad uri-res URL %s\n", urlres);
229 ErrorState *err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND);
230 err->url = urlres;
6dd9f4bd 231 err->request = HTTPMSGLOCK(r);
62e76326 232 urlres = NULL;
233 errorAppendEntry(entry, err);
234 return;
0adbab7c 235 }
62e76326 236
6dd9f4bd 237 HTTPMSGLOCK(urlres_r);
a9925b40 238 urlres_r->header.putStr(HDR_ACCEPT, "text/plain");
e6ccf245 239}
240
241void
190154cf 242UrnState::start(HttpRequest * r, StoreEntry * e)
e6ccf245 243{
244 debug(52, 3) ("urnStart: '%s'\n", storeUrl(e));
245 entry = e;
6dd9f4bd 246 request = HTTPMSGLOCK(r);
e6ccf245 247 storeLockObject(entry);
248 setUriResFromRequest(r);
62e76326 249
e6ccf245 250 if (urlres_r == NULL)
62e76326 251 return;
252
3b13a8fd 253 StoreEntry::getPublic (this, urlres, METHOD_GET);
e6ccf245 254}
255
256void
3b13a8fd 257UrnState::created(StoreEntry *newEntry)
e6ccf245 258{
259 urlres_e = newEntry;
62e76326 260
e6ccf245 261 if (urlres_e->isNull()) {
62e76326 262 urlres_e = storeCreateEntry(urlres, urlres, request_flags(), METHOD_GET);
263 sc = storeClientListAdd(urlres_e, this);
b6b6f466 264 FwdState::fwdStart(-1, urlres_e, urlres_r);
cf26e54c 265 } else {
62e76326 266 storeLockObject(urlres_e);
267 sc = storeClientListAdd(urlres_e, this);
85491f8d 268 }
62e76326 269
e6ccf245 270 reqofs = 0;
528b2c61 271 StoreIOBuffer tempBuffer;
e6ccf245 272 tempBuffer.offset = reqofs;
c8be6d7b 273 tempBuffer.length = URN_REQBUF_SZ;
e6ccf245 274 tempBuffer.data = reqbuf;
275 storeClientCopy(sc, urlres_e,
62e76326 276 tempBuffer,
277 urnHandleReply,
278 this);
e6ccf245 279}
280
281void
190154cf 282urnStart(HttpRequest * r, StoreEntry * e)
e6ccf245 283{
284 UrnState *anUrn = new UrnState();
285 anUrn->start (r, e);
85491f8d 286}
287
9ce5e3e6 288static int
289url_entry_sort(const void *A, const void *B)
290{
e6ccf245 291 const url_entry *u1 = (const url_entry *)A;
292 const url_entry *u2 = (const url_entry *)B;
62e76326 293
9ce5e3e6 294 if (u2->rtt == u1->rtt)
62e76326 295 return 0;
9ce5e3e6 296 else if (0 == u1->rtt)
62e76326 297 return 1;
9ce5e3e6 298 else if (0 == u2->rtt)
62e76326 299 return -1;
9ce5e3e6 300 else
62e76326 301 return u1->rtt - u2->rtt;
9ce5e3e6 302}
303
528b2c61 304/* TODO: use the clientStream support for this */
85491f8d 305static void
c8be6d7b 306urnHandleReply(void *data, StoreIOBuffer result)
85491f8d 307{
e6ccf245 308 UrnState *urnState = static_cast<UrnState *>(data);
cf26e54c 309 StoreEntry *e = urnState->entry;
310 StoreEntry *urlres_e = urnState->urlres_e;
23d92c64 311 char *s = NULL;
2334c194 312 size_t k;
cb69b4c7 313 HttpReply *rep;
9ce5e3e6 314 url_entry *urls;
00141c96 315 url_entry *u;
9ce5e3e6 316 url_entry *min_u;
032785bf 317 MemBuf *mb = NULL;
cf26e54c 318 ErrorState *err;
9ce5e3e6 319 int i;
320 int urlcnt = 0;
add2192d 321 char *buf = urnState->reqbuf;
c8be6d7b 322 StoreIOBuffer tempBuffer;
cf26e54c 323
c4b7a5a9 324 debug(52, 3) ("urnHandleReply: Called with size=%u.\n", (unsigned int)result.length);
62e76326 325
450e0c10 326 /* Can't be lower because of the goto's */
327 HttpVersion version(1, 0);
328
b7fe0ab0 329 if (EBIT_TEST(urlres_e->flags, ENTRY_ABORTED)) {
62e76326 330 goto error;
85491f8d 331 }
62e76326 332
c8be6d7b 333 if (result.length == 0) {
62e76326 334 goto error;
c8be6d7b 335 } else if (result.flags.error < 0) {
62e76326 336 goto error;
85491f8d 337 }
62e76326 338
add2192d 339 /* Update reqofs to point to where in the buffer we'd be */
c8be6d7b 340 urnState->reqofs += result.length;
add2192d 341
342 /* Handle reqofs being bigger than normal */
343 if (urnState->reqofs >= URN_REQBUF_SZ) {
62e76326 344 goto error;
add2192d 345 }
62e76326 346
add2192d 347 /* If we haven't received the entire object (urn), copy more */
348 if (urlres_e->store_status == STORE_PENDING &&
62e76326 349 urnState->reqofs < URN_REQBUF_SZ) {
350 tempBuffer.offset = urnState->reqofs;
351 tempBuffer.length = URN_REQBUF_SZ;
352 tempBuffer.data = urnState->reqbuf + urnState->reqofs;
353 storeClientCopy(urnState->sc, urlres_e,
354 tempBuffer,
355 urnHandleReply,
356 urnState);
357 return;
23d92c64 358 }
62e76326 359
23d92c64 360 /* we know its STORE_OK */
add2192d 361 k = headersEnd(buf, urnState->reqofs);
62e76326 362
2334c194 363 if (0 == k) {
62e76326 364 debug(52, 1) ("urnHandleReply: didn't find end-of-headers for %s\n",
365 storeUrl(e));
366 goto error;
85491f8d 367 }
62e76326 368
2334c194 369 s = buf + k;
528b2c61 370 assert(urlres_e->getReply());
06a5ae20 371 rep = new HttpReply;
59eed7dc 372 rep->parseCharBuf(buf, k);
4a56ee8d 373 debug(52, 3) ("reply exists, code=%d.\n", rep->sline.status);
62e76326 374
528b2c61 375 if (rep->sline.status != HTTP_OK) {
62e76326 376 debug(52, 3) ("urnHandleReply: failed.\n");
377 err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND);
6dd9f4bd 378 err->request = HTTPMSGLOCK(urnState->request);
62e76326 379 err->url = xstrdup(storeUrl(e));
380 errorAppendEntry(e, err);
06a5ae20 381 delete rep;
62e76326 382 goto error;
85491f8d 383 }
62e76326 384
06a5ae20 385 delete rep;
62e76326 386
b6a2f15e 387 while (xisspace(*s))
62e76326 388 s++;
389
9ce5e3e6 390 urls = urnParseReply(s, urnState->request->method);
62e76326 391
00141c96 392 for (i = 0; NULL != urls[i].url; i++)
62e76326 393 urlcnt++;
394
94934dbe 395 debug(53, 3) ("urnFindMinRtt: Counted %d URLs\n", i);
62e76326 396
164f7660 397 if (urls == NULL) { /* unkown URN error */
62e76326 398 debug(52, 3) ("urnTranslateDone: unknown URN %s\n", storeUrl(e));
399 err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND);
6dd9f4bd 400 err->request = HTTPMSGLOCK(urnState->request);
62e76326 401 err->url = xstrdup(storeUrl(e));
402 errorAppendEntry(e, err);
403 goto error;
164f7660 404 }
62e76326 405
9ce5e3e6 406 min_u = urnFindMinRtt(urls, urnState->request->method, NULL);
407 qsort(urls, urlcnt, sizeof(*urls), url_entry_sort);
cf26e54c 408 storeBuffer(e);
032785bf 409 mb = new MemBuf;
2fe7eff9 410 mb->init();
411 mb->Printf( "<TITLE>Select URL for %s</TITLE>\n"
412 "<STYLE type=\"text/css\"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}--></STYLE>\n"
413 "<H2>Select URL for %s</H2>\n"
414 "<TABLE BORDER=\"0\" WIDTH=\"100%%\">\n", storeUrl(e), storeUrl(e));
62e76326 415
9ce5e3e6 416 for (i = 0; i < urlcnt; i++) {
62e76326 417 u = &urls[i];
418 debug(52, 3) ("URL {%s}\n", u->url);
2fe7eff9 419 mb->Printf(
420 "<TR><TD><A HREF=\"%s\">%s</A></TD>", u->url, u->url);
62e76326 421
422 if (urls[i].rtt > 0)
2fe7eff9 423 mb->Printf(
424 "<TD align=\"right\">%4d <it>ms</it></TD>", u->rtt);
62e76326 425 else
2fe7eff9 426 mb->Printf("<TD align=\"right\">Unknown</TD>");
62e76326 427
2fe7eff9 428 mb->Printf(
429 "<TD>%s</TD></TR>\n", u->flags.cached ? " [cached]" : " ");
cf26e54c 430 }
62e76326 431
2fe7eff9 432 mb->Printf(
433 "</TABLE>"
434 "<HR noshade size=\"1px\">\n"
435 "<ADDRESS>\n"
436 "Generated by %s@%s\n"
437 "</ADDRESS>\n",
438 full_appname_string, getMyHostname());
06a5ae20 439 rep = new HttpReply;
440 rep->setHeaders(version, HTTP_MOVED_TEMPORARILY, NULL,
441 "text/html", mb->contentSize(), 0, squid_curtime);
62e76326 442
b515fc11 443 if (urnState->flags.force_menu) {
62e76326 444 debug(51, 3) ("urnHandleReply: forcing menu\n");
9ce5e3e6 445 } else if (min_u) {
a9925b40 446 rep->header.putStr(HDR_LOCATION, min_u->url);
cb69b4c7 447 }
62e76326 448
032785bf 449 httpBodySet(&rep->body, mb);
450 /* don't clean or delete mb; rep->body owns it now */
db237875 451 e->replaceHttpReply(rep);
528b2c61 452 e->complete();
62e76326 453
9ce5e3e6 454 for (i = 0; i < urlcnt; i++) {
62e76326 455 safe_free(urls[i].url);
456 safe_free(urls[i].host);
9ce5e3e6 457 }
62e76326 458
9ce5e3e6 459 safe_free(urls);
96a5be3d 460 /* mb was absorbed in httpBodySet call, so we must not clean it */
06d2839d 461 storeUnregister(urnState->sc, urlres_e, urnState);
62e76326 462
463error:
cf26e54c 464 storeUnlockObject(urlres_e);
8d709a1b 465 storeUnlockObject(urnState->entry);
6dd9f4bd 466 HTTPMSGUNLOCK(urnState->request);
467 HTTPMSGUNLOCK(urnState->urlres_r);
e6ccf245 468 delete urnState;
85491f8d 469}
470
9ce5e3e6 471static url_entry *
472urnParseReply(const char *inbuf, method_t m)
85491f8d 473{
23d92c64 474 char *buf = xstrdup(inbuf);
475 char *token;
9ce5e3e6 476 char *url;
477 char *host;
9ce5e3e6 478 int rtt;
479 url_entry *list;
480 url_entry *old;
481 int n = 32;
482 int i = 0;
6f6f0853 483 debug(52, 3) ("urnParseReply\n");
e6ccf245 484 list = (url_entry *)xcalloc(n + 1, sizeof(*list));
62e76326 485
23d92c64 486 for (token = strtok(buf, crlf); token; token = strtok(NULL, crlf)) {
62e76326 487 debug(52, 3) ("urnParseReply: got '%s'\n", token);
488
489 if (i == n) {
490 old = list;
491 n <<= 2;
492 list = (url_entry *)xcalloc(n + 1, sizeof(*list));
493 xmemcpy(list, old, i * sizeof(*list));
494 safe_free(old);
495 }
496
497 url = xstrdup(token);
498 host = urlHostname(url);
499
500 if (NULL == host)
501 continue;
502
503 rtt = netdbHostRtt(host);
504
505 if (0 == rtt) {
506 debug(52, 3) ("urnParseReply: Pinging %s\n", host);
507 netdbPingSite(host);
508 }
509
510 list[i].url = url;
511 list[i].host = xstrdup(host);
512 list[i].rtt = rtt;
513 list[i].flags.cached = storeGetPublic(url, m) ? 1 : 0;
514 i++;
85491f8d 515 }
62e76326 516
94934dbe 517 debug(52, 3) ("urnParseReply: Found %d URLs\n", i);
9ce5e3e6 518 return list;
85491f8d 519}