Compliance: handle HTTP OPTIONS and TRACE requests with asterisk URIs.

Handle '*' URIs in urlParse(). This allows Squid properly respond to OPTIONS and TRACE requests with '*' URIs and Max-Forwards value of zero. Forwarding similar requests with positive Max-Forwards value is out of this change scope and still does not work, because the upstream host and port are not set.

Co-Advisor test cases:
    test_case/rfc2616/options-bodyless-asterisk
    test_case/rfc2616/maxForwardsZero-OPTIONS-asterisk
    test_case/rfc2616/maxForwardsZero-TRACE-asterisk
Compliance: handle HTTP OPTIONS and TRACE requests with asterisk URIs,

Handle '*' URIs in urlParse(). This allows Squid properly respond to OPTIONS
and TRACE requests with '*' URIs and Max-Forwards value of zero. Forwarding
similar requests with positive Max-Forwards value is out of this change scope
and still does not work, because the upstream host and port are not set.

Co-Advisor test cases: test_case/rfc2616/options-bodyless-asterisk
                       test_case/rfc2616/maxForwardsZero-OPTIONS-asterisk
                       test_case/rfc2616/maxForwardsZero-TRACE-asterisk

=== modified file 'src/client_side.cc'
--- src/client_side.cc	2010-08-24 04:18:51 +0000
+++ src/client_side.cc	2010-08-30 23:00:10 +0000
@@ -2378,40 +2378,41 @@ ConnStateData::clientAfterReadingRequest
             /* Partial request received. Abort client connection! */
             debugs(33, 3, "clientAfterReadingRequests: FD " << fd << " aborted, partial request");
             comm_close(fd);
             return;
         }
     }
 
     clientMaybeReadData (do_next_read);
 }
 
 static void
 clientProcessRequest(ConnStateData *conn, HttpParser *hp, ClientSocketContext *context, const HttpRequestMethod& method, HttpVersion http_ver)
 {
     ClientHttpRequest *http = context->http;
     HttpRequest *request = NULL;
     bool notedUseOfBuffer = false;
     bool tePresent = false;
     bool deChunked = false;
     bool mustReplyToOptions = false;
     bool unsupportedTe = false;
+    bool unsupportedUri = false;
 
     /* We have an initial client stream in place should it be needed */
     /* setup our private context */
     context->registerWithConn();
 
     if (context->flags.parsed_ok == 0) {
         clientStreamNode *node = context->getClientReplyContext();
         debugs(33, 1, "clientProcessRequest: Invalid Request");
         clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
         assert (repContext);
         switch (hp->request_parse_status) {
         case HTTP_HEADER_TOO_LARGE:
             repContext->setReplyToError(ERR_TOO_BIG, HTTP_HEADER_TOO_LARGE, method, http->uri, conn->peer, NULL, conn->in.buf, NULL);
             break;
         case HTTP_METHOD_NOT_ALLOWED:
             repContext->setReplyToError(ERR_UNSUP_REQ, HTTP_METHOD_NOT_ALLOWED, method, http->uri, conn->peer, NULL, conn->in.buf, NULL);
             break;
         default:
             repContext->setReplyToError(ERR_INVALID_REQ, HTTP_BAD_REQUEST, method, http->uri, conn->peer, NULL, conn->in.buf, NULL);
         }
@@ -2502,46 +2503,49 @@ clientProcessRequest(ConnStateData *conn
 #if USE_SQUID_EUI
     request->client_eui48 = conn->peer_eui48;
     request->client_eui64 = conn->peer_eui64;
 #endif
 #if FOLLOW_X_FORWARDED_FOR
     request->indirect_client_addr = conn->peer;
 #endif /* FOLLOW_X_FORWARDED_FOR */
     request->my_addr = conn->me;
     request->http_ver = http_ver;
 
     tePresent = request->header.has(HDR_TRANSFER_ENCODING);
     deChunked = conn->in.dechunkingState == ConnStateData::chunkReady;
     if (deChunked) {
         assert(tePresent);
         request->setContentLength(conn->in.dechunked.contentSize());
         request->header.delById(HDR_TRANSFER_ENCODING);
         conn->finishDechunkingRequest(hp);
     } else
         conn->cleanDechunkingRequest();
 
-    if (method == METHOD_TRACE || method == METHOD_OPTIONS)
+    if (method == METHOD_TRACE || method == METHOD_OPTIONS) {
         request->max_forwards = request->header.getInt64(HDR_MAX_FORWARDS);
+        unsupportedUri = (request->max_forwards != 0) && (request->urlpath == "*");
+    }
 
     mustReplyToOptions = (method == METHOD_OPTIONS) && (request->max_forwards == 0);
     unsupportedTe = tePresent && !deChunked;
-    if (!urlCheckRequest(request) || mustReplyToOptions || unsupportedTe) {
+    if (!urlCheckRequest(request) || mustReplyToOptions || unsupportedTe ||
+        unsupportedUri) {
         clientStreamNode *node = context->getClientReplyContext();
         clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
         assert (repContext);
         repContext->setReplyToError(ERR_UNSUP_REQ,
                                     HTTP_NOT_IMPLEMENTED, request->method, NULL,
                                     conn->peer, request, NULL, NULL);
         assert(context->http->out.offset == 0);
         context->pullData();
         conn->flags.readMoreRequests = false;
         goto finish;
     }
 
 
     if (!clientIsContentLengthValid(request)) {
         clientStreamNode *node = context->getClientReplyContext();
         clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
         assert (repContext);
         repContext->setReplyToError(ERR_INVALID_REQ,
                                     HTTP_LENGTH_REQUIRED, request->method, NULL,
                                     conn->peer, request, NULL, NULL);

=== modified file 'src/url.cc'
--- src/url.cc	2010-07-25 08:10:12 +0000
+++ src/url.cc	2010-08-30 22:44:58 +0000
@@ -207,40 +207,43 @@ urlParse(const HttpRequestMethod& method
     int i;
     const char *src;
     char *dst;
     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';
         debugs(23, 1, "urlParse: URL too large (" << l << " bytes)");
         return NULL;
     }
     if (method == METHOD_CONNECT) {
         port = CONNECT_PORT;
 
         if (sscanf(url, "[%[^]]]:%d", host, &port) < 1)
             if (sscanf(url, "%[^:]:%d", host, &port) < 1)
                 return NULL;
 
     } else if (!strncmp(url, "urn:", 4)) {
         return urnParse(method, url);
+    } else if ((method == METHOD_OPTIONS || method == METHOD_TRACE) &&
+               strcmp(url, "*") == 0) {
+        strcpy(urlpath, url);
     } else {
         /* Parse the URL: */
         src = url;
         i = 0;
         /* Find first : - everything before is protocol */
         for (i = 0, dst = proto; i < l && *src != ':'; i++, src++, dst++) {
             *dst = *src;
         }
         if (i >= l)
             return NULL;
         *dst = '\0';
 
         /* Then its :// */
         /* (XXX yah, I'm not checking we've got enough data left before checking the array..) */
         if (*src != ':' || *(src + 1) != '/' || *(src + 2) != '/')
             return NULL;
         i += 3;
         src += 3;
 
         /* Then everything until first /; thats host (and port; which we'll look for here later) */
@@ -339,41 +342,41 @@ urlParse(const HttpRequestMethod& method
 
     if (Config.onoff.check_hostnames && strspn(host, Config.onoff.allow_underscore ? valid_hostname_chars_u : valid_hostname_chars) != strlen(host)) {
         debugs(23, 1, "urlParse: Illegal character in hostname '" << host << "'");
         return NULL;
     }
 
     /* For IPV6 addresses also check for a colon */
     if (Config.appendDomain && !strchr(host, '.') && !strchr(host, ':'))
         strncat(host, Config.appendDomain, SQUIDHOSTNAMELEN - strlen(host) - 1);
 
     /* remove trailing dots from hostnames */
     while ((l = strlen(host)) > 0 && host[--l] == '.')
         host[l] = '\0';
 
     /* reject duplicate or leading dots */
     if (strstr(host, "..") || *host == '.') {
         debugs(23, 1, "urlParse: Illegal hostname '" << host << "'");
         return NULL;
     }
 
-    if (port < 1 || port > 65535) {
+    if ((port < 1 || port > 65535) && strcmp(urlpath, "*") != 0) {
         debugs(23, 3, "urlParse: Invalid port '" << port << "'");
         return NULL;
     }
 
 #if 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) {
         debugs(23, 0, "urlParse: Deny access to port " << port);
         return NULL;
     }
 #endif
 
     if (stringHasWhitespace(urlpath)) {
         debugs(23, 2, "urlParse: URI has whitespace: {" << url << "}");
 
         switch (Config.uri_whitespace) {
 
         case URI_WHITESPACE_DENY:
             return NULL;

Reply via email to