On 08/30/2010 09:49 PM, Amos Jeffries wrote:
On Mon, 30 Aug 2010 19:33:39 -0600, Alex Rousskov
<[email protected]>  wrote:
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


* The purpose of urlCheckRequest(request) is to determine if the request
is servicable and should be updated to contain the condition:

   if ((method == METHOD_TRACE || method == METHOD_OPTIONS)&&
       (request->max_forwards == 0&&  request->urlpath == "*"))
     return 1;

this removes the need all changes to client_side.cc.

Fixed. Good point! I think we can even exit urlCheckRequest() once TRACE or OPTIONS method is detected, but please let me know if I am wrong.


url.cc:

* Please do the parser method check before the check for "urn:" unless the
request:  "OPTIONS urn:*" is valid and to be rejected. Which I don't think
it is.

Done. I think the two checks are mutually exclusive, but they are now swapped anyway.


* Please copy the request setup from the end of the function and return
immediately from the parser after finding "*". There is no need to run
through (or change) any of the validation code in this special case.

Done. I hate code duplication so I moved the code you asked me to copy into a reusable function.


Thank you,

Alex.
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 such requests 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/url.cc'
--- src/url.cc	2010-07-25 08:10:12 +0000
+++ src/url.cc	2010-08-31 15:33:47 +0000
@@ -21,40 +21,47 @@
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 2 of the License, or
  *  (at your option) any later version.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  */
 
 #include "URL.h"
 #include "HttpRequest.h"
 #include "URLScheme.h"
 #include "rfc1738.h"
 
+static HttpRequest *urlParseFinish(const HttpRequestMethod& method,
+                                   const protocol_t protocol,
+                                   const char *const urlpath,
+                                   const char *const host,
+                                   const char *const login,
+                                   const int port,
+                                   HttpRequest *request);
 static HttpRequest *urnParse(const HttpRequestMethod& method, char *urn);
 static const char valid_hostname_chars_u[] =
     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
     "abcdefghijklmnopqrstuvwxyz"
     "0123456789-._"
     "[:]"
     ;
 static const char valid_hostname_chars[] =
     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
     "abcdefghijklmnopqrstuvwxyz"
     "0123456789-."
     "[:]"
     ;
 
 void
 urlInitialize(void)
 {
     debugs(23, 5, "urlInitialize: Initializing...");
     /* this ensures that the number of protocol strings is the same as
      * the enum slots allocated because the last enum is always 'TOTAL'.
@@ -205,40 +212,45 @@ urlParse(const HttpRequestMethod& method
     protocol_t protocol = PROTO_NONE;
     int l;
     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 ((method == METHOD_OPTIONS || method == METHOD_TRACE) &&
+               strcmp(url, "*") == 0) {
+        protocol = PROTO_HTTP;
+        port = urlDefaultPort(protocol);
+        return urlParseFinish(method, protocol, url, host, login, port, request);
     } else if (!strncmp(url, "urn:", 4)) {
         return urnParse(method, 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;
@@ -385,40 +397,57 @@ urlParse(const HttpRequestMethod& method
             t = rfc1738_escape_unescaped(urlpath);
             xstrncpy(urlpath, t, MAX_URL);
             break;
 
         case URI_WHITESPACE_CHOP:
             *(urlpath + strcspn(urlpath, w_space)) = '\0';
             break;
 
         case URI_WHITESPACE_STRIP:
         default:
             t = q = urlpath;
             while (*t) {
                 if (!xisspace(*t))
                     *q++ = *t;
                 t++;
             }
             *q = '\0';
         }
     }
 
+    return urlParseFinish(method, protocol, urlpath, host, login, port, request);
+}
+
+/**
+ * Update request with parsed URI data.  If the request arg is
+ * non-NULL, put parsed values there instead of allocating a new
+ * HttpRequest.
+ */
+static HttpRequest *
+urlParseFinish(const HttpRequestMethod& method,
+               const protocol_t protocol,
+               const char *const urlpath,
+               const char *const host,
+               const char *const login,
+               const int port,
+               HttpRequest *request)
+{
     if (NULL == request)
         request = new HttpRequest(method, protocol, urlpath);
     else {
         request->initHTTP(method, protocol, urlpath);
     }
 
     request->SetHost(host);
     xstrncpy(request->login, login, MAX_LOGIN_SZ);
     request->port = (u_short) port;
     return request;
 }
 
 static HttpRequest *
 urnParse(const HttpRequestMethod& method, char *urn)
 {
     debugs(50, 5, "urnParse: " << urn);
     return new HttpRequest(method, PROTO_URN, urn + 4);
 }
 
 const char *
@@ -750,42 +779,42 @@ matchDomainName(const char *h, const cha
  * return true if we can serve requests for this method.
  */
 int
 urlCheckRequest(const HttpRequest * r)
 {
     int rc = 0;
     /* protocol "independent" methods
      *
      * actually these methods are specific to HTTP:
      * they are methods we recieve on our HTTP port,
      * and if we had a FTP listener would not be relevant
      * there.
      *
      * So, we should delegate them to HTTP. The problem is that we
      * do not have a default protocol from the client side of HTTP.
      */
 
     if (r->method == METHOD_CONNECT)
         return 1;
 
-    if (r->method == METHOD_TRACE)
-        return 1;
+    if (r->method == METHOD_OPTIONS || r->method == METHOD_TRACE)
+        return (r->max_forwards == 0 || r->urlpath != "*");
 
     if (r->method == METHOD_PURGE)
         return 1;
 
     /* does method match the protocol? */
     switch (r->protocol) {
 
     case PROTO_URN:
 
     case PROTO_HTTP:
 
     case PROTO_CACHEOBJ:
         rc = 1;
         break;
 
     case PROTO_FTP:
 
         if (r->method == METHOD_PUT)
             rc = 1;
 

Reply via email to