urn.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:10k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  *
  3.  * $Id: urn.c,v 1.52.2.1 1999/02/12 19:38:33 wessels Exp $
  4.  *
  5.  * DEBUG: section 52    URN Parsing
  6.  * AUTHOR: Kostas Anagnostakis
  7.  *
  8.  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
  9.  * ----------------------------------------------------------
  10.  *
  11.  *  Squid is the result of efforts by numerous individuals from the
  12.  *  Internet community.  Development is led by Duane Wessels of the
  13.  *  National Laboratory for Applied Network Research and funded by the
  14.  *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
  15.  *  Duane Wessels and the University of California San Diego.  Please
  16.  *  see the COPYRIGHT file for full details.  Squid incorporates
  17.  *  software developed and/or copyrighted by other sources.  Please see
  18.  *  the CREDITS file for full details.
  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
  32.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  33.  *
  34.  */
  35. #include "squid.h"
  36. typedef struct {
  37.     StoreEntry *entry;
  38.     StoreEntry *urlres_e;
  39.     request_t *request;
  40.     request_t *urlres_r;
  41.     struct {
  42. int force_menu:1;
  43.     } flags;
  44. } UrnState;
  45. typedef struct {
  46.     char *url;
  47.     char *host;
  48.     int rtt;
  49.     struct {
  50. int cached;
  51.     } flags;
  52. } url_entry;
  53. static STCB urnHandleReply;
  54. static url_entry *urnParseReply(const char *inbuf, method_t);
  55. static const char *const crlf = "rn";
  56. static QS url_entry_sort;
  57. url_entry *
  58. urnFindMinRtt(url_entry * urls, method_t m, int *rtt_ret)
  59. {
  60.     int min_rtt = 0;
  61.     url_entry *u = NULL;
  62.     url_entry *min_u = NULL;
  63.     int i;
  64.     int urlcnt = 0;
  65.     debug(52, 3) ("urnFindMinRttn");
  66.     assert(urls != NULL);
  67.     for (i = 0; NULL != urls[i].url; i++)
  68. urlcnt++;
  69.     debug(53, 3) ("urnFindMinRtt: Counted %d URLsn", i);
  70.     if (1 == urlcnt) {
  71. debug(52, 3) ("urnFindMinRtt: Only one URL - return it!n");
  72. return urls;
  73.     }
  74.     for (i = 0; i < urlcnt; i++) {
  75. u = &urls[i];
  76. debug(52, 3) ("urnFindMinRtt: %s rtt=%dn", u->host, u->rtt);
  77. if (u->rtt == 0)
  78.     continue;
  79. if (u->rtt > min_rtt && min_rtt != 0)
  80.     continue;
  81. min_rtt = u->rtt;
  82. min_u = u;
  83.     }
  84.     if (rtt_ret)
  85. *rtt_ret = min_rtt;
  86.     debug(52, 1) ("urnFindMinRtt: Returning '%s' RTT %dn",
  87. min_u ? min_u->url : "NONE",
  88. min_rtt);
  89.     return min_u;
  90. }
  91. void
  92. urnStart(request_t * r, StoreEntry * e)
  93. {
  94.     LOCAL_ARRAY(char, urlres, 4096);
  95.     request_t *urlres_r = NULL;
  96.     const char *t;
  97.     char *host;
  98.     UrnState *urnState;
  99.     StoreEntry *urlres_e;
  100.     ErrorState *err;
  101.     debug(52, 3) ("urnStart: '%s'n", storeUrl(e));
  102.     urnState = xcalloc(1, sizeof(UrnState));
  103.     urnState->entry = e;
  104.     urnState->request = requestLink(r);
  105.     cbdataAdd(urnState, cbdataXfree, 0);
  106.     storeLockObject(urnState->entry);
  107.     if (strncasecmp(strBuf(r->urlpath), "menu.", 5) == 0) {
  108. char *new_path = xstrdup(strBuf(r->urlpath) + 5);
  109. urnState->flags.force_menu = 1;
  110. stringReset(&r->urlpath, new_path);
  111. xfree(new_path);
  112.     }
  113.     if ((t = strChr(r->urlpath, ':')) != NULL) {
  114. strSet(r->urlpath, t, '');
  115. host = xstrdup(strBuf(r->urlpath));
  116. strSet(r->urlpath, t, ':');
  117.     } else {
  118. host = xstrdup(strBuf(r->urlpath));
  119.     }
  120.     snprintf(urlres, 4096, "http://%s/uri-res/N2L?urn:%s", host, strBuf(r->urlpath));
  121.     safe_free(host);
  122.     urlres_r = urlParse(METHOD_GET, urlres);
  123.     if (urlres_r == NULL) {
  124. debug(52, 3) ("urnStart: Bad uri-res URL %sn", urlres);
  125. err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND);
  126. err->url = xstrdup(urlres);
  127. errorAppendEntry(e, err);
  128. return;
  129.     }
  130.     httpHeaderPutStr(&urlres_r->header, HDR_ACCEPT, "text/plain");
  131.     if ((urlres_e = storeGetPublic(urlres, METHOD_GET)) == NULL) {
  132. urlres_e = storeCreateEntry(urlres, urlres, null_request_flags, METHOD_GET);
  133. storeClientListAdd(urlres_e, urnState);
  134. fwdStart(-1, urlres_e, urlres_r, no_addr, no_addr);
  135.     } else {
  136. storeLockObject(urlres_e);
  137. storeClientListAdd(urlres_e, urnState);
  138.     }
  139. #if DELAY_POOLS
  140.     delaySetStoreClient(urlres_e, urnState, 0);
  141. #endif
  142.     urnState->urlres_e = urlres_e;
  143.     urnState->urlres_r = requestLink(urlres_r);
  144.     storeClientCopy(urlres_e,
  145. 0,
  146. 0,
  147. 4096,
  148. memAllocate(MEM_4K_BUF),
  149. urnHandleReply,
  150. urnState);
  151. }
  152. static int
  153. url_entry_sort(const void *A, const void *B)
  154. {
  155.     const url_entry *u1 = A;
  156.     const url_entry *u2 = B;
  157.     if (u2->rtt == u1->rtt)
  158. return 0;
  159.     else if (0 == u1->rtt)
  160. return 1;
  161.     else if (0 == u2->rtt)
  162. return -1;
  163.     else
  164. return u1->rtt - u2->rtt;
  165. }
  166. static void
  167. urnHandleReply(void *data, char *buf, ssize_t size)
  168. {
  169.     UrnState *urnState = data;
  170.     StoreEntry *e = urnState->entry;
  171.     StoreEntry *urlres_e = urnState->urlres_e;
  172.     char *s = NULL;
  173.     size_t k;
  174.     HttpReply *rep;
  175.     url_entry *urls;
  176.     url_entry *u;
  177.     url_entry *min_u;
  178.     MemBuf mb;
  179.     ErrorState *err;
  180.     int i;
  181.     int urlcnt = 0;
  182.     debug(52, 3) ("urnHandleReply: Called with size=%d.n", size);
  183.     if (EBIT_TEST(urlres_e->flags, ENTRY_ABORTED)) {
  184. memFree(buf, MEM_4K_BUF);
  185. return;
  186.     }
  187.     if (size == 0) {
  188. memFree(buf, MEM_4K_BUF);
  189. return;
  190.     } else if (size < 0) {
  191. memFree(buf, MEM_4K_BUF);
  192. return;
  193.     }
  194.     if (urlres_e->store_status == STORE_PENDING && size < SM_PAGE_SIZE) {
  195. storeClientCopy(urlres_e,
  196.     size,
  197.     0,
  198.     SM_PAGE_SIZE,
  199.     buf,
  200.     urnHandleReply,
  201.     urnState);
  202. return;
  203.     }
  204.     /* we know its STORE_OK */
  205.     k = headersEnd(buf, size);
  206.     if (0 == k) {
  207. debug(52, 1) ("urnHandleReply: didn't find end-of-headers for %sn",
  208.     storeUrl(e));
  209. return;
  210.     }
  211.     s = buf + k;
  212.     assert(urlres_e->mem_obj->reply);
  213.     httpReplyParse(urlres_e->mem_obj->reply, buf);
  214.     debug(52, 3) ("mem->reply exists, code=%d.n",
  215. urlres_e->mem_obj->reply->sline.status);
  216.     if (urlres_e->mem_obj->reply->sline.status != HTTP_OK) {
  217. debug(52, 3) ("urnHandleReply: failed.n");
  218. err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND);
  219. err->request = requestLink(urnState->request);
  220. err->url = xstrdup(storeUrl(e));
  221. errorAppendEntry(e, err);
  222. return;
  223.     }
  224.     while (xisspace(*s))
  225. s++;
  226.     urls = urnParseReply(s, urnState->request->method);
  227.     for (i = 0; NULL != urls[i].url; i++)
  228. urlcnt++;
  229.     debug(53, 3) ("urnFindMinRtt: Counted %d URLsn", i);
  230.     if (urls == NULL) { /* unkown URN error */
  231. debug(52, 3) ("urnTranslateDone: unknown URN %sn", storeUrl(e));
  232. err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND);
  233. err->request = requestLink(urnState->request);
  234. err->url = xstrdup(storeUrl(e));
  235. errorAppendEntry(e, err);
  236. return;
  237.     }
  238.     min_u = urnFindMinRtt(urls, urnState->request->method, NULL);
  239.     qsort(urls, urlcnt, sizeof(*urls), url_entry_sort);
  240.     storeBuffer(e);
  241.     memBufDefInit(&mb);
  242.     memBufPrintf(&mb,
  243. "<TITLE>Select URL for %s</TITLE>n"
  244. "<H2>Select URL for %s</H2>n"
  245. "<TABLE BORDER=0 WIDTH="100%%">n", storeUrl(e), storeUrl(e));
  246.     for (i = 0; i < urlcnt; i++) {
  247. u = &urls[i];
  248. debug(52, 3) ("URL {%s}n", u->url);
  249. memBufPrintf(&mb,
  250.     "<TR><TD><A HREF="%s">%s</A></TD>", u->url, u->url);
  251. if (urls[i].rtt > 0)
  252.     memBufPrintf(&mb,
  253. "<TD align=right>%4d </it>ms</it></TD>", u->rtt);
  254. else
  255.     memBufPrintf(&mb, "<TD align=right>Unknown</TD>");
  256. memBufPrintf(&mb,
  257.     "<TD>%s</TD></TR>n", u->flags.cached ? "    [cached]" : " ");
  258.     }
  259.     memBufPrintf(&mb,
  260. "</TABLE>"
  261. "<HR>n"
  262. "<ADDRESS>n"
  263. "Generated by %s@%sn"
  264. "</ADDRESS>n",
  265. full_appname_string, getMyHostname());
  266.     rep = e->mem_obj->reply;
  267.     httpReplyReset(rep);
  268.     httpReplySetHeaders(rep, 1.0, HTTP_MOVED_TEMPORARILY, NULL,
  269. "text/html", mb.size, 0, squid_curtime);
  270.     if (urnState->flags.force_menu) {
  271. debug(51, 3) ("urnHandleReply: forcing menun");
  272.     } else if (min_u) {
  273. httpHeaderPutStr(&rep->header, HDR_LOCATION, min_u->url);
  274.     }
  275.     httpBodySet(&rep->body, &mb);
  276.     httpReplySwapOut(rep, e);
  277.     storeComplete(e);
  278.     memFree(buf, MEM_4K_BUF);
  279.     for (i = 0; i < urlcnt; i++) {
  280. safe_free(urls[i].url);
  281. safe_free(urls[i].host);
  282.     }
  283.     safe_free(urls);
  284.     /* mb was absorbed in httpBodySet call, so we must not clean it */
  285.     storeUnregister(urlres_e, urnState);
  286.     storeUnlockObject(urlres_e);
  287.     storeUnlockObject(urnState->entry);
  288.     requestUnlink(urnState->request);
  289.     requestUnlink(urnState->urlres_r);
  290.     cbdataFree(urnState);
  291. }
  292. static url_entry *
  293. urnParseReply(const char *inbuf, method_t m)
  294. {
  295.     char *buf = xstrdup(inbuf);
  296.     char *token;
  297.     char *url;
  298.     char *host;
  299.     int rtt;
  300.     url_entry *list;
  301.     url_entry *old;
  302.     int n = 32;
  303.     int i = 0;
  304.     debug(52, 3) ("urnParseReplyn");
  305.     list = xcalloc(n + 1, sizeof(*list));
  306.     for (token = strtok(buf, crlf); token; token = strtok(NULL, crlf)) {
  307. debug(52, 3) ("urnParseReply: got '%s'n", token);
  308. if (i == n) {
  309.     old = list;
  310.     n <<= 2;
  311.     list = xcalloc(n + 1, sizeof(*list));
  312.     xmemcpy(list, old, i * sizeof(*list));
  313.     safe_free(old);
  314. }
  315. url = xstrdup(token);
  316. host = urlHostname(url);
  317. if (NULL == host)
  318.     continue;
  319. rtt = netdbHostRtt(host);
  320. if (0 == rtt) {
  321.     debug(52, 3) ("urnParseReply: Pinging %sn", host);
  322.     netdbPingSite(host);
  323. }
  324. list[i].url = url;
  325. list[i].host = xstrdup(host);
  326. list[i].rtt = rtt;
  327. list[i].flags.cached = storeGetPublic(url, m) ? 1 : 0;
  328. i++;
  329.     }
  330.     debug(52, 3) ("urnParseReply: Found %d URLsn", i);
  331.     return list;
  332. }