]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
INITIAL URN SUPPORT by Kostas
authorwessels <>
Sat, 6 Dec 1997 12:16:52 +0000 (12:16 +0000)
committerwessels <>
Sat, 6 Dec 1997 12:16:52 +0000 (12:16 +0000)
15 files changed:
src/Makefile.in
src/cf.data.pre
src/client_side.cc
src/enums.h
src/errorpage.cc
src/ftp.cc
src/net_db.cc
src/protos.h
src/redirect.cc
src/store.cc
src/structs.h
src/tools.cc
src/typedefs.h
src/url.cc
src/urn.cc

index ac305a07766be5330ecd3edd8e899ab1763aa0bb..0037b1fee0e657d9eceb5663c960f1a8cddbeb66 100644 (file)
@@ -1,7 +1,7 @@
 #
 #  Makefile for the Squid Object Cache server
 #
-#  $Id: Makefile.in,v 1.107 1997/12/05 22:01:13 wessels Exp $
+#  $Id: Makefile.in,v 1.108 1997/12/06 05:16:52 wessels Exp $
 #
 #  Uncomment and customize the following to suit your needs:
 #
@@ -127,6 +127,7 @@ OBJS                = \
                tools.o \
                unlinkd.o \
                url.o \
+               urn.o \
                useragent.o \
                wais.o \
                $(XTRA_OBJS)
index bfee8722feb42f570c9c3776a8d24f600ea73ca6..34336ecf3cc0d3c0dae4ee97648ee1c230882d58 100644 (file)
@@ -313,7 +313,9 @@ DOC_START
 source_ping off
 DOC_END
 
+#ifndef USE_URNS
 
+#endif /* USE_URNS */
 NAME: neighbor_timeout neighbour_timeout
 COMMENT: (seconds)
 DEFAULT: 2 seconds
@@ -750,7 +752,9 @@ DOC_START
 ftp_list_width 32
 DOC_END
 
+#ifndef USE_URNS
 
+#endif /* USE_URNS */
 NAME: cache_dns_program
 TYPE: string
 DEFAULT: @DEFAULT_DNSSERVER@
@@ -761,7 +765,9 @@ DOC_START
 cache_dns_program @DEFAULT_DNSSERVER@
 DOC_END
 
+#ifndef USE_URNS
 
+#endif /* USE_URNS */
 NAME: dns_children
 TYPE: int
 DEFAULT: 5
@@ -1041,6 +1047,18 @@ DOC_START
 connect_timeout 120 seconds
 DOC_END
 
+#ifdef USE_URNS
+NAME: siteselect_timeout
+COMMENT: time-units
+TYPE: time_t
+LOC: Config.Timeout.siteSelect
+DEFAULT: 4 seconds
+DOC_START
+       For URN to multiple URL's URL selection
+
+siteselect_timeout 4 seconds
+DOC_END
+#endif /* USE_URNS */
 
 NAME: read_timeout
 COMMENT: time-units
@@ -2073,5 +2091,8 @@ DOC_START
                snmp_agent_conf community public squid squid
                snmp_agent_conf community readwrite all all
 DOC_END
+#ifdef USE_URNS
+
+#endif /* USE_URNS */
 
 EOF
index 7ab2051ba972d3d3390e7c74e27b4aa890ffaf5b..c2cbc5bb7bfaa16b2f2b882a1f46b7bb722b1330 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: client_side.cc,v 1.173 1997/12/04 23:07:51 wessels Exp $
+ * $Id: client_side.cc,v 1.174 1997/12/06 05:16:53 wessels Exp $
  *
  * DEBUG: section 33    Client-side Routines
  * AUTHOR: Duane Wessels
@@ -75,7 +75,6 @@ static void clientProcessExpired(void *data);
 static char *clientConstructProxyAuthReply(clientHttpRequest * http);
 static int clientCachable(clientHttpRequest * http);
 static int clientHierarchical(clientHttpRequest * http);
-static StoreEntry *clientCreateStoreEntry(clientHttpRequest *, method_t, int);
 
 static int
 checkAccelOnly(clientHttpRequest * http)
@@ -145,7 +144,7 @@ clientConstructProxyAuthReply(clientHttpRequest * http)
        "<ADDRESS>\n"
        "Generated by %s/%s@%s\n"
        "</ADDRESS>\n",
-       http->url,
+       http->uri,
        Config.adminEmail,
        getMyHostname(),
        Config.errHtmlText,
@@ -165,7 +164,7 @@ clientConstructProxyAuthReply(clientHttpRequest * http)
     return buf;
 }
 
-static StoreEntry *
+StoreEntry *
 clientCreateStoreEntry(clientHttpRequest * h, method_t m, int flags)
 {
     StoreEntry *e;
@@ -180,7 +179,7 @@ clientCreateStoreEntry(clientHttpRequest * h, method_t m, int flags)
        r->protocol = PROTO_NONE;
        h->request = requestLink(r);
     }
-    e = storeCreateEntry(h->url, h->log_url, flags, m);
+    e = storeCreateEntry(h->uri, h->log_uri, flags, m);
     storeClientListAdd(e, h);
     storeClientCopy(e, 0, 0, 4096, get_free_4k_page(), clientSendMoreData, h);
     return e;
@@ -194,10 +193,10 @@ clientAccessCheckDone(int answer, void *data)
     char *redirectUrl = NULL;
     char *buf;
     ErrorState *err = NULL;
-    debug(33, 5) ("clientAccessCheckDone: '%s' answer=%d\n", http->url, answer);
+    debug(33, 5) ("clientAccessCheckDone: '%s' answer=%d\n", http->uri, answer);
     http->acl_checklist = NULL;
     if (answer == ACCESS_ALLOWED) {
-       urlCanonical(http->request, http->url);
+       urlCanonical(http->request, http->uri);
        assert(http->redirect_state == REDIRECT_NONE);
        http->redirect_state = REDIRECT_PENDING;
        redirectStart(http, clientRedirectDone, http);
@@ -208,7 +207,7 @@ clientAccessCheckDone(int answer, void *data)
        http->entry = clientCreateStoreEntry(http, http->request->method, 0);
        storeAppend(http->entry, buf, strlen(buf));
     } else {
-       debug(33, 5) ("Access Denied: %s\n", http->url);
+       debug(33, 5) ("Access Denied: %s\n", http->uri);
        http->log_type = LOG_TCP_DENIED;
        http->entry = clientCreateStoreEntry(http, http->request->method, 0);
        redirectUrl = aclGetDenyInfoUrl(&Config.denyInfoList, AclMatchedName);
@@ -236,29 +235,29 @@ clientRedirectDone(void *data, char *result)
     size_t l;
     request_t *new_request = NULL;
     request_t *old_request = http->request;
-    debug(33, 5) ("clientRedirectDone: '%s' result=%s\n", http->url,
+    debug(33, 5) ("clientRedirectDone: '%s' result=%s\n", http->uri,
        result ? result : "NULL");
     assert(http->redirect_state == REDIRECT_PENDING);
     http->redirect_state = REDIRECT_DONE;
     if (result)
        new_request = urlParse(old_request->method, result);
     if (new_request) {
-       safe_free(http->url);
+       safe_free(http->uri);
        /* need to malloc because the URL returned by the redirector might
         * not be big enough to append the local domain
         * -- David Lamkin drl@net-tel.co.uk */
        l = strlen(result) + Config.appendDomainLen + 5;
-       http->url = xcalloc(l, 1);
-       xstrncpy(http->url, result, l);
+       http->uri = xcalloc(l, 1);
+       xstrncpy(http->uri, result, l);
        new_request->http_ver = old_request->http_ver;
        new_request->headers = old_request->headers;
        new_request->headers_sz = old_request->headers_sz;
        requestUnlink(old_request);
        http->request = requestLink(new_request);
-       urlCanonical(http->request, http->url);
+       urlCanonical(http->request, http->uri);
     }
     clientParseRequestHeaders(http);
-    fd_note(http->conn->fd, http->url);
+    fd_note(http->conn->fd, http->uri);
     clientProcessRequest(http);
 }
 
@@ -266,13 +265,13 @@ static void
 clientProcessExpired(void *data)
 {
     clientHttpRequest *http = data;
-    char *url = http->url;
+    char *url = http->uri;
     StoreEntry *entry = NULL;
-    debug(33, 3) ("clientProcessExpired: '%s'\n", http->url);
+    debug(33, 3) ("clientProcessExpired: '%s'\n", http->uri);
     EBIT_SET(http->request->flags, REQ_REFRESH);
     http->old_entry = http->entry;
     entry = storeCreateEntry(url,
-       http->log_url,
+       http->log_uri,
        http->request->flags,
        http->request->method);
     /* NOTE, don't call storeLockObject(), storeCreateEntry() does it */
@@ -480,7 +479,7 @@ clientPurgeRequest(clientHttpRequest * http)
        return;
     }
     http->log_type = LOG_TCP_MISS;
-    k = storeKeyPublic(http->url, METHOD_GET);
+    k = storeKeyPublic(http->uri, METHOD_GET);
     if ((entry = storeGet(k)) == NULL) {
        http->http_code = HTTP_NOT_FOUND;
     } else {
@@ -529,7 +528,7 @@ httpRequestFree(void *data)
        mem = entry->mem_obj;
     if (http->out.size || http->log_type) {
        http->al.icp.opcode = 0;
-       http->al.url = http->url;
+       http->al.url = http->uri;
        if (mem) {
            http->al.http.code = mem->reply->code;
            http->al.http.content_type = mem->reply->content_type;
@@ -551,15 +550,16 @@ httpRequestFree(void *data)
        clientdbUpdate(conn->peer.sin_addr, http->log_type, PROTO_HTTP);
     }
     if (http->redirect_state == REDIRECT_PENDING)
-       redirectUnregister(http->url, http);
+       redirectUnregister(http->uri, http);
     if (http->acl_checklist)
        aclChecklistFree(http->acl_checklist);
 #if CHECK_FAILURE_IS_BROKE
     checkFailureRatio(http->log_type, http->al.hier.code);
 #endif
-    safe_free(http->url);
-    safe_free(http->log_url);
+    safe_free(http->uri);
+    safe_free(http->log_uri);
     safe_free(http->al.headers.reply);
+    wordlistDestroy(&http->urls);
     if (entry) {
        http->entry = NULL;
        storeUnregister(entry, http);
@@ -648,7 +648,7 @@ clientParseRequestHeaders(clientHttpRequest * http)
        if (strstr(t, ThisCache)) {
            if (!http->accel) {
                debug(12, 1) ("WARNING: Forwarding loop detected for '%s'\n",
-                   http->url);
+                   http->uri);
                debug(12, 1) ("--> %s\n", t);
            }
            EBIT_SET(request->flags, REQ_LOOPDETECT);
@@ -681,7 +681,7 @@ clientParseRequestHeaders(clientHttpRequest * http)
 static int
 clientCachable(clientHttpRequest * http)
 {
-    const char *url = http->url;
+    const char *url = http->uri;
     request_t *req = http->request;
     method_t method = req->method;
     const wordlist *p;
@@ -712,7 +712,7 @@ clientCachable(clientHttpRequest * http)
 static int
 clientHierarchical(clientHttpRequest * http)
 {
-    const char *url = http->url;
+    const char *url = http->uri;
     request_t *request = http->request;
     method_t method = request->method;
     const wordlist *p = NULL;
@@ -1145,7 +1145,7 @@ static log_type
 clientProcessRequest2(clientHttpRequest * http)
 {
     const request_t *r = http->request;
-    const cache_key *key = storeKeyPublic(http->url, r->method);
+    const cache_key *key = storeKeyPublic(http->uri, r->method);
     StoreEntry *e;
     if ((e = http->entry = storeGet(key)) == NULL) {
        /* this object isn't in the cache */
@@ -1197,7 +1197,7 @@ clientProcessRequest2(clientHttpRequest * http)
 static void
 clientProcessRequest(clientHttpRequest * http)
 {
-    char *url = http->url;
+    char *url = http->uri;
     StoreEntry *entry = NULL;
     request_t *r = http->request;
     int fd = http->conn->fd;
@@ -1234,10 +1234,10 @@ clientProcessRequest(clientHttpRequest * http)
     http->log_type = clientProcessRequest2(http);
     debug(12, 4) ("clientProcessRequest: %s for '%s'\n",
        log_tags[http->log_type],
-       http->url);
+       http->uri);
     if ((entry = http->entry) != NULL) {
        storeLockObject(entry);
-       storeCreateMemObject(entry, http->url, http->log_url);
+       storeCreateMemObject(entry, http->uri, http->log_uri);
        storeClientListAdd(entry, http);
     }
     http->out.offset = 0;
@@ -1278,7 +1278,7 @@ clientProcessRequest(clientHttpRequest * http)
 static void
 clientProcessMiss(clientHttpRequest * http)
 {
-    char *url = http->url;
+    char *url = http->uri;
     request_t *r = http->request;
     char *request_hdr = r->headers;
     aclCheck_t ch;
@@ -1365,8 +1365,8 @@ parseHttpRequest(ConnStateData * conn, method_t * method_p, int *status,
        http->conn = conn;
        http->start = current_time;
        http->req_sz = conn->in.offset;
-       http->url = xstrdup("error:invalid-request-method");
-       http->log_url = xstrdup("error:invalid-request-method");
+       http->uri = xstrdup("error:invalid-request-method");
+       http->log_uri = xstrdup("error:invalid-request-method");
        *headers_sz_p = conn->in.offset;
        *headers_p = inbuf;
        *method_p = METHOD_NONE;
@@ -1381,8 +1381,8 @@ parseHttpRequest(ConnStateData * conn, method_t * method_p, int *status,
        http->conn = conn;
        http->start = current_time;
        http->req_sz = conn->in.offset;
-       http->url = xstrdup("error:unsupported-request-method");
-       http->log_url = xstrdup("error:unsupported-request-method");
+       http->uri = xstrdup("error:unsupported-request-method");
+       http->log_uri = xstrdup("error:unsupported-request-method");
        *headers_sz_p = conn->in.offset;
        *headers_p = inbuf;
        *method_p = METHOD_NONE;
@@ -1400,8 +1400,8 @@ parseHttpRequest(ConnStateData * conn, method_t * method_p, int *status,
        http->conn = conn;
        http->start = current_time;
        http->req_sz = conn->in.offset;
-       http->url = xstrdup("error:missing-url");
-       http->log_url = xstrdup("error:missing-url");
+       http->uri = xstrdup("error:missing-url");
+       http->log_uri = xstrdup("error:missing-url");
        *headers_sz_p = conn->in.offset;
        *headers_p = inbuf;
        *status = -1;
@@ -1418,8 +1418,8 @@ parseHttpRequest(ConnStateData * conn, method_t * method_p, int *status,
        http->conn = conn;
        http->start = current_time;
        http->req_sz = conn->in.offset;
-       http->url = xstrdup("error:missing-http-ident");
-       http->log_url = xstrdup("error:missing-http-ident");
+       http->uri = xstrdup("error:missing-http-ident");
+       http->log_uri = xstrdup("error:missing-http-ident");
        *headers_sz_p = conn->in.offset;
        *headers_p = inbuf;
        *status = -1;
@@ -1453,7 +1453,7 @@ parseHttpRequest(ConnStateData * conn, method_t * method_p, int *status,
 
     debug(12, 5) ("parseHttpRequest: Request Header is\n%s\n", *headers_p);
 
-    /* Assign http->url */
+    /* Assign http->uri */
     if ((t = strchr(url, '\n')))       /* remove NL */
        *t = '\0';
     if ((t = strchr(url, '\r')))       /* remove CR */
@@ -1467,12 +1467,12 @@ parseHttpRequest(ConnStateData * conn, method_t * method_p, int *status,
        if (vhost_mode) {
            /* Put the local socket IP address as the hostname */
            url_sz = strlen(url) + 32 + Config.appendDomainLen;
-           http->url = xcalloc(url_sz, 1);
-           snprintf(http->url, url_sz, "http://%s:%d%s",
+           http->uri = xcalloc(url_sz, 1);
+           snprintf(http->uri, url_sz, "http://%s:%d%s",
                inet_ntoa(http->conn->me.sin_addr),
                (int) Config.Accel.port,
                url);
-           debug(12, 5) ("VHOST REWRITE: '%s'\n", http->url);
+           debug(12, 5) ("VHOST REWRITE: '%s'\n", http->uri);
        } else if (opt_accel_uses_host && (t = mime_get_header(req_hdr, "Host"))) {
            /* If a Host: header was specified, use it to build the URL 
             * instead of the one in the Config file. */
@@ -1485,24 +1485,24 @@ parseHttpRequest(ConnStateData * conn, method_t * method_p, int *status,
             * handling requests for non-local servers */
            strtok(t, " :/;@");
            url_sz = strlen(url) + 32 + Config.appendDomainLen;
-           http->url = xcalloc(url_sz, 1);
-           snprintf(http->url, url_sz, "http://%s:%d%s",
+           http->uri = xcalloc(url_sz, 1);
+           snprintf(http->uri, url_sz, "http://%s:%d%s",
                t, (int) Config.Accel.port, url);
        } else {
            url_sz = strlen(Config2.Accel.prefix) + strlen(url) +
                Config.appendDomainLen + 1;
-           http->url = xcalloc(url_sz, 1);
-           snprintf(http->url, url_sz, "%s%s", Config2.Accel.prefix, url);
+           http->uri = xcalloc(url_sz, 1);
+           snprintf(http->uri, url_sz, "%s%s", Config2.Accel.prefix, url);
        }
        http->accel = 1;
     } else {
        /* URL may be rewritten later, so make extra room */
        url_sz = strlen(url) + Config.appendDomainLen + 5;
-       http->url = xcalloc(url_sz, 1);
-       strcpy(http->url, url);
+       http->uri = xcalloc(url_sz, 1);
+       strcpy(http->uri, url);
        http->accel = 0;
     }
-    http->log_url = xstrdup(http->url);
+    http->log_uri = xstrdup(http->uri);
     debug(12, 5) ("parseHttpRequest: Complete request received\n");
     if (free_request)
        safe_free(url);
@@ -1597,19 +1597,19 @@ clientReadRequest(int fd, void *data)
                errorAppendEntry(http->entry, err);
                break;
            }
-           if ((request = urlParse(method, http->url)) == NULL) {
-               debug(12, 5) ("Invalid URL: %s\n", http->url);
+           if ((request = urlParse(method, http->uri)) == NULL) {
+               debug(12, 5) ("Invalid URL: %s\n", http->uri);
                err = errorCon(ERR_INVALID_URL, HTTP_BAD_REQUEST);
                err->src_addr = conn->peer.sin_addr;
-               err->url = xstrdup(http->url);
+               err->url = xstrdup(http->uri);
                http->al.http.code = err->http_status;
                http->entry = clientCreateStoreEntry(http, method, 0);
                errorAppendEntry(http->entry, err);
                safe_free(headers);
                break;
            }
-           safe_free(http->log_url);
-           http->log_url = xstrdup(urlCanonicalClean(request));
+           safe_free(http->log_uri);
+           http->log_uri = xstrdup(urlCanonicalClean(request));
            request->client_addr = conn->peer.sin_addr;
            request->http_ver = http->http_ver;
            request->headers = headers;
@@ -1624,7 +1624,10 @@ clientReadRequest(int fd, void *data)
                break;
            }
            http->request = requestLink(request);
-           clientAccessCheck(http);
+           if (request->protocol == PROTO_URN)
+               urnStart(http);
+           else
+               clientAccessCheck(http);
            /*
             * break here for NON-GET because most likely there is a
             * reqeust body following and we don't want to parse it
index c7144e22970bb780c88644febeed61b59d28a0f7..63079f394d9d8b866db425931bd81c0735bde1f3 100644 (file)
@@ -41,6 +41,7 @@ typedef enum {
     ERR_ZERO_SIZE_OBJECT,
     ERR_FTP_DISABLED,
     ERR_FTP_FAILURE,
+    ERR_URN_RESOLVE,
     ERR_ACCESS_DENIED,
     ERR_MAX
 } err_type;
@@ -252,6 +253,7 @@ typedef enum {
     PROTO_WAIS,
     PROTO_CACHEOBJ,
     PROTO_ICP,
+    PROTO_URN,
     PROTO_MAX
 } protocol_t;
 
index ae9984c4f0878d3cd7f006094beaaebe2995c987..6a8ae3621a8667e9024dda0d1c06c9e1b9c9237d 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: errorpage.cc,v 1.110 1997/12/03 09:00:16 wessels Exp $
+ * $Id: errorpage.cc,v 1.111 1997/12/06 05:16:55 wessels Exp $
  *
  * DEBUG: section 4     Error Generation
  * AUTHOR: Duane Wessels
@@ -236,7 +236,10 @@ errorConvert(char token, ErrorState * err)
        snprintf(buf, CVT_BUF_SZ, "%d", err->xerrno);
        break;
     case 'E':
+       if (err->xerrno)
        snprintf(buf, CVT_BUF_SZ, "(%d) %s", err->xerrno, strerror(err->xerrno));
+       else
+           snprintf(buf, CVT_BUF_SZ, "(%d) -unknown-", err->xerrno);
        break;
     case 'f':
        /* FTP REQUEST LINE */
index 596cd8000d5cd3d5f1c6991ef9d52caa8c7e0cb9..75415d6df6024ae59aafb6cff89523a4ce97e65f 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: ftp.cc,v 1.179 1997/12/06 01:26:02 wessels Exp $
+ * $Id: ftp.cc,v 1.180 1997/12/06 05:16:56 wessels Exp $
  *
  * DEBUG: section 9     File Transfer Protocol (FTP)
  * AUTHOR: Harvest Derived
@@ -1816,6 +1816,8 @@ ftpUrlWith2f(const request_t * request)
     LOCAL_ARRAY(char, portbuf, 32);
     char *t;
     portbuf[0] = '\0';
+    if (request->protocol != PROTO_FTP)
+       return NULL;
     if (request->port != urlDefaultPort(request->protocol))
        snprintf(portbuf, 32, ":%d", request->port);
     loginbuf[0] = '\0';
index fb941a27c8048b486acf6697ab69f6ca38a8223e..e0de4251bfc6da033b8ccb7315e3845aca56bf1c 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: net_db.cc,v 1.54 1997/12/03 01:33:15 wessels Exp $
+ * $Id: net_db.cc,v 1.55 1997/12/06 05:16:57 wessels Exp $
  *
  * DEBUG: section 37    Network Measurement Database
  * AUTHOR: Duane Wessels
@@ -43,6 +43,7 @@ static void netdbHashDelete(const char *key);
 static void netdbHashLink(netdbEntry * n, const char *hostname);
 static void netdbHashUnlink(const char *key);
 static void netdbPurgeLRU(void);
+static netdbEntry *netdbLookupHost(const char *key);
 static net_db_peer *netdbPeerByName(const netdbEntry * n, const char *);
 static net_db_peer *netdbPeerAdd(netdbEntry * n, peer * e);
 static char *netdbPeerName(const char *name);
@@ -673,6 +674,7 @@ var_netdb_entry(struct variable * vp, oid * name, int *length, int exact, int *v
     static netdbEntry *n = NULL;
     static long long_return;
        int cnt=1;
+    int result;
 
     debug(49, 3) ("snmp: var_netdb_entry called with magic=%d\n", vp->magic);
     debug(49, 3) ("snmp: var_netdb_entry with (%d,%d)\n", *length, *var_len);
index 7e3fff753addba012846ffb7136023cd09ca5a3f..8532a182145d8296e398abc7d1b765c425e0314a 100644 (file)
@@ -77,6 +77,7 @@ extern char *clientConstructTraceEcho(clientHttpRequest *);
 extern void clientPurgeRequest(clientHttpRequest *);
 extern int checkNegativeHit(StoreEntry *);
 extern void clientHttpConnectionsOpen(void);
+extern StoreEntry *clientCreateStoreEntry(clientHttpRequest *, method_t, int);
 
 extern int commSetNonBlocking(int fd);
 extern void commSetCloseOnExec(int fd);
@@ -331,8 +332,6 @@ extern void netdbFreeMemory(void);
 extern int netdbHostHops(const char *host);
 extern int netdbHostRtt(const char *host);
 extern void netdbUpdatePeer(request_t *, peer * e, int rtt, int hops);
-extern netdbEntry *netdbGetFirst(hash_table * table);
-extern netdbEntry *netdbGetNext(hash_table * table);
 
 extern void objcachePasswdAdd(cachemgr_passwd **, char *, wordlist *);
 extern void objcachePasswdDestroy(cachemgr_passwd ** a);
@@ -349,6 +348,9 @@ extern int protoUnregister(StoreEntry *, request_t *);
 extern int protoAbortFetch(StoreEntry * entry);
 extern DEFER protoCheckDeferRead;
 
+extern void urnStart(clientHttpRequest *);
+extern UH urnTranslateDone;
+
 extern void redirectStart(clientHttpRequest *, RH *, void *);
 extern void redirectOpenServers(void);
 extern void redirectShutdownServers(void);
index 6837a32692891b278a136038d05c367d8742cf0c..f00c6c1fc040e52c5c8284862267c6c5e4d0a629 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: redirect.cc,v 1.50 1997/12/02 00:17:40 wessels Exp $
+ * $Id: redirect.cc,v 1.51 1997/12/06 05:16:59 wessels Exp $
  *
  * DEBUG: section 29    Redirector
  * AUTHOR: Duane Wessels
@@ -335,13 +335,13 @@ redirectStart(clientHttpRequest * http, RH * handler, void *data)
        fatal_dump("redirectStart: NULL clientHttpRequest");
     if (!handler)
        fatal_dump("redirectStart: NULL handler");
-    debug(29, 5) ("redirectStart: '%s'\n", http->url);
+    debug(29, 5) ("redirectStart: '%s'\n", http->uri);
     if (Config.Program.redirect == NULL) {
        handler(data, NULL);
        return;
     }
     r = xcalloc(1, sizeof(redirectStateData));
-    r->orig_url = xstrdup(http->url);
+    r->orig_url = xstrdup(http->uri);
     r->client_addr = conn->log_addr;
     if (conn->ident.ident == NULL || *conn->ident.ident == '\0') {
        r->client_ident = dash_str;
index f3b7db67721fdd478c54f24afa3b35f906709f03..9d2e471c5cc7568f24c964d675fdfffa8bdb297c 100644 (file)
@@ -1,6 +1,5 @@
-
 /*
- * $Id: store.cc,v 1.354 1997/12/02 05:06:44 wessels Exp $
+ * $Id: store.cc,v 1.355 1997/12/06 05:17:01 wessels Exp $
  *
  * DEBUG: section 20    Storeage Manager
  * AUTHOR: Harvest Derived
index d74b3630c7bcf538f6e551649aefddac492e9786..ea9c80ba326d935b1c110e28dd286b5cd129fb09 100644 (file)
@@ -167,6 +167,7 @@ struct _SquidConfig {
        time_t connect;
        time_t request;
        time_t pconn;
+       time_t siteSelect;
     } Timeout;
     size_t maxRequestSize;
     struct {
@@ -508,8 +509,9 @@ struct _AccessLogEntry {
 struct _clientHttpRequest {
     ConnStateData *conn;
     request_t *request;                /* Parsed URL ... */
-    char *url;
-    char *log_url;
+    char *uri;
+    char *log_uri;
+    wordlist *urls;
     struct {
        char *buf;
        off_t offset;
index 9f1890b429279b67a6910c471c4b9cbd460c8adf..c1a38f25092df7d3bf063213c54c3a5d1e4c73e0 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: tools.cc,v 1.133 1997/12/06 01:26:50 wessels Exp $
+ * $Id: tools.cc,v 1.134 1997/12/06 05:17:03 wessels Exp $
  *
  * DEBUG: section 21    Misc Functions
  * AUTHOR: Harvest Derived
@@ -328,7 +328,7 @@ death(int sig)
 
 
 void
-sigusr2_handle(int signotused)
+sigusr2_handle(int sig)
 {
     static int state = 0;
     /* no debug() here; bad things happen if the signal is delivered during _db_print() */
@@ -460,7 +460,7 @@ debug_trap(const char *message)
 }
 
 void
-sig_child(int signotused)
+sig_child(int sig)
 {
 #ifdef _SQUID_NEXT_
     union wait status;
index d10089868d9d57b0b53a48ea67c38cf28f6dcf78..c6b6a651bea286a5bc9edc78677879721ada961a 100644 (file)
@@ -92,7 +92,8 @@ typedef void IDCB(void *);
 typedef void IPH(const ipcache_addrs *, void *);
 typedef void IRCB(peer *, peer_t, icp_common_t *, void *data);
 typedef void PSC(peer *, void *);
-typedef void RH(void *data, char *result);
+typedef void RH(void *data, char *);
+typedef void UH(void *data, wordlist *);
 typedef int DEFER(int fd, void *data);
 
 typedef void SIH(int fd, void *);      /* swap in */
index 8c0fe01e6b55c92e9293483ff6f6acc082544bab..e2bb2d650c20c90c32bd3a87a19ab1080ff42bf6 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: url.cc,v 1.68 1997/11/28 08:14:09 wessels Exp $
+ * $Id: url.cc,v 1.69 1997/12/06 05:17:04 wessels Exp $
  *
  * DEBUG: section 23    URL Parsing
  * AUTHOR: Duane Wessels
@@ -56,6 +56,7 @@ const char *ProtocolStr[] =
 
 static int url_acceptable[256];
 static const char *const hex = "0123456789abcdef";
+static request_t * urnParse(method_t method, char *urn);
 
 /* convert %xx in url string to a character 
  * Allocate a new string and return a pointer to converted string */
@@ -167,6 +168,8 @@ urlParseProtocol(const char *s)
        return PROTO_WAIS;
     if (strncasecmp(s, "cache_object", 12) == 0)
        return PROTO_CACHEOBJ;
+    if (strncasecmp(s, "urn", 3) == 0)
+       return PROTO_URN;
     return PROTO_NONE;
 }
 
@@ -214,6 +217,8 @@ urlParse(method_t method, char *url)
        port = CONNECT_PORT;
        if (sscanf(url, "%[^:]:%d", host, &port) < 1)
            return NULL;
+    } else if (!strncmp(url, "urn:", 4)) {
+       return urnParse(method, url);
     } else {
        if (sscanf(url, "%[^:]://%[^/]%s", proto, host, urlpath) < 2)
            return NULL;
@@ -271,6 +276,20 @@ urlParse(method_t method, char *url)
     return request;
 }
 
+static request_t *
+urnParse(method_t method, char *urn)
+{
+    request_t *request = NULL;
+    debug(50,5)("urnParse: %s\n", urn);
+    request = get_free_request_t();
+    request->method = method;
+    request->protocol = PROTO_URN;
+    xstrncpy(request->urlpath, &urn[4], MAX_URL);
+    request->max_age = -1;
+    request->max_forwards = -1;
+    return request;
+}
+
 char *
 urlCanonical(const request_t * request, char *buf)
 {
@@ -305,7 +324,9 @@ urlCanonicalClean(const request_t * request)
     LOCAL_ARRAY(char, portbuf, 32);
     LOCAL_ARRAY(char, loginbuf, MAX_LOGIN_SZ + 1);
     char *t;
-    switch (request->method) {
+    if (request->protocol == PROTO_URN) {
+       snprintf(buf, MAX_URL, "urn:%s", request->urlpath);
+    } else switch (request->method) {
     case METHOD_CONNECT:
        snprintf(buf, MAX_URL, "%s:%d", request->host, request->port);
        break;
@@ -393,6 +414,7 @@ urlCheckRequest(const request_t * r)
     if (r->method == METHOD_PURGE)
        return 1;
     switch (r->protocol) {
+    case PROTO_URN:
     case PROTO_HTTP:
     case PROTO_CACHEOBJ:
        rc = 1;
index bae6138d937a21107025b3ae768aa7d1c11a2ad2..14b1c9ba70f32da939efc2f1a8e7cd422ee38149 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * DEBUG: section 50    URN Parsing
+ * DEBUG: section 51    URN Parsing
  * AUTHOR: Kostas Anagnostakis
  *
  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
 
 #include "squid.h"
 
-typedef struct {
-    void *data;
-    char *orig_url;
-    struct in_addr client_addr;
-    const char *client_ident;
-    const char *method_s;
-    RH *handler;
-} urnStateData;
+static STCB urnHandleReply;
+static wordlist *urn_parsebuffer(const char *inbuf);
+static const char *const crlf = "\r\n";
+static char *urnConstructMenu(clientHttpRequest * http);
 
-struct urnQueueData {
-    struct urnQueueData *next;
-    urnStateData *urnState;
-};
-
-static struct urnQueueData *urnQueueHead = NULL;
-static struct urnQueueData **urnQueueTailP = &urnQueueHead;
-
-static char **urn_parsebuffer(const char *,urnserver_t *);
-
-static int urnOpenServer(const char *command);
-static void urnHandleRead(int, void *);
-static void urnStateFree(urnStateData * );
-
-static PF urnShutdownRead;
-static urnserver_t **urn_child_table = NULL;
-static void Enqueue (urnStateData *);
-static urnStateData *Dequeue();
-
-
-static void
-urnDispatch(urnserver_t * urn, urnStateData * r)
-{
-    char *buf = NULL;
-       clientHttpRequest *http=r->data;
-
-    int len;
-    if (r->handler == NULL) {
-        debug(50, 1) ("urnDispatch: skipping '%s' because no handler\n",
-               http->urn);
-        urnStateFree(r);
-        return;
-    }
-    EBIT_SET(urn->flags, HELPER_BUSY);
-    urn->urnState = r;
-    urn->dispatch_time = current_time;
-    buf = get_free_8k_page();
-       snprintf(buf, 8192, "%s\n", http->urn);
-       debug(50,1)("urnDispatch: urn=%s\n",buf);
-    len = strlen(buf);
-    comm_write(urn->outpipe,
-        buf,
-        len,
-        NULL,                   /* Handler */
-        NULL,                   /* Handler-data */
-        put_free_8k_page);
-    debug(50, 5) ("urnDispatch: Request sent to Redirector #%d, %d bytes\n",
-        urn->id, len);
-    commSetSelect(urn->outpipe,
-        COMM_SELECT_READ,
-        urnHandleRead,
-        urn, 0);
-
-}
-
-static void
-urnHandleRead(int fd, void *data)
-{
-    urnserver_t *urnData = data;
-       char **x  = NULL;
-       urnStateData *sd=urnData->urnState;
-       RH *handler=sd->handler;
-    clientHttpRequest *f = sd->data;
-    int len;
-    debug(50,5)("urnHandleRead for %s\n",f->urn);
-    len = read(fd,
-        urnData->urn_buf + urnData->offset,
-        urnData->size - urnData->offset);
-    fd_bytes(fd, len, FD_READ);
-    debug(50, 5) ("urnHandleRead: Result from URN ID %d (%d bytes)\n",
-        urnData->id, len);
-    if (len <= 0) {
-        if (len < 0 && ignoreErrno(errno)) {
-            commSetSelect(fd,
-                COMM_SELECT_READ,
-                urnHandleRead,
-                urnData,
-                0);
-            return;
-        }
-        debug(50, EBIT_TEST(urnData->flags, HELPER_CLOSING) ? 5 : 1)
-            ("FD %d: Connection from URNSERVER #%d is closed, disabling\n",
-            fd, urnData->id);
-        urnData->flags = 0;
-        commSetSelect(fd, COMM_SELECT_WRITE, NULL, NULL, 0);
-        comm_close(fd);
-        return;
-    }
-    urnData->offset += len;
-    urnData->urn_buf[urnData->offset] = '\0';
-    if (strstr(urnData->urn_buf, "$end\n")) {
-        /* end of record found */
-        x = urn_parsebuffer(urnData->urn_buf, urnData);
-            urnData->offset = 0;
-            urnData->urn_buf[0] = '\0';
-           f->urls=x;
-           if (f->urls)
-               handler(f, f->urls[0]);
-           else 
-               handler(f, NULL);
-#ifdef HAVE_URNLOCKS
-        urnUnlockEntry(f);        /* unlock from URN_DISPATCHED */
-#endif
-    }
-    if (urnData->offset == 0) {
-        urnData->data = NULL;
-        EBIT_CLR(urnData->flags, HELPER_BUSY);
-    }
-    /* reschedule */
-    commSetSelect(urnData->inpipe,
-        COMM_SELECT_READ,
-        urnHandleRead,
-        urnData, 0);
-}
-
-void
-urnFindClosestStart(clientHttpRequest *http,RH *handler, void *data)
+wordlist *
+urnFindMinRtt(wordlist * urls, method_t m, int *rtt_ret)
 {
-       int i=0;
-       int avail=0;
-       double min_rtt=-1.0;
-       int min_nr=0;
-       static request_t *tmpr[MAX_URNTOURL];
-       netdbEntry *net=NULL;
-
-       assert(http->urls);
-       for (i=0;http->urls[i]!=NULL;i++)
-       {
-               tmpr[i]=urlParse(http->request->method,http->urls[i]);
-               debug(50,5)("Parsed %s\n",http->urls[i]);
-               net=netdbLookupHost(tmpr[i]->host);
-               if (net==NULL)
-               {
-                       debug(50,5)("Pinging up %s\n",tmpr[i]->host);
-                       netdbPingSite(tmpr[i]->host);
-               }
-               else debug(50,5)("Already here with %s and rtt=%f\n",
-                       tmpr[i]->host,net->rtt);
+    int min_rtt = 0;
+    request_t *r;
+    int rtt;
+    wordlist *w;
+    wordlist *min_w = NULL;
+    debug(50, 1) ("urnFindMinRtt\n");
+    assert(urls != NULL);
+    for (w = urls; w; w = w->next) {
+       r = urlParse(m, w->key);
+       if (r == NULL)
+           continue;
+       debug(50, 1) ("Parsed %s\n", w->key);
+       rtt = netdbHostRtt(r->host);
+       if (rtt == 0) {
+           debug(50, 1) ("Pinging %s\n", r->host);
+           netdbPingSite(r->host);
+           put_free_request_t(r);
+           continue;
        }
-       net=NULL;
-       for (i=0, avail=0;http->urls[i]!=NULL;i++)
-               if ((net=netdbLookupHost(tmpr[i]->host))!=NULL)
-               {
-                       avail++;
-                       if (min_rtt==-1.0 || net->rtt<min_rtt)
-                       {
-                               min_rtt=net->rtt;
-                               min_nr=i;
-                       }
-               }
-       if (avail>1)    /* we got one */
-       {
-               http->url=http->urls[min_nr];
-               urnFindClosestDone(0,http);
-               return;
-       }
-
-       /* none received yet, must set timeout and wait */
-       commSetTimeout(http->conn->fd, Config.Timeout.siteSelect, 
-               (void *)urnFindClosestDone, http);
-}
-
-static void
-urnNudgeQueue(void)
-{
-    urnserver_t *urnData;
-    urnStateData *i = NULL;
-    while ((urnData = urnGetFirstAvailable()) && (i = Dequeue()))
-        urnDispatch(urnData, i);
+       debug(0, 0) ("%s rtt=%d\n", r->host, rtt);
+       if (rtt == 0)
+               continue;
+       if (rtt > min_rtt && min_rtt != 0)
+               continue;
+       min_rtt = rtt;
+       min_w = w;
+       put_free_request_t(r);
+    }
+    if (rtt_ret)
+       *rtt_ret = min_rtt;
+    debug(50, 1) ("Returning '%s' RTT %d\n",
+       min_w ? min_w->key : "NONE",
+       min_rtt);
+    return min_w;
 }
 
 void
-urnTranslateStart(clientHttpRequest * http, RH * handler, void *data)
+urnStart(clientHttpRequest * http)
 {
-    ConnStateData *conn = http->conn;
-    urnStateData *r = NULL;
-    urnserver_t *urns = NULL;
-    if (!http)
-        fatal_dump("urnTranslateStart: NULL clientHttpRequest");
-    if (!handler)
-        fatal_dump("urnTranslateStart: NULL handler");
-    debug(50, 5) ("urnStart: '%s'\n", http->urn);
-    if (Config.Program.urnserver == NULL) {
-        handler(data, NULL);
-        return;
+    LOCAL_ARRAY(char, urlres, 4096);
+    StoreEntry *e;
+    request_t *r = http->request;
+    request_t *urlres_r = NULL;
+    const cache_key *k;
+    char *t;
+    debug(50, 1) ("urnStart\n");
+    assert(http != NULL);
+    debug(50, 1) ("urnStart: '%s'\n", http->uri);
+    t = strchr(r->urlpath, ':');
+    if (t == NULL) {
+        ErrorState *err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND);
+       err->request = requestLink(http->request);
+       err->url = http->uri;
+       err->src_addr = http->conn->peer.sin_addr;
+       errorAppendEntry(http->entry, err);
+       return;
     }
-    r = xcalloc(1, sizeof(urnStateData));
-    r->client_addr = conn->log_addr;
-    if (conn->ident.ident == NULL || *conn->ident.ident == '\0') {
-        r->client_ident = dash_str;
-    } else {
-        r->client_ident = conn->ident.ident;
+    *t = '\0';
+    snprintf(urlres, 4096, "http://%s/uri-res/N2L?%s", r->urlpath, t+1);
+    k = storeKeyPublic(urlres, METHOD_GET);
+    urlres_r = urlParse(METHOD_GET, urlres);
+    urlres_r->headers = xstrdup("Accept: */*\r\n\r\n");
+    urlres_r->headers_sz = strlen(urlres_r->headers);
+    if ((e = storeGet(k)) == NULL) {
+       e = storeCreateEntry(urlres, urlres, 0, METHOD_GET);
+       storeClientListAdd(e, http);
+       protoDispatch(0, e, urlres_r);
     }
-    r->method_s = RequestMethodStr[http->request->method];
-    r->handler = handler;
-    r->data = http;
-
-    /*
-     * Build a URL of the form http://host/uri-res?path
-     *
-     * Create a key
-     * storeGet(key);
-     * if NULL {
-     *     call protoStart()  or httpStart()
-     *  }
-     *  register to receive the data
-     *  storeClientCopy(..., urnHandleSomething, r);
-     * 
-     */
-     
-       
-    if ((urns = urnGetFirstAvailable()))
-       {
-       debug(50,5)("urnTranslateStart: dispatching with %s\n",http->urn);
-        urnDispatch(urns, r);
-       }
-    else
-        Enqueue(r);
-}
-
-static void
-urnStateFree(urnStateData * r)
-{
-    safe_free(r->orig_url);
-    safe_free(r);
+    http->entry = e;
+    storeClientCopy(e, 0, 0, 4096, get_free_4k_page(), urnHandleReply, http);
 }
 
 static void
-Enqueue(urnStateData * r)
-{
-    struct urnQueueData *new = xcalloc(1, sizeof(struct urnQueueData));
-    new->urnState = r;
-    *urnQueueTailP = new;
-    urnQueueTailP = &new->next;
-}
-
-static urnStateData *
-Dequeue(void)
-{
-    struct urnQueueData *old = NULL;
-    urnStateData *r = NULL;
-    if (urnQueueHead) {
-        r = urnQueueHead->urnState;
-        old = urnQueueHead;
-        urnQueueHead = urnQueueHead->next;
-        if (urnQueueHead == NULL)
-            urnQueueTailP = &urnQueueHead;
-        safe_free(old);
-    }
-    return r;
-}
-
-
-#ifdef URN_URL_TOGETHER
-request_t *
-urlParse(method_t method, char *url)
-{
-    LOCAL_ARRAY(char, proto, MAX_URL);
-    LOCAL_ARRAY(char, login, MAX_URL);
-    LOCAL_ARRAY(char, host, MAX_URL);
-    LOCAL_ARRAY(char, urlpath, MAX_URL);
-    request_t *request = NULL;
-    char *t = NULL;
-    int port;
-    protocol_t protocol = PROTO_NONE;
-    int l;
-    proto[0] = host[0] = urlpath[0] = login[0] = '\0';
-
-    if ((l = strlen(url)) + Config.appendDomainLen > (MAX_URL - 1)) {
-       /* terminate so it doesn't overflow other buffers */
-       *(url + (MAX_URL >> 1)) = '\0';
-       debug(50, 0) ("urlParse: URL too large (%d bytes)\n", l);
-       return NULL;
-    }
-    if (method == METHOD_CONNECT) {
-       port = CONNECT_PORT;
-       if (sscanf(url, "%[^:]:%d", host, &port) < 1)
-           return NULL;
-    } else {
-       if (sscanf(url, "%[^:]://%[^/]%s", proto, host, urlpath) < 2)
-           return NULL;
-       protocol = urlParseProtocol(proto);
-       port = urlDefaultPort(protocol);
-       /* Is there any login informaiton? */
-       if ((t = strrchr(host, '@'))) {
-           strcpy(login, host);
-           t = strrchr(login, '@');
-           *t = 0;
-           strcpy(host, t + 1);
-       }
-       if ((t = strrchr(host, ':'))) {
-           *t++ = '\0';
-           if (*t != '\0')
-               port = atoi(t);
-       }
-    }
-    for (t = host; *t; t++)
-       *t = tolower(*t);
-    /* remove trailing dots from hostnames */
-    while ((l = strlen(host)) > 0 && host[--l] == '.')
-       host[l] = '\0';
-    if (Config.appendDomain && !strchr(host, '.'))
-       strncat(host, Config.appendDomain, SQUIDHOSTNAMELEN);
-    if (port == 0) {
-       debug(50, 0) ("urlParse: Invalid port == 0\n");
-       return NULL;
-    }
-#ifdef HARDCODE_DENY_PORTS
-    /* These ports are filtered in the default squid.conf, but
-     * maybe someone wants them hardcoded... */
-    if (port == 7 || port == 9 || port = 19) {
-       debug(50, 0) ("urlParse: Deny access to port %d\n", port);
-       return NULL;
-    }
-#endif
-#ifdef REMOVE_FTP_TRAILING_SLASHES
-    /* remove trailing slashes from FTP URLs */
-    if (protocol == PROTO_FTP) {
-       t = urlpath + strlen(urlpath);
-       while (t > urlpath && *(--t) == '/')
-           *t = '\0';
-    }
-#endif
-    request = get_free_request_t();
-    request->method = method;
-    request->protocol = protocol;
-    xstrncpy(request->host, host, SQUIDHOSTNAMELEN);
-    xstrncpy(request->login, login, MAX_LOGIN_SZ);
-    request->port = (u_short) port;
-    xstrncpy(request->urlpath, urlpath, MAX_URL);
-    request->max_age = -1;
-    request->max_forwards = -1;
-    return request;
-}
-
-char *
-urlCanonical(const request_t * request, char *buf)
+urnHandleReply(void *data, char *buf, ssize_t size)
 {
-    LOCAL_ARRAY(char, urlbuf, MAX_URL);
-    LOCAL_ARRAY(char, portbuf, 32);
-    if (buf == NULL)
-       buf = urlbuf;
-    switch (request->method) {
-    case METHOD_CONNECT:
-       snprintf(buf, MAX_URL, "%s:%d", request->host, request->port);
-       break;
-    default:
-       portbuf[0] = '\0';
-       if (request->port != urlDefaultPort(request->protocol))
-           snprintf(portbuf, 32, ":%d", request->port);
-       snprintf(buf, MAX_URL, "%s://%s%s%s%s%s",
-           ProtocolStr[request->protocol],
-           request->login,
-           *request->login ? "@" : null_string,
-           request->host,
-           portbuf,
-           request->urlpath);
-       break;
+    clientHttpRequest *http = data;
+    StoreEntry *entry = http->entry;
+    char *s = NULL;
+    wordlist *urls = NULL;
+    debug(50, 1) ("urnHandleReply: Called with size=%d.\n", size);
+    if (entry->store_status == STORE_ABORTED) {
+       put_free_4k_page(buf);
+       return;
     }
-    return buf;
-}
-
-char *
-urlCanonicalClean(const request_t * request)
-{
-    LOCAL_ARRAY(char, buf, MAX_URL);
-    LOCAL_ARRAY(char, portbuf, 32);
-    LOCAL_ARRAY(char, loginbuf, MAX_LOGIN_SZ + 1);
-    char *t;
-    switch (request->method) {
-    case METHOD_CONNECT:
-       snprintf(buf, MAX_URL, "%s:%d", request->host, request->port);
-       break;
-    default:
-       portbuf[0] = '\0';
-       if (request->port != urlDefaultPort(request->protocol))
-           snprintf(portbuf, 32, ":%d", request->port);
-       loginbuf[0] = '\0';
-       if (strlen(request->login) > 0) {
-           strcpy(loginbuf, request->login);
-           if ((t = strchr(loginbuf, ':')))
-               *t = '\0';
-           strcat(loginbuf, "@");
-       }
-       snprintf(buf, MAX_URL, "%s://%s%s%s%s",
-           ProtocolStr[request->protocol],
-           loginbuf,
-           request->host,
-           portbuf,
-           request->urlpath);
-       if ((t = strchr(buf, '?')))
-           *t = '\0';
-       break;
+    if (size == 0) {
+       put_free_4k_page(buf);
+       return;
+    } else if (size < 0) {
+       put_free_4k_page(buf);
+       return;
     }
-    return buf;
-}
-
-char *
-urlClean(char *dirty)
-{
-    char *clean;
-    request_t *r = urlParse(METHOD_GET, dirty);
-    if (r == NULL)
-       return dirty;
-    clean = urlCanonicalClean(r);
-    put_free_request_t(r);
-    return clean;
-}
-
-
-request_t *
-requestLink(request_t * request)
-{
-    request->link_count++;
-    return request;
-}
-
-void
-requestUnlink(request_t * request)
-{
-    if (request == NULL)
+    if (entry->store_status == STORE_PENDING) {
+       storeClientCopy(entry,
+           entry->mem_obj->inmem_hi,
+           0,
+           SM_PAGE_SIZE,
+           buf,
+           urnHandleReply,
+           http);
        return;
-    request->link_count--;
-    if (request->link_count)
+    }
+    /* we know its STORE_OK */
+    s = mime_headers_end(buf);
+    if (s == NULL) {
+       debug(0, 0) ("urnHandleReply: didn't find end-of-headers for %s\n",
+           storeUrl(entry));
        return;
-    safe_free(request->headers);
-    put_free_request_t(request);
-}
-
-int
-matchDomainName(const char *domain, const char *host)
-{
-    int offset;
-    if ((offset = strlen(host) - strlen(domain)) < 0)
-       return 0;               /* host too short */
-    if (strcasecmp(domain, host + offset) != 0)
-       return 0;               /* no match at all */
-    if (*domain == '.')
-       return 1;
-    if (*(host + offset - 1) == '.')
-       return 1;
-    if (offset == 0)
-       return 1;
-    return 0;
-}
-
-int
-urlCheckRequest(const request_t * r)
-{
-    int rc = 0;
-    if (r->method == METHOD_CONNECT)
-       return 1;
-    if (r->method == METHOD_TRACE)
-       return 1;
-    if (r->method == METHOD_PURGE)
-       return 1;
-    switch (r->protocol) {
-    case PROTO_HTTP:
-    case PROTO_CACHEOBJ:
-       rc = 1;
-       break;
-    case PROTO_FTP:
-       if (r->method == METHOD_PUT)
-           rc = 1;
-    case PROTO_GOPHER:
-    case PROTO_WAIS:
-       if (r->method == METHOD_GET)
-           rc = 1;
-       else if (r->method == METHOD_HEAD)
-           rc = 1;
-       break;
-    default:
-       break;
     }
-    return rc;
-}
-#endif
-
-
-
-void
-urnShutdownServers(void)
-{
-    urnserver_t *urn = NULL;
-    int k;
-
-    debug(50, 3) ("urnShutdownServers:\n");
-
-    for (k = 0; k < NUrnServersAlloc; k++) {
-        urn = *(urn_child_table + k);
-        if (!EBIT_TEST(urn->flags, HELPER_ALIVE)) {
-            debug(50, 3) ("urnShutdownServers: #%d is NOT ALIVE.\n", urn->id);
-            continue;
-        }
-        if (EBIT_TEST(urn->flags, HELPER_BUSY)) {
-            debug(50, 3) ("urnShutdownServers: #%d is BUSY.\n", urn->id);
-            EBIT_SET(urn->flags, HELPER_SHUTDOWN);
-            continue;
-        }
-        if (EBIT_TEST(urn->flags, HELPER_CLOSING)) {
-            debug(50, 3) ("urnShutdownServers: #%d is CLOSING.\n", urn->id);
-            continue;
-        }
-        urnShutdownServer(urn);
+    assert(http->entry->mem_obj);
+    assert(http->entry->mem_obj->reply);
+    httpParseReplyHeaders(buf, http->entry->mem_obj->reply);
+    debug(50, 1) ("mem->reply exists, code=%d.\n",
+       http->entry->mem_obj->reply->code);
+    if (http->entry->mem_obj->reply->code != 200) {
+       debug(50, 1) ("urnHandleReply: failed.\n");
+       /* XX - return error message */
+       urnTranslateDone(http, NULL);
+       return;
     }
+    while (isspace(*s))
+       s++;
+    urls = urn_parsebuffer(s);
+    urnTranslateDone(http, urls);
+    put_free_4k_page(buf);
 }
 
-void
-urnShutdownServer(urnserver_t * urn)
-{
-    static char *shutdown_cmd = "$shutdown\n";
-    debug(50, 3) ("urnShutdownServer: sending '$shutdown' to urnserver #%d\n",
-        urn->id);
-    debug(50, 3) ("urnShutdownServer: --> FD %d\n", urn->outpipe);
-    cbdataLock(urn);
-    comm_write(urn->outpipe,
-        xstrdup(shutdown_cmd),
-        strlen(shutdown_cmd),
-        NULL,                   /* Handler */
-        NULL,                   /* Handler-data */
-        xfree);
-    commSetSelect(urn->inpipe,
-        COMM_SELECT_READ,
-        urnShutdownRead,
-        urn,
-        0);
-    EBIT_SET(urn->flags, HELPER_CLOSING);
-}
-
-static void
-urnShutdownRead(int fd, void *data)
-{
-    urnserver_t *urn = data;
-    debug(50, EBIT_TEST(urn->flags, HELPER_CLOSING) ? 5 : 1)
-        ("FD %d: Connection from URNSERVER #%d is closed, disabling\n",
-        fd,
-        urn->id);
-    urn->flags = 0;
-    commSetSelect(fd, COMM_SELECT_WRITE, NULL, NULL, 0);
-    cbdataUnlock(urn);
-    comm_close(fd);
-}
 
-void
-urnOpenServers(void)
+static wordlist *
+urn_parsebuffer(const char *inbuf)
 {
-    int N = Config.urnChildren;
-    char *prg = Config.Program.urnserver;
-    int k;
-    int urnsocket;
-    LOCAL_ARRAY(char, fd_note_buf, FD_DESC_SZ);
-    char *s;
-       
-    urnFreeMemory();
-    urn_child_table = xcalloc(N, sizeof(urnserver_t *));
-    NUrnServersAlloc = 0;
-    for (k = 0; k < N; k++) {
-        urn_child_table[k] = xcalloc(1, sizeof(urnserver_t));
-        cbdataAdd(urn_child_table[k]);
-        if ((urnsocket = urnOpenServer(prg)) < 0) {
-            debug(50, 1) ("urnOpenServers: WARNING: Failed to start 'urnserver' #%d. %s \n", k + 1, prg);
-            EBIT_CLR(urn_child_table[k]->flags, HELPER_ALIVE);
-            urn_child_table[k]->id = k + 1;
-            urn_child_table[k]->inpipe = -1;
-            urn_child_table[k]->outpipe = -1;
-        } else {
-            debug(50, 4) ("urnOpenServers: FD %d connected to %s #%d.\n",
-                urnsocket, prg, k + 1);
-            EBIT_SET(urn_child_table[k]->flags, HELPER_ALIVE);
-            urn_child_table[k]->id = k + 1;
-            urn_child_table[k]->inpipe = urnsocket;
-            urn_child_table[k]->outpipe = urnsocket;
-            urn_child_table[k]->answer = squid_curtime;
-            urn_child_table[k]->dispatch_time = current_time;
-            urn_child_table[k]->size = URN_INBUF_SZ - 1;
-            urn_child_table[k]->offset = 0;
-            if ((s = strrchr(prg, '/')))
-                s++;
-            else
-                s = prg;
-            snprintf(fd_note_buf, FD_DESC_SZ, "%s #%d", s, urn_child_table[k]->id);
-            fd_note(urn_child_table[k]->inpipe, fd_note_buf);
-            commSetNonBlocking(urn_child_table[k]->inpipe);
-            debug(50, 3) ("urnOpenServers: 'urn_server' %d started\n", k);
-            NUrnServersAlloc++;
-        }
+    char *buf = xstrdup(inbuf);
+    char *token;
+    wordlist *u;
+    wordlist *head = NULL;
+    wordlist **last = &head;
+    debug(50, 1) ("urn_parsebuffer\n");
+    for (token = strtok(buf, crlf); token; token = strtok(NULL, crlf)) {
+       debug(0, 0) ("urn_parsebuffer: got '%s'\n", token);
+       u = xmalloc(sizeof(wordlist));
+       u->key = xstrdup(token);
+       u->next = NULL;
+       *last = u;
+       last = &u->next;
     }
-    if (NUrnServersAlloc == 0 && Config.urnChildren > 0)
-        fatal("Failed to start any urnservers");
-    debug(50, 1) ("Started %d 'urnserver' processes\n", NUrnServersAlloc);
+    return head;
 }
 
 void
-urnFreeMemory(void)
-{
-    int k;
-    /* free old structures if present */
-    if (urn_child_table) {
-        for (k = 0; k < NUrnServersAlloc; k++)
-            cbdataFree(urn_child_table[k]);
-        safe_free(urn_child_table);
-    }
-}
-urnserver_t *
-urnGetFirstAvailable(void)
-{
-    int k;
-    urnserver_t *urn = NULL;
-    for (k = 0; k < NUrnServersAlloc; k++) {
-        urn = *(urn_child_table + k);
-        if (EBIT_TEST(urn->flags, HELPER_BUSY))
-            continue;
-        if (EBIT_TEST(urn->flags, HELPER_CLOSING))
-            continue;
-        if (!EBIT_TEST(urn->flags, HELPER_ALIVE))
-            continue;
-        return urn;
-    }
-    return NULL;
-}
-
-static int
-urnOpenServer(const char *command)
+urnTranslateDone(void *data, wordlist * urls)
 {
-    pid_t pid;
-    struct sockaddr_in S;
-    int cfd;
-    int sfd;
-    int fd;
-    int len;
-    LOCAL_ARRAY(char, buf, 128);
-
-    cfd = comm_open(SOCK_STREAM,
-        0,
-        local_addr,
-        0,
-        COMM_NOCLOEXEC,
-        "urnserver listen socket");
-    if (cfd < 0) {
-        debug(50, 0) ("urnOpenServer: Failed to create urnserver\n");
-        return -1;
-    }
-    len = sizeof(S);
-    memset(&S, '\0', len);
-    if (getsockname(cfd, (struct sockaddr *) &S, &len) < 0) {
-        debug(50, 5) ("urnOpenServer: getsockname: %s\n", xstrerror());
-        comm_close(cfd);
-        return -1;
-    }
-    listen(cfd, 1);
-
-    /* flush or else we get dup data if unbuffered_logs is set */
-    logsFlush();
-    if ((pid = fork()) < 0) {
-        debug(50, 5) ("urnOpenServer: fork: %s\n", xstrerror());
-        comm_close(cfd);
-               fprintf(stderr,"ERR 1\n");
-        return -1;
-    }
-    if (pid > 0) {              /* parent */
-        comm_close(cfd);        /* close shared socket with child */
-        /* open new socket for parent process */
-        sfd = comm_open(SOCK_STREAM,
-            0,                  /* protocol */
-            local_addr,
-            0,                  /* port */
-            0,                  /* flags */
-            "squid <-> urnserver");
-        if (sfd == COMM_ERROR) {
-            comm_close(sfd);
-            return -1;
-       }
-        if (comm_connect_addr(sfd, &S) == COMM_ERROR) {
-            comm_close(sfd);
-            return -1;
-        }
-        if (write(sfd, "$hello\n", 7) < 0) {
-            debug(50, 0) ("urnOpenServer: $hello write test failed \n");
-               perror("squid");
-            comm_close(sfd);
-            return -1;
-        }
-        memset(buf, '\0', 128);
-        if (read(sfd, buf, 127) < 0) {
-            debug(50, 0) ("urnOpenServer: $hello read test failed\n");
-            debug(50, 0) ("--> read: %s\n", xstrerror());
-            comm_close(sfd);
-            return -1;
-        } else if (strcmp(buf, "$alive\n$end\n")) {
-            debug(50, 0) ("urnOpenServer: $hello read test failed\n");
-            debug(50, 0) ("--> got '%s'\n", rfc1738_escape(buf));
-            comm_close(sfd);
-            return -1;
-        }
-        commSetTimeout(sfd, -1, NULL, NULL);
-        return sfd;
+    clientHttpRequest *http = data;
+    request_t *new_request = NULL;
+    request_t *old_request = http->request;
+    ErrorState *err = NULL;
+    wordlist *min_w;
+    char *buf;
+    debug(50, 1) ("urnTranslateDone\n");
+    if ((http->urls = urls) == NULL) { /* unkown URN error */
+       debug(50, 1) ("urnTranslateDone: unknown URN (%s).\n", http->uri);
+       http->entry = clientCreateStoreEntry(http, old_request->method, 0);
+       err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND);
+       err->request = requestLink(http->request);
+       err->url = http->uri;
+       err->src_addr = http->conn->peer.sin_addr;
+       errorAppendEntry(http->entry, err);
+       return;
     }
-    /* child */
-    if ((fd = accept(cfd, NULL, NULL)) < 0) {
-        debug(50, 0) ("urnOpenServer: FD %d accept: %s\n", cfd, xstrerror());
-        exit(1);
+    min_w = urnFindMinRtt(http->urls, http->request->method, NULL);
+    if (min_w != NULL) {
+       safe_free(http->uri);
+       http->uri = xstrdup(min_w->key);
+       new_request = urlParse(old_request->method, http->uri);
+       new_request->http_ver = old_request->http_ver;
+       new_request->headers = old_request->headers;
+       new_request->headers_sz = old_request->headers_sz;
+       requestUnlink(http->request);
+       http->request = requestLink(new_request);
+       clientAccessCheck(http);
+    } else {
+       buf = urnConstructMenu(http);
+       storeAppend(http->entry, buf, strlen(buf));
+       storeComplete(http->entry);
     }
-    dup2(fd, 0);
-    dup2(fd, 1);
-    dup2(fileno(debug_log), 2);
-    fclose(debug_log);
-    close(fd);
-    close(cfd);
-
-    execlp(command, "(urnserver)", NULL);
-    debug(50, 0) ("urnOpenServer: %s: %s\n", command, xstrerror());
-    _exit(1);
-    return 0;
 }
 
-static char **
-urn_parsebuffer(const char *inbuf, urnserver_t * urnData)
+static char *
+urnConstructMenu(clientHttpRequest * http)
 {
-    char *buf = xstrdup(inbuf);
-    char *token;
-    char **urls=NULL;
-    int k;
-    int urlcount;
-
-    debug(50, 5) ("urn_parsebuffer: parsing:\n%s", inbuf);
-    for (token = strtok(buf, w_space); token; token = strtok(NULL, w_space)) {
-        if (!strcmp(token, "$end")) {
-            break;
-       } else if (!strcmp(token, "$none")) {
-               return NULL;
-        } else if (!strcmp(token, "$alive")) {
-            urnData->answer = squid_curtime;
-        } else if (!strcmp(token, "$fail")) {
-            if ((token = strtok(NULL, "\n")) == NULL)
-                fatal_dump("Invalid $fail");
-        } else if (!strcmp(token, "$message")) {
-            if ((token = strtok(NULL, "\n")) == NULL)
-                fatal_dump("Invalid $message");
-        } else if (!strcmp(token, "$urlcount")) {
-            if ((token = strtok(NULL, w_space)) == NULL)
-                fatal_dump("Invalid $urlcount");
-            urlcount = atoi(token);
-               if (urlcount== 0 ) 
-                       return NULL;
-               if (urls==NULL) 
-                       urls=xmalloc((urlcount+1)*sizeof(char *));
-            for (k = 0; k < urlcount; k++) {
-                if ((token = strtok(NULL, w_space)) == NULL)
-                    fatal_dump("Invalid URL");
-               urls[k]=xstrdup(token);
-            }
-           urls[k]=NULL;
-        } else {
-            debug(50, 0) ("--> %s <--\n", inbuf);
-            debug_trap("Invalid urnserver output");
-        }
+    LOCAL_ARRAY(char, buf, 8192);
+    LOCAL_ARRAY(char, line, 256);
+    LOCAL_ARRAY(char, content, 4096);
+    char *hdr;
+    wordlist *w;
+    debug(50, 1) ("urnConstructMenu\n");
+    memset(buf, '\0', 8192);
+    memset(content, '\0', 4096);
+    assert(http->urls);
+    for (w = http->urls; w; w = w->next) {
+       snprintf(line, 256, "<LI><A HREF=\"%s\">%s</A>\n", w->key, w->key);
+       strcat(buf, line);
     }
-    xfree(buf);
-
-       return (urls);
+    snprintf(content, 4096,
+       "<TITLE>Select URL for %s</TITLE>\n"
+       "<H2>Select URL for %s</H2>\n<UL>\n%s</UL>"
+       "<HR>\n"
+       "<ADDRESS>\n"
+       "Generated by %s/%s@%s\n"
+       "</ADDRESS>\n",
+       http->uri, http->uri, buf, appname, version_string, getMyHostname());
+    memset(buf, '\0', 8192);
+    hdr = httpReplyHeader(1.0,
+       HTTP_OK,
+       "text/html",
+       strlen(content),
+       0,
+       squid_curtime);
+    snprintf(buf, 8192, "%s\r\n%s",
+       hdr,
+       content);
+    return buf;
 }
-