summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2023-10-18 13:07:23 +0000
committerLaurent Bercot <ska@appnovation.com>2023-10-18 13:07:23 +0000
commit1a7e3d00588725da3d8764fa9d624bc8611be070 (patch)
tree65d28b52bd1d4ccdbeb418d4d681b1999ed46b7a
parent24fb88dbb023ae08adc9989bf19e0c6c569a6607 (diff)
downloadtipidee-1a7e3d00588725da3d8764fa9d624bc8611be070.tar.xz
Add infrastructure for custom error files
Signed-off-by: Laurent Bercot <ska@appnovation.com>
-rw-r--r--doc/tipidee.conf.html7
-rw-r--r--doc/tipideed.html10
-rw-r--r--package/deps.mak16
-rw-r--r--src/include/tipidee/conf.h1
-rw-r--r--src/include/tipidee/log.h2
-rw-r--r--src/include/tipidee/response.h10
-rw-r--r--src/libtipidee/deps-lib/tipidee4
-rw-r--r--src/libtipidee/tipidee_conf_get_errorfile.c24
-rw-r--r--src/libtipidee/tipidee_log_request.c2
-rw-r--r--src/libtipidee/tipidee_log_resource.c13
-rw-r--r--src/libtipidee/tipidee_response_error.c41
-rw-r--r--src/libtipidee/tipidee_response_error_nofile.c35
-rw-r--r--src/libtipidee/tipidee_response_file.c31
-rw-r--r--src/libtipidee/tipidee_response_header_common_put.c17
-rw-r--r--src/libtipidee/tipidee_response_status.c4
-rw-r--r--src/libtipidee/tipidee_rql_read.c5
-rw-r--r--src/tipideed/cgi.c144
-rw-r--r--src/tipideed/regular.c25
-rw-r--r--src/tipideed/responses.c80
-rw-r--r--src/tipideed/tipideed-internal.h73
-rw-r--r--src/tipideed/tipideed.c106
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) ;
}