Browse Source

[tests] t/test_mod_staticfile

move some tests from tests/request.t to src/t/test_mod_staticfile.c
master
Glenn Strauss 5 months ago
parent
commit
91472ab768
  1. 1
      .gitignore
  2. 27
      src/CMakeLists.txt
  3. 5
      src/Makefile.am
  4. 44
      src/meson.build
  5. 32
      src/mod_staticfile.c
  6. 458
      src/t/test_mod_staticfile.c
  7. 1
      tests/CMakeLists.txt
  8. 1
      tests/Makefile.am
  9. 211
      tests/cachable.t
  10. 9
      tests/core-request.t
  11. 17
      tests/core-response.t
  12. 1
      tests/meson.build
  13. 56
      tests/request.t

1
.gitignore

@ -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

27
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})

5
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)

44
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,
))

32
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) {

458
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;
}

1
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

1
tests/Makefile.am

@ -13,7 +13,6 @@ TESTS=\
CONFS=\
404-handler.conf \
cachable.t \
condition.conf \
core-404-handler.t \
core-condition.t \

211
tests/cachable.t

@ -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");

9
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();
@ -75,13 +75,6 @@ EOF
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'Content-Type' => 'image/jpeg' } ];
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

17
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

1
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',

56
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();
@ -18,13 +18,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

Loading…
Cancel
Save