diff options
author | Laurent Bercot <ska-skaware@skarnet.org> | 2023-10-18 13:07:23 +0000 |
---|---|---|
committer | Laurent Bercot <ska@appnovation.com> | 2023-10-18 13:07:23 +0000 |
commit | 1a7e3d00588725da3d8764fa9d624bc8611be070 (patch) | |
tree | 65d28b52bd1d4ccdbeb418d4d681b1999ed46b7a | |
parent | 24fb88dbb023ae08adc9989bf19e0c6c569a6607 (diff) | |
download | tipidee-1a7e3d00588725da3d8764fa9d624bc8611be070.tar.xz |
Add infrastructure for custom error files
Signed-off-by: Laurent Bercot <ska@appnovation.com>
-rw-r--r-- | doc/tipidee.conf.html | 7 | ||||
-rw-r--r-- | doc/tipideed.html | 10 | ||||
-rw-r--r-- | package/deps.mak | 16 | ||||
-rw-r--r-- | src/include/tipidee/conf.h | 1 | ||||
-rw-r--r-- | src/include/tipidee/log.h | 2 | ||||
-rw-r--r-- | src/include/tipidee/response.h | 10 | ||||
-rw-r--r-- | src/libtipidee/deps-lib/tipidee | 4 | ||||
-rw-r--r-- | src/libtipidee/tipidee_conf_get_errorfile.c | 24 | ||||
-rw-r--r-- | src/libtipidee/tipidee_log_request.c | 2 | ||||
-rw-r--r-- | src/libtipidee/tipidee_log_resource.c | 13 | ||||
-rw-r--r-- | src/libtipidee/tipidee_response_error.c | 41 | ||||
-rw-r--r-- | src/libtipidee/tipidee_response_error_nofile.c | 35 | ||||
-rw-r--r-- | src/libtipidee/tipidee_response_file.c | 31 | ||||
-rw-r--r-- | src/libtipidee/tipidee_response_header_common_put.c | 17 | ||||
-rw-r--r-- | src/libtipidee/tipidee_response_status.c | 4 | ||||
-rw-r--r-- | src/libtipidee/tipidee_rql_read.c | 5 | ||||
-rw-r--r-- | src/tipideed/cgi.c | 144 | ||||
-rw-r--r-- | src/tipideed/regular.c | 25 | ||||
-rw-r--r-- | src/tipideed/responses.c | 80 | ||||
-rw-r--r-- | src/tipideed/tipideed-internal.h | 73 | ||||
-rw-r--r-- | src/tipideed/tipideed.c | 106 |
21 files changed, 379 insertions, 271 deletions
diff --git a/doc/tipidee.conf.html b/doc/tipidee.conf.html index 76ffae1..483d9d0 100644 --- a/doc/tipidee.conf.html +++ b/doc/tipidee.conf.html @@ -407,9 +407,12 @@ malicious clients messing with log lines. This keyword has no effect when given without the <tt>request</tt> keyword. </dd> <dt> <tt>resource</tt> </dt> <dd> Log a <tt>resource</tt> line when <a href="tipideed.html">tipideed</a> has found a resource corresponding to the URI and is willing to serve it. The line looks like -<tt>resource docroot <em>docroot</em> file <em>file</em> type <em>type</em></tt>. <em>docroot</em> is -the document root of the virtual host; <em>file</em> is the path to the served file; <em>type</em> +<tt>resource <em>file</em> type <em>type</em></tt>. +<em>file</em> is the path to the served file; the first component of that path is always +the document root of the virtual host. <em>type</em> is <tt>nph</tt> for an NPH script, <tt>cgi</tt> for a CGI script, or the Content-Type for a regular file. +If it's a CGI or NPH script being called with a non-empty PATH_INFO, an additional <tt>path_info <em>path_info</em></tt> +field is added to the log line. If a served CGI script outputs a local redirection, several <tt>resource</tt> lines may appear for a single request. </dd> <dt> <tt>answer</tt> </dt> <dd> Log an <tt>answer</tt> line when <a href="tipideed.html">tipideed</a> diff --git a/doc/tipideed.html b/doc/tipideed.html index 254fa2f..eebdb6d 100644 --- a/doc/tipideed.html +++ b/doc/tipideed.html @@ -120,8 +120,8 @@ underlying system. </dd> <p> tipideed expects the following variables in its environment, and will exit with an error message if they are undefined. When tipideed is run under -<a href="//skarnet.org/s6-networking/s6-tcpserver.html">s6-tcpserver</a> or -<a href="//skarnet.org/s6-networking/s6-tlsserver.html">s6-tlsserver</a>, +<a href="//skarnet.org/software/s6-networking/s6-tcpserver.html">s6-tcpserver</a> or +<a href="//skarnet.org/software/s6-networking/s6-tlsserver.html">s6-tlsserver</a>, these variables are automatically set by the super-server. This is the way tipidee gets its network information without having to perform network operations itself. @@ -153,11 +153,11 @@ to CGI scripts. </dd> <p> tipideed can function without these variables, but if they're present, it uses them to get more information. They're typically obtained by calling -<a href="//skarnet.org/s6-networking/s6-tcpserver-access.html">s6-tcpserver-access</a> +<a href="//skarnet.org/software/s6-networking/s6-tcpserver-access.html">s6-tcpserver-access</a> before tipideed in the -<a href="//skarnet.org/s6-networking/s6-tcpserver.html">s6-tcpserver</a> +<a href="//skarnet.org/software/s6-networking/s6-tcpserver.html">s6-tcpserver</a> command line. -(For HTTPS, <a href="//skarnet.org/s6-networking/s6-tlsserver.html">s6-tlsserver</a> +(For HTTPS, <a href="//skarnet.org/software/s6-networking/s6-tlsserver.html">s6-tlsserver</a> calls it implicitly.) </p> diff --git a/package/deps.mak b/package/deps.mak index f389e28..3b29af0 100644 --- a/package/deps.mak +++ b/package/deps.mak @@ -18,6 +18,7 @@ src/libtipidee/tipidee_conf_free.o src/libtipidee/tipidee_conf_free.lo: src/libt src/libtipidee/tipidee_conf_get.o src/libtipidee/tipidee_conf_get.lo: src/libtipidee/tipidee_conf_get.c src/include/tipidee/conf.h src/libtipidee/tipidee_conf_get_argv.o src/libtipidee/tipidee_conf_get_argv.lo: src/libtipidee/tipidee_conf_get_argv.c src/include/tipidee/conf.h src/libtipidee/tipidee_conf_get_content_type.o src/libtipidee/tipidee_conf_get_content_type.lo: src/libtipidee/tipidee_conf_get_content_type.c src/include/tipidee/conf.h +src/libtipidee/tipidee_conf_get_errorfile.o src/libtipidee/tipidee_conf_get_errorfile.lo: src/libtipidee/tipidee_conf_get_errorfile.c src/include/tipidee/conf.h src/libtipidee/tipidee_conf_get_redirection.o src/libtipidee/tipidee_conf_get_redirection.lo: src/libtipidee/tipidee_conf_get_redirection.c src/include/tipidee/conf.h src/libtipidee/tipidee_conf_get_string.o src/libtipidee/tipidee_conf_get_string.lo: src/libtipidee/tipidee_conf_get_string.c src/include/tipidee/conf.h src/libtipidee/tipidee_conf_get_uint32.o src/libtipidee/tipidee_conf_get_uint32.lo: src/libtipidee/tipidee_conf_get_uint32.c src/include/tipidee/conf.h @@ -32,9 +33,10 @@ src/libtipidee/tipidee_log_request.o src/libtipidee/tipidee_log_request.lo: src/ src/libtipidee/tipidee_log_resource.o src/libtipidee/tipidee_log_resource.lo: src/libtipidee/tipidee_log_resource.c src/include/tipidee/log.h src/libtipidee/tipidee_log_start.o src/libtipidee/tipidee_log_start.lo: src/libtipidee/tipidee_log_start.c src/include/tipidee/log.h src/libtipidee/tipidee_method.o src/libtipidee/tipidee_method.lo: src/libtipidee/tipidee_method.c src/include/tipidee/method.h -src/libtipidee/tipidee_response_error.o src/libtipidee/tipidee_response_error.lo: src/libtipidee/tipidee_response_error.c src/include/tipidee/method.h src/include/tipidee/response.h src/include/tipidee/rql.h +src/libtipidee/tipidee_response_error_nofile.o src/libtipidee/tipidee_response_error_nofile.lo: src/libtipidee/tipidee_response_error_nofile.c src/include/tipidee/method.h src/include/tipidee/response.h +src/libtipidee/tipidee_response_file.o src/libtipidee/tipidee_response_file.lo: src/libtipidee/tipidee_response_file.c src/include/tipidee/conf.h src/include/tipidee/method.h src/include/tipidee/response.h src/include/tipidee/rql.h src/include/tipidee/util.h src/libtipidee/tipidee_response_header_builtin.o src/libtipidee/tipidee_response_header_builtin.lo: src/libtipidee/tipidee_response_header_builtin.c src/include/tipidee/config.h src/include/tipidee/response.h -src/libtipidee/tipidee_response_header_common_put.o src/libtipidee/tipidee_response_header_common_put.lo: src/libtipidee/tipidee_response_header_common_put.c src/include/tipidee/config.h src/include/tipidee/response.h +src/libtipidee/tipidee_response_header_common_put.o src/libtipidee/tipidee_response_header_common_put.lo: src/libtipidee/tipidee_response_header_common_put.c src/include/tipidee/response.h src/libtipidee/tipidee_response_header_date.o src/libtipidee/tipidee_response_header_date.lo: src/libtipidee/tipidee_response_header_date.c src/include/tipidee/response.h src/libtipidee/tipidee_response_header_date_fmt.o src/libtipidee/tipidee_response_header_date_fmt.lo: src/libtipidee/tipidee_response_header_date_fmt.c src/include/tipidee/response.h src/libtipidee/tipidee_response_header_lastmodified.o src/libtipidee/tipidee_response_header_lastmodified.lo: src/libtipidee/tipidee_response_header_lastmodified.c src/include/tipidee/response.h @@ -44,11 +46,11 @@ src/libtipidee/tipidee_uri_parse.o src/libtipidee/tipidee_uri_parse.lo: src/libt src/libtipidee/tipidee_util_chunked_read.o src/libtipidee/tipidee_util_chunked_read.lo: src/libtipidee/tipidee_util_chunked_read.c src/include/tipidee/util.h src/libtipidee/tipidee_util_defaulttext.o src/libtipidee/tipidee_util_defaulttext.lo: src/libtipidee/tipidee_util_defaulttext.c src/include/tipidee/util.h src/libtipidee/tipidee_util_httpdate.o src/libtipidee/tipidee_util_httpdate.lo: src/libtipidee/tipidee_util_httpdate.c src/include/tipidee/util.h -src/tipideed/cgi.o src/tipideed/cgi.lo: src/tipideed/cgi.c src/include/tipidee/headers.h src/include/tipidee/method.h src/include/tipidee/response.h src/include/tipidee/uri.h src/tipideed/tipideed-internal.h +src/tipideed/cgi.o src/tipideed/cgi.lo: src/tipideed/cgi.c src/include/tipidee/tipidee.h src/tipideed/tipideed-internal.h src/tipideed/harden.o src/tipideed/harden.lo: src/tipideed/harden.c src/tipideed/tipideed-internal.h src/tipideed/options.o src/tipideed/options.lo: src/tipideed/options.c src/include/tipidee/log.h src/include/tipidee/response.h src/tipideed/tipideed-internal.h src/tipideed/regular.o src/tipideed/regular.lo: src/tipideed/regular.c src/include/tipidee/log.h src/include/tipidee/method.h src/include/tipidee/response.h src/tipideed/tipideed-internal.h -src/tipideed/responses.o src/tipideed/responses.lo: src/tipideed/responses.c src/include/tipidee/log.h src/include/tipidee/response.h src/include/tipidee/rql.h src/tipideed/tipideed-internal.h +src/tipideed/responses.o src/tipideed/responses.lo: src/tipideed/responses.c src/include/tipidee/log.h src/include/tipidee/response.h src/include/tipidee/util.h src/tipideed/tipideed-internal.h src/tipideed/send_file.o src/tipideed/send_file.lo: src/tipideed/send_file.c src/tipideed/tipideed-internal.h src/tipideed/tipideed.o src/tipideed/tipideed.lo: src/tipideed/tipideed.c src/include/tipidee/tipidee.h src/tipideed/tipideed-internal.h src/tipideed/trace.o src/tipideed/trace.lo: src/tipideed/trace.c src/include/tipidee/log.h src/include/tipidee/method.h src/include/tipidee/response.h src/tipideed/tipideed-internal.h @@ -58,12 +60,12 @@ tipidee-config: src/config/tipidee-config.o src/config/confnode.o src/config/con tipidee-config-preprocess: EXTRA_LIBS := -lskarnet tipidee-config-preprocess: src/config/tipidee-config-preprocess.o ifeq ($(strip $(STATIC_LIBS_ARE_PIC)),) -libtipidee.a.xyzzy: src/libtipidee/tipidee_conf_free.o src/libtipidee/tipidee_conf_get.o src/libtipidee/tipidee_conf_get_argv.o src/libtipidee/tipidee_conf_get_content_type.o src/libtipidee/tipidee_conf_get_redirection.o src/libtipidee/tipidee_conf_get_string.o src/libtipidee/tipidee_conf_get_uint32.o src/libtipidee/tipidee_conf_init.o src/libtipidee/tipidee_headers_get_content_length.o src/libtipidee/tipidee_headers_init.o src/libtipidee/tipidee_headers_parse.o src/libtipidee/tipidee_headers_search.o src/libtipidee/tipidee_log_answer.o src/libtipidee/tipidee_log_exit.o src/libtipidee/tipidee_log_resource.o src/libtipidee/tipidee_log_request.o src/libtipidee/tipidee_log_start.o src/libtipidee/tipidee_method.o src/libtipidee/tipidee_response_error.o src/libtipidee/tipidee_response_header_builtin.o src/libtipidee/tipidee_response_header_common_put.o src/libtipidee/tipidee_response_header_date.o src/libtipidee/tipidee_response_header_date_fmt.o src/libtipidee/tipidee_response_header_lastmodified.o src/libtipidee/tipidee_response_status.o src/libtipidee/tipidee_rql_read.o src/libtipidee/tipidee_uri_parse.o src/libtipidee/tipidee_util_chunked_read.o src/libtipidee/tipidee_util_defaulttext.o src/libtipidee/tipidee_util_httpdate.o +libtipidee.a.xyzzy: src/libtipidee/tipidee_conf_free.o src/libtipidee/tipidee_conf_get.o src/libtipidee/tipidee_conf_get_argv.o src/libtipidee/tipidee_conf_get_content_type.o src/libtipidee/tipidee_conf_get_errorfile.o src/libtipidee/tipidee_conf_get_redirection.o src/libtipidee/tipidee_conf_get_string.o src/libtipidee/tipidee_conf_get_uint32.o src/libtipidee/tipidee_conf_init.o src/libtipidee/tipidee_headers_get_content_length.o src/libtipidee/tipidee_headers_init.o src/libtipidee/tipidee_headers_parse.o src/libtipidee/tipidee_headers_search.o src/libtipidee/tipidee_log_answer.o src/libtipidee/tipidee_log_exit.o src/libtipidee/tipidee_log_resource.o src/libtipidee/tipidee_log_request.o src/libtipidee/tipidee_log_start.o src/libtipidee/tipidee_method.o src/libtipidee/tipidee_response_error_nofile.o src/libtipidee/tipidee_response_file.o src/libtipidee/tipidee_response_header_builtin.o src/libtipidee/tipidee_response_header_common_put.o src/libtipidee/tipidee_response_header_date.o src/libtipidee/tipidee_response_header_date_fmt.o src/libtipidee/tipidee_response_header_lastmodified.o src/libtipidee/tipidee_response_status.o src/libtipidee/tipidee_rql_read.o src/libtipidee/tipidee_uri_parse.o src/libtipidee/tipidee_util_chunked_read.o src/libtipidee/tipidee_util_defaulttext.o src/libtipidee/tipidee_util_httpdate.o else -libtipidee.a.xyzzy: src/libtipidee/tipidee_conf_free.lo src/libtipidee/tipidee_conf_get.lo src/libtipidee/tipidee_conf_get_argv.lo src/libtipidee/tipidee_conf_get_content_type.lo src/libtipidee/tipidee_conf_get_redirection.lo src/libtipidee/tipidee_conf_get_string.lo src/libtipidee/tipidee_conf_get_uint32.lo src/libtipidee/tipidee_conf_init.lo src/libtipidee/tipidee_headers_get_content_length.lo src/libtipidee/tipidee_headers_init.lo src/libtipidee/tipidee_headers_parse.lo src/libtipidee/tipidee_headers_search.lo src/libtipidee/tipidee_log_answer.lo src/libtipidee/tipidee_log_exit.lo src/libtipidee/tipidee_log_resource.lo src/libtipidee/tipidee_log_request.lo src/libtipidee/tipidee_log_start.lo src/libtipidee/tipidee_method.lo src/libtipidee/tipidee_response_error.lo src/libtipidee/tipidee_response_header_builtin.lo src/libtipidee/tipidee_response_header_common_put.lo src/libtipidee/tipidee_response_header_date.lo src/libtipidee/tipidee_response_header_date_fmt.lo src/libtipidee/tipidee_response_header_lastmodified.lo src/libtipidee/tipidee_response_status.lo src/libtipidee/tipidee_rql_read.lo src/libtipidee/tipidee_uri_parse.lo src/libtipidee/tipidee_util_chunked_read.lo src/libtipidee/tipidee_util_defaulttext.lo src/libtipidee/tipidee_util_httpdate.lo +libtipidee.a.xyzzy: src/libtipidee/tipidee_conf_free.lo src/libtipidee/tipidee_conf_get.lo src/libtipidee/tipidee_conf_get_argv.lo src/libtipidee/tipidee_conf_get_content_type.lo src/libtipidee/tipidee_conf_get_errorfile.lo src/libtipidee/tipidee_conf_get_redirection.lo src/libtipidee/tipidee_conf_get_string.lo src/libtipidee/tipidee_conf_get_uint32.lo src/libtipidee/tipidee_conf_init.lo src/libtipidee/tipidee_headers_get_content_length.lo src/libtipidee/tipidee_headers_init.lo src/libtipidee/tipidee_headers_parse.lo src/libtipidee/tipidee_headers_search.lo src/libtipidee/tipidee_log_answer.lo src/libtipidee/tipidee_log_exit.lo src/libtipidee/tipidee_log_resource.lo src/libtipidee/tipidee_log_request.lo src/libtipidee/tipidee_log_start.lo src/libtipidee/tipidee_method.lo src/libtipidee/tipidee_response_error_nofile.lo src/libtipidee/tipidee_response_file.lo src/libtipidee/tipidee_response_header_builtin.lo src/libtipidee/tipidee_response_header_common_put.lo src/libtipidee/tipidee_response_header_date.lo src/libtipidee/tipidee_response_header_date_fmt.lo src/libtipidee/tipidee_response_header_lastmodified.lo src/libtipidee/tipidee_response_status.lo src/libtipidee/tipidee_rql_read.lo src/libtipidee/tipidee_uri_parse.lo src/libtipidee/tipidee_util_chunked_read.lo src/libtipidee/tipidee_util_defaulttext.lo src/libtipidee/tipidee_util_httpdate.lo endif libtipidee.so.xyzzy: EXTRA_LIBS := -lskarnet -libtipidee.so.xyzzy: src/libtipidee/tipidee_conf_free.lo src/libtipidee/tipidee_conf_get.lo src/libtipidee/tipidee_conf_get_argv.lo src/libtipidee/tipidee_conf_get_content_type.lo src/libtipidee/tipidee_conf_get_redirection.lo src/libtipidee/tipidee_conf_get_string.lo src/libtipidee/tipidee_conf_get_uint32.lo src/libtipidee/tipidee_conf_init.lo src/libtipidee/tipidee_headers_get_content_length.lo src/libtipidee/tipidee_headers_init.lo src/libtipidee/tipidee_headers_parse.lo src/libtipidee/tipidee_headers_search.lo src/libtipidee/tipidee_log_answer.lo src/libtipidee/tipidee_log_exit.lo src/libtipidee/tipidee_log_resource.lo src/libtipidee/tipidee_log_request.lo src/libtipidee/tipidee_log_start.lo src/libtipidee/tipidee_method.lo src/libtipidee/tipidee_response_error.lo src/libtipidee/tipidee_response_header_builtin.lo src/libtipidee/tipidee_response_header_common_put.lo src/libtipidee/tipidee_response_header_date.lo src/libtipidee/tipidee_response_header_date_fmt.lo src/libtipidee/tipidee_response_header_lastmodified.lo src/libtipidee/tipidee_response_status.lo src/libtipidee/tipidee_rql_read.lo src/libtipidee/tipidee_uri_parse.lo src/libtipidee/tipidee_util_chunked_read.lo src/libtipidee/tipidee_util_defaulttext.lo src/libtipidee/tipidee_util_httpdate.lo +libtipidee.so.xyzzy: src/libtipidee/tipidee_conf_free.lo src/libtipidee/tipidee_conf_get.lo src/libtipidee/tipidee_conf_get_argv.lo src/libtipidee/tipidee_conf_get_content_type.lo src/libtipidee/tipidee_conf_get_errorfile.lo src/libtipidee/tipidee_conf_get_redirection.lo src/libtipidee/tipidee_conf_get_string.lo src/libtipidee/tipidee_conf_get_uint32.lo src/libtipidee/tipidee_conf_init.lo src/libtipidee/tipidee_headers_get_content_length.lo src/libtipidee/tipidee_headers_init.lo src/libtipidee/tipidee_headers_parse.lo src/libtipidee/tipidee_headers_search.lo src/libtipidee/tipidee_log_answer.lo src/libtipidee/tipidee_log_exit.lo src/libtipidee/tipidee_log_resource.lo src/libtipidee/tipidee_log_request.lo src/libtipidee/tipidee_log_start.lo src/libtipidee/tipidee_method.lo src/libtipidee/tipidee_response_error_nofile.lo src/libtipidee/tipidee_response_file.lo src/libtipidee/tipidee_response_header_builtin.lo src/libtipidee/tipidee_response_header_common_put.lo src/libtipidee/tipidee_response_header_date.lo src/libtipidee/tipidee_response_header_date_fmt.lo src/libtipidee/tipidee_response_header_lastmodified.lo src/libtipidee/tipidee_response_status.lo src/libtipidee/tipidee_rql_read.lo src/libtipidee/tipidee_uri_parse.lo src/libtipidee/tipidee_util_chunked_read.lo src/libtipidee/tipidee_util_defaulttext.lo src/libtipidee/tipidee_util_httpdate.lo tipideed: EXTRA_LIBS := -lskarnet tipideed: src/tipideed/tipideed.o src/tipideed/cgi.o src/tipideed/harden.o src/tipideed/options.o src/tipideed/regular.o src/tipideed/responses.o src/tipideed/send_file.o src/tipideed/tipideed.o src/tipideed/trace.o libtipidee.a.xyzzy INTERNAL_LIBS := diff --git a/src/include/tipidee/conf.h b/src/include/tipidee/conf.h index abc8313..d0b8fb0 100644 --- a/src/include/tipidee/conf.h +++ b/src/include/tipidee/conf.h @@ -40,5 +40,6 @@ extern unsigned int tipidee_conf_get_argv (tipidee_conf const *, char const *, c extern char const *tipidee_conf_get_docroot (tipidee_conf const *, tipidee_uri const *, uint16_t) ; extern int tipidee_conf_get_redirection (tipidee_conf const *, char const *, size_t, char const *, tipidee_redirection *) ; extern char const *tipidee_conf_get_content_type (tipidee_conf const *, char const *) ; +extern char const *tipidee_conf_get_errorfile (tipidee_conf const *, char const *, unsigned int) ; #endif diff --git a/src/include/tipidee/log.h b/src/include/tipidee/log.h index 7453bb7..bf3b812 100644 --- a/src/include/tipidee/log.h +++ b/src/include/tipidee/log.h @@ -39,7 +39,7 @@ extern void tipidee_log_start (uint32_t, char const *, char const *) ; extern void tipidee_log_exit (uint32_t, unsigned int) ; extern void tipidee_log_request (uint32_t, tipidee_rql const *, tipidee_headers const *, stralloc *) ; -extern void tipidee_log_resource (uint32_t, tipidee_rql const *, char const *, char const *, tipidee_resattr const *) ; +extern void tipidee_log_resource (uint32_t, tipidee_rql const *, char const *, tipidee_resattr const *, char const *) ; extern void tipidee_log_answer (uint32_t, tipidee_rql const *, unsigned int, uint64_t) ; #define tipidee_log_debug(v, ...) do { if ((v) & TIPIDEE_LOG_DEBUG) strerr_warn(PROG, ": debug: ", __VA_ARGS__) ; } while (0) diff --git a/src/include/tipidee/response.h b/src/include/tipidee/response.h index d969d9c..3850970 100644 --- a/src/include/tipidee/response.h +++ b/src/include/tipidee/response.h @@ -3,11 +3,13 @@ #ifndef TIPIDEE_RESPONSE_H #define TIPIDEE_RESPONSE_H -#include <sys/stat.h> +#include <skalibs/bsdsnowflake.h> + #include <stddef.h> #include <stdint.h> #include <skalibs/gccattributes.h> +#include <skalibs/stat.h> #include <skalibs/buffer.h> #include <skalibs/strerr.h> #include <skalibs/tai.h> @@ -31,7 +33,11 @@ extern size_t tipidee_response_header_lastmodified (char *, size_t, struct stat extern size_t tipidee_response_header_common_put (buffer *, uint32_t, tain const *) ; #define tipidee_response_header_common_put_g(b, options) tipidee_response_header_common_put(b, (options), &STAMP) -extern size_t tipidee_response_error (buffer *, tipidee_rql const *, unsigned int, char const *, char const *, uint32_t) ; +size_t tipidee_response_file (buffer *, tipidee_rql const *, unsigned int, char const *, struct stat const *, char const *, uint32_t, tain const *) ; +#define tipidee_response_file_g(b, rql, status, reason, st, ct, options) tipidee_response_file(b, rql, status, reason, st, ct, (options), &STAMP) + +extern size_t tipidee_response_error_nofile (buffer *, tipidee_rql const *, unsigned int, char const *, char const *, uint32_t, tain const *) ; +#define tipidee_response_error_nofile_g(b, rql, status, reason, text, options) tipidee_response_error_nofile(b, rql, status, reason, text, (options), &STAMP) extern tipidee_response_header_builtin const *tipidee_response_header_builtin_table ; extern char const *tipidee_response_header_builtin_search (char const *) ; diff --git a/src/libtipidee/deps-lib/tipidee b/src/libtipidee/deps-lib/tipidee index cba7e43..93e261a 100644 --- a/src/libtipidee/deps-lib/tipidee +++ b/src/libtipidee/deps-lib/tipidee @@ -2,6 +2,7 @@ tipidee_conf_free.o tipidee_conf_get.o tipidee_conf_get_argv.o tipidee_conf_get_content_type.o +tipidee_conf_get_errorfile.o tipidee_conf_get_redirection.o tipidee_conf_get_string.o tipidee_conf_get_uint32.o @@ -16,7 +17,8 @@ tipidee_log_resource.o tipidee_log_request.o tipidee_log_start.o tipidee_method.o -tipidee_response_error.o +tipidee_response_error_nofile.o +tipidee_response_file.o tipidee_response_header_builtin.o tipidee_response_header_common_put.o tipidee_response_header_date.o diff --git a/src/libtipidee/tipidee_conf_get_errorfile.c b/src/libtipidee/tipidee_conf_get_errorfile.c new file mode 100644 index 0000000..732ff9d --- /dev/null +++ b/src/libtipidee/tipidee_conf_get_errorfile.c @@ -0,0 +1,24 @@ +/* ISC license. */ + +#include <string.h> +#include <errno.h> + +#include <skalibs/types.h> + +#include <tipidee/conf.h> + +char const *tipidee_conf_get_errorfile (tipidee_conf const *conf, char const *docroot, unsigned int status) +{ + size_t docrootlen = strlen(docroot) ; + char key[7 + docrootlen] ; + if (status < 100 || status > 999) goto err ; + key[0] = 'E' ; key[1] = ':' ; + uint_fmt(key + 2, status) ; + key[5] = ':' ; + memcpy(key + 6, docroot, docrootlen + 1) ; + return tipidee_conf_get_string(conf, key) ; + + err: + errno = EINVAL ; + return 0 ; +} diff --git a/src/libtipidee/tipidee_log_request.c b/src/libtipidee/tipidee_log_request.c index a50169d..d633f0b 100644 --- a/src/libtipidee/tipidee_log_request.c +++ b/src/libtipidee/tipidee_log_request.c @@ -17,7 +17,7 @@ void tipidee_log_request (uint32_t v, tipidee_rql const *rql, tipidee_headers co size_t start = sa->len ; /* assert: not zero */ size_t refpos = 0, uapos = 0 ; if (!(v & TIPIDEE_LOG_REQUEST)) return ; - if (!string_quotes(sa, rql->uri.path)) goto eerr ; + if (!string_quotes(sa, rql->uri.path) || !stralloc_0(sa)) goto eerr ; if (v & TIPIDEE_LOG_REFERRER) { char const *x = tipidee_headers_search(hdr, "Referrer") ; diff --git a/src/libtipidee/tipidee_log_resource.c b/src/libtipidee/tipidee_log_resource.c index b730612..75196b0 100644 --- a/src/libtipidee/tipidee_log_resource.c +++ b/src/libtipidee/tipidee_log_resource.c @@ -6,9 +6,9 @@ #include <tipidee/log.h> -void tipidee_log_resource (uint32_t v, tipidee_rql const *rql, char const *docroot, char const *file, tipidee_resattr const *ra) +void tipidee_log_resource (uint32_t v, tipidee_rql const *rql, char const *file, tipidee_resattr const *ra, char const *infopath) { - char const *a[8] = { PROG, ": info:" } ; + char const *a[10] = { PROG, ": info:" } ; size_t m = 2 ; if (!(v & TIPIDEE_LOG_RESOURCE)) return ; if (v & TIPIDEE_LOG_HOSTASPREFIX) @@ -16,11 +16,14 @@ void tipidee_log_resource (uint32_t v, tipidee_rql const *rql, char const *docro a[m++] = " host " ; a[m++] = rql->uri.host ; } - a[m++] = " resource docroot " ; - a[m++] = docroot ; - a[m++] = " file " ; + a[m++] = " resource " ; a[m++] = file ; a[m++] = " type " ; a[m++] = ra->iscgi ? ra->isnph ? "nph" : "cgi" : ra->content_type ; + if (ra->iscgi && infopath) + { + a[m++] = " path_info /" ; + a[m++] = infopath ; + } strerr_warnv(a, m) ; } diff --git a/src/libtipidee/tipidee_response_error.c b/src/libtipidee/tipidee_response_error.c deleted file mode 100644 index 7c77e80..0000000 --- a/src/libtipidee/tipidee_response_error.c +++ /dev/null @@ -1,41 +0,0 @@ -/* ISC license. */ - -#include <stddef.h> - -#include <skalibs/types.h> -#include <skalibs/buffer.h> - -#include <tipidee/method.h> -#include <tipidee/rql.h> -#include <tipidee/response.h> - -size_t tipidee_response_error (buffer *b, tipidee_rql const *rql, unsigned int status, char const *rsl, char const *text, uint32_t options) -{ - size_t n = 0 ; - static char const txt1[] = "<html>\n<head><title>" ; - static char const txt2[] = "</title></head>\n<body>\n<h1> " ; - static char const txt3[] = " </h1>\n<p>\n" ; - static char const txt4[] = "\n</p>\n</body>\n</html>\n" ; - n += tipidee_response_status(b, rql, status, rsl) ; - n += tipidee_response_header_common_put_g(buffer_1, options) ; - if (!(options & 2)) - { - char fmt[SIZE_FMT] ; - n += buffer_putsnoflush(buffer_1, "Content-Type: text/html; charset=UTF-8\r\n") ; - n += buffer_putsnoflush(buffer_1, "Content-Length: ") ; - n += buffer_putnoflush(buffer_1, fmt, size_fmt(fmt, sizeof(txt1) + sizeof(txt2) + sizeof(txt3) + sizeof(txt4) - 4 + 2 * strlen(rsl) + strlen(text))) ; - n += buffer_putnoflush(buffer_1, "\r\n", 2) ; - } - n += buffer_putnoflush(buffer_1, "\r\n", 2) ; - if (rql->m != TIPIDEE_METHOD_HEAD) - { - n += buffer_putsnoflush(buffer_1, txt1) ; - n += buffer_putsnoflush(buffer_1, rsl) ; - n += buffer_putsnoflush(buffer_1, txt2) ; - n += buffer_putsnoflush(buffer_1, rsl) ; - n += buffer_putsnoflush(buffer_1, txt3) ; - n += buffer_putsnoflush(buffer_1, text) ; - n += buffer_putsnoflush(buffer_1, txt4) ; - } - return n ; -} diff --git a/src/libtipidee/tipidee_response_error_nofile.c b/src/libtipidee/tipidee_response_error_nofile.c new file mode 100644 index 0000000..4f628ac --- /dev/null +++ b/src/libtipidee/tipidee_response_error_nofile.c @@ -0,0 +1,35 @@ +/* ISC license. */ + +#include <string.h> + +#include <skalibs/types.h> +#include <skalibs/buffer.h> + +#include <tipidee/method.h> +#include <tipidee/response.h> + +size_t tipidee_response_error_nofile (buffer *b, tipidee_rql const *rql, unsigned int status, char const *reason, char const *text, uint32_t options, tain const *stamp) +{ + static char const txt1[] = "<html>\n<head><title>" ; + static char const txt2[] = "</title></head>\n<body>\n<h1> " ; + static char const txt3[] = " </h1>\n<p>\n" ; + static char const txt4[] = "\n</p>\n</body>\n</html>\n" ; + char fmt[SIZE_FMT] ; + size_t n = tipidee_response_status(b, rql, status, reason) ; + n += tipidee_response_header_common_put(b, options, stamp) ; + n += buffer_putsnoflush(b, "Content-Type: text/html; charset=UTF-8\r\n") ; + n += buffer_putsnoflush(b, "Content-Length: ") ; + n += buffer_putnoflush(b, fmt, size_fmt(fmt, text ? sizeof(txt1) + sizeof(txt2) + sizeof(txt3) + sizeof(txt4) - 4 + 2 * strlen(reason) + strlen(text) : 0)) ; + n += buffer_putnoflush(b, "\r\n\r\n", 4) ; + if (text && rql->m != TIPIDEE_METHOD_HEAD) + { + n += buffer_putsnoflush(b, txt1) ; + n += buffer_putsnoflush(b, reason) ; + n += buffer_putsnoflush(b, txt2) ; + n += buffer_putsnoflush(b, reason) ; + n += buffer_putsnoflush(b, txt3) ; + n += buffer_putsnoflush(b, text) ; + n += buffer_putsnoflush(b, txt4) ; + } + return n ; +} diff --git a/src/libtipidee/tipidee_response_file.c b/src/libtipidee/tipidee_response_file.c new file mode 100644 index 0000000..0cbe8f4 --- /dev/null +++ b/src/libtipidee/tipidee_response_file.c @@ -0,0 +1,31 @@ +/* ISC license. */ + +#include <stddef.h> + +#include <skalibs/types.h> +#include <skalibs/buffer.h> + +#include <tipidee/conf.h> +#include <tipidee/method.h> +#include <tipidee/rql.h> +#include <tipidee/response.h> +#include <tipidee/util.h> + +size_t tipidee_response_file (buffer *b, tipidee_rql const *rql, unsigned int status, char const *reason, struct stat const *st, char const *ct, uint32_t options, tain const *stamp) +{ + char fmt[128] ; + size_t n = tipidee_response_status(b, rql, status, reason) ; + n += tipidee_response_header_common_put(b, options & 1, stamp) ; + if (options & 2) + { + size_t l = tipidee_response_header_lastmodified(fmt, 128, st) ; + if (l) n += buffer_putnoflush(b, fmt, l) ; + } + n += buffer_putsnoflush(b, "Content-Type: ") ; + n += buffer_putsnoflush(b, ct) ; + n += buffer_putsnoflush(b, "\r\nContent-Length: ") ; + fmt[uint64_fmt(fmt, st->st_size)] = 0 ; + n += buffer_putsnoflush(b, fmt) ; + n += buffer_putnoflush(b, "\r\n\r\n", 4) ; + return n ; +} diff --git a/src/libtipidee/tipidee_response_header_common_put.c b/src/libtipidee/tipidee_response_header_common_put.c index c67cc94..e9a1a07 100644 --- a/src/libtipidee/tipidee_response_header_common_put.c +++ b/src/libtipidee/tipidee_response_header_common_put.c @@ -1,23 +1,20 @@ /* ISC license. */ -#include <stdint.h> - #include <skalibs/buffer.h> -#include <tipidee/config.h> #include <tipidee/response.h> size_t tipidee_response_header_common_put (buffer *b, uint32_t options, tain const *stamp) { char fmt[128] ; - size_t m = buffer_putnoflush(b, fmt, tipidee_response_header_date(fmt, 128, stamp)) ; + size_t n = buffer_putnoflush(b, fmt, tipidee_response_header_date(fmt, 128, stamp)) ; for (tipidee_response_header_builtin const *p = tipidee_response_header_builtin_table ; p->key ; p++) { - m += buffer_putsnoflush(b, p->key) ; - m += buffer_putnoflush(b, ": ", 2) ; - m += buffer_putsnoflush(b, p->value) ; - m += buffer_putnoflush(b, "\r\n", 2) ; + n += buffer_putsnoflush(b, p->key) ; + n += buffer_putnoflush(b, ": ", 2) ; + n += buffer_putsnoflush(b, p->value) ; + n += buffer_putnoflush(b, "\r\n", 2) ; } - if (options & 1) m += buffer_putsnoflush(b, "Connection: close\r\n") ; - return m ; + if (options & 1) n += buffer_putsnoflush(b, "Connection: close\r\n") ; + return n ; } diff --git a/src/libtipidee/tipidee_response_status.c b/src/libtipidee/tipidee_response_status.c index 4315f61..3c8977a 100644 --- a/src/libtipidee/tipidee_response_status.c +++ b/src/libtipidee/tipidee_response_status.c @@ -5,7 +5,7 @@ #include <tipidee/response.h> -size_t tipidee_response_status (buffer *b, tipidee_rql const *rql, unsigned int status, char const *line) +size_t tipidee_response_status (buffer *b, tipidee_rql const *rql, unsigned int status, char const *reason) { size_t n = 0 ; char fmt[UINT_FMT] ; @@ -16,7 +16,7 @@ size_t tipidee_response_status (buffer *b, tipidee_rql const *rql, unsigned int n += buffer_putnoflush(b, " ", 1) ; n += buffer_putnoflush(b, fmt, uint_fmt(fmt, status)) ; n += buffer_putnoflush(b, " ", 1) ; - n += buffer_putsnoflush(b, line) ; + n += buffer_putsnoflush(b, reason) ; n += buffer_putnoflush(b, "\r\n", 2) ; return n ; } diff --git a/src/libtipidee/tipidee_rql_read.c b/src/libtipidee/tipidee_rql_read.c index fc99f37..fe6091d 100644 --- a/src/libtipidee/tipidee_rql_read.c +++ b/src/libtipidee/tipidee_rql_read.c @@ -66,8 +66,9 @@ static inline int get_version (char const *in, tipidee_rql *rql) int tipidee_rql_read (buffer *b, char *buf, size_t max, size_t *w, tipidee_rql *rql, tain const *deadline, tain *stamp) { size_t pos[3] = { 0 } ; - if (timed_getlnmax(b, buf, max, &pos[0], '\n', deadline, stamp) == -1) - return errno == ETIMEDOUT ? 99 : -1 ; + ssize_t r = timed_getlnmax(b, buf, max, &pos[0], '\n', deadline, stamp) ; + if (r == -1) return errno == ETIMEDOUT ? 99 : -1 ; + if (!r) return 98 ; buf[--pos[0]] = 0 ; if (buf[pos[0] - 1] == '\r') buf[--pos[0]] = 0 ; if (!rql_tokenize(buf, pos)) return 400 ; diff --git a/src/tipideed/cgi.c b/src/tipideed/cgi.c index 8dde023..0d7e104 100644 --- a/src/tipideed/cgi.c +++ b/src/tipideed/cgi.c @@ -21,55 +21,51 @@ #include <skalibs/env.h> #include <skalibs/exec.h> #include <skalibs/unix-timed.h> -#include <skalibs/lolstdio.h> -#include <tipidee/method.h> -#include <tipidee/headers.h> -#include <tipidee/response.h> -#include <tipidee/uri.h> +#include <tipidee/tipidee.h> #include "tipideed-internal.h" -static void addenv_ (tipidee_rql const *rql, char const *k, char const *v, int slash) +static void addenv_ (tipidee_rql const *rql, char const *docroot, char const *k, char const *v, int slash) { if (!stralloc_cats(&g.sa, k) || !stralloc_catb(&g.sa, "=/", 1 + !!slash) || !stralloc_cats(&g.sa, v) || !stralloc_0(&g.sa)) - die500sys(rql, 111, "stralloc_catb") ; + die500sys(rql, 111, docroot, "stralloc_catb") ; } -#define addenv(rql, k, v) addenv_(rql, k, (v), 0) -#define addenvslash(rql, k, v) addenv_(rql, k, (v), 1) +#define addenv(rql, d, k, v) addenv_(rql, d, k, (v), 0) +#define addenvslash(rql, d, k, v) addenv_(rql, d, k, (v), 1) -static void delenv (tipidee_rql const *rql, char const *k) +static void delenv (tipidee_rql const *rql, char const *docroot, char const *k) { if (!stralloc_cats(&g.sa, k) || !stralloc_0(&g.sa)) - die500sys(rql, 111, "stralloc_catb") ; + die500sys(rql, 111, docroot, "stralloc_catb") ; } -static inline void modify_env (tipidee_rql const *rql, tipidee_headers const *hdr, size_t cl, char const *script, char const *infopath) +static inline void modify_env (tipidee_rql const *rql, char const *docroot, tipidee_headers const *hdr, size_t cl, char const *script, char const *infopath) { uint32_t got = 0 ; - addenv(rql, "REQUEST_METHOD", tipidee_method_tostr(rql->m)) ; + addenv(rql, docroot, "REQUEST_METHOD", tipidee_method_tostr(rql->m)) ; if (cl) { char fmt[SIZE_FMT] ; fmt[size_fmt(fmt, cl)] = 0 ; - addenv(rql, "CONTENT_LENGTH", fmt) ; + addenv(rql, docroot, "CONTENT_LENGTH", fmt) ; } - else delenv(rql, "CONTENT_LENGTH") ; + else delenv(rql, docroot, "CONTENT_LENGTH") ; - if (infopath) addenvslash(rql, "PATH_INFO", infopath) ; - else delenv(rql, "PATH_INFO") ; - if (rql->uri.query) addenv(rql, "QUERY_STRING", rql->uri.query) ; - else delenv(rql, "QUERY_STRING") ; - addenv(rql, "SCRIPT_NAME", script) ; - addenv(rql, "SERVER_NAME", rql->uri.host) ; + if (infopath) addenvslash(rql, docroot, "PATH_INFO", infopath) ; + else delenv(rql, docroot, "PATH_INFO") ; + if (rql->uri.query) addenv(rql, docroot, "QUERY_STRING", rql->uri.query) ; + else delenv(rql, docroot, "QUERY_STRING") ; + addenv(rql, docroot, "SCRIPT_NAME", script) ; + addenv(rql, docroot, "SERVER_NAME", rql->uri.host) ; { char proto[9] = "HTTP/1.1" ; if (!rql->http_minor) proto[7] = '0' ; - addenv(rql, "SERVER_PROTOCOL", proto) ; + addenv(rql, docroot, "SERVER_PROTOCOL", proto) ; } for (size_t i = 0 ; i < hdr->n ; i++) @@ -84,36 +80,36 @@ static inline void modify_env (tipidee_rql const *rql, tipidee_headers const *hd char scheme[n] ; memcpy(scheme, val, n-1) ; scheme[n-1] = 0 ; - addenv(rql, "AUTH_TYPE", scheme) ; + addenv(rql, docroot, "AUTH_TYPE", scheme) ; got |= 1 ; } } - else if (!strcasecmp(key, "Content-Type")) { addenv(rql, "CONTENT_TYPE", val) ; got |= 2 ; } + else if (!strcasecmp(key, "Content-Type")) { addenv(rql, docroot, "CONTENT_TYPE", val) ; got |= 2 ; } else if (!strcasecmp(key, "Content-Length") || !strcasecmp(key, "Connection") || !strcasecmp(key, "Host")) ; else { size_t len = strlen(key), pos = g.sa.len + 5 ; if (!stralloc_catb(&g.sa, "HTTP_", 5)) die500sys(rql, 111, "stralloc_catb") ; - addenv(rql, key, val) ; + addenv(rql, docroot, key, val) ; for (char *s = g.sa.s + pos ; len-- ; s++) if (*s == '-') *s = '_' ; else if (*s >= 'a' && *s <= 'z') *s -= 32 ; } } - if (!(got & 1)) delenv(rql, "AUTH_TYPE") ; - if (!(got & 2)) delenv(rql, "CONTENT_TYPE") ; + if (!(got & 1)) delenv(rql, docroot, "AUTH_TYPE") ; + if (!(got & 2)) delenv(rql, docroot, "CONTENT_TYPE") ; } -static inline int do_nph (tipidee_rql const *rql, char const *const *argv, char const *const *envp, char const *body, size_t bodylen) gccattr_noreturn ; -static inline int do_nph (tipidee_rql const *rql, char const *const *argv, char const *const *envp, char const *body, size_t bodylen) +static inline int do_nph (tipidee_rql const *rql, char const *docroot, char const *const *argv, char const *const *envp, char const *body, size_t bodylen) gccattr_noreturn ; +static inline int do_nph (tipidee_rql const *rql, char const *docroot, char const *const *argv, char const *const *envp, char const *body, size_t bodylen) { int p[2] ; - if (pipe(p) == -1) die500sys(rql, 111, "pipe") ; + if (pipe(p) == -1) die500sys(rql, 111, docroot, "pipe") ; if (bodylen) { switch (fork()) { - case -1 : die500sys(rql, 111, "fork") ; + case -1 : die500sys(rql, 111, docroot, "fork") ; case 0 : { #define NAME "tipideed (nph helper for pid " @@ -138,12 +134,12 @@ static inline int do_nph (tipidee_rql const *rql, char const *const *argv, char } } close(p[1]) ; - if (fd_move(0, p[0]) == -1) die500sys(rql, 111, "fd_move") ; + if (fd_move(0, p[0]) == -1) die500sys(rql, 111, docroot, "fd_move") ; exec_e(argv, envp) ; - die500sys(rql, errno == ENOENT ? 127 : 126, "exec nph ", argv[0]) ; + die500sys(rql, errno == ENOENT ? 127 : 126, docroot, "exec nph ", argv[0]) ; } -static inline int run_cgi (tipidee_rql const *rql, char const *const *argv, char const *const *envp, char const *body, size_t bodylen, tipidee_headers *hdr, stralloc *sa) +static inline int run_cgi (tipidee_rql const *rql, char const *docroot, char const *const *argv, char const *const *envp, char const *body, size_t bodylen, tipidee_headers *hdr, stralloc *sa) { iopause_fd x[2] = { { .events = IOPAUSE_READ }, { .events = IOPAUSE_WRITE } } ; size_t bodyw = 0 ; @@ -157,26 +153,25 @@ static inline int run_cgi (tipidee_rql const *rql, char const *const *argv, char { int fd[2] = { 0, 1 } ; pid = child_spawn2(argv[0], argv, envp, fd) ; - if (!pid) die500sys(rql, 111, "spawn ", argv[0]) ; + if (!pid) die500sys(rql, 111, docroot, "spawn ", argv[0]) ; x[0].fd = fd[0] ; x[1].fd = fd[1] ; } if (!bodylen) { close(x[1].fd) ; x[1].fd = -1 ; - LOLDEBUG("run_cgi: no request body, closing writing pipe to cgi") ; } buffer_init(&b, &buffer_read, x[0].fd, buf, 4096) ; tain_add_g(&deadline, &g.cgitto) ; while (x[0].fd >= 0) { int r = iopause_g(x, 1 + (x[1].fd >= 0), &deadline) ; - if (r == -1) die500sys(rql, 111, "iopause") ; + if (r == -1) die500sys(rql, 111, docroot, "iopause") ; if (!r) { kill(pid, SIGTERM) ; - respond_504(rql) ; strerr_warnw3x("cgi ", argv[0], " timed out") ; + respond_504(rql, docroot) ; break ; } if (x[1].fd >= 0 && x[1].revents & (IOPAUSE_WRITE | IOPAUSE_EXCEPT)) @@ -192,7 +187,6 @@ static inline int run_cgi (tipidee_rql const *rql, char const *const *argv, char { close(x[1].fd) ; x[1].fd = -1 ; - LOLDEBUG("run_cgi: finished writing body") ; } } if (x[0].fd >= 0 && x[0].revents & (IOPAUSE_READ | IOPAUSE_EXCEPT)) @@ -205,20 +199,20 @@ static inline int run_cgi (tipidee_rql const *rql, char const *const *argv, char switch (r) { case -2 : break ; - case -1 : die500sys(rql, 111, "read from cgi ", argv[0]) ; + case -1 : die500sys(rql, 111, docroot, "read from cgi ", argv[0]) ; case 0 : { size_t n = buffer_len(&b) ; - if (!stralloc_readyplus(sa, n)) die500sys(rql, 111, "stralloc_readyplus") ; + if (!stralloc_readyplus(sa, n)) die500sys(rql, 111, docroot, "stralloc_readyplus") ; buffer_getnofill(&b, sa->s + sa->len, n) ; sa->len += n ; rstate = 1 ; break ; } - case 400 : die502x(rql, 2, "invalid headers", " from cgi ", argv[0]) ; - case 413 : die502x(rql, 2, hdr->n >= TIPIDEE_HEADERS_MAX ? "Too many headers" : "Too much header data", " from cgi ", argv[0]) ; - case 500 : die500x(rql, 101, "can't happen: ", "avltreen_insert failed", " in do_cgi") ; - default : die500x(rql, 101, "can't happen: ", "unknown tipidee_headers_parse return code", " in do_cgi") ; + case 400 : die502x(rql, 2, docroot, "invalid headers", " from cgi ", argv[0]) ; + case 413 : die502x(rql, 2, docroot, hdr->n >= TIPIDEE_HEADERS_MAX ? "Too many headers" : "Too much header data", " from cgi ", argv[0]) ; + case 500 : die500x(rql, 101, docroot, "can't happen: ", "avltreen_insert failed", " in do_cgi") ; + default : die500x(rql, 101, docroot, "can't happen: ", "unknown tipidee_headers_parse return code", " in do_cgi") ; } if (!rstate) break ; } @@ -227,13 +221,12 @@ static inline int run_cgi (tipidee_rql const *rql, char const *const *argv, char if (!slurpn(x[0].fd, sa, g.maxcgibody)) { if (error_isagain(errno)) break ; - else if (errno == ENOBUFS) die502x(rql, 2, "Too fat body", " from cgi ", argv[0]) ; - else die500sys(rql, 111, "read body", " from cgi ", argv[0]) ; + else if (errno == ENOBUFS) die502x(rql, 2, docroot, "Too fat body", " from cgi ", argv[0]) ; + else die500sys(rql, 111, docroot, "read body", " from cgi ", argv[0]) ; } close(x[0].fd) ; x[0].fd = -1 ; rstate = 2 ; - LOLDEBUG("run_cgi: rstate = 2") ; } } } @@ -243,7 +236,7 @@ static inline int run_cgi (tipidee_rql const *rql, char const *const *argv, char return rstate == 2 ; } -static inline int local_redirect (tipidee_rql *rql, char const *loc, char *uribuf, char const *cginame) +static inline int local_redirect (tipidee_rql *rql, char const *docroot, char const *loc, char *uribuf, char const *cginame) { size_t n ; size_t hostlen = strlen(rql->uri.host) ; @@ -253,7 +246,7 @@ static inline int local_redirect (tipidee_rql *rql, char const *loc, char *uribu memcpy(hosttmp, rql->uri.host, hostlen + 1) ; n = tipidee_uri_parse(uribuf, URI_BUFSIZE, loc, &rql->uri) ; if (!n || n + hostlen + 1 > URI_BUFSIZE) - die502x(rql, 2, "cgi ", cginame, " returned an invalid ", "Location", " value", " for local redirection") ; + die502x(rql, 2, docroot, "cgi ", cginame, " returned an invalid ", "Location", " value", " for local redirection") ; memcpy(uribuf + n, hosttmp, hostlen + 1) ; rql->uri.host = uribuf + n ; rql->uri.port = port ; @@ -292,11 +285,11 @@ static inline void print_cgi_headers (tipidee_headers const *hdr, size_t rbodyle buffer_putnoflush(buffer_1, "\r\n", 2) ; } -static inline int process_cgi_output (tipidee_rql *rql, tipidee_headers const *hdr, char const *rbody, size_t rbodylen, char *uribuf, char const *cginame) +static inline int process_cgi_output (tipidee_rql *rql, char const *docroot, tipidee_headers const *hdr, char const *rbody, size_t rbodylen, char *uribuf, char const *cginame) { char const *location = tipidee_headers_search(hdr, "Location") ; char const *x = tipidee_headers_search(hdr, "Status") ; - char const *reason_phrase = "OK" ; + char const *reason = "OK" ; unsigned int status = 0 ; tain deadline ; tain_add_g(&deadline, &g.writetto) ; @@ -304,23 +297,28 @@ static inline int process_cgi_output (tipidee_rql *rql, tipidee_headers const *h { size_t m = uint_scan(x, &status) ; if (!m || (x[m] && x[m] != ' ')) - die502x(rql, 2, "cgi ", cginame, " returned an invalid ", "Status", " header") ; - reason_phrase = x[m] ? x + m + 1 : "" ; + die502x(rql, 2, docroot, "cgi ", cginame, " returned an invalid ", "Status", " header") ; + if (x[m]) reason = x + m + 1 ; + else + { + tipidee_defaulttext dt ; + reason = tipidee_util_defaulttext(status, &dt) ? dt.reason : "" ; + } if (!location && (status == 301 || status == 302 || status == 307 || status == 308)) - die502x(rql, 2, "cgi ", cginame, " returned a redirection status code without a ", "Location", " header") ; + die502x(rql, 2, docroot, "cgi ", cginame, " returned a redirection status code without a ", "Location", " header") ; if (status < 100 || status > 999) - die502x(rql, 2, "cgi ", cginame, " returned an invalid ", "Status", " value") ; + die502x(rql, 2, docroot, "cgi ", cginame, " returned an invalid ", "Status", " value") ; } if (location) { - if (!location[0]) die502x(rql, 2, "cgi ", cginame, " returned an invalid ", "Location", " header") ; - if (location[0] == '/' && location[1] != '/') return local_redirect(rql, location, uribuf, cginame) ; + if (!location[0]) die502x(rql, 2, docroot, "cgi ", cginame, " returned an invalid ", "Location", " header") ; + if (location[0] == '/' && location[1] != '/') return local_redirect(rql, docroot, location, uribuf, cginame) ; if (rbodylen) { if (!status) - die502x(rql, 2, "cgi ", cginame, " didn't output a ", "Status", " header", " for a client redirect response with document") ; + die502x(rql, 2, docroot, "cgi ", cginame, " didn't output a ", "Status", " header", " for a client redirect response with document") ; if (status < 300 || status > 399) - die502x(rql, 2, "cgi ", cginame, " returned an invalid ", "Status", " value", " for a client redirect response with document") ; + die502x(rql, 2, docroot, "cgi ", cginame, " returned an invalid ", "Status", " value", " for a client redirect response with document") ; } else { @@ -329,12 +327,12 @@ static inline int process_cgi_output (tipidee_rql *rql, tipidee_headers const *h char const *key = hdr->buf + hdr->list[i].left ; if (!strcasecmp(key, "Location") || !strcasecmp(key, "Status")) continue ; if (str_start(key, "X-CGI-")) continue ; - die502x(rql, 2, "cgi ", cginame, " returned extra headers", " for a client redirect response without document") ; + die502x(rql, 2, docroot, "cgi ", cginame, " returned extra headers", " for a client redirect response without document") ; } if (!status) { status = 302 ; - reason_phrase = "Found" ; + reason = "Found" ; } } } @@ -342,19 +340,19 @@ static inline int process_cgi_output (tipidee_rql *rql, tipidee_headers const *h { if (!status) status = 200 ; if (!tipidee_headers_search(hdr, "Content-Type")) - die502x(rql, 2, "cgi ", cginame, " didn't output a ", "Content-Type", " header") ; + die502x(rql, 2, docroot, "cgi ", cginame, " didn't output a ", "Content-Type", " header") ; } x = tipidee_headers_search(hdr, "Content-Length") ; if (x) { size_t cln ; if (!size0_scan(x, &cln)) - die502x(rql, 2, "cgi ", cginame, " returned an invalid ", "Content-Length", " header") ; + die502x(rql, 2, docroot, "cgi ", cginame, " returned an invalid ", "Content-Length", " header") ; if (cln != rbodylen) - die502x(rql, 2, "cgi ", cginame, " returned a mismatching ", "Content-Length", " header") ; + die502x(rql, 2, docroot, "cgi ", cginame, " returned a mismatching ", "Content-Length", " header") ; } - tipidee_response_status(buffer_1, rql, status, reason_phrase) ; + tipidee_response_status(buffer_1, rql, status, reason) ; tipidee_response_header_common_put_g(buffer_1, !g.cont) ; print_cgi_headers(hdr, rbodylen) ; if (buffer_timed_put_g(buffer_1, "\r\n", 2, &deadline) < 2) @@ -370,26 +368,26 @@ static inline int process_cgi_output (tipidee_rql *rql, tipidee_headers const *h return 0 ; } -static inline int do_cgi (tipidee_rql *rql, char const *const *argv, char const *const *envp, char const *body, size_t bodylen, char *uribuf) +static inline int do_cgi (tipidee_rql *rql, char const *docroot, char const *const *argv, char const *const *envp, char const *body, size_t bodylen, char *uribuf) { static stralloc sa = STRALLOC_ZERO ; tipidee_headers hdr ; char hdrbuf[2048] ; sa.len = 0 ; tipidee_headers_init(&hdr, hdrbuf, 2048) ; - if (!run_cgi(rql, argv, envp, body, bodylen, &hdr, &sa)) return 0 ; - return process_cgi_output(rql, &hdr, sa.s, sa.len, uribuf, argv[0]) ; + if (!run_cgi(rql, docroot, argv, envp, body, bodylen, &hdr, &sa)) return 0 ; + return process_cgi_output(rql, docroot, &hdr, sa.s, sa.len, uribuf, argv[0]) ; } -int respond_cgi (tipidee_rql *rql, char const *fn, size_t docrootlen, char const *infopath, char *uribuf, tipidee_headers const *hdr, tipidee_resattr const *ra, char const *body, size_t bodylen) +int respond_cgi (tipidee_rql *rql, char const *docroot, char const *fn, size_t docrootlen, char const *infopath, char *uribuf, tipidee_headers const *hdr, tipidee_resattr const *ra, char const *body, size_t bodylen) { size_t sabase = g.sa.len ; size_t envmax = g.envlen + 16 + TIPIDEE_HEADERS_MAX ; char const *argv[2] = { fn, 0 } ; char const *envp[envmax] ; - modify_env(rql, hdr, bodylen, fn + docrootlen, infopath) ; + modify_env(rql, docroot, hdr, bodylen, fn + docrootlen, infopath) ; env_merge(envp, envmax, (char const *const *)environ, g.envlen, g.sa.s + g.cwdlen + 1, g.sa.len - (g.cwdlen+1)) ; g.sa.len = sabase ; - return ra->isnph ? do_nph(rql, argv, envp, body, bodylen) : - do_cgi(rql, argv, envp, body, bodylen, uribuf) ; + return ra->isnph ? do_nph(rql, docroot, argv, envp, body, bodylen) : + do_cgi(rql, docroot, argv, envp, body, bodylen, uribuf) ; } diff --git a/src/tipideed/regular.c b/src/tipideed/regular.c index 845f12b..aa937ad 100644 --- a/src/tipideed/regular.c +++ b/src/tipideed/regular.c @@ -4,7 +4,6 @@ #include <errno.h> -#include <skalibs/uint64.h> #include <skalibs/stat.h> #include <skalibs/types.h> #include <skalibs/buffer.h> @@ -18,24 +17,12 @@ #include <tipidee/log.h> #include "tipideed-internal.h" -int respond_regular (tipidee_rql const *rql, char const *fn, struct stat const *st, tipidee_resattr const *ra) +int respond_regular (tipidee_rql const *rql, char const *docroot, char const *fn, struct stat const *st, tipidee_resattr const *ra) { - tain deadline ; - char fmt[128] ; - size_t n = tipidee_response_status(buffer_1, rql, 200, "OK") ; - n += tipidee_response_header_common_put_g(buffer_1, !g.cont) ; - { - size_t l = tipidee_response_header_lastmodified(fmt, 128, st) ; - if (l) n += buffer_putnoflush(buffer_1, fmt, l) ; - } - n += buffer_putsnoflush(buffer_1, "Content-Type: ") ; - n += buffer_putsnoflush(buffer_1, ra->content_type) ; - n += buffer_putsnoflush(buffer_1, "\r\nContent-Length: ") ; - fmt[uint64_fmt(fmt, st->st_size)] = 0 ; - n += buffer_putsnoflush(buffer_1, fmt) ; - n += buffer_putnoflush(buffer_1, "\r\n\r\n", 4) ; if (rql->m == TIPIDEE_METHOD_HEAD) { + tain deadline ; + tipidee_response_file_g(buffer_1, rql, 200, "OK", st, ra->content_type, 2 | !g.cont) ; tipidee_log_answer(g.logv, rql, 200, st->st_size) ; tain_add_g(&deadline, &g.writetto) ; if (!buffer_timed_flush_g(buffer_1, &deadline)) @@ -46,14 +33,14 @@ int respond_regular (tipidee_rql const *rql, char const *fn, struct stat const * int fd = open_read(fn) ; if (fd == -1) { - buffer_unput(buffer_1, n) ; if (errno == EACCES) { - respond_403(rql) ; + respond_403(rql, docroot) ; return 0 ; } - else die500sys(rql, 111, "open ", fn) ; + else die500sys(rql, 111, docroot, "open ", fn) ; } + tipidee_response_file_g(buffer_1, rql, 200, "OK", st, ra->content_type, 2 | !g.cont) ; tipidee_log_answer(g.logv, rql, 200, st->st_size) ; send_file(fd, st->st_size, fn) ; fd_close(fd) ; diff --git a/src/tipideed/responses.c b/src/tipideed/responses.c index e5706e2..0d0840c 100644 --- a/src/tipideed/responses.c +++ b/src/tipideed/responses.c @@ -1,44 +1,99 @@ /* ISC license. */ +#include <skalibs/bsdsnowflake.h> + #include <unistd.h> +#include <skalibs/stat.h> #include <skalibs/types.h> #include <skalibs/buffer.h> #include <skalibs/strerr.h> #include <skalibs/tai.h> +#include <skalibs/djbunix.h> #include <skalibs/unix-timed.h> -#include <tipidee/rql.h> #include <tipidee/log.h> +#include <tipidee/util.h> #include <tipidee/response.h> #include "tipideed-internal.h" -void response_error (tipidee_rql const *rql, unsigned int status, char const *rsl, char const *text, uint32_t options) +void response_error_early (tipidee_rql const *rql, unsigned int status, char const *reason, char const *text, uint32_t options) { tain deadline ; - tipidee_response_error(buffer_1, rql, status, rsl, text, options & 1 || !g.cont) ; + tipidee_response_error_nofile_g(buffer_1, rql, status, reason, text, options & 1 || !g.cont) ; + tain_add_g(&deadline, &g.writetto) ; + if (!buffer_timed_flush_g(buffer_1, &deadline)) + strerr_diefu1sys(111, "write to stdout") ; +} + +void response_error_early_and_exit (tipidee_rql const *rql, unsigned int status, char const *reason, char const *text) +{ + response_error_early(rql, status, reason, text, 1) ; + log_and_exit(1) ; +} + +void response_error (tipidee_rql const *rql, char const *docroot, unsigned int status, uint32_t options) +{ + tain deadline ; + tipidee_defaulttext dt ; + char const *file = tipidee_conf_get_errorfile(&g.conf, docroot, status) ; + if (!tipidee_util_defaulttext(status, &dt)) + { + char fmt[UINT_FMT] ; + fmt[uint_fmt(fmt, status)] = 0 ; + strerr_dief2x(101, "can't happen: unknown response code ", fmt) ; + } + + if (file) + { + int fd = open_read(file) ; + if (fd == -1) strerr_warnwu3sys("open ", "custom error file ", file) ; + else + { + struct stat st ; + if (fstat(fd, &st) == -1) + { + fd_close(fd) ; + strerr_warnwu3sys("stat ", "custom error file ", file) ; + } + else if (!S_ISREG(st.st_mode)) + { + fd_close(fd) ; + strerr_warnw3x("custom error file ", file, " is not a regular file") ; + } + else + { + tipidee_response_file_g(buffer_1, rql, status, dt.reason, &st, tipidee_conf_get_content_type(&g.conf, file), options) ; + tipidee_log_answer(g.logv, rql, status, st.st_size) ; + send_file(fd, st.st_size, file) ; + fd_close(fd) ; + return ; + } + } + } + + tipidee_response_error_nofile_g(buffer_1, rql, status, dt.reason, dt.text, options & 1 || !g.cont) ; + tipidee_log_answer(g.logv, rql, status, 0) ; tain_add_g(&deadline, &g.writetto) ; - if (!(options & 2)) tipidee_log_answer(g.logv, rql, status, 0) ; if (!buffer_timed_flush_g(buffer_1, &deadline)) strerr_diefu1sys(111, "write to stdout") ; } -void response_error_and_exit (tipidee_rql const *rql, unsigned int status, char const *rsl, char const *text, uint32_t options) +void response_error_and_exit (tipidee_rql const *rql, char const *docroot, unsigned int status) { - response_error(rql, status, rsl, text, options | 1) ; - tipidee_log_exit(g.logv, 0) ; - _exit(0) ; + response_error(rql, docroot, status, 1) ; + log_and_exit(0) ; } -void response_error_and_die (tipidee_rql const *rql, int e, unsigned int status, char const *rsl, char const *text, char const *const *v, unsigned int n, uint32_t options) +void response_error_and_die (tipidee_rql const *rql, int e, char const *docroot, unsigned int status, char const *const *v, unsigned int n, uint32_t options) { - response_error(rql, status, rsl, text, options | 1) ; + response_error(rql, docroot, status, options | 1) ; if (options & 1) strerr_dievsys(e, v, n) ; else strerr_diev(e, v, n) ; } -void exit_405 (tipidee_rql const *rql, uint32_t options) +void exit_405_ (tipidee_rql const *rql, uint32_t options) { tain deadline ; tipidee_response_status(buffer_1, rql, 405, "Method Not Allowed") ; @@ -50,8 +105,7 @@ void exit_405 (tipidee_rql const *rql, uint32_t options) tain_add_g(&deadline, &g.writetto) ; if (!buffer_timed_flush_g(buffer_1, &deadline)) strerr_diefu1sys(111, "write to stdout") ; - tipidee_log_exit(g.logv, 0) ; - _exit(0) ; + log_and_exit(0) ; } void respond_30x (tipidee_rql const *rql, tipidee_redirection const *rd) diff --git a/src/tipideed/tipideed-internal.h b/src/tipideed/tipideed-internal.h index fe01152..a4f6d95 100644 --- a/src/tipideed/tipideed-internal.h +++ b/src/tipideed/tipideed-internal.h @@ -71,42 +71,38 @@ extern void tipideed_harden (unsigned int) ; /* Responses */ -extern void response_error (tipidee_rql const *, unsigned int, char const *, char const *, uint32_t) ; /* set bit 0 for Connection: close, bit 1 for preexit */ -extern void response_error_and_exit (tipidee_rql const *, unsigned int, char const *, char const *, uint32_t) gccattr_noreturn ; -extern void response_error_and_die (tipidee_rql const *, int e, unsigned int, char const *, char const *, char const *const *, unsigned int, uint32_t) gccattr_noreturn ; - - /* - preexit is meant to be called before tipidee_log_request(), it won't log an answer line. - Use for early parsing, when the request isn't even validated yet. - exit is meant to be called after tipidee_log_request(), it will log an answer line. - respond can only happen after tipidee_log_request(), it will log an answer line. - - exit will log an informational exit line. - die will not; there will be a fatal line instead. - die will log an answer line. There is no "predie", we just use strerr_die instead. - */ - -#define preexit_400(r, s) response_error_and_exit(r, 400, "Bad Request", s, 2) -#define exit_400(r, s) response_error_and_exit(r, 400, "Bad Request", s, 0) -extern void exit_405 (tipidee_rql const *, uint32_t) gccattr_noreturn ; /* set bit 0 for Allow: POST, bit 1 for preexit */ -#define preexit_408(r) response_error_and_exit(r, 408, "Request Timeout", "", 2) -#define exit_408(r) response_error_and_exit(r, 408, "Request Timeout", "", 0) -#define preexit_413(r, s) response_error_and_exit(r, 413, "Request Entity Too Large", s, 2) -#define exit_413(r, s) response_error_and_exit(r, 413, "Request Entity Too Large", s, 0) -#define preexit_501(r, s) response_error_and_exit(r, 501, "Not Implemented", s, 2) -#define exit_501(r, s) response_error_and_exit(r, 501, "Not Implemented", s, 0) - -#define respond_403(r) response_error(r, 403, "Forbidden", "Missing credentials to access the URI.", 0) -#define respond_404(r) response_error(r, 404, "Not Found", "The request URI was not found.", 0) -#define respond_414(r) response_error(r, 414, "URI Too Long", "The request URI had an oversized component.", 0) +extern void response_error_early (tipidee_rql const *, unsigned int, char const *, char const *, uint32_t) ; /* set bit 0 for Connection: close */ +extern void response_error_early_and_exit (tipidee_rql const *, unsigned int, char const *, char const *) gccattr_noreturn ; +extern void exit_405_ (tipidee_rql const *, uint32_t) gccattr_noreturn ; /* set bit 0 for Allow: POST, bit 1 for preexit */ + +#define eexit_400(r, s) response_error_early_and_exit(r, 400, "Bad Request", s) +#define eexit_405(r) exit_405_((r), 3) +#define eexit_408(r) response_error_early_and_exit((r), 408, "Request Timeout", 0) +#define eexit_413(r, s) response_error_early_and_exit(r, 413, "Request Entity Too Large", s) +#define eexit_501(r, s) response_error_early_and_exit(r, 501, "Not Implemented", s) + + +extern void response_error (tipidee_rql const *, char const *, unsigned int, uint32_t) ; /* set bit 0 for Connection: close */ +extern void response_error_and_exit (tipidee_rql const *, char const *, unsigned int) gccattr_noreturn ; +extern void response_error_and_die (tipidee_rql const *, int, char const *, unsigned int, char const *const *, unsigned int, uint32_t) gccattr_noreturn ; /* set bit 0 for diesys */ + +#define exit_400(r, d) response_error_and_exit(r, (d), 400) +#define exit_405(r) exit_405_((r), 0) +#define exit_408(r, d) response_error_and_exit(r, (d), 408) +#define exit_413(r, d) response_error_and_exit(r, (d), 413) +#define exit_501(r, d) response_error_and_exit(r, (d), 501) + extern void respond_30x (tipidee_rql const *, tipidee_redirection const *) ; -#define respond_504(r) response_error(r, 504, "Gateway Timeout", "The CGI script took too long to answer.", 0) +#define respond_403(r, d) response_error(r, (d), 403, 0) +#define respond_404(r, d) response_error(r, (d), 404, 0) +#define respond_414(r, d) response_error(r, (d), 414, 0) +#define respond_504(r, d) response_error(r, (d), 504, 0) -#define diefx(r, e, status, rsl, text, ...) response_error_and_die(r, e, status, rsl, text, strerr_array(PROG, ": fatal: ", __VA_ARGS__), sizeof(strerr_array(__VA_ARGS__))/sizeof(char const *)+2, 0) -#define diefusys(r, e, status, rsl, text, ...) response_error_and_die(r, e, status, rsl, text, strerr_array(PROG, ": fatal: ", "unable to ", __VA_ARGS__), sizeof(strerr_array(__VA_ARGS__))/sizeof(char const *)+3, 1) -#define die500x(r, e, ...) diefx(r, e, 500, "Internal Server Error", "Bad server configuration.", __VA_ARGS__) -#define die500sys(r, e, ...) diefusys(r, e, 500, "Internal Server Error", "System error.", __VA_ARGS__) -#define die502x(r, e, ...) diefx(r, e, 502, "Bad Gateway", "Bad CGI script.", __VA_ARGS__) +#define diefx(r, e, d, status, ...) response_error_and_die(r, e, d, status, strerr_array(PROG, ": fatal: ", __VA_ARGS__), sizeof(strerr_array(__VA_ARGS__))/sizeof(char const *)+2, 0) +#define diefusys(r, e, d, status, ...) response_error_and_die(r, e, d, status, strerr_array(PROG, ": fatal: ", "unable to ", __VA_ARGS__), sizeof(strerr_array(__VA_ARGS__))/sizeof(char const *)+3, 1) +#define die500x(r, e, d, ...) diefx(r, e, d, 500, __VA_ARGS__) +#define die500sys(r, e, d, ...) diefusys(r, e, d, 500, __VA_ARGS__) +#define die502x(r, e, d, ...) diefx(r, e, d, 502, __VA_ARGS__) /* Trace */ @@ -127,12 +123,17 @@ extern void send_file (int, uint64_t, char const *) ; /* regular */ -extern int respond_regular (tipidee_rql const *, char const *, struct stat const *, tipidee_resattr const *) ; +extern int respond_regular (tipidee_rql const *, char const *, char const *, struct stat const *, tipidee_resattr const *) ; extern int respond_304 (tipidee_rql const *, char const *, struct stat const *) ; /* cgi */ -extern int respond_cgi (tipidee_rql *, char const *, size_t, char const *, char *, tipidee_headers const *, tipidee_resattr const *, char const *, size_t) ; +extern int respond_cgi (tipidee_rql *, char const *, char const *, size_t, char const *, char *, tipidee_headers const *, tipidee_resattr const *, char const *, size_t) ; + + + /* main */ + +extern void log_and_exit (int) gccattr_noreturn ; #endif diff --git a/src/tipideed/tipideed.c b/src/tipideed/tipideed.c index fb5ede4..b004782 100644 --- a/src/tipideed/tipideed.c +++ b/src/tipideed/tipideed.c @@ -45,7 +45,7 @@ static void sigchld_handler (int sig) wait_reap() ; } -static inline void log_and_exit (int e) +void log_and_exit (int e) { tipidee_log_exit(g.logv, e) ; _exit(e) ; @@ -164,7 +164,7 @@ static void inittto (tain *tto, char const *key) else *tto = tain_infinite_relative ; } -static inline unsigned int indexify (tipidee_rql const *rql, char *s, struct stat *st) +static inline unsigned int indexify (tipidee_rql const *rql, char const *docroot, char *s, struct stat *st) { unsigned int e = 0 ; size_t len = strlen(s) ; @@ -184,22 +184,22 @@ static inline unsigned int indexify (tipidee_rql const *rql, char *s, struct sta case ENAMETOOLONG : return 414 ; case ENOTDIR : return 404 ; case ENOENT : continue ; - default : die500sys(rql, 111, "stat ", s) ; + default : die500sys(rql, 111, docroot, "stat ", s) ; } } if (i >= g.indexn) return 404 ; - if (S_ISDIR(st->st_mode)) die500x(rql, 103, "bad document hierarchy: ", s, " is a directory") ; + if (S_ISDIR(st->st_mode)) die500x(rql, 102, docroot, "bad document hierarchy: ", s, " is a directory") ; if (e == 308) s[len] = 0 ; return e ; } -static inline void get_resattr (tipidee_rql const *rql, char const *res, tipidee_resattr *ra) +static inline void get_resattr (tipidee_rql const *rql, char const *docroot, char const *res, tipidee_resattr *ra) { static stralloc sa = STRALLOC_ZERO ; sa.len = 0 ; - if (sarealpath(&sa, res) == -1 || !stralloc_0(&sa)) die500sys(rql, 111, "realpath ", res) ; + if (sarealpath(&sa, res) == -1 || !stralloc_0(&sa)) die500sys(rql, 111, docroot, "realpath ", res) ; if (strncmp(sa.s, g.sa.s, g.cwdlen) || sa.s[g.cwdlen] != '/') - die500x(rql, 102, "resource ", res, " points outside of the server's root") ; + die500x(rql, 102, docroot, "resource ", res, " points outside of the server's root") ; { char const *attr = 0 ; @@ -211,7 +211,7 @@ static inline void get_resattr (tipidee_rql const *rql, char const *res, tipidee errno = ENOENT ; while (!attr) { - if (errno != ENOENT) die500x(rql, 102, "invalid configuration data for ", key) ; + if (errno != ENOENT) die500x(rql, 102, docroot, "invalid configuration data for ", key) ; while (len > 2 && key[len] != '/') len-- ; if (len <= 2) break ; key[len--] = 0 ; @@ -220,7 +220,7 @@ static inline void get_resattr (tipidee_rql const *rql, char const *res, tipidee } if (attr) { - if (*attr < '@' || *attr > 'G') die500x(rql, 102, "invalid configuration data for ", key) ; + if (*attr < '@' || *attr > 'G') die500x(rql, 102, docroot, "invalid configuration data for ", key) ; ra->iscgi = *attr & ~'@' & 1 ; if (attr[1]) ra->content_type = attr + 1 ; if (ra->iscgi) @@ -243,7 +243,7 @@ static inline void get_resattr (tipidee_rql const *rql, char const *res, tipidee if (!ra->iscgi && !ra->content_type) { ra->content_type = tipidee_conf_get_content_type(&g.conf, sa.s + g.cwdlen) ; - if (!ra->content_type) die500sys(rql, 111, "get content type for ", sa.s + g.cwdlen) ; + if (!ra->content_type) die500sys(rql, 111, docroot, "get content type for ", sa.s + g.cwdlen) ; } } @@ -276,7 +276,7 @@ static inline int serve (tipidee_rql *rql, char const *docroot, char *uribuf, ti { tipidee_redirection rd = TIPIDEE_REDIRECTION_ZERO ; int e = tipidee_conf_get_redirection(&g.conf, docroot, docrootlen, rql->uri.path, &rd) ; - if (e == -1) die500sys(rql, 111, "get redirection data for ", fn) ; + if (e == -1) die500sys(rql, 111, docroot, "get redirection data for ", fn) ; if (e) { respond_30x(rql, &rd) ; @@ -292,49 +292,49 @@ static inline int serve (tipidee_rql *rql, char const *docroot, char *uribuf, ti for (;;) { while (fn[pos] != '/') pos-- ; - if (pos <= docrootlen) { respond_404(rql) ; return 0 ; } + if (pos <= docrootlen) { respond_404(rql, docroot) ; return 0 ; } fn[pos] = 0 ; if (stat(fn, &st) == 0) break ; switch (errno) { case ENOTDIR : case ENOENT : fn[pos--] = '/' ; break ; - case EACCES : respond_403(rql) ; return 0 ; - case ENAMETOOLONG : respond_414(rql) ; return 0 ; - default : die500sys(rql, 111, "stat ", fn) ; + case EACCES : respond_403(rql, docroot) ; return 0 ; + case ENAMETOOLONG : respond_414(rql, docroot) ; return 0 ; + default : die500sys(rql, 111, docroot, "stat ", fn) ; } } infopath = fn + pos + 1 ; } if (S_ISDIR(st.st_mode)) { - if (infopath) { respond_404(rql) ; return 0 ; } - switch (indexify(rql, fn, &st)) + if (infopath) { respond_404(rql, docroot) ; return 0 ; } + switch (indexify(rql, docroot, fn, &st)) { - case 403 : respond_403(rql) ; return 0 ; - case 404 : respond_404(rql) ; return 0 ; - case 414 : respond_414(rql) ; return 0 ; + case 403 : respond_403(rql, docroot) ; return 0 ; + case 404 : respond_404(rql, docroot) ; return 0 ; + case 414 : respond_414(rql, docroot) ; return 0 ; case 308 : force_redirect(rql, fn) ; return 0 ; case 0 : break ; } } - LOLDEBUG("serve: %s with %s %s, docroot %s", fn, infopath ? "infopath" : "no", infopath ? infopath : "infopath", docroot) ; + tipidee_log_debug(g.logv, "serve: docroot ", docroot, " file ", fn, " infopath ", infopath ? infopath : "(none)") ; - get_resattr(rql, fn, &ra) ; + get_resattr(rql, docroot, fn, &ra) ; if (!ra.iscgi) { - if (infopath) { respond_404(rql) ; return 0 ; } - if (rql->m == TIPIDEE_METHOD_POST) exit_405(rql, 0) ; + if (infopath) { respond_404(rql, docroot) ; return 0 ; } + if (rql->m == TIPIDEE_METHOD_POST) exit_405(rql) ; } if (rql->m == TIPIDEE_METHOD_OPTIONS) return respond_options(rql, 2 | ra.iscgi) ; - tipidee_log_resource(g.logv, rql, docroot, fn, &ra) ; + tipidee_log_resource(g.logv, rql, fn, &ra, infopath) ; if (ra.iscgi) - return respond_cgi(rql, fn, docrootlen, infopath, uribuf, hdr, &ra, body, bodylen) ; + return respond_cgi(rql, docroot, fn, docrootlen, infopath, uribuf, hdr, &ra, body, bodylen) ; infopath = tipidee_headers_search(hdr, "If-Modified-Since") ; if (infopath) @@ -345,7 +345,7 @@ static inline int serve (tipidee_rql *rql, char const *docroot, char *uribuf, ti && tain_less(&actual, &wanted)) return respond_304(rql, fn, &st) ; } - return respond_regular(rql, fn, &st, &ra) ; + return respond_regular(rql, docroot, fn, &st, &ra) ; } int main (int argc, char const *const *argv, char const *const *envp) @@ -403,6 +403,8 @@ int main (int argc, char const *const *argv, char const *const *envp) init_splice_pipe() ; if (!sig_catch(SIGCHLD, &sigchld_handler)) strerr_diefu1sys(111, "set SIGCHLD handler") ; + if (!sig_altignore(SIGPIPE)) + strerr_diefu1sys(111, "ignore SIGPIPE") ; if (!tain_now_set_stopwatch_g()) strerr_diefu1sys(111, "initialize clock") ; tipidee_log_start(g.logv, g.sa.s + remoteip, g.sa.s + remotehost) ; @@ -430,14 +432,15 @@ int main (int argc, char const *const *argv, char const *const *envp) e = tipidee_rql_read_g(buffer_0, uribuf, URI_BUFSIZE, &content_length, &rql, &deadline) ; switch (e) { - case -1 : log_and_exit(1) ; /* Malicious or shitty client */ + case -1 : log_and_exit(1) ; /* bad client */ case 0 : break ; - case 99 : g.cont = 0 ; continue ; /* timeout, it's ok */ - case 400 : preexit_400(&rql, "Syntax error in request line") ; + case 98 : /* client exited */ + case 99 : g.cont = 0 ; continue ; /* timeout */ + case 400 : eexit_400(&rql, "Syntax error in request line") ; default : strerr_dief2x(101, "can't happen: ", "unknown tipidee_rql_read return code") ; } if (rql.http_major != 1) log_and_exit(1) ; - if (rql.http_minor > 1) preexit_400(&rql, "Bad HTTP version") ; + if (rql.http_minor > 1) eexit_400(&rql, "Bad HTTP version") ; content_length = 0 ; tipidee_headers_init(&hdr, hdrbuf, HDR_BUFSIZE) ; @@ -446,9 +449,9 @@ int main (int argc, char const *const *argv, char const *const *envp) { case -1 : log_and_exit(1) ; /* connection issue, client timeout, etc. */ case 0 : break ; - case 400 : preexit_400(&rql, "Syntax error in headers") ; - case 408 : preexit_408(&rql) ; /* timeout */ - case 413 : preexit_413(&rql, hdr.n >= TIPIDEE_HEADERS_MAX ? "Too many headers" : "Too much header data") ; + case 400 : eexit_400(&rql, "Syntax error in headers") ; + case 408 : eexit_408(&rql) ; /* timeout */ + case 413 : eexit_413(&rql, hdr.n >= TIPIDEE_HEADERS_MAX ? "Too many headers" : "Too much header data") ; case 500 : strerr_dief2x(101, "can't happen: ", "avltreen_insert failed") ; default : strerr_dief2x(101, "can't happen: ", "unknown tipidee_headers_parse return code") ; } @@ -467,7 +470,7 @@ int main (int argc, char const *const *argv, char const *const *envp) x = tipidee_headers_search(&hdr, "Transfer-Encoding") ; if (x) { - if (strcasecmp(x, "chunked")) preexit_400(&rql, "unsupported Transfer-Encoding") ; + if (strcasecmp(x, "chunked")) eexit_400(&rql, "unsupported Transfer-Encoding") ; else tcoding = TIPIDEE_TRANSFERCODING_CHUNKED ; } else @@ -475,7 +478,7 @@ int main (int argc, char const *const *argv, char const *const *envp) x = tipidee_headers_search(&hdr, "Content-Length") ; if (x) { - if (!size_scan(x, &content_length)) preexit_400(&rql, "Invalid Content-Length") ; + if (!size_scan(x, &content_length)) eexit_400(&rql, "Invalid Content-Length") ; else if (content_length) tcoding = TIPIDEE_TRANSFERCODING_FIXED ; else tcoding = TIPIDEE_TRANSFERCODING_NONE ; } @@ -483,7 +486,7 @@ int main (int argc, char const *const *argv, char const *const *envp) } if (tcoding != TIPIDEE_TRANSFERCODING_NONE && rql.m != TIPIDEE_METHOD_POST) - preexit_400(&rql, "only POST requests can have an entity body") ; + eexit_400(&rql, "only POST requests can have an entity body") ; switch (rql.m) { @@ -495,9 +498,9 @@ int main (int argc, char const *const *argv, char const *const *envp) if (!rql.uri.path) { respond_options(&rql, 1) ; continue ; } break ; case TIPIDEE_METHOD_PUT : - case TIPIDEE_METHOD_DELETE : exit_405(&rql, 3) ; - case TIPIDEE_METHOD_CONNECT : preexit_501(&rql, "CONNECT method unsupported") ; - case TIPIDEE_METHOD_PRI : preexit_501(&rql, "PRI method attempted with HTTP version 1") ; + case TIPIDEE_METHOD_DELETE : eexit_405(&rql) ; + case TIPIDEE_METHOD_CONNECT : eexit_501(&rql, "CONNECT method unsupported") ; + case TIPIDEE_METHOD_PRI : eexit_501(&rql, "PRI method attempted with HTTP version 1") ; default : strerr_dief2x(101, "can't happen: ", "unknown HTTP method") ; } @@ -509,13 +512,13 @@ int main (int argc, char const *const *argv, char const *const *envp) char *p = strchr(x, ':') ; if (p) { - if (!uint160_scan(p+1, &rql.uri.port)) preexit_400(&rql, "Invalid Host header") ; + if (!uint160_scan(p+1, &rql.uri.port)) eexit_400(&rql, "Invalid Host header") ; *p = 0 ; } - if (!*x || *x == '.') preexit_400(&rql, "Invalid Host header") ; + if (!*x || *x == '.') eexit_400(&rql, "Invalid Host header") ; rql.uri.host = x ; } - else if (!rql.uri.host) preexit_400(&rql, "Missing Host header") ; + else if (!rql.uri.host) eexit_400(&rql, "Missing Host header") ; } else if (!rql.uri.host) rql.uri.host = g.defaulthost ; if (!rql.uri.port) rql.uri.port = g.defaultport ; @@ -541,12 +544,12 @@ int main (int argc, char const *const *argv, char const *const *envp) { case TIPIDEE_TRANSFERCODING_FIXED : { - if (content_length > g.maxrqbody) exit_413(&rql, "Request body too large") ; - if (!stralloc_ready(&bodysa, content_length)) die500sys(&rql, 111, "stralloc_ready") ; + if (content_length > g.maxrqbody) exit_413(&rql, docroot) ; + if (!stralloc_ready(&bodysa, content_length)) die500sys(&rql, 111, docroot, "stralloc_ready") ; if (buffer_timed_get_g(buffer_0, bodysa.s, content_length, &deadline) < content_length) { - if (errno == ETIMEDOUT) exit_408(&rql) ; - else exit_400(&rql, "Request body does not match Content-Length") ; + if (errno == ETIMEDOUT) exit_408(&rql, docroot) ; + else exit_400(&rql, docroot) ; } bodysa.len = content_length ; break ; @@ -555,9 +558,9 @@ int main (int argc, char const *const *argv, char const *const *envp) { if (!tipidee_util_chunked_read_g(buffer_0, &bodysa, g.maxrqbody, &deadline)) { - if (error_temp(errno)) die500sys(&rql, 111, "decode chunked body") ; - else if (errno == EMSGSIZE) exit_413(&rql, "Request body too large") ; - else exit_400(&rql, "Invalid chunked body") ; + if (error_temp(errno)) die500sys(&rql, 111, docroot, "decode chunked body") ; + else if (errno == EMSGSIZE) exit_413(&rql, docroot) ; + else exit_400(&rql, docroot) ; } break ; } @@ -569,8 +572,9 @@ int main (int argc, char const *const *argv, char const *const *envp) while (serve(&rql, docroot, uribuf, &hdr, bodysa.s, bodysa.len)) if (localredirs++ >= MAX_LOCALREDIRS) - die502x(&rql, 2, "too many local redirections - possible loop involving path ", rql.uri.path) ; + die502x(&rql, 2, docroot, "too many local redirections - possible loop involving path ", rql.uri.path) ; } } + log_and_exit(0) ; } |