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