diff options
author | Glenn Strauss <gstrauss@gluelogic.com> | 2021-07-06 22:58:13 -0400 |
---|---|---|
committer | Glenn Strauss <gstrauss@gluelogic.com> | 2021-09-04 08:08:26 -0400 |
commit | 91472ab7681b26f36b813f3b245c0e98f91b4c3f (patch) | |
tree | c0a71cb0f9d52747ec4c0409f8863b9f64233e83 | |
parent | a0a8cf821d2292e6662119e158e73c175452f1c3 (diff) | |
download | lighttpd-git-91472ab7681b26f36b813f3b245c0e98f91b4c3f.tar.gz |
[tests] t/test_mod_staticfile
move some tests from tests/request.t to src/t/test_mod_staticfile.c
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | src/CMakeLists.txt | 27 | ||||
-rw-r--r-- | src/Makefile.am | 5 | ||||
-rw-r--r-- | src/meson.build | 44 | ||||
-rw-r--r-- | src/mod_staticfile.c | 32 | ||||
-rw-r--r-- | src/t/test_mod_staticfile.c | 458 | ||||
-rw-r--r-- | tests/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tests/Makefile.am | 1 | ||||
-rwxr-xr-x | tests/cachable.t | 211 | ||||
-rwxr-xr-x | tests/core-request.t | 9 | ||||
-rwxr-xr-x | tests/core-response.t | 17 | ||||
-rw-r--r-- | tests/meson.build | 1 | ||||
-rwxr-xr-x | tests/request.t | 56 |
13 files changed, 556 insertions, 307 deletions
@@ -55,6 +55,7 @@ test_configfile test_mod_access test_mod_evhost test_mod_simple_vhost +test_mod_staticfile test_mod_userdir test_request versionstamp.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5fec0207..c92a85b7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -927,6 +927,30 @@ add_executable(test_mod_simple_vhost ) add_test(NAME test_mod_simple_vhost COMMAND test_mod_simple_vhost) +add_executable(test_mod_staticfile + t/test_mod_staticfile.c + request.c + base64.c + buffer.c + burl.c + array.c + chunk.c + fdevent.c + http-header-glue.c + http_cgi.c + http_chunk.c + http_date.c + http_etag.c + http_header.c + http_kv.c + log.c + sock_addr.c + stat_cache.c + algo_splaytree.c + ck.c +) +add_test(NAME test_mod_staticfile COMMAND test_mod_staticfile) + add_executable(test_mod_userdir t/test_mod_userdir.c buffer.c @@ -1084,6 +1108,7 @@ endif() if(HAVE_LIBFAM) target_link_libraries(lighttpd fam) + target_link_libraries(test_mod_staticfile fam) endif() if(HAVE_GDBM_H) @@ -1204,6 +1229,8 @@ if(WITH_LIBUNWIND) add_target_properties(test_mod_evhost COMPILE_FLAGS ${LIBUNWIND_CFLAGS}) target_link_libraries(test_mod_simple_vhost ${LIBUNWIND_LDFLAGS}) add_target_properties(test_mod_simple_vhost COMPILE_FLAGS ${LIBUNWIND_CFLAGS}) + target_link_libraries(test_mod_staticfile ${LIBUNWIND_LDFLAGS}) + add_target_properties(test_mod_staticfile COMPILE_FLAGS ${LIBUNWIND_CFLAGS}) target_link_libraries(test_mod_userdir ${LIBUNWIND_LDFLAGS}) add_target_properties(test_mod_userdir COMPILE_FLAGS ${LIBUNWIND_CFLAGS}) target_link_libraries(test_request ${LIBUNWIND_LDFLAGS}) diff --git a/src/Makefile.am b/src/Makefile.am index fe7341e6..1f15aec4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -10,6 +10,7 @@ noinst_PROGRAMS=\ t/test_mod_access \ t/test_mod_evhost \ t/test_mod_simple_vhost \ + t/test_mod_staticfile \ t/test_mod_userdir \ t/test_request @@ -26,6 +27,7 @@ TESTS=\ t/test_mod_access$(EXEEXT) \ t/test_mod_evhost$(EXEEXT) \ t/test_mod_simple_vhost$(EXEEXT) \ + t/test_mod_staticfile$(EXEEXT) \ t/test_mod_userdir$(EXEEXT) \ t/test_request$(EXEEXT) @@ -663,6 +665,9 @@ t_test_mod_evhost_LDADD = $(LIBUNWIND_LIBS) t_test_mod_simple_vhost_SOURCES = t/test_mod_simple_vhost.c buffer.c array.c log.c ck.c t_test_mod_simple_vhost_LDADD = $(LIBUNWIND_LIBS) +t_test_mod_staticfile_SOURCES = t/test_mod_staticfile.c request.c base64.c buffer.c burl.c array.c chunk.c fdevent.c http-header-glue.c http_cgi.c http_chunk.c http_date.c http_etag.c http_header.c http_kv.c log.c sock_addr.c stat_cache.c algo_splaytree.c ck.c +t_test_mod_staticfile_LDADD = $(LIBUNWIND_LIBS) $(FAM_LIBS) + t_test_mod_userdir_SOURCES = t/test_mod_userdir.c buffer.c array.c log.c ck.c t_test_mod_userdir_LDADD = $(LIBUNWIND_LIBS) diff --git a/src/meson.build b/src/meson.build index fdf57ca9..a0c6ee9e 100644 --- a/src/meson.build +++ b/src/meson.build @@ -895,7 +895,11 @@ test('test_configfile', executable('test_configfile', 'sock_addr.c', 'ck.c', ], - dependencies: common_flags + libpcre + libunwind, + dependencies: [ common_flags + , libpcre + , libunwind + , libws2_32 + ], build_by_default: false, )) @@ -949,6 +953,38 @@ test('test_mod_simple_vhost', executable('test_mod_simple_vhost', build_by_default: false, )) +test('test_mod_staticfile', executable('test_mod_staticfile', + sources: [ + 't/test_mod_staticfile.c', + 'request.c', + 'base64.c', + 'buffer.c', + 'burl.c', + 'array.c', + 'chunk.c', + 'fdevent.c', + 'http-header-glue.c', + 'http_cgi.c', + 'http_chunk.c', + 'http_date.c', + 'http_etag.c', + 'http_header.c', + 'http_kv.c', + 'log.c', + 'sock_addr.c', + 'stat_cache.c', + 'algo_splaytree.c', + 'ck.c' + ], + dependencies: [ common_flags + , libfam + , libpcre + , libunwind + , libws2_32 + ], + build_by_default: false, +)) + test('test_mod_userdir', executable('test_mod_userdir', sources: [ 't/test_mod_userdir.c', @@ -974,7 +1010,11 @@ test('test_request', executable('test_request', 'sock_addr.c', 'ck.c', ], - dependencies: common_flags + libunwind, + dependencies: [ common_flags + , libpcre + , libunwind + , libws2_32 + ], build_by_default: false, )) diff --git a/src/mod_staticfile.c b/src/mod_staticfile.c index 763cc521..d39abe29 100644 --- a/src/mod_staticfile.c +++ b/src/mod_staticfile.c @@ -107,25 +107,19 @@ mod_staticfile_not_handled(request_st * const r, const char * const msg) return HANDLER_GO_ON; } -URIHANDLER_FUNC(mod_staticfile_subrequest) { - if (NULL != r->handler_module) return HANDLER_GO_ON; - if (!http_method_get_head_post(r->http_method)) return HANDLER_GO_ON; - /* r->physical.path is non-empty for handle_subrequest_start */ - /*if (buffer_is_blank(&r->physical.path)) return HANDLER_GO_ON;*/ - - plugin_data * const p = p_d; - mod_staticfile_patch_config(r, p); - - if (p->conf.disable_pathinfo && !buffer_is_blank(&r->pathinfo)) { +static handler_t +mod_staticfile_process (request_st * const r, plugin_config * const pconf) +{ + if (pconf->disable_pathinfo && !buffer_is_blank(&r->pathinfo)) { return mod_staticfile_not_handled(r, "pathinfo"); } - if (p->conf.exclude_ext - && array_match_value_suffix(p->conf.exclude_ext, &r->physical.path)) { + if (pconf->exclude_ext + && array_match_value_suffix(pconf->exclude_ext, &r->physical.path)) { return mod_staticfile_not_handled(r, "extension"); } - if (!p->conf.etags_used) r->conf.etag_flags = 0; + if (!pconf->etags_used) r->conf.etag_flags = 0; /* r->tmp_sce is set in http_response_physical_path_check() and is valid * in handle_subrequest_start callback -- handle_subrequest_start callbacks @@ -138,6 +132,18 @@ URIHANDLER_FUNC(mod_staticfile_subrequest) { return HANDLER_FINISHED; } +URIHANDLER_FUNC(mod_staticfile_subrequest) { + if (NULL != r->handler_module) return HANDLER_GO_ON; + if (!http_method_get_head_post(r->http_method)) return HANDLER_GO_ON; + /* r->physical.path is non-empty for handle_subrequest_start */ + /*if (buffer_is_blank(&r->physical.path)) return HANDLER_GO_ON;*/ + + plugin_data * const p = p_d; + mod_staticfile_patch_config(r, p); + + return mod_staticfile_process(r, &p->conf); +} + int mod_staticfile_plugin_init(plugin *p); int mod_staticfile_plugin_init(plugin *p) { diff --git a/src/t/test_mod_staticfile.c b/src/t/test_mod_staticfile.c new file mode 100644 index 00000000..58e4e968 --- /dev/null +++ b/src/t/test_mod_staticfile.c @@ -0,0 +1,458 @@ +#include "first.h" + +#undef NDEBUG +#include <sys/types.h> +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> + +#include "mod_staticfile.c" +#include "http_date.h" +#include "http_etag.h" +#include "http_header.h" + +__attribute_noinline__ +static void test_mod_staticfile_reset (request_st * const r) +{ + r->http_status = 0; + r->resp_htags = 0; + array_reset_data_strings(&r->resp_headers); + http_response_body_clear(r, 0); + buffer_clear(&r->physical.etag); + r->conf.etag_flags = ETAG_USE_INODE | ETAG_USE_MTIME | ETAG_USE_SIZE; +} + +__attribute_noinline__ +static void +run_http_response_send_file (request_st * const r, int line, int status, const char *desc) +{ + http_response_send_file(r, &r->physical.path, NULL); + if (r->http_status != status) { + fprintf(stderr, + "%s.%d: %s() failed: expected '%d', got '%d' for test %s\n", + __FILE__, line, "http_response_send_file", status, + r->http_status, desc); + fflush(stderr); + abort(); + } +} + +static void +test_http_response_send_file (request_st * const r, time_t lmtime) +{ + test_mod_staticfile_reset(r); + const buffer *vb; + + /*(mismatch test must be first, else stat_cache will have cached mimetype)*/ + array * const mimetypes_empty = array_init(0); + const array * const mimetypes_orig = r->conf.mimetypes; + r->conf.mimetypes = mimetypes_empty; + run_http_response_send_file(r, __LINE__, 200, + "basic static file (w/o mimetype match)"); + vb = http_header_response_get(r, HTTP_HEADER_CONTENT_TYPE, + CONST_STR_LEN("Content-Type")); + assert(vb && buffer_eq_slen(vb, CONST_STR_LEN("application/octet-stream"))); + test_mod_staticfile_reset(r); + r->conf.mimetypes = mimetypes_orig; + array_free(mimetypes_empty); + + run_http_response_send_file(r, __LINE__, 200, + "basic static file (w/ mimetype match)"); + vb = http_header_response_get(r, HTTP_HEADER_CONTENT_TYPE, + CONST_STR_LEN("Content-Type")); + assert(vb && buffer_eq_slen(vb, CONST_STR_LEN("text/plain"))); + vb = http_header_response_get(r, HTTP_HEADER_ETAG, + CONST_STR_LEN("ETag")); + assert(vb && vb->ptr[0] == '"' && vb->ptr[buffer_clen(vb)-1] == '"'); + vb = http_header_response_get(r, HTTP_HEADER_LAST_MODIFIED, + CONST_STR_LEN("Last-Modified")); + assert(vb); + test_mod_staticfile_reset(r); + + const uint32_t plen = buffer_clen(&r->physical.path); + buffer_append_string_len(&r->physical.path, CONST_STR_LEN("-nonexistent")); + run_http_response_send_file(r, __LINE__, 404, + "non-existent file"); + test_mod_staticfile_reset(r); + buffer_truncate(&r->physical.path, plen); + + http_header_request_set(r, HTTP_HEADER_IF_MODIFIED_SINCE, + CONST_STR_LEN("If-Modified-Since"), + CONST_STR_LEN("")); + run_http_response_send_file(r, __LINE__, 200, + "if-modified-since invalid (empty)"); + test_mod_staticfile_reset(r); + + http_header_request_set(r, HTTP_HEADER_IF_MODIFIED_SINCE, + CONST_STR_LEN("If-Modified-Since"), + CONST_STR_LEN("foobar")); + run_http_response_send_file(r, __LINE__, 200, + "if-modified-since invalid (not time string)"); + test_mod_staticfile_reset(r); + + http_header_request_set(r, HTTP_HEADER_IF_MODIFIED_SINCE, + CONST_STR_LEN("If-Modified-Since"), + CONST_STR_LEN("this string is too long to be a valid timestamp")); + run_http_response_send_file(r, __LINE__, 200, + "if-modified-since invalid (too long to be valid time string)"); + test_mod_staticfile_reset(r); + + char lmtime_str[HTTP_DATE_SZ]; + uint32_t lmtime_len; + + lmtime_len = http_date_time_to_str(lmtime_str,sizeof(lmtime_str), + lmtime ? lmtime-1 : lmtime); + http_header_request_set(r, HTTP_HEADER_IF_MODIFIED_SINCE, + CONST_STR_LEN("If-Modified-Since"), + lmtime_str, lmtime_len); + run_http_response_send_file(r, __LINE__, 200, + "if-modified-since older than st_mtime"); + test_mod_staticfile_reset(r); + + lmtime_len = http_date_time_to_str(lmtime_str,sizeof(lmtime_str),lmtime); + http_header_request_set(r, HTTP_HEADER_IF_MODIFIED_SINCE, + CONST_STR_LEN("If-Modified-Since"), + lmtime_str, lmtime_len); + run_http_response_send_file(r, __LINE__, 304, + "if-modified-since matches st_mtime"); + test_mod_staticfile_reset(r); + + lmtime_len = http_date_time_to_str(lmtime_str,sizeof(lmtime_str),lmtime+1); + http_header_request_set(r, HTTP_HEADER_IF_MODIFIED_SINCE, + CONST_STR_LEN("If-Modified-Since"), + lmtime_str, lmtime_len); + run_http_response_send_file(r, __LINE__, 304, + "if-modified-since newer than st_mtime"); + test_mod_staticfile_reset(r); + + buffer_append_string_len( + http_header_request_get(r, HTTP_HEADER_IF_MODIFIED_SINCE, + CONST_STR_LEN("If-Modified-Since")), + CONST_STR_LEN("; foo")); + run_http_response_send_file(r, __LINE__, 200, + "if-modified-since newer but overload (invalid)"); + test_mod_staticfile_reset(r); + + http_header_request_unset(r, HTTP_HEADER_IF_MODIFIED_SINCE, + CONST_STR_LEN("If-Modified-Since")); + + buffer *etag = buffer_init(); + http_header_request_set(r, HTTP_HEADER_IF_NONE_MATCH, + CONST_STR_LEN("If-None-Match"), + CONST_STR_LEN("foo")); + run_http_response_send_file(r, __LINE__, 200, + "if-none-match (etag mismatch)"); + vb = http_header_response_get(r, HTTP_HEADER_ETAG, + CONST_STR_LEN("ETag")); + assert(vb); + buffer_copy_buffer(etag, vb); + test_mod_staticfile_reset(r); + + http_header_request_set(r, HTTP_HEADER_IF_NONE_MATCH, + CONST_STR_LEN("If-None-Match"), + CONST_BUF_LEN(etag)); + run_http_response_send_file(r, __LINE__, 304, + "if-none-match (etag match)"); + test_mod_staticfile_reset(r); + + r->conf.etag_flags = 0; + http_header_request_set(r, HTTP_HEADER_IF_NONE_MATCH, + CONST_STR_LEN("If-None-Match"), + CONST_BUF_LEN(etag)); + run_http_response_send_file(r, __LINE__, 200, + "if-none-match (etag would match, but etags disabled in config)"); + test_mod_staticfile_reset(r); + r->conf.etag_flags = ETAG_USE_INODE | ETAG_USE_MTIME | ETAG_USE_SIZE; + + http_header_request_set(r, HTTP_HEADER_IF_NONE_MATCH, + CONST_STR_LEN("If-None-Match"), + CONST_BUF_LEN(etag)); + lmtime_len = http_date_time_to_str(lmtime_str,sizeof(lmtime_str), + lmtime ? lmtime-1 : lmtime); + http_header_request_set(r, HTTP_HEADER_IF_MODIFIED_SINCE, + CONST_STR_LEN("If-Modified-Since"), + lmtime_str, lmtime_len); + run_http_response_send_file(r, __LINE__, 304, + "if-none-match (etag match), " + "if-modified-since (old) (should be ignored)"); + test_mod_staticfile_reset(r); + + http_header_request_set(r, HTTP_HEADER_IF_NONE_MATCH, + CONST_STR_LEN("If-None-Match"), + CONST_BUF_LEN(etag)); + lmtime_len = http_date_time_to_str(lmtime_str,sizeof(lmtime_str),lmtime); + http_header_request_set(r, HTTP_HEADER_IF_MODIFIED_SINCE, + CONST_STR_LEN("If-Modified-Since"), + lmtime_str, lmtime_len); + run_http_response_send_file(r, __LINE__, 304, + "if-none-match (etag match), " + "if-modified-since (now) (should be ignored)"); + test_mod_staticfile_reset(r); + + http_header_request_set(r, HTTP_HEADER_IF_NONE_MATCH, + CONST_STR_LEN("If-None-Match"), + CONST_BUF_LEN(etag)); + http_header_request_set(r, HTTP_HEADER_IF_MODIFIED_SINCE, + CONST_STR_LEN("If-Modified-Since"), + CONST_STR_LEN("Sun, 01 Jan 1970 00:00:01 GMT foo")); + run_http_response_send_file(r, __LINE__, 304, + "if-none-match (etag match), " + "if-modified-since (overlong; invalid) (should be ignored)"); + test_mod_staticfile_reset(r); + + http_header_request_set(r, HTTP_HEADER_IF_NONE_MATCH, + CONST_STR_LEN("If-None-Match"), + CONST_STR_LEN("foo")); + lmtime_len = http_date_time_to_str(lmtime_str,sizeof(lmtime_str), + lmtime ? lmtime-1 : lmtime); + http_header_request_set(r, HTTP_HEADER_IF_MODIFIED_SINCE, + CONST_STR_LEN("If-Modified-Since"), + lmtime_str, lmtime_len); + run_http_response_send_file(r, __LINE__, 200, + "if-none-match (etag mismatch), " + "if-modified-since (old) (should be ignored)"); + test_mod_staticfile_reset(r); + + http_header_request_set(r, HTTP_HEADER_IF_NONE_MATCH, + CONST_STR_LEN("If-None-Match"), + CONST_STR_LEN("foo")); + lmtime_len = http_date_time_to_str(lmtime_str,sizeof(lmtime_str),lmtime); + http_header_request_set(r, HTTP_HEADER_IF_MODIFIED_SINCE, + CONST_STR_LEN("If-Modified-Since"), + lmtime_str, lmtime_len); + run_http_response_send_file(r, __LINE__, 200, + "if-none-match (etag mismatch), " + "if-modified-since (now) (should be ignored)"); + test_mod_staticfile_reset(r); + + http_header_request_unset(r, HTTP_HEADER_IF_MODIFIED_SINCE, + CONST_STR_LEN("If-Modified-Since")); + + http_header_request_set(r, HTTP_HEADER_IF_NONE_MATCH, + CONST_STR_LEN("If-None-Match"), + etag->ptr, buffer_clen(etag)-1); + run_http_response_send_file(r, __LINE__, 200, + "if-none-match (etag invalid; mismatched quotes)"); + test_mod_staticfile_reset(r); + + http_header_request_set(r, HTTP_HEADER_IF_NONE_MATCH, + CONST_STR_LEN("If-None-Match"), + etag->ptr+1, buffer_clen(etag)-2); + run_http_response_send_file(r, __LINE__, 200, + "if-none-match (etag invalid; no quotes)"); + test_mod_staticfile_reset(r); + + http_header_request_set(r, HTTP_HEADER_IF_NONE_MATCH, + CONST_STR_LEN("If-None-Match"), + CONST_STR_LEN("*")); + run_http_response_send_file(r, __LINE__, 304, + "if-none-match (etag * (unquoted) matches any ETag)"); + test_mod_staticfile_reset(r); + + http_header_request_set(r, HTTP_HEADER_IF_NONE_MATCH, + CONST_STR_LEN("If-None-Match"), + CONST_STR_LEN("\"*\"")); + run_http_response_send_file(r, __LINE__, 200, + "if-none-match (etag \"*\" (quoted) is a regular ETag)"); + test_mod_staticfile_reset(r); + + buffer * const rqst_etag = + http_header_request_set_ptr(r, HTTP_HEADER_IF_NONE_MATCH, + CONST_STR_LEN("If-None-Match")); + + buffer_copy_string_len(rqst_etag, CONST_STR_LEN("W/")); + buffer_append_buffer(rqst_etag, etag); + run_http_response_send_file(r, __LINE__, 304, + "if-none-match (weak etag) matches like ETag for GET and HEAD)"); + test_mod_staticfile_reset(r); + + /*(200 expected here instead of 206 since Range is handled later)*/ + http_header_request_set(r, HTTP_HEADER_RANGE, + CONST_STR_LEN("Range"), + CONST_STR_LEN("bytes=0-0")); + run_http_response_send_file(r, __LINE__, 200, + "if-none-match (weak etag) does not match for Range request)"); + test_mod_staticfile_reset(r); + http_header_request_unset(r, HTTP_HEADER_RANGE, CONST_STR_LEN("Range")); + + buffer_copy_string_len(rqst_etag, CONST_STR_LEN("W/\"12345\"")); + run_http_response_send_file(r, __LINE__, 200, + "if-none-match (weak etag no match)"); + test_mod_staticfile_reset(r); + + buffer_append_string_len(rqst_etag, CONST_STR_LEN(", ")); + buffer_append_buffer(rqst_etag, etag); + run_http_response_send_file(r, __LINE__, 304, + "if-none-match (etag list, second etag matches)"); + test_mod_staticfile_reset(r); + + buffer_append_string_len(rqst_etag, CONST_STR_LEN(", W/")); + buffer_append_buffer(rqst_etag, etag); + run_http_response_send_file(r, __LINE__, 304, + "if-none-match (etag list, second etag matches weakly)"); + test_mod_staticfile_reset(r); + + buffer_copy_string_len(rqst_etag, CONST_STR_LEN("\"12345\",, ,, , ")); + buffer_append_buffer(rqst_etag, etag); + run_http_response_send_file(r, __LINE__, 304, + "if-none-match (etag list non-normalized, ending with etag match)"); + test_mod_staticfile_reset(r); + + buffer_copy_string_len(rqst_etag, CONST_STR_LEN("\"1234\", ")); + buffer_append_buffer(rqst_etag, etag); + buffer_append_string_len(rqst_etag, CONST_STR_LEN(", \"brokentrailing")); + run_http_response_send_file(r, __LINE__, 304, + "if-none-match (etag list with etag match then invalid trailing data)"); + test_mod_staticfile_reset(r); + + http_header_request_unset(r, HTTP_HEADER_IF_NONE_MATCH, + CONST_STR_LEN("If-None-Match")); + + buffer_free(etag); +} + +__attribute_noinline__ +static void +run_mod_staticfile_process (request_st * const r, plugin_config * const pconf, int line, int status, const char *desc) +{ + handler_t rc = mod_staticfile_process(r, pconf); + if (r->http_status != status + || rc != (status ? HANDLER_FINISHED : HANDLER_GO_ON)) { + fprintf(stderr, + "%s.%d: %s() failed: expected '%d', got '%d' for test %s\n", + __FILE__, line, "mod_staticfile_process", status, + r->http_status, desc); + fflush(stderr); + abort(); + } +} + +static void +test_mod_staticfile_process (request_st * const r, plugin_config * const pconf) +{ + test_mod_staticfile_reset(r); + + pconf->disable_pathinfo = 0; + buffer_copy_string_len(&r->pathinfo, CONST_STR_LEN("/pathinfo")); + run_mod_staticfile_process(r, pconf, __LINE__, 200, + "pathinfo allowed and present"); + test_mod_staticfile_reset(r); + pconf->disable_pathinfo = 1; + run_mod_staticfile_process(r, pconf, __LINE__, 0, + "pathinfo denied and present"); + test_mod_staticfile_reset(r); + buffer_clear(&r->pathinfo); + run_mod_staticfile_process(r, pconf, __LINE__, 200, + "pathinfo denied and not present"); + test_mod_staticfile_reset(r); + pconf->disable_pathinfo = 0; + + array * const a = array_init(1); + array_insert_value(a, CONST_STR_LEN(".exe")); + pconf->exclude_ext = a; + run_mod_staticfile_process(r, pconf, __LINE__, 200, + "extension disallowed (no match)"); + test_mod_staticfile_reset(r); + buffer_append_string_len(&r->physical.path, CONST_STR_LEN(".exe")); + run_mod_staticfile_process(r, pconf, __LINE__, 0, + "extension disallowed (match)"); + test_mod_staticfile_reset(r); + pconf->exclude_ext = NULL; + array_free(a); +} + +#include <unistd.h> /* unlink() */ + +int main (void) +{ + char fn[] = "/tmp/lighttpd_mod_staticfile.XXXXXX"; + #ifdef __COVERITY__ + /* POSIX-2008 requires mkstemp create file with 0600 perms */ + umask(0600); + #endif + /* coverity[secure_temp : FALSE] */ + int fd = mkstemp(fn); + if (fd < 0) { + perror("mkstemp()"); + exit(1); + } + struct stat st; + if (0 != fstat(fd, &st)) { + perror("fstat()"); + exit(1); + } + + plugin_data * const p = mod_staticfile_init(); + assert(NULL != p); + p->conf.etags_used = 1; + + request_st r; + + memset(&r, 0, sizeof(request_st)); + r.http_method = HTTP_METHOD_GET; + r.http_version = HTTP_VERSION_1_1; + r.tmp_buf = buffer_init(); + r.conf.errh = log_error_st_init(); + r.conf.errh->errorlog_fd = -1; /* (disable) */ + r.conf.follow_symlink = 1; + buffer_copy_string_len(&r.uri.path, CONST_STR_LEN("/")); + array * const mimetypes = array_init(1); + r.conf.mimetypes = mimetypes; + array_set_key_value(mimetypes, fn+sizeof(fn)-8, 7, + CONST_STR_LEN("text/plain")); + + strftime_cache_reset(); + + buffer_copy_string_len(&r.physical.path, fn, sizeof(fn)-1); + test_http_response_send_file(&r, st.st_mtime); + + r.rqst_htags = 0; + array_reset_data_strings(&r.rqst_headers); + + buffer_copy_string_len(&r.physical.path, fn, sizeof(fn)-1); + test_mod_staticfile_process(&r, &p->conf); + + array_free(mimetypes); + log_error_st_free(r.conf.errh); + buffer_free(r.tmp_buf); + chunkqueue_reset(&r.write_queue); + + free(r.uri.path.ptr); + free(r.physical.etag.ptr); + free(r.physical.path.ptr); + free(r.physical.rel_path.ptr); + free(r.physical.doc_root.ptr); + + free(p); + stat_cache_free(); + unlink(fn); + return 0; +} + + +/* + * stub functions + */ + +#include "fdevent_impl.h" +int fdevent_select_init(struct fdevents *ev) { return NULL == ev; } +int fdevent_poll_init(struct fdevents *ev) { return NULL == ev; } +int fdevent_linux_sysepoll_init(struct fdevents *ev) { return NULL == ev; } +int fdevent_solaris_devpoll_init(struct fdevents *ev) { return NULL == ev; } +int fdevent_solaris_port_init(struct fdevents *ev) { return NULL == ev; } +int fdevent_freebsd_kqueue_init(struct fdevents *ev) { return NULL == ev; } +int fdevent_libev_init(struct fdevents *ev) { return NULL == ev; } + +int config_plugin_values_init(server *srv, void *p_d, const config_plugin_keys_t *cpk, const char *mname) { + UNUSED(srv); + UNUSED(p_d); + UNUSED(cpk); + UNUSED(mname); + return 0; +} + +int config_check_cond(request_st *r, int context_ndx) { + UNUSED(r); + UNUSED(context_ndx); + return 0; +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index e199811b..0db1a440 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -3,7 +3,6 @@ add_executable(scgi-responder scgi-responder.c) set(T_FILES prepare.sh - cachable.t core-404-handler.t core-condition.t core-keepalive.t diff --git a/tests/Makefile.am b/tests/Makefile.am index c6c1231b..a23c519a 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -13,7 +13,6 @@ TESTS=\ CONFS=\ 404-handler.conf \ - cachable.t \ condition.conf \ core-404-handler.t \ core-condition.t \ diff --git a/tests/cachable.t b/tests/cachable.t deleted file mode 100755 index 5dfd5a3b..00000000 --- a/tests/cachable.t +++ /dev/null @@ -1,211 +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 => 24; -use LightyTest; - -my $tf = LightyTest->new(); -my $t; - -ok($tf->start_proc == 0, "Starting lighttpd") or die(); - -## check if If-Modified-Since, If-None-Match works - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'Conditional GET - old If-Modified-Since'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+Last-Modified' => ''} ]; -ok($tf->handle_http($t) == 0, 'Conditional GET - old If-Modified-Since, comment'); - -my $now = $t->{date}; - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -If-Modified-Since: $now -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ]; -ok($tf->handle_http($t) == 0, 'Conditional GET - new If-Modified-Since'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -If-None-Match: foo -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+ETag' => ''} ]; -ok($tf->handle_http($t) == 0, 'Conditional GET - old If-None-Match'); - -my $etag = $t->{etag}; - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -If-None-Match: $etag -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ]; -ok($tf->handle_http($t) == 0, 'Conditional GET - old If-None-Match'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -If-None-Match: $etag -If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ]; -ok($tf->handle_http($t) == 0, 'Conditional GET - ETag + old Last-Modified (which should be ignored)'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -If-None-Match: $etag -If-Modified-Since: $now; foo -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ]; -ok($tf->handle_http($t) == 0, 'Conditional GET - ETag, Last-Modified + comment (which should be ignored)'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -If-None-Match: Foo -If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'Conditional GET - old ETAG + old Last-Modified'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -If-None-Match: $etag -If-Modified-Since: $now foo -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ]; -ok($tf->handle_http($t) == 0, 'Conditional GET - ETag + Last-Modified + overlong timestamp (which should be ignored)'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -If-None-Match: $etag -Host: etag.example.org -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'Conditional GET - ETag + disabled etags on server side'); - -############### - -ok($etag =~ /^\"(.*)\"$/, "The server must quote ETags"); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -If-None-Match: $1 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'The client must send a quoted ETag'); - -$etag =~ /^(\".*)\"$/; -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -If-None-Match: $1 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'The ETag must be surrounded by quotes'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -If-None-Match: * -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ]; -ok($tf->handle_http($t) == 0, 'An unquoted star matches any ETag'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -If-None-Match: "*" -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'A quoted star is just a regular ETag'); - -{ - $t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -If-None-Match: W/$etag -EOF - ); - $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ]; - ok($tf->handle_http($t) == 0, 'A weak etag matches like a regular ETag for HEAD and GET'); -} - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.1 -Host: www.example.org -If-None-Match: W/$etag -Connection: close -Range: bytes=0-0 -EOF -); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 206, 'HTTP-Content' => '<' } ]; -ok($tf->handle_http($t) == 0, 'A weak etag does not match for ranged requests'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -If-None-Match: W/"12345" -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'However, a weak ETag is not *'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -If-None-Match: "12345", $etag -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ]; -ok($tf->handle_http($t) == 0, 'Client sent a list of ETags, the second matches'); - -{ - $t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -If-None-Match: "12345", W/$etag -EOF - ); - $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ]; - ok($tf->handle_http($t) == 0, 'The second provided ETag matches weakly'); -} - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -If-None-Match: "12345",, ,, , $etag -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ]; -ok($tf->handle_http($t) == 0, 'Broken client did get around to sending good data'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -If-None-Match: "1234", $etag, "brokentrailing -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ]; -ok($tf->handle_http($t) == 0, 'Bad syntax *after* a matching ETag doesn\'t matter'); - -ok($tf->stop_proc == 0, "Stopping lighttpd"); - diff --git a/tests/core-request.t b/tests/core-request.t index 8d982fc8..d30e952c 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 => 11; +use Test::More tests => 10; use LightyTest; my $tf = LightyTest->new(); @@ -76,13 +76,6 @@ $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'Conte ok($tf->handle_http($t) == 0, 'Content-Type - image/jpeg (upper case)'); $t->{REQUEST} = ( <<EOF -GET /a HTTP/1.0 -EOF - ); -$t->{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} = ( <<EOF GET /Foo.txt HTTP/1.0 EOF ); diff --git a/tests/core-response.t b/tests/core-response.t index d9ea023e..1c19e85c 100755 --- a/tests/core-response.t +++ b/tests/core-response.t @@ -8,7 +8,7 @@ BEGIN { use strict; use IO::Socket; -use Test::More tests => 13; +use Test::More tests => 11; use LightyTest; my $tf = LightyTest->new(); @@ -27,21 +27,6 @@ EOF $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200, '+Date' => '' } ]; ok($tf->handle_http($t) == 0, 'Date header'); -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+ETag' => '' } ]; -ok($tf->handle_http($t) == 0, 'ETag is set'); - -$t->{REQUEST} = ( <<EOF -GET / HTTP/1.0 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'ETag' => '/^".+"$/' } ]; -ok($tf->handle_http($t) == 0, 'ETag has quotes'); - - ## Low-Level Response-Header Parsing - Content-Length diff --git a/tests/meson.build b/tests/meson.build index 9ecc9192..943c1adf 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -13,7 +13,6 @@ env.set('srcdir', meson.current_source_dir()) env.set('top_builddir', meson.build_root()) tests = [ - 'cachable.t', 'core-404-handler.t', 'core-condition.t', 'core-keepalive.t', diff --git a/tests/request.t b/tests/request.t index ea8852d6..f2264486 100755 --- a/tests/request.t +++ b/tests/request.t @@ -8,7 +8,7 @@ BEGIN { use strict; use IO::Socket; -use Test::More tests => 52; +use Test::More tests => 44; use LightyTest; my $tf = LightyTest->new(); @@ -19,13 +19,6 @@ ok($tf->start_proc == 0, "Starting lighttpd") or die(); ## Basic Request-Handling $t->{REQUEST} = ( <<EOF -GET /foobar HTTP/1.0 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404 } ]; -ok($tf->handle_http($t) == 0, 'file not found'); - -$t->{REQUEST} = ( <<EOF GET /foobar?foobar HTTP/1.0 EOF ); @@ -48,14 +41,6 @@ EOF $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '12345'."\n", 'Content-Type' => 'text/html' } ]; ok($tf->handle_http($t) == 0, 'GET, content == 12345, mimetype text/html'); -$t->{REQUEST} = ( <<EOF -GET /dummyfile.bla HTTP/1.0 -Host: 123.example.org -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 @@ -445,19 +430,6 @@ ok($tf->handle_http($t) == 0, 'OPTIONS for RTSP'); my $nextyr = (gmtime(time()))[5] + 1900 + 1; -$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'); - -$t->{REQUEST} = ( "GET / HTTP/1.0\r\nIf-Modified-Since: foobar\r\n\r\n" ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'broken If-Modified-Since'); - -$t->{REQUEST} = ( "GET / HTTP/1.0\r\nIf-Modified-Since: this string is too long to be a valid timestamp\r\n\r\n" ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; -ok($tf->handle_http($t) == 0, 'broken If-Modified-Since'); - - $t->{REQUEST} = ( <<EOF GET /index.html HTTP/1.0 If-Modified-Since2: Sun, 01 Jan $nextyr 00:00:03 GMT @@ -472,15 +444,7 @@ GET /index.html HTTP/1.0 If-Modified-Since: Sun, 01 Jan $nextyr 00:00:02 GMT EOF ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304, 'Content-Type' => 'text/html' } ]; -ok($tf->handle_http($t) == 0, 'If-Modified-Since'); - -$t->{REQUEST} = ( <<EOF -GET /index.html HTTP/1.0 -If-Modified-Since: Sun, 01 Jan $nextyr 00:00:02 GMT -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304, '-Content-Length' => '' } ]; +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304, '-Content-Length' => '', 'Content-Type' => 'text/html' } ]; ok($tf->handle_http($t) == 0, 'Status 304 has no Content-Length (#1002)'); $t->{REQUEST} = ( <<EOF @@ -493,22 +457,6 @@ $t->{SLOWREQUEST} = 1; ok($tf->handle_http($t) == 0, 'GET, slow \\r\\n\\r\\n (#2105)'); undef $t->{SLOWREQUEST}; -print "\nPathinfo for static files\n"; -$t->{REQUEST} = ( <<EOF -GET /image.jpg/index.php HTTP/1.0 -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'Content-Type' => 'image/jpeg' } ]; -ok($tf->handle_http($t) == 0, 'static file accepting pathinfo by default'); - -$t->{REQUEST} = ( <<EOF -GET /image.jpg/index.php HTTP/1.0 -Host: zzz.example.org -EOF - ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ]; -ok($tf->handle_http($t) == 0, 'static file with forbidden pathinfo'); - $t->{REQUEST} = ( <<EOF GET /www/abc/def HTTP/1.0 EOF |