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;