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;