diff options
author | Glenn Strauss <gstrauss@gluelogic.com> | 2018-04-21 17:23:17 -0400 |
---|---|---|
committer | Glenn Strauss <gstrauss@gluelogic.com> | 2018-08-05 03:44:15 -0400 |
commit | 1b62dc325c0c1ecba1bb993a4111310cd4c798c7 (patch) | |
tree | 1690c969d76a842998f28644a70c6fbc6f6c0938 | |
parent | e8c1efd5dfc11b5001113198741536648067c024 (diff) | |
download | lighttpd-git-1b62dc325c0c1ecba1bb993a4111310cd4c798c7.tar.gz |
[tests] test_request unit tests
unit tests for request processing
collect existing request processing tests from Perl tests/*.t
(test_request.c runs *much* more quickly than Perl tests/*.t)
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | src/CMakeLists.txt | 16 | ||||
-rw-r--r-- | src/Makefile.am | 8 | ||||
-rw-r--r-- | src/meson.build | 15 | ||||
-rw-r--r-- | src/test_request.c | 462 | ||||
-rw-r--r-- | tests/Makefile.am | 1 | ||||
-rw-r--r-- | tests/SConscript | 1 | ||||
-rwxr-xr-x | tests/core-request.t | 256 | ||||
-rwxr-xr-x | tests/core.t | 166 | ||||
-rw-r--r-- | tests/meson.build | 1 | ||||
-rwxr-xr-x | tests/request.t | 88 |
11 files changed, 516 insertions, 499 deletions
@@ -50,4 +50,5 @@ stamp-h1 test_base64 test_buffer test_configfile +test_request versionstamp.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c1c6627d..acaa7e89 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -671,6 +671,18 @@ add_executable(test_configfile ) add_test(NAME test_configfile COMMAND test_configfile) +add_executable(test_request + test_request.c + request.c + buffer.c + array.c + data_string.c + keyvalue.c + log.c + sock_addr.c +) +add_test(NAME test_request COMMAND test_request) + if(HAVE_PCRE_H) target_link_libraries(lighttpd ${PCRE_LDFLAGS}) add_target_properties(lighttpd COMPILE_FLAGS ${PCRE_CFLAGS}) @@ -682,6 +694,8 @@ if(HAVE_PCRE_H) add_target_properties(mod_redirect COMPILE_FLAGS ${PCRE_CFLAGS}) target_link_libraries(test_configfile ${PCRE_LDFLAGS}) add_target_properties(test_configfile COMPILE_FLAGS ${PCRE_CFLAGS}) + target_link_libraries(test_request ${PCRE_LDFLAGS}) + add_target_properties(test_request COMPILE_FLAGS ${PCRE_CFLAGS}) endif() if(WITH_PCRE AND (WITH_MEMCACHED OR WITH_GDBM)) @@ -864,6 +878,8 @@ if(WITH_LIBUNWIND) add_target_properties(test_base64 COMPILE_FLAGS ${LIBUNWIND_CFLAGS}) target_link_libraries(test_configfile ${PCRE_LDFLAGS} ${LIBUNWIND_LDFLAGS}) add_target_properties(test_configfile COMPILE_FLAGS ${PCRE_CFLAGS} ${LIBUNWIND_CFLAGS}) + target_link_libraries(test_request ${PCRE_LDFLAGS} ${LIBUNWIND_LDFLAGS}) + add_target_properties(test_request COMPILE_FLAGS ${PCRE_CFLAGS} ${LIBUNWIND_CFLAGS}) endif() if(NOT WIN32) diff --git a/src/Makefile.am b/src/Makefile.am index 66de3219..7696dae4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,13 +1,14 @@ AM_CFLAGS = $(FAM_CFLAGS) $(LIBUNWIND_CFLAGS) -noinst_PROGRAMS=proc_open test_buffer test_base64 test_configfile +noinst_PROGRAMS=proc_open test_buffer test_base64 test_configfile test_request sbin_PROGRAMS=lighttpd lighttpd-angel LEMON=$(top_builddir)/src/lemon$(BUILD_EXEEXT) TESTS=\ test_buffer$(EXEEXT) \ test_base64$(EXEEXT) \ - test_configfile$(EXEEXT) + test_configfile$(EXEEXT) \ + test_request$(EXEEXT) lemon$(BUILD_EXEEXT): lemon.c $(AM_V_CC)$(CC_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) -o $@ $(srcdir)/lemon.c @@ -523,6 +524,9 @@ test_base64_LDADD = $(LIBUNWIND_LIBS) test_configfile_SOURCES = test_configfile.c buffer.c array.c data_config.c data_string.c keyvalue.c vector.c log.c sock_addr.c test_configfile_LDADD = $(PCRE_LIB) $(LIBUNWIND_LIBS) +test_request_SOURCES = test_request.c request.c buffer.c array.c data_string.c keyvalue.c log.c sock_addr.c +test_request_LDADD = $(PCRE_LIB) $(LIBUNWIND_LIBS) + noinst_HEADERS = $(hdr) EXTRA_DIST = \ mod_skeleton.c \ diff --git a/src/meson.build b/src/meson.build index 855e52b1..d676ef19 100644 --- a/src/meson.build +++ b/src/meson.build @@ -714,6 +714,21 @@ test('test_configfile', executable('test_configfile', build_by_default: false, )) +test('test_request', executable('test_request', + sources: [ + 'test_request.c', + 'request.c', + 'buffer.c', + 'array.c', + 'data_string.c', + 'keyvalue.c', + 'log.c', + 'sock_addr.c', + ], + dependencies: common_flags + libpcre + libunwind, + build_by_default: false, +)) + modules = [ [ 'mod_access', [ 'mod_access.c' ] ], [ 'mod_accesslog', [ 'mod_accesslog.c' ] ], diff --git a/src/test_request.c b/src/test_request.c new file mode 100644 index 00000000..b73127e1 --- /dev/null +++ b/src/test_request.c @@ -0,0 +1,462 @@ +#include "request.h" + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> + +#include "base.h" + +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; + con->request.content_length = 0; + con->header_len = 0; + con->http_status = 0; + buffer_reset(con->proto); + buffer_reset(con->parse_request); + buffer_reset(con->request.request); + buffer_reset(con->request.request_line); + buffer_reset(con->request.orig_uri); + buffer_reset(con->request.uri); + array_reset(con->request.headers); +} + +static void run_http_request_parse(server *srv, connection *con, int line, int status, const char *desc, const char *req, size_t reqlen) +{ + test_request_connection_reset(con); + buffer_copy_string_len(con->request.request, req, reqlen); + http_request_parse(srv, con); + if (con->http_status != status) { + fprintf(stderr, + "%s.%d: %s() failed: expected '%d', got '%d' for test %s\n", + __FILE__, line, "http_request_parse", status, con->http_status, + desc); + fflush(stderr); + abort(); + } +} + +static void test_request_http_request_parse(server *srv, connection *con) +{ + data_string *ds; + + run_http_request_parse(srv, con, __LINE__, 0, + "hostname", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Host: www.example.org\r\n" + "\r\n")); + assert(buffer_is_equal_string(con->request.http_host, + CONST_STR_LEN("www.example.org"))); + + run_http_request_parse(srv, con, __LINE__, 0, + "IPv4 address", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Host: 127.0.0.1\r\n" + "\r\n")); + assert(buffer_is_equal_string(con->request.http_host, + CONST_STR_LEN("127.0.0.1"))); + + run_http_request_parse(srv, con, __LINE__, 0, + "IPv6 address", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Host: [::1]\r\n" + "\r\n")); + assert(buffer_is_equal_string(con->request.http_host, + CONST_STR_LEN("[::1]"))); + + run_http_request_parse(srv, con, __LINE__, 0, + "hostname + port", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Host: www.example.org:80\r\n" + "\r\n")); + assert(buffer_is_equal_string(con->request.http_host, + CONST_STR_LEN("www.example.org"))); + + run_http_request_parse(srv, con, __LINE__, 0, + "IPv4 address + port", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Host: 127.0.0.1:80\r\n" + "\r\n")); + assert(buffer_is_equal_string(con->request.http_host, + CONST_STR_LEN("127.0.0.1"))); + + run_http_request_parse(srv, con, __LINE__, 0, + "IPv6 address + port", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Host: [::1]:80\r\n" + "\r\n")); + assert(buffer_is_equal_string(con->request.http_host, + CONST_STR_LEN("[::1]"))); + + run_http_request_parse(srv, con, __LINE__, 400, + "directory traversal", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Host: ../123.org\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 400, + "leading and trailing dot", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Host: .jsdh.sfdg.sdfg.\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 0, + "trailing dot is ok", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Host: jsdh.sfdg.sdfg.\r\n" + "\r\n")); + assert(buffer_is_equal_string(con->request.http_host, + CONST_STR_LEN("jsdh.sfdg.sdfg"))); + + run_http_request_parse(srv, con, __LINE__, 400, + "leading dot", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Host: .jsdh.sfdg.sdfg\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 400, + "two dots", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Host: jsdh..sfdg.sdfg\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 400, + "broken port-number", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Host: jsdh.sfdg.sdfg:asd\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 400, + "negative port-number", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Host: jsdh.sfdg.sdfg:-1\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 400, + "port given but host missing", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Host: :80\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 400, + "port and host are broken", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Host: .jsdh.sfdg.:sdfg.\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 0, + "allowed characters in host-name", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Host: a.b-c.d123\r\n" + "\r\n")); + assert(buffer_is_equal_string(con->request.http_host, + CONST_STR_LEN("a.b-c.d123"))); + + run_http_request_parse(srv, con, __LINE__, 400, + "leading dash", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Host: -a.c\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 400, + "dot only", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Host: .\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 400, + "broken IPv4 address - non-digit", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Host: a192.168.2.10:1234\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 400, + "broken IPv4 address - too short", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Host: 192.168.2:1234\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 400, + "IPv6 address + SQL injection", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Host: [::1]' UNION SELECT '/\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 400, + "IPv6 address + path traversal", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Host: [::1]/../../../\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 400, + "negative Content-Length", + CONST_STR_LEN("POST /12345.txt HTTP/1.0\r\n" + "Content-Length: -2\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 411, + "Content-Length is empty", + CONST_STR_LEN("POST /12345.txt HTTP/1.0\r\n" + "Host: 123.example.org\r\n" + "Content-Length:\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 400, + "Host missing", + CONST_STR_LEN("GET / HTTP/1.1\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 400, + "empty request-URI", + CONST_STR_LEN("GET HTTP/1.0\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 0, + "#1232 - duplicate headers with line-wrapping", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Location: foo\r\n" + "Location: foobar\r\n" + " baz\r\n" + "\r\n")); + ds = (data_string *) + array_get_element_klen(con->request.headers, CONST_STR_LEN("Location")); + assert(ds + && buffer_is_equal_string(ds->value, + CONST_STR_LEN("foo, foobar baz"))); + + run_http_request_parse(srv, con, __LINE__, 0, + "#1232 - duplicate headers with line-wrapping - test 2", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Location: \r\n" + "Location: foobar\r\n" + " baz\r\n" + "\r\n")); + ds = (data_string *) + array_get_element_klen(con->request.headers, CONST_STR_LEN("Location")); + assert(ds + && buffer_is_equal_string(ds->value, CONST_STR_LEN("foobar baz"))); + + run_http_request_parse(srv, con, __LINE__, 0, + "#1232 - duplicate headers with line-wrapping - test 3", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "A: \r\n" + "Location: foobar\r\n" + " baz\r\n" + "\r\n")); + ds = (data_string *) + array_get_element_klen(con->request.headers, CONST_STR_LEN("Location")); + assert(ds + && buffer_is_equal_string(ds->value, CONST_STR_LEN("foobar baz"))); + + run_http_request_parse(srv, con, __LINE__, 400, + "missing protocol", + CONST_STR_LEN("GET /\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 0, + "zeros in protocol version", + CONST_STR_LEN("GET / HTTP/01.01\r\n" + "Host: foo\r\n" + "\r\n")); + assert(con->request.http_version == HTTP_VERSION_1_1); + + run_http_request_parse(srv, con, __LINE__, 400, + "missing major version", + CONST_STR_LEN("GET / HTTP/.01\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 400, + "missing minor version", + CONST_STR_LEN("GET / HTTP/01.\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 400, + "strings as version", + CONST_STR_LEN("GET / HTTP/a.b\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 400, + "missing protocol + unknown method", + CONST_STR_LEN("BC /\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 400, + "missing protocol + unknown method + missing URI", + CONST_STR_LEN("ABC\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 501, + "unknown method", + CONST_STR_LEN("ABC / HTTP/1.0\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 505, + "unknown protocol", + CONST_STR_LEN("GET / HTTP/1.3\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 0, + "absolute URI", + CONST_STR_LEN("GET http://www.example.org/ HTTP/1.0\r\n" + "\r\n")); + assert(buffer_is_equal_string(con->request.http_host, + CONST_STR_LEN("www.example.org"))); + assert(buffer_is_equal_string(con->request.uri, + CONST_STR_LEN("/"))); + + run_http_request_parse(srv, con, __LINE__, 0, + "whitespace after key", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "ABC : foo\r\n" + "\r\n")); + ds = (data_string *) + array_get_element_klen(con->request.headers, CONST_STR_LEN("ABC")); + assert(ds && buffer_is_equal_string(ds->value, CONST_STR_LEN("foo"))); + + run_http_request_parse(srv, con, __LINE__, 400, + "whitespace within key", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "ABC a: foo\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 0, + "no whitespace", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "ABC:foo\r\n" + "\r\n")); + ds = (data_string *) + array_get_element_klen(con->request.headers, CONST_STR_LEN("ABC")); + assert(ds && buffer_is_equal_string(ds->value, CONST_STR_LEN("foo"))); + + run_http_request_parse(srv, con, __LINE__, 0, + "line-folding", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "ABC:foo\r\n" + " bc\r\n" + "\r\n")); + ds = (data_string *) + array_get_element_klen(con->request.headers, CONST_STR_LEN("ABC")); + assert(ds && buffer_is_equal_string(ds->value, CONST_STR_LEN("foo bc"))); + + run_http_request_parse(srv, con, __LINE__, 411, + "POST request, no Content-Length", + CONST_STR_LEN("POST / HTTP/1.0\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 400, + "Duplicate Host headers, Bug #25", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Host: www.example.org\r\n" + "Host: 123.example.org\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 400, + "Duplicate Content-Length headers", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Content-Length: 5\r\n" + "Content-Length: 4\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 400, + "Duplicate Content-Type headers", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Content-Type: 5\r\n" + "Content-Type: 4\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 400, + "Duplicate Range headers", + 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 If-None-Match headers", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "If-None-Match: 5\r\n" + "If-None-Match: 4\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 400, + "Duplicate If-Modified-Since headers", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "If-Modified-Since: 5\r\n" + "If-Modified-Since: 4\r\n" + "\r\n")); + + run_http_request_parse(srv, con, __LINE__, 400, + "GET with Content-Length", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Content-Length: 4\r\n" + "\r\n" + "1234")); + + run_http_request_parse(srv, con, __LINE__, 400, + "HEAD with Content-Length", + CONST_STR_LEN("HEAD / HTTP/1.0\r\n" + "Content-Length: 4\r\n" + "\r\n" + "1234")); + + run_http_request_parse(srv, con, __LINE__, 400, + "invalid chars in Header values (bug #1286)", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "If-Modified-Since: \0\r\n" + "\r\n")); + + /* (quick check that none of above tests were left in a state + * which resulted in subsequent tests returning 400 for other + * reasons) */ + run_http_request_parse(srv, con, __LINE__, 0, + "valid", + CONST_STR_LEN("GET / HTTP/1.0\r\n" + "Host: www.example.org\r\n" + "\r\n")); +} + +int main (void) +{ + server srv; + connection con; + + memset(&srv, 0, sizeof(server)); + srv.errorlog_fd = -1; /* use 2 for STDERR_FILENO from unistd.h */ + srv.errorlog_mode = ERRORLOG_FD; + srv.errorlog_buf = buffer_init(); + srv.split_vals = array_init(); + + memset(&con, 0, sizeof(connection)); + con.proto = buffer_init(); + con.parse_request = buffer_init(); + con.request.request = buffer_init(); + con.request.request_line = buffer_init(); + con.request.orig_uri = buffer_init(); + con.request.uri = buffer_init(); + con.request.headers = array_init(); + con.conf.allow_http11 = 1; + con.conf.http_parseopts = HTTP_PARSEOPT_HEADER_STRICT + | HTTP_PARSEOPT_HOST_STRICT + | HTTP_PARSEOPT_HOST_NORMALIZE; + + test_request_http_request_parse(&srv, &con); + + buffer_free(con.proto); + buffer_free(con.parse_request); + buffer_free(con.request.request); + buffer_free(con.request.request_line); + buffer_free(con.request.orig_uri); + buffer_free(con.request.uri); + array_free(con.request.headers); + + array_free(srv.split_vals); + buffer_free(srv.errorlog_buf); + + return 0; +} diff --git a/tests/Makefile.am b/tests/Makefile.am index 37f0d0b0..398c67c3 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -30,7 +30,6 @@ CONFS=\ core-request.t \ core-response.t \ core-var-include.t \ - core.t \ fastcgi-10.conf \ fastcgi-13.conf \ fastcgi-auth.conf \ diff --git a/tests/SConscript b/tests/SConscript index 003a69c4..e542dc1c 100644 --- a/tests/SConscript +++ b/tests/SConscript @@ -18,7 +18,6 @@ extra_dist = Split('fastcgi-10.conf \ core-request.t \ core-response.t \ core-keepalive.t \ - core.t \ mod-access.t \ mod-auth.t \ mod-cgi.t \ diff --git a/tests/core-request.t b/tests/core-request.t index 6cbfb718..6de62f85 100755 --- a/tests/core-request.t +++ b/tests/core-request.t @@ -8,7 +8,7 @@ BEGIN { use strict; use IO::Socket; -use Test::More tests => 38; +use Test::More tests => 12; use LightyTest; my $tf = LightyTest->new(); @@ -16,216 +16,46 @@ my $t; ok($tf->start_proc == 0, "Starting lighttpd") or die(); -## Low-Level Request-Header Parsing - URI - -$t->{REQUEST} = ( <<EOF -GET /index%2ehtml HTTP/1.0 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'URL-encoding'); - -$t->{REQUEST} = ( <<EOF -GET /index.html%00 HTTP/1.0 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404 } ]; -ok($tf->handle_http($t) == 0, 'URL-encoding, %00'); - - - -## Low-Level Request-Header Parsing - Host $t->{REQUEST} = ( <<EOF GET / HTTP/1.0 -Host: www.example.org EOF ); $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'hostname'); +ok($tf->handle_http($t) == 0, 'Valid HTTP/1.0 Request') or die(); $t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -Host: 127.0.0.1 +OPTIONS * HTTP/1.0 EOF ); $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'IPv4 address'); +ok($tf->handle_http($t) == 0, 'OPTIONS'); $t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -Host: [::1] -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'IPv6 address'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -Host: www.example.org:80 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'hostname + port'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -Host: 127.0.0.1:80 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'IPv4 address + port'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -Host: [::1]:80 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'IPv6 address + port'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -Host: ../123.org -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'directory traversal'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -Host: .jsdh.sfdg.sdfg. -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'leading and trailing dot'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -Host: jsdh.sfdg.sdfg. -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'trailing dot is ok'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -Host: .jsdh.sfdg.sdfg -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'leading dot'); - - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -Host: jsdh..sfdg.sdfg -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'two dots'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -Host: jsdh.sfdg.sdfg:asd -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'broken port-number'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -Host: jsdh.sfdg.sdfg:-1 +OPTIONS / HTTP/1.1 +Host: www.example.org +Connection: close EOF ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'negative port-number'); - +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200 } ]; +ok($tf->handle_http($t) == 0, 'OPTIONS'); -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -Host: :80 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'port given but host missing'); -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -Host: .jsdh.sfdg.:sdfg. -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'port and host are broken'); +## Low-Level Request-Header Parsing - URI $t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -Host: a.b-c.d123 +GET /index%2ehtml HTTP/1.0 EOF ); $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'allowed characters in host-name'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -Host: -a.c -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'leading dash'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -Host: . -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'dot only'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -Host: a192.168.2.10:1234 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'broken IPv4 address - non-digit'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -Host: 192.168.2:1234 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'broken IPv4 address - too short'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -Host: [::1]' UNION SELECT '/ -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'IPv6 address + SQL injection'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -Host: [::1]/../../../ -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'IPv6 address + path traversal'); - - - -## Low-Level Request-Header Parsing - Content-Length - +ok($tf->handle_http($t) == 0, 'URL-encoding'); $t->{REQUEST} = ( <<EOF -GET /index.html HTTP/1.0 -Content-Length: -2 +GET /index.html%00 HTTP/1.0 EOF ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'negative Content-Length'); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404 } ]; +ok($tf->handle_http($t) == 0, 'URL-encoding, %00'); $t->{REQUEST} = ( <<EOF POST /12345.txt HTTP/1.0 @@ -236,22 +66,6 @@ EOF $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 413 } ]; ok($tf->handle_http($t) == 0, 'Content-Length > max-request-size'); -$t->{REQUEST} = ( <<EOF -POST /12345.txt HTTP/1.0 -Host: 123.example.org -Content-Length: -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 411 } ]; -ok($tf->handle_http($t) == 0, 'Content-Length is empty'); - -print "\nLow-Level Request-Header Parsing - HTTP/1.1\n"; -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.1 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'Host missing'); print "\nContent-Type\n"; $t->{REQUEST} = ( <<EOF @@ -276,51 +90,11 @@ $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'Conte ok($tf->handle_http($t) == 0, 'Content-Type - unknown'); $t->{REQUEST} = ( <<EOF -GET HTTP/1.0 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'empty request-URI'); - -$t->{REQUEST} = ( <<EOF GET /Foo.txt HTTP/1.0 EOF ); $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; ok($tf->handle_http($t) == 0, 'uppercase filenames'); -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -Location: foo -Location: foobar - baz -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, '#1232 - duplicate headers with line-wrapping'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -Location: -Location: foobar - baz -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, '#1232 - duplicate headers with line-wrapping - test 2'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -A: -Location: foobar - baz -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, '#1232 - duplicate headers with line-wrapping - test 3'); - - - ok($tf->stop_proc == 0, "Stopping lighttpd"); - diff --git a/tests/core.t b/tests/core.t deleted file mode 100755 index b196666a..00000000 --- a/tests/core.t +++ /dev/null @@ -1,166 +0,0 @@ -#!/usr/bin/env perl -BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s,/[^/]+$,/,; - unshift @INC, $srcdir; -} - -use strict; -use IO::Socket; -use Test::More tests => 21; -use LightyTest; - -my $tf = LightyTest->new(); -my $t; - -ok($tf->start_proc == 0, "Starting lighttpd") or die(); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'Valid HTTP/1.0 Request') or die(); - -$t->{REQUEST} = ( <<EOF -GET / -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'missing Protocol'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/01.01 -Host: foo -Connection: close -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'zeros in protocol version'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/.01 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'missing major version'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/01. -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'missing minor version'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/a.b -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'strings as version'); - -$t->{REQUEST} = ( <<EOF -BC / -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'missing protocol + unknown method'); - -$t->{REQUEST} = ( <<EOF -ABC -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'missing protocol + unknown method + missing URI'); - -$t->{REQUEST} = ( <<EOF -ABC / HTTP/1.0 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 501 } ]; -ok($tf->handle_http($t) == 0, 'unknown method'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.3 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 505 } ]; -ok($tf->handle_http($t) == 0, 'unknown protocol'); - -$t->{REQUEST} = ( <<EOF -GET http://www.example.org/ HTTP/1.0 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'absolute URI'); - -print "\nLow-Level Request-Header Parsing\n"; -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -ABC : foo -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'whitespace after key'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -ABC a: foo -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'whitespace with-in key'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -ABC:foo -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'no whitespace'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -ABC:foo - bc -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'line-folding'); - -print "\nLow-Level Request-Header Parsing - URI\n"; -$t->{REQUEST} = ( <<EOF -GET /index%2ehtml HTTP/1.0 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'URL-encoding'); - -$t->{REQUEST} = ( <<EOF -GET /index.html%00 HTTP/1.0 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404 } ]; -ok($tf->handle_http($t) == 0, 'URL-encoding, %00'); - -$t->{REQUEST} = ( <<EOF -OPTIONS * HTTP/1.0 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'OPTIONS'); - -$t->{REQUEST} = ( <<EOF -OPTIONS / HTTP/1.1 -Host: www.example.org -Connection: close -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'OPTIONS'); - - - -ok($tf->stop_proc == 0, "Stopping lighttpd"); - diff --git a/tests/meson.build b/tests/meson.build index 0ac68a68..1ed3624e 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -29,7 +29,6 @@ tests = [ 'core-request.t', 'core-response.t', 'core-var-include.t', - 'core.t', 'lowercase.t', 'mod-access.t', 'mod-auth.t', diff --git a/tests/request.t b/tests/request.t index fd853bf2..a9fe3f6a 100755 --- a/tests/request.t +++ b/tests/request.t @@ -8,7 +8,7 @@ BEGIN { use strict; use IO::Socket; -use Test::More tests => 60; +use Test::More tests => 50; use LightyTest; my $tf = LightyTest->new(); @@ -56,13 +56,6 @@ EOF $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '12345'."\n", 'Content-Type' => 'application/octet-stream' } ]; ok($tf->handle_http($t) == 0, 'GET, content == 12345, mimetype application/octet-stream'); -$t->{REQUEST} = ( <<EOF -POST / HTTP/1.0 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 411 } ]; -ok($tf->handle_http($t) == 0, 'POST request, no Content-Length'); - $t->{REQUEST} = ( <<EOF POST / HTTP/1.0 @@ -391,61 +384,6 @@ ok($tf->handle_http($t) == 0, 'larger headers'); $t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -Host: www.example.org -Host: 123.example.org -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'Duplicate Host headers, Bug #25'); - - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -Content-Length: 5 -Content-Length: 4 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'Duplicate Content-Length headers'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -Content-Type: 5 -Content-Type: 4 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'Duplicate Content-Type headers'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -Range: bytes=5-6 -Range: bytes=5-9 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'Duplicate Range headers'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -If-None-Match: 5 -If-None-Match: 4 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'Duplicate If-None-Match headers'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -If-Modified-Since: 5 -If-Modified-Since: 4 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'Duplicate If-Modified-Since headers'); - -$t->{REQUEST} = ( <<EOF GET /range.pdf HTTP/1.0 Range: bytes=0- EOF @@ -454,16 +392,6 @@ $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 @@ -482,16 +410,6 @@ $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; ok($tf->handle_http($t) == 0, 'OPTIONS for RTSP'); $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 /index.html HTTP/1.0 If-Modified-Since: Sun, 01 Jan 2036 00:00:02 GMT If-Modified-Since: Sun, 01 Jan 2036 00:00:02 GMT @@ -500,10 +418,6 @@ EOF $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ]; ok($tf->handle_http($t) == 0, 'Duplicate If-Mod-Since, with equal timestamps'); -$t->{REQUEST} = ( "GET / HTTP/1.0\r\nIf-Modified-Since: \0\r\n\r\n" ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'invalid chars in Header values (bug #1286)'); - $t->{REQUEST} = ( "GET / HTTP/1.0\r\nIf-Modified-Since: \r\n\r\n" ); $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; ok($tf->handle_http($t) == 0, 'empty If-Modified-Since'); |