diff options
-rw-r--r-- | NEWS | 5 | ||||
-rw-r--r-- | src/connections.c | 8 | ||||
-rw-r--r-- | src/request.c | 47 | ||||
-rwxr-xr-x | tests/request.t | 40 |
4 files changed, 83 insertions, 17 deletions
@@ -7,10 +7,15 @@ NEWS * added server.core-files option (sandy <sandy@meebo.com>) * added docs for mod_status + * added mod_evasive to limit the number of connections by IP (<w1zzard@techpowerup.com>) + * added the power-magnet to mod_cml + * added framework for internal statistics * fixed 100% cpu loops in mod_cgi ("sandy" <sjen@cs.stanford.edu>) * fixed handling for secure-download.timeout (jamis@37signals.com) * fixed IE bug in content-charset in the output of mod_dirlisting (sniper@php.net) * fixed typos and language in the docs (ryan-2005@ryandesign.com) + * fixed assertion in mod_cgi on HEAD request is Content-Length (<sandy@meebo.com>) + * fixed handling if equal but duplicate If-Modified-Since request headers - 1.4.8 - 2005-11-23 diff --git a/src/connections.c b/src/connections.c index 4322a020..cdb8c942 100644 --- a/src/connections.c +++ b/src/connections.c @@ -352,7 +352,13 @@ static int connection_handle_write_prepare(server *srv, connection *con) { case HTTP_METHOD_PROPPATCH: break; case HTTP_METHOD_OPTIONS: - if (con->uri.path->ptr[0] != '*') { + /* + * 400 is coming from the request-parser BEFORE uri.path is set + * 403 is from the response handler when noone else catched it + * + * */ + if (con->uri.path->used && + con->uri.path->ptr[0] != '*') { response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST")); con->http_status = 200; diff --git a/src/request.c b/src/request.c index 09357258..5d561ee0 100644 --- a/src/request.c +++ b/src/request.c @@ -815,9 +815,14 @@ int http_request_parse(server *srv, connection *con) { return 0; } } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-Modified-Since")))) { - /* if dup, only the first one will survive */ + /* Proxies sometimes send dup headers + * if they are the same we ignore the second + * if not, we raise an error */ if (!con->request.http_if_modified_since) { con->request.http_if_modified_since = ds->value->ptr; + } else if (0 == strcasecmp(con->request.http_if_modified_since, + ds->value->ptr)) { + /* ignore it if they are the same */ } else { con->http_status = 400; con->keep_alive = 0; @@ -963,22 +968,25 @@ int http_request_parse(server *srv, connection *con) { return 0; } - - /* check if we have read post data */ - if (con->request.http_method == HTTP_METHOD_POST - || (con->request.http_method != HTTP_METHOD_GET - && con->request.http_method != HTTP_METHOD_HEAD - && con->request.http_method != HTTP_METHOD_OPTIONS - && con_length_set)) { -#if 0 - if (con->request.http_content_type == NULL) { + switch(con->request.http_method) { + case HTTP_METHOD_GET: + case HTTP_METHOD_HEAD: + case HTTP_METHOD_OPTIONS: + /* content-length is forbidden for those */ + if (con_length_set) { + /* content-length is missing */ log_error_write(srv, __FILE__, __LINE__, "s", - "Content-Length request, but content-type not set"); + "GET/HEAD/OPTIONS with content-length -> 400"); + con->keep_alive = 0; + + con->http_status = 400; + return 0; } -#endif - - if (con_length_set == 0) { + break; + case HTTP_METHOD_POST: + /* content-length is required for them */ + if (!con_length_set) { /* content-length is missing */ log_error_write(srv, __FILE__, __LINE__, "s", "POST-request, but content-length missing -> 411"); @@ -986,8 +994,17 @@ int http_request_parse(server *srv, connection *con) { con->http_status = 411; return 0; + } - + break; + default: + /* the may have a content-length */ + break; + } + + + /* check if we have read post data */ + if (con_length_set) { /* don't handle more the SSIZE_MAX bytes in content-length */ if (con->request.content_length > SSIZE_MAX) { con->http_status = 413; diff --git a/tests/request.t b/tests/request.t index 40490131..be1f5d8f 100755 --- a/tests/request.t +++ b/tests/request.t @@ -8,7 +8,7 @@ BEGIN { use strict; use IO::Socket; -use Test::More tests => 29; +use Test::More tests => 33; use LightyTest; my $tf = LightyTest->new(); @@ -300,7 +300,45 @@ EOF $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; ok($tf->handle_http($t) == 0, 'GET, Range with range-requests-disabled'); +$t->{REQUEST} = ( <<EOF +GET / HTTP/1.0 +Content-Length: 4 + +1234 +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; +ok($tf->handle_http($t) == 0, 'GET with Content-Length'); + +$t->{REQUEST} = ( <<EOF +OPTIONS / HTTP/1.0 +Content-Length: 4 + +1234 +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; +ok($tf->handle_http($t) == 0, 'OPTIONS with Content-Length'); +$t->{REQUEST} = ( <<EOF +HEAD / HTTP/1.0 +Content-Length: 4 + +1234 +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; +ok($tf->handle_http($t) == 0, 'HEAD with Content-Length'); + + +$t->{REQUEST} = ( <<EOF +GET / HTTP/1.0 +If-Modified-Since: Sun, 1970 Jan 01 00:00:01 GMT +If-Modified-Since: Sun, 1970 Jan 01 00:00:01 GMT +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; +ok($tf->handle_http($t) == 0, 'Duplicate If-Mod-Since, with equal timestamps'); ok($tf->stop_proc == 0, "Stopping lighttpd"); |