/* * $Id: urn.c,v 1.80 2006/08/25 12:26:07 serassio Exp $ * * DEBUG: section 52 URN Parsing * AUTHOR: Kostas Anagnostakis * * SQUID Web Proxy Cache http://www.squid-cache.org/ * ---------------------------------------------------------- * * Squid is the result of efforts by numerous individuals from * the Internet community; see the CONTRIBUTORS file for full * details. Many organizations have provided support for Squid's * development; see the SPONSORS file for full details. Squid is * Copyrighted (C) 2001 by the Regents of the University of * California; see the COPYRIGHT file for full details. Squid * incorporates software developed and/or copyrighted by other * sources; see the CREDITS file for full details. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * */ #include "squid.h" typedef struct { StoreEntry *entry; store_client *sc; StoreEntry *urlres_e; request_t *request; request_t *urlres_r; struct { unsigned int force_menu:1; } flags; } UrnState; typedef struct { char *url; char *host; int rtt; struct { int cached; } flags; } url_entry; static STCB urnHandleReply; static url_entry *urnParseReply(const char *inbuf, method_t); static const char *const crlf = "\r\n"; static QS url_entry_sort; static url_entry * urnFindMinRtt(url_entry * urls, method_t m, int *rtt_ret) { int min_rtt = 0; url_entry *u = NULL; url_entry *min_u = NULL; int i; int urlcnt = 0; debug(52, 3) ("urnFindMinRtt\n"); assert(urls != NULL); for (i = 0; NULL != urls[i].url; i++) urlcnt++; debug(52, 3) ("urnFindMinRtt: Counted %d URLs\n", i); if (1 == urlcnt) { debug(52, 3) ("urnFindMinRtt: Only one URL - return it!\n"); return urls; } for (i = 0; i < urlcnt; i++) { u = &urls[i]; debug(52, 3) ("urnFindMinRtt: %s rtt=%d\n", u->host, u->rtt); if (u->rtt == 0) continue; if (u->rtt > min_rtt && min_rtt != 0) continue; min_rtt = u->rtt; min_u = u; } if (rtt_ret) *rtt_ret = min_rtt; debug(52, 1) ("urnFindMinRtt: Returning '%s' RTT %d\n", min_u ? min_u->url : "NONE", min_rtt); return min_u; } CBDATA_TYPE(UrnState); void urnStart(request_t * r, StoreEntry * e) { LOCAL_ARRAY(char, urlres, 4096); request_t *urlres_r = NULL; const char *t; char *host; UrnState *urnState; StoreEntry *urlres_e; ErrorState *err; debug(52, 3) ("urnStart: '%s'\n", storeUrl(e)); CBDATA_INIT_TYPE(UrnState); urnState = cbdataAlloc(UrnState); urnState->entry = e; urnState->request = requestLink(r); storeLockObject(urnState->entry); if (strncasecmp(strBuf(r->urlpath), "menu.", 5) == 0) { char *new_path = xstrdup(strBuf(r->urlpath) + 5); urnState->flags.force_menu = 1; stringReset(&r->urlpath, new_path); xfree(new_path); } if ((t = strChr(r->urlpath, ':')) != NULL) { strSet(r->urlpath, t, '\0'); host = xstrdup(strBuf(r->urlpath)); strSet(r->urlpath, t, ':'); } else { host = xstrdup(strBuf(r->urlpath)); } snprintf(urlres, 4096, "http://%s/uri-res/N2L?urn:%s", host, strBuf(r->urlpath)); safe_free(host); urlres_r = urlParse(METHOD_GET, urlres); if (urlres_r == NULL) { debug(52, 3) ("urnStart: Bad uri-res URL %s\n", urlres); err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND, r); err->url = xstrdup(urlres); errorAppendEntry(e, err); return; } httpHeaderPutStr(&urlres_r->header, HDR_ACCEPT, "text/plain"); if ((urlres_e = storeGetPublic(urlres, METHOD_GET)) == NULL) { urlres_e = storeCreateEntry(urlres, urlres, null_request_flags, METHOD_GET); urnState->sc = storeClientRegister(urlres_e, urnState); fwdStart(-1, urlres_e, urlres_r); } else { storeLockObject(urlres_e); urnState->sc = storeClientRegister(urlres_e, urnState); } urnState->urlres_e = urlres_e; urnState->urlres_r = requestLink(urlres_r); storeClientCopy(urnState->sc, urlres_e, 0, 0, 4096, memAllocate(MEM_4K_BUF), urnHandleReply, urnState); } static int url_entry_sort(const void *A, const void *B) { const url_entry *u1 = A; const url_entry *u2 = B; if (u2->rtt == u1->rtt) return 0; else if (0 == u1->rtt) return 1; else if (0 == u2->rtt) return -1; else return u1->rtt - u2->rtt; } static void urnHandleReply(void *data, char *buf, ssize_t size) { UrnState *urnState = data; StoreEntry *e = urnState->entry; StoreEntry *urlres_e = urnState->urlres_e; char *s = NULL; size_t k; HttpReply *rep; url_entry *urls; url_entry *u; url_entry *min_u; MemBuf mb; ErrorState *err; int i; int urlcnt = 0; http_version_t version; debug(52, 3) ("urnHandleReply: Called with size=%d.\n", (int) size); if (EBIT_TEST(urlres_e->flags, ENTRY_ABORTED)) { memFree(buf, MEM_4K_BUF); return; } if (size == 0) { memFree(buf, MEM_4K_BUF); return; } else if (size < 0) { memFree(buf, MEM_4K_BUF); return; } if (urlres_e->store_status == STORE_PENDING && size < SM_PAGE_SIZE) { storeClientCopy(urnState->sc, urlres_e, size, 0, SM_PAGE_SIZE, buf, urnHandleReply, urnState); return; } /* we know its STORE_OK */ k = headersEnd(buf, size); if (0 == k) { debug(52, 1) ("urnHandleReply: didn't find end-of-headers for %s\n", storeUrl(e)); return; } s = buf + k; assert(urlres_e->mem_obj->reply); httpReplyParse(urlres_e->mem_obj->reply, buf, k); debug(52, 3) ("mem->reply exists, code=%d.\n", urlres_e->mem_obj->reply->sline.status); if (urlres_e->mem_obj->reply->sline.status != HTTP_OK) { debug(52, 3) ("urnHandleReply: failed.\n"); err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND, urnState->request); err->url = xstrdup(storeUrl(e)); errorAppendEntry(e, err); return; } while (xisspace(*s)) s++; urls = urnParseReply(s, urnState->request->method); for (i = 0; NULL != urls[i].url; i++) urlcnt++; debug(52, 3) ("urnHandleReply: Counted %d URLs\n", i); if (urls == NULL) { /* unkown URN error */ debug(52, 3) ("urnHandleReply: unknown URN %s\n", storeUrl(e)); err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND, urnState->request); err->url = xstrdup(storeUrl(e)); errorAppendEntry(e, err); return; } min_u = urnFindMinRtt(urls, urnState->request->method, NULL); qsort(urls, urlcnt, sizeof(*urls), url_entry_sort); storeBuffer(e); memBufDefInit(&mb); memBufPrintf(&mb, "
%s | ", u->url, u->url); if (urls[i].rtt > 0) memBufPrintf(&mb, "%4d | ", u->rtt);
else
memBufPrintf(&mb, "Unknown | "); memBufPrintf(&mb, "%s |