From 1b62dc325c0c1ecba1bb993a4111310cd4c798c7 Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Sat, 21 Apr 2018 17:23:17 -0400 Subject: [PATCH] [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) --- .gitignore | 1 + src/CMakeLists.txt | 16 ++ src/Makefile.am | 8 +- src/meson.build | 15 ++ src/test_request.c | 462 +++++++++++++++++++++++++++++++++++++++++++ tests/Makefile.am | 1 - tests/SConscript | 1 - tests/core-request.t | 256 ++---------------------- tests/core.t | 166 ---------------- tests/meson.build | 1 - tests/request.t | 88 +-------- 11 files changed, 516 insertions(+), 499 deletions(-) create mode 100644 src/test_request.c delete mode 100755 tests/core.t diff --git a/.gitignore b/.gitignore index af7344f3..5ddf8cbe 100644 --- a/.gitignore +++ b/.gitignore @@ -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 +#include +#include + +#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} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'URL-encoding'); - -$t->{REQUEST} = ( <{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} = ( <{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} = ( <{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} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'IPv6 address'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'hostname + port'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'IPv4 address + port'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'IPv6 address + port'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'directory traversal'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'leading and trailing dot'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'trailing dot is ok'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'leading dot'); - - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'two dots'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'broken port-number'); - -$t->{REQUEST} = ( <{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} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'port given but host missing'); -$t->{REQUEST} = ( <{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} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'allowed characters in host-name'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'leading dash'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'dot only'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'broken IPv4 address - non-digit'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'broken IPv4 address - too short'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'IPv6 address + SQL injection'); - -$t->{REQUEST} = ( <{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} = ( <{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} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 413 } ]; ok($tf->handle_http($t) == 0, 'Content-Length > max-request-size'); -$t->{REQUEST} = ( <{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} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'Host missing'); print "\nContent-Type\n"; $t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'Content-Type' => 'application/octet-stream' } ]; ok($tf->handle_http($t) == 0, 'Content-Type - unknown'); -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'empty request-URI'); - $t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; ok($tf->handle_http($t) == 0, 'uppercase filenames'); -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, '#1232 - duplicate headers with line-wrapping'); - -$t->{REQUEST} = ( <{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} = ( <{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} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'Valid HTTP/1.0 Request') or die(); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'missing Protocol'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'zeros in protocol version'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'missing major version'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'missing minor version'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'strings as version'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'missing protocol + unknown method'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'missing protocol + unknown method + missing URI'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 501 } ]; -ok($tf->handle_http($t) == 0, 'unknown method'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 505 } ]; -ok($tf->handle_http($t) == 0, 'unknown protocol'); - -$t->{REQUEST} = ( <{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} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'whitespace after key'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'whitespace with-in key'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'no whitespace'); - -$t->{REQUEST} = ( <{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} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'URL-encoding'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404 } ]; -ok($tf->handle_http($t) == 0, 'URL-encoding, %00'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'OPTIONS'); - -$t->{REQUEST} = ( <{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} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 411 } ]; -ok($tf->handle_http($t) == 0, 'POST request, no Content-Length'); - $t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; ok($tf->handle_http($t) == 0, 'larger headers'); -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'Duplicate Host headers, Bug #25'); - - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'Duplicate Content-Length headers'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'Duplicate Content-Type headers'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'Duplicate Range headers'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'Duplicate If-None-Match headers'); - -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'Duplicate If-Modified-Since headers'); - $t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; ok($tf->handle_http($t) == 0, 'GET, Range with range-requests-disabled'); -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'GET with Content-Length'); - $t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; ok($tf->handle_http($t) == 0, 'OPTIONS for RTSP'); -$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; -ok($tf->handle_http($t) == 0, 'HEAD with Content-Length'); - $t->{REQUEST} = ( <{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');