]> git.ipfire.org Git - thirdparty/squid.git/blame - src/urn.cc
moved updating byte counters to after read() and write() calls
[thirdparty/squid.git] / src / urn.cc
CommitLineData
85491f8d 1
2/*
ebe14c5d 3 *
40548fef 4 * $Id: urn.cc,v 1.27 1998/04/09 17:54:23 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/
10 * --------------------------------------------------------
11 *
12 * Squid is the result of efforts by numerous individuals from the
13 * Internet community. Development is led by Duane Wessels of the
14 * National Laboratory for Applied Network Research and funded by
15 * the National Science Foundation.
16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30 *
31 */
32
33#include "squid.h"
34
23d92c64 35static STCB urnHandleReply;
d017efc3 36static wordlist *urnParseReply(const char *inbuf);
23d92c64 37static const char *const crlf = "\r\n";
cf26e54c 38
fa040df2 39enum {
164f7660 40 URN_FORCE_MENU
fa040df2 41};
42
cf26e54c 43typedef struct {
164f7660 44 StoreEntry *entry;
45 StoreEntry *urlres_e;
46 request_t *request;
40548fef 47 request_t *urlres_r;
164f7660 48 int flags;
cf26e54c 49} UrnState;
85491f8d 50
23d92c64 51wordlist *
52urnFindMinRtt(wordlist * urls, method_t m, int *rtt_ret)
85491f8d 53{
23d92c64 54 int min_rtt = 0;
55 request_t *r;
56 int rtt;
57 wordlist *w;
58 wordlist *min_w = NULL;
6f6f0853 59 debug(52, 3) ("urnFindMinRtt\n");
23d92c64 60 assert(urls != NULL);
61 for (w = urls; w; w = w->next) {
62 r = urlParse(m, w->key);
63 if (r == NULL)
64 continue;
6f6f0853 65 debug(52, 3) ("Parsed %s\n", w->key);
23d92c64 66 rtt = netdbHostRtt(r->host);
67 if (rtt == 0) {
6f6f0853 68 debug(52, 3) ("Pinging %s\n", r->host);
23d92c64 69 netdbPingSite(r->host);
02922e76 70 stringClean(&r->urlpath);
3f6c0fb2 71 memFree(MEM_REQUEST_T, r);
23d92c64 72 continue;
85491f8d 73 }
6f6f0853 74 debug(52, 3) ("%s rtt=%d\n", r->host, rtt);
23d92c64 75 if (rtt == 0)
164f7660 76 continue;
23d92c64 77 if (rtt > min_rtt && min_rtt != 0)
164f7660 78 continue;
23d92c64 79 min_rtt = rtt;
80 min_w = w;
02922e76 81 stringClean(&r->urlpath);
3f6c0fb2 82 memFree(MEM_REQUEST_T, r);
23d92c64 83 }
84 if (rtt_ret)
85 *rtt_ret = min_rtt;
6f6f0853 86 debug(52, 1) ("urnFindMinRtt: Returning '%s' RTT %d\n",
23d92c64 87 min_w ? min_w->key : "NONE",
88 min_rtt);
89 return min_w;
85491f8d 90}
91
92void
164f7660 93urnStart(request_t * r, StoreEntry * e)
85491f8d 94{
23d92c64 95 LOCAL_ARRAY(char, urlres, 4096);
23d92c64 96 request_t *urlres_r = NULL;
97 const cache_key *k;
02922e76 98 const char *t;
c6528ea4 99 char *host;
cf26e54c 100 UrnState *urnState;
101 StoreEntry *urlres_e;
0adbab7c 102 ErrorState *err;
6f6f0853 103 debug(52, 3) ("urnStart: '%s'\n", storeUrl(e));
cf26e54c 104 urnState = xcalloc(1, sizeof(UrnState));
105 urnState->entry = e;
106 urnState->request = requestLink(r);
3f6c0fb2 107 cbdataAdd(urnState, MEM_NONE);
8d709a1b 108 storeLockObject(urnState->entry);
02922e76 109 if (strncasecmp(strBuf(r->urlpath), "menu.", 5) == 0) {
110 char *new_path = xstrdup(strBuf(r->urlpath) + 5);
de28f103 111 EBIT_SET(urnState->flags, URN_FORCE_MENU);
02922e76 112#if OLD_CODE
113 t = xstrdup(strBuf(r->urlpath) + 5);
de28f103 114 xstrncpy(r->urlpath, t, MAX_URL);
115 xfree(t);
02922e76 116#else
117 stringReset(&r->urlpath, new_path);
118 xfree(new_path);
119#endif
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 k = storeKeyPublic(urlres, METHOD_GET);
131 urlres_r = urlParse(METHOD_GET, urlres);
0adbab7c 132 if (urlres_r == NULL) {
133 debug(52, 3) ("urnStart: Bad uri-res URL %s\n", urlres);
134 err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND);
135 err->url = xstrdup(urlres);
136 errorAppendEntry(e, err);
137 return;
138 }
8d709a1b 139 urlres_r->headers = xstrdup("Accept: text/plain\r\n\r\n");
23d92c64 140 urlres_r->headers_sz = strlen(urlres_r->headers);
cf26e54c 141 if ((urlres_e = storeGet(k)) == NULL) {
142 urlres_e = storeCreateEntry(urlres, urlres, 0, METHOD_GET);
143 storeClientListAdd(urlres_e, urnState);
144 protoDispatch(0, urlres_e, urlres_r);
145 } else {
164f7660 146 storeLockObject(urlres_e);
147 storeClientListAdd(urlres_e, urnState);
85491f8d 148 }
cf26e54c 149 urnState->urlres_e = urlres_e;
40548fef 150 urnState->urlres_r = requestLink(urlres_r);
cf26e54c 151 storeClientCopy(urlres_e,
152 0,
153 0,
154 4096,
7021844c 155 memAllocate(MEM_4K_BUF),
cf26e54c 156 urnHandleReply,
157 urnState);
85491f8d 158}
159
160static void
23d92c64 161urnHandleReply(void *data, char *buf, ssize_t size)
85491f8d 162{
cf26e54c 163 UrnState *urnState = data;
164 StoreEntry *e = urnState->entry;
165 StoreEntry *urlres_e = urnState->urlres_e;
23d92c64 166 char *s = NULL;
2334c194 167 size_t k;
cb69b4c7 168 HttpReply *rep;
cf26e54c 169 wordlist *w;
170 wordlist *urls;
171 wordlist *min_w;
02922e76 172 MemBuf mb;
cf26e54c 173 ErrorState *err;
164f7660 174 double tmprtt;
175 StoreEntry *tmpentry;
cf26e54c 176
6f6f0853 177 debug(52, 3) ("urnHandleReply: Called with size=%d.\n", size);
cf26e54c 178 if (urlres_e->store_status == STORE_ABORTED) {
3f6c0fb2 179 memFree(MEM_4K_BUF, buf);
23d92c64 180 return;
85491f8d 181 }
23d92c64 182 if (size == 0) {
3f6c0fb2 183 memFree(MEM_4K_BUF, buf);
23d92c64 184 return;
185 } else if (size < 0) {
3f6c0fb2 186 memFree(MEM_4K_BUF, buf);
23d92c64 187 return;
85491f8d 188 }
4b534024 189 if (urlres_e->store_status == STORE_PENDING && size < SM_PAGE_SIZE) {
cf26e54c 190 storeClientCopy(urlres_e,
191 size,
23d92c64 192 0,
193 SM_PAGE_SIZE,
194 buf,
195 urnHandleReply,
cf26e54c 196 urnState);
85491f8d 197 return;
23d92c64 198 }
199 /* we know its STORE_OK */
2334c194 200 k = headersEnd(buf, size);
201 if (0 == k) {
6f6f0853 202 debug(52, 1) ("urnHandleReply: didn't find end-of-headers for %s\n",
cf26e54c 203 storeUrl(e));
85491f8d 204 return;
85491f8d 205 }
2334c194 206 s = buf + k;
cf26e54c 207 assert(urlres_e->mem_obj->reply);
cb69b4c7 208 httpReplyParse(urlres_e->mem_obj->reply, buf);
6f6f0853 209 debug(52, 3) ("mem->reply exists, code=%d.\n",
cb69b4c7 210 urlres_e->mem_obj->reply->sline.status);
211 if (urlres_e->mem_obj->reply->sline.status != HTTP_OK) {
6f6f0853 212 debug(52, 3) ("urnHandleReply: failed.\n");
cf26e54c 213 err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND);
214 err->request = requestLink(urnState->request);
215 err->url = xstrdup(storeUrl(e));
216 errorAppendEntry(e, err);
23d92c64 217 return;
85491f8d 218 }
23d92c64 219 while (isspace(*s))
220 s++;
d017efc3 221 urls = urnParseReply(s);
164f7660 222 if (urls == NULL) { /* unkown URN error */
6f6f0853 223 debug(52, 3) ("urnTranslateDone: unknown URN %s\n", storeUrl(e));
cf26e54c 224 err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND);
225 err->request = requestLink(urnState->request);
226 err->url = xstrdup(storeUrl(e));
227 errorAppendEntry(e, err);
228 return;
164f7660 229 }
230 min_w = urnFindMinRtt(urls, urnState->request->method, NULL);
cf26e54c 231 storeBuffer(e);
02922e76 232 memBufDefInit(&mb);
233 memBufPrintf(&mb,
cf26e54c 234 "<TITLE>Select URL for %s</TITLE>\n"
235 "<H2>Select URL for %s</H2>\n"
2e141322 236 "<TABLE BORDER=0 WIDTH=\"100%%\">\n", storeUrl(e), storeUrl(e));
cf26e54c 237 for (w = urls; w; w = w->next) {
164f7660 238 request_t *tmpr = urlParse(urnState->request->method, w->key);
239 const cache_key *tmpk = storeKeyPublic(w->key, urnState->request->method);
240 tmpentry = storeGet(tmpk);
241 if (tmpr && tmpr->host && (tmprtt = netdbHostRtt(tmpr->host)))
02922e76 242 memBufPrintf(&mb, "<TR><TD><A HREF=\"%s\">%s</A></TD><TD align=right>%4.0f </it>ms</it></TD><TD>%s</TD></TR>\n",
164f7660 243 w->key, w->key, tmprtt, tmpentry ? " [cached]" : " ");
244 else
02922e76 245 memBufPrintf(&mb, "<TR><TD><A HREF=\"%s\">%s</A></TD></TR>", w->key, w->key);
cf26e54c 246 }
02922e76 247 memBufPrintf(&mb,
2e141322 248 "</TABLE>"
cf26e54c 249 "<HR>\n"
250 "<ADDRESS>\n"
02922e76 251 "Generated by %s@%s\n"
cf26e54c 252 "</ADDRESS>\n",
02922e76 253 full_appname_string, getMyHostname());
cb69b4c7 254 rep = e->mem_obj->reply;
255 httpReplyReset(rep);
256 httpReplySetHeaders(rep, 1.0, HTTP_MOVED_TEMPORARILY, NULL,
02922e76 257 "text/html", mb.size, 0, squid_curtime);
cb69b4c7 258 if (EBIT_TEST(urnState->flags, URN_FORCE_MENU)) {
259 debug(51, 3) ("urnHandleReply: forcing menu\n");
2ac76861 260 } else if (min_w) {
d8b249ef 261 httpHeaderPutStr(&rep->header, HDR_LOCATION, min_w->key);
cb69b4c7 262 }
1afe05c5 263 httpBodySet(&rep->body, mb.buf, mb.size + 1, memBufFreeFunc(&mb));
cb69b4c7 264 httpReplySwapOut(rep, e);
cf26e54c 265 storeComplete(e);
3f6c0fb2 266 memFree(MEM_4K_BUF, buf);
d017efc3 267 wordlistDestroy(&urls);
02922e76 268 /* mb was frozen with memBufFreeFunc call, so we must not clean it */
8d709a1b 269 storeUnregister(urlres_e, urnState);
cf26e54c 270 storeUnlockObject(urlres_e);
8d709a1b 271 storeUnlockObject(urnState->entry);
272 requestUnlink(urnState->request);
40548fef 273 requestUnlink(urnState->urlres_r);
8d709a1b 274 cbdataFree(urnState);
85491f8d 275}
276
23d92c64 277static wordlist *
d017efc3 278urnParseReply(const char *inbuf)
85491f8d 279{
23d92c64 280 char *buf = xstrdup(inbuf);
281 char *token;
282 wordlist *u;
283 wordlist *head = NULL;
284 wordlist **last = &head;
6f6f0853 285 debug(52, 3) ("urnParseReply\n");
23d92c64 286 for (token = strtok(buf, crlf); token; token = strtok(NULL, crlf)) {
6f6f0853 287 debug(52, 3) ("urnParseReply: got '%s'\n", token);
23d92c64 288 u = xmalloc(sizeof(wordlist));
289 u->key = xstrdup(token);
290 u->next = NULL;
291 *last = u;
292 last = &u->next;
85491f8d 293 }
d017efc3 294 safe_free(buf);
23d92c64 295 return head;
85491f8d 296}