summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/base.h4
-rw-r--r--src/connections.c1
-rw-r--r--src/http-header-glue.c45
-rw-r--r--src/request.c24
-rw-r--r--src/t/test_request.c32
-rwxr-xr-xtests/request.t22
6 files changed, 75 insertions, 53 deletions
diff --git a/src/base.h b/src/base.h
index ea040f46..2fe60b6b 100644
--- a/src/base.h
+++ b/src/base.h
@@ -47,7 +47,6 @@ typedef struct {
/* strings to the header */
buffer *http_host; /* not alloced */
- const char *http_range;
const char *http_content_type;
const char *http_if_modified_since;
const char *http_if_none_match;
@@ -58,9 +57,6 @@ typedef struct {
off_t content_length; /* returned by strtoll() */
off_t te_chunked;
- /* internal representation */
- int accept_encoding;
-
/* internal */
buffer *pathinfo;
} request;
diff --git a/src/connections.c b/src/connections.c
index 24365687..f06c89ea 100644
--- a/src/connections.c
+++ b/src/connections.c
@@ -685,7 +685,6 @@ int connection_reset(server *srv, connection *con) {
con->request.x = NULL;
CLEAN(http_host);
- CLEAN(http_range);
CLEAN(http_content_type);
#undef CLEAN
con->request.content_length = 0;
diff --git a/src/http-header-glue.c b/src/http-header-glue.c
index 63057ee3..5d4f1f5f 100644
--- a/src/http-header-glue.c
+++ b/src/http-header-glue.c
@@ -229,7 +229,7 @@ int http_response_handle_cachable(server *srv, connection *con, buffer *mtime) {
}
-static int http_response_parse_range(server *srv, connection *con, buffer *path, stat_cache_entry *sce) {
+static int http_response_parse_range(server *srv, connection *con, buffer *path, stat_cache_entry *sce, const char *range) {
int multipart = 0;
int error;
off_t start, end;
@@ -247,11 +247,26 @@ static int http_response_parse_range(server *srv, connection *con, buffer *path,
content_type = ds->value;
}
- for (s = con->request.http_range, error = 0;
+ for (s = range, error = 0;
!error && *s && NULL != (minus = strchr(s, '-')); ) {
char *err;
off_t la, le;
+ if (s != minus) {
+ la = strtoll(s, &err, 10);
+ if (err != minus) {
+ /* should not have multiple range-unit in Range, but
+ * handle just in case multiple Range headers merged */
+ while (*s == ' ' || *s == '\t') ++s;
+ if (0 != strncmp(s, "bytes=", 6)) return -1;
+ s += 6;
+ if (s != minus) {
+ la = strtoll(s, &err, 10);
+ if (err != minus) return -1;
+ }
+ }
+ }
+
if (s == minus) {
/* -<stop> */
@@ -281,9 +296,6 @@ static int http_response_parse_range(server *srv, connection *con, buffer *path,
} else if (*(minus+1) == '\0' || *(minus+1) == ',') {
/* <start>- */
- la = strtoll(s, &err, 10);
-
- if (err == minus) {
/* ok */
if (*(err + 1) == '\0') {
@@ -301,16 +313,9 @@ static int http_response_parse_range(server *srv, connection *con, buffer *path,
} else {
error = 1;
}
- } else {
- /* error */
- error = 1;
- }
} else {
/* <start>-<stop> */
- la = strtoll(s, &err, 10);
-
- if (err == minus) {
le = strtoll(minus+1, &err, 10);
/* RFC 2616 - 14.35.1 */
@@ -335,11 +340,6 @@ static int http_response_parse_range(server *srv, connection *con, buffer *path,
error = 1;
}
- } else {
- /* error */
-
- error = 1;
- }
}
if (!error) {
@@ -516,9 +516,11 @@ void http_response_send_file (server *srv, connection *con, buffer *path) {
}
}
- if (con->request.http_range && con->conf.range_requests
+ if (con->conf.range_requests
&& (200 == con->http_status || 0 == con->http_status)
+ && NULL != (ds = (data_string *)array_get_element(con->request.headers, "Range"))
&& NULL == array_get_element(con->response.headers, "Content-Encoding")) {
+ buffer *range = ds->value;
int do_range_request = 1;
/* check if we have a conditional GET */
@@ -547,11 +549,14 @@ void http_response_send_file (server *srv, connection *con, buffer *path) {
}
}
- if (do_range_request) {
+ if (do_range_request
+ && !buffer_string_is_empty(range)
+ && 0 == strncmp(range->ptr, "bytes=", 6)) {
+ /* support only "bytes" byte-unit */
/* content prepared, I'm done */
con->file_finished = 1;
- if (0 == http_response_parse_range(srv, con, path, sce)) {
+ if (0 == http_response_parse_range(srv, con, path, sce, range->ptr+6)) {
con->http_status = 206;
}
return;
diff --git a/src/request.c b/src/request.c
index 4e7b1792..213a87e1 100644
--- a/src/request.c
+++ b/src/request.c
@@ -1118,30 +1118,6 @@ int http_request_parse(server *srv, connection *con) {
ds->free((data_unset*) ds);
ds = NULL;
}
- } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Range")))) {
- if (!con->request.http_range) {
- /* bytes=.*-.* */
-
- if (0 == strncasecmp(ds->value->ptr, "bytes=", 6) &&
- NULL != strchr(ds->value->ptr+6, '-')) {
-
- /* if dup, only the first one will survive */
- con->request.http_range = ds->value->ptr + 6;
- }
- } else {
- con->http_status = 400;
- con->keep_alive = 0;
-
- if (srv->srvconf.log_request_header_on_error) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "duplicate Range-header -> 400");
- log_error_write(srv, __FILE__, __LINE__, "Sb",
- "request-header:\n",
- con->request.request);
- }
- array_insert_unique(con->request.headers, (data_unset *)ds);
- return 0;
- }
}
if (ds) array_insert_unique(con->request.headers, (data_unset *)ds);
diff --git a/src/t/test_request.c b/src/t/test_request.c
index 3b6671b4..c7734a0d 100644
--- a/src/t/test_request.c
+++ b/src/t/test_request.c
@@ -13,7 +13,6 @@ static void test_request_connection_reset(connection *con)
con->request.http_method = HTTP_METHOD_UNSET;
con->request.http_version = HTTP_VERSION_UNSET;
con->request.http_host = NULL;
- con->request.http_range = NULL;
con->request.http_content_type = NULL;
con->request.http_if_modified_since = NULL;
con->request.http_if_none_match = NULL;
@@ -372,14 +371,41 @@ static void test_request_http_request_parse(server *srv, connection *con)
"Content-Type: 4\r\n"
"\r\n"));
- run_http_request_parse(srv, con, __LINE__, 400,
- "Duplicate Range headers",
+ /* (not actually testing Range here anymore; parsing deferred until use) */
+
+ run_http_request_parse(srv, con, __LINE__, 0,
+ "Duplicate Range headers (get appended)",
CONST_STR_LEN("GET / HTTP/1.0\r\n"
"Range: bytes=5-6\r\n"
"Range: bytes=5-9\r\n"
"\r\n"));
run_http_request_parse(srv, con, __LINE__, 0,
+ "Duplicate Range headers with invalid range (a)",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Range: bytes=0\r\n"
+ "Range: bytes=5-9\r\n"
+ "\r\n"));
+ run_http_request_parse(srv, con, __LINE__, 0,
+ "Duplicate Range headers with invalid range (b)",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Range: bytes=5-9\r\n"
+ "Range: bytes=0\r\n"
+ "\r\n"));
+ run_http_request_parse(srv, con, __LINE__, 0,
+ "Duplicate Range headers with invalid range (c)",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Range: 0\r\n"
+ "Range: bytes=5-9\r\n"
+ "\r\n"));
+ run_http_request_parse(srv, con, __LINE__, 0,
+ "Duplicate Range headers with invalid range (d)",
+ CONST_STR_LEN("GET / HTTP/1.0\r\n"
+ "Range: bytes=5-9\r\n"
+ "Range: 0\r\n"
+ "\r\n"));
+
+ run_http_request_parse(srv, con, __LINE__, 0,
"Duplicate If-None-Match headers",
CONST_STR_LEN("GET / HTTP/1.0\r\n"
"If-None-Match: 5\r\n"
diff --git a/tests/request.t b/tests/request.t
index a9fe3f6a..c1e8f472 100755
--- a/tests/request.t
+++ b/tests/request.t
@@ -8,7 +8,7 @@ BEGIN {
use strict;
use IO::Socket;
-use Test::More tests => 50;
+use Test::More tests => 52;
use LightyTest;
my $tf = LightyTest->new();
@@ -392,6 +392,26 @@ $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 /12345.txt HTTP/1.0
+Host: 123.example.org
+Range: 0
+Range: bytes=0-3
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => "12345\n" } ];
+ok($tf->handle_http($t) == 0, 'GET, Range invalid range-unit (first)');
+
+$t->{REQUEST} = ( <<EOF
+GET /12345.txt HTTP/1.0
+Host: 123.example.org
+Range: bytes=0-3
+Range: 0
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 206 } ];
+ok($tf->handle_http($t) == 0, 'GET, Range ignore invalid range (second)');
+
+$t->{REQUEST} = ( <<EOF
OPTIONS / HTTP/1.0
Content-Length: 4