about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2023-10-24 12:38:53 +0000
committerLaurent Bercot <ska@appnovation.com>2023-10-24 12:38:53 +0000
commit305385e06f90ca3216e1aa4e43b20dd7d53c1222 (patch)
tree899d3460b511567889d5e5d78f77931af572b5fb
parent37d2f8cb438f68eaa1da8a56ea9ce5023091f128 (diff)
downloadtipidee-305385e06f90ca3216e1aa4e43b20dd7d53c1222.tar.gz
tipidee-305385e06f90ca3216e1aa4e43b20dd7d53c1222.tar.xz
tipidee-305385e06f90ca3216e1aa4e43b20dd7d53c1222.zip
Make the switch to custom headers
Signed-off-by: Laurent Bercot <ska@appnovation.com>
-rw-r--r--package/deps.mak11
-rw-r--r--src/include/tipidee/response.h25
-rw-r--r--src/libtipidee/deps-lib/tipidee4
-rw-r--r--src/libtipidee/tipidee_response_error_nofile.c4
-rw-r--r--src/libtipidee/tipidee_response_file.c4
-rw-r--r--src/libtipidee/tipidee_response_header_builtin.c40
-rw-r--r--src/libtipidee/tipidee_response_header_common_put.c20
-rw-r--r--src/libtipidee/tipidee_response_header_writeall.c20
-rw-r--r--src/libtipidee/tipidee_response_header_writemerge.c54
-rw-r--r--src/tipideed/cgi.c44
-rw-r--r--src/tipideed/options.c2
-rw-r--r--src/tipideed/regular.c6
-rw-r--r--src/tipideed/responses.c10
-rw-r--r--src/tipideed/tipideed-internal.h2
-rw-r--r--src/tipideed/tipideed.c6
-rw-r--r--src/tipideed/trace.c2
16 files changed, 120 insertions, 134 deletions
diff --git a/package/deps.mak b/package/deps.mak
index 81bbddd..07ca168 100644
--- a/package/deps.mak
+++ b/package/deps.mak
@@ -4,7 +4,7 @@
 
 src/include/tipidee/conf.h: src/include/tipidee/uri.h
 src/include/tipidee/log.h: src/include/tipidee/headers.h src/include/tipidee/rql.h
-src/include/tipidee/response.h: src/include/tipidee/rql.h
+src/include/tipidee/response.h: src/include/tipidee/headers.h src/include/tipidee/rql.h
 src/include/tipidee/rql.h: src/include/tipidee/method.h src/include/tipidee/uri.h
 src/include/tipidee/tipidee.h: src/include/tipidee/conf.h src/include/tipidee/config.h src/include/tipidee/headers.h src/include/tipidee/log.h src/include/tipidee/method.h src/include/tipidee/response.h src/include/tipidee/rql.h src/include/tipidee/uri.h src/include/tipidee/util.h
 src/tipideed/tipideed-internal.h: src/include/tipidee/tipidee.h
@@ -40,11 +40,12 @@ src/libtipidee/tipidee_method.o src/libtipidee/tipidee_method.lo: src/libtipidee
 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/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
 src/libtipidee/tipidee_response_header_preparebuiltin.o src/libtipidee/tipidee_response_header_preparebuiltin.lo: src/libtipidee/tipidee_response_header_preparebuiltin.c src/include/tipidee/response.h
+src/libtipidee/tipidee_response_header_writeall.o src/libtipidee/tipidee_response_header_writeall.lo: src/libtipidee/tipidee_response_header_writeall.c src/include/tipidee/response.h
+src/libtipidee/tipidee_response_header_writemerge.o src/libtipidee/tipidee_response_header_writemerge.lo: src/libtipidee/tipidee_response_header_writemerge.c src/include/tipidee/headers.h src/include/tipidee/response.h
 src/libtipidee/tipidee_response_status.o src/libtipidee/tipidee_response_status.lo: src/libtipidee/tipidee_response_status.c src/include/tipidee/response.h
 src/libtipidee/tipidee_rql_read.o src/libtipidee/tipidee_rql_read.lo: src/libtipidee/tipidee_rql_read.c src/include/tipidee/method.h src/include/tipidee/rql.h src/include/tipidee/uri.h
 src/libtipidee/tipidee_uri_parse.o src/libtipidee/tipidee_uri_parse.lo: src/libtipidee/tipidee_uri_parse.c src/include/tipidee/uri.h
@@ -65,12 +66,12 @@ tipidee-config: src/config/tipidee-config.o src/config/util.o src/config/node.o
 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_errorfile.o src/libtipidee/tipidee_conf_get_redirection.o src/libtipidee/tipidee_conf_get_responseheaders.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_header_preparebuiltin.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_responseheaders.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_date.o src/libtipidee/tipidee_response_header_date_fmt.o src/libtipidee/tipidee_response_header_lastmodified.o src/libtipidee/tipidee_response_header_preparebuiltin.o src/libtipidee/tipidee_response_header_writeall.o src/libtipidee/tipidee_response_header_writemerge.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_errorfile.lo src/libtipidee/tipidee_conf_get_redirection.lo src/libtipidee/tipidee_conf_get_responseheaders.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_header_preparebuiltin.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_responseheaders.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_date.lo src/libtipidee/tipidee_response_header_date_fmt.lo src/libtipidee/tipidee_response_header_lastmodified.lo src/libtipidee/tipidee_response_header_preparebuiltin.lo src/libtipidee/tipidee_response_header_writeall.lo src/libtipidee/tipidee_response_header_writemerge.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_errorfile.lo src/libtipidee/tipidee_conf_get_redirection.lo src/libtipidee/tipidee_conf_get_responseheaders.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_header_preparebuiltin.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_responseheaders.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_date.lo src/libtipidee/tipidee_response_header_date_fmt.lo src/libtipidee/tipidee_response_header_lastmodified.lo src/libtipidee/tipidee_response_header_preparebuiltin.lo src/libtipidee/tipidee_response_header_writeall.lo src/libtipidee/tipidee_response_header_writemerge.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/response.h b/src/include/tipidee/response.h
index bc83fc6..ea0e835 100644
--- a/src/include/tipidee/response.h
+++ b/src/include/tipidee/response.h
@@ -15,6 +15,7 @@
 #include <skalibs/tai.h>
 
 #include <tipidee/rql.h>
+#include <tipidee/headers.h>
 
 typedef struct tipidee_response_header_s tipidee_response_header, *tipidee_response_header_ref ;
 struct tipidee_response_header_s
@@ -24,13 +25,6 @@ struct tipidee_response_header_s
   uint8_t options ;
 } ;
 
-typedef struct tipidee_response_header_builtin_s tipidee_response_header_builtin, *tipidee_response_header_builtin_ref ;
-struct tipidee_response_header_builtin_s
-{
-  char const *key ;
-  char const *value ;
-} ;
-
 extern size_t tipidee_response_status (buffer *, tipidee_rql const *, unsigned int, char const *) ;
 
 extern size_t tipidee_response_header_date_fmt (char *, size_t, tain const *) ;
@@ -38,17 +32,16 @@ extern size_t tipidee_response_header_date (char *, size_t, tain const *) ;
 #define tipidee_response_header_date_g(buf, max) tipidee_response_header_date(buf, (max), &STAMP)
 extern size_t tipidee_response_header_lastmodified (char *, size_t, struct stat const *) ;
 
-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)
-
-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_header_writeall (buffer *, tipidee_response_header const *, uint32_t, uint32_t, tain const *) ;
+#define tipidee_response_header_writeall_g(b, rhdr, rhdrn, options) tipidee_response_header_writeall(b, rhdr, rhdrn, (options), &STAMP)
+extern size_t tipidee_response_header_writemerge (buffer *, tipidee_response_header const *, uint32_t, tipidee_headers const *, uint32_t, tain const *) ;
+#define tipidee_response_header_writemerge_g(b, rhdr, rhdrn, hdr, options) tipidee_response_header_writemerge(b, rhdr, rhdrn, hdr, (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)
+size_t tipidee_response_file (buffer *, tipidee_rql const *, unsigned int, char const *, struct stat const *, char const *, tipidee_response_header const *, uint32_t, uint32_t, tain const *) ;
+#define tipidee_response_file_g(b, rql, status, reason, st, ct, rhdr, rhdrn, options) tipidee_response_file(b, rql, status, reason, st, ct, rhdr, rhdrn, (options), &STAMP)
 
-extern tipidee_response_header_builtin const *tipidee_response_header_builtin_table ;
-extern char const *tipidee_response_header_builtin_search (char const *) ;
+extern size_t tipidee_response_error_nofile (buffer *, tipidee_rql const *, unsigned int, char const *, char const *, tipidee_response_header const *, uint32_t, uint32_t, tain const *) ;
+#define tipidee_response_error_nofile_g(b, rql, status, reason, text, rhdr, rhdrn, options) tipidee_response_error_nofile(b, rql, status, reason, text, rhdr, rhdrn, (options), &STAMP)
 
 extern int tipidee_response_header_preparebuiltin (tipidee_response_header *, uint32_t, char const *, size_t) ;
 
diff --git a/src/libtipidee/deps-lib/tipidee b/src/libtipidee/deps-lib/tipidee
index d406e5c..b20898b 100644
--- a/src/libtipidee/deps-lib/tipidee
+++ b/src/libtipidee/deps-lib/tipidee
@@ -20,12 +20,12 @@ tipidee_log_start.o
 tipidee_method.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
 tipidee_response_header_date_fmt.o
 tipidee_response_header_lastmodified.o
 tipidee_response_header_preparebuiltin.o
+tipidee_response_header_writeall.o
+tipidee_response_header_writemerge.o
 tipidee_response_status.o
 tipidee_rql_read.o
 tipidee_uri_parse.o
diff --git a/src/libtipidee/tipidee_response_error_nofile.c b/src/libtipidee/tipidee_response_error_nofile.c
index 4f628ac..8a7cd53 100644
--- a/src/libtipidee/tipidee_response_error_nofile.c
+++ b/src/libtipidee/tipidee_response_error_nofile.c
@@ -8,7 +8,7 @@
 #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)
+size_t tipidee_response_error_nofile (buffer *b, tipidee_rql const *rql, unsigned int status, char const *reason, char const *text, tipidee_response_header const *rhdr, uint32_t rhdrn, uint32_t options, tain const *stamp)
 {
   static char const txt1[] = "<html>\n<head><title>" ;
   static char const txt2[] = "</title></head>\n<body>\n<h1> " ;
@@ -16,7 +16,7 @@ size_t tipidee_response_error_nofile (buffer *b, tipidee_rql const *rql, unsigne
   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 += tipidee_response_header_writeall(b, rhdr, rhdrn, 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)) ;
diff --git a/src/libtipidee/tipidee_response_file.c b/src/libtipidee/tipidee_response_file.c
index 0cbe8f4..f2021ee 100644
--- a/src/libtipidee/tipidee_response_file.c
+++ b/src/libtipidee/tipidee_response_file.c
@@ -11,11 +11,11 @@
 #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)
+size_t tipidee_response_file (buffer *b, tipidee_rql const *rql, unsigned int status, char const *reason, struct stat const *st, char const *ct, tipidee_response_header const *rhdr, uint32_t rhdrn, 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) ;
+  n += tipidee_response_header_writeall(b, rhdr, rhdrn, options & 1, stamp) ;
   if (options & 2)
   {
     size_t l = tipidee_response_header_lastmodified(fmt, 128, st) ;
diff --git a/src/libtipidee/tipidee_response_header_builtin.c b/src/libtipidee/tipidee_response_header_builtin.c
deleted file mode 100644
index 0125cb8..0000000
--- a/src/libtipidee/tipidee_response_header_builtin.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/* ISC license. */
-
-#include <string.h>
-#include <stdlib.h>
-
-#include <tipidee/config.h>
-#include <tipidee/response.h>
-
-static tipidee_response_header_builtin const tipidee_response_header_builtin_table_[] =
-{
-  { .key = "Accept-Ranges", .value = "none" },
-  { .key = "Cache-Control", .value = "private" },
-  { .key = "Content-Security-Policy", .value = "default-src 'self'; style-src 'self' 'unsafe-inline';" },
-  { .key = "Referrer-Policy", .value = "no-referrer-when-downgrade" },
-  { .key = "Server", .value = "tipidee/" TIPIDEE_VERSION },
-  { .key = "Vary", .value = "Accept-Encoding" },
-  { .key = "X-Content-Type-Options", .value = "nosniff" },
-  { .key = "X-Frame-Options", .value = "DENY" },
-  { .key = "X-XSS-Protection", .value = "1; mode=block" },
-  { .key = 0, .value = 0 },
-} ;
-
-tipidee_response_header_builtin const *tipidee_response_header_builtin_table = tipidee_response_header_builtin_table_ ;
-
-static int tipidee_response_header_builtin_cmp (void const *a, void const *b)
-{
-  return strcmp((char const *)a, ((tipidee_response_header_builtin const *)b)->key) ;
-}
-
-char const *tipidee_response_header_builtin_search (char const *key)
-{
-  tipidee_response_header_builtin const *p = bsearch(
-    key,
-    tipidee_response_header_builtin_table_,
-    sizeof(tipidee_response_header_builtin_table_) / sizeof(tipidee_response_header_builtin) - 1,
-    sizeof(tipidee_response_header_builtin),
-    &tipidee_response_header_builtin_cmp) ;
-  return p ? p->value : 0 ;
-}
-
diff --git a/src/libtipidee/tipidee_response_header_common_put.c b/src/libtipidee/tipidee_response_header_common_put.c
deleted file mode 100644
index e9a1a07..0000000
--- a/src/libtipidee/tipidee_response_header_common_put.c
+++ /dev/null
@@ -1,20 +0,0 @@
-/* ISC license. */
-
-#include <skalibs/buffer.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 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++)
-  {
-    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) n += buffer_putsnoflush(b, "Connection: close\r\n") ;
-  return n ;
-}
diff --git a/src/libtipidee/tipidee_response_header_writeall.c b/src/libtipidee/tipidee_response_header_writeall.c
new file mode 100644
index 0000000..a61a80d
--- /dev/null
+++ b/src/libtipidee/tipidee_response_header_writeall.c
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#include <skalibs/buffer.h>
+
+#include <tipidee/response.h>
+
+size_t tipidee_response_header_writeall (buffer *b, tipidee_response_header const *rhdr, uint32_t rhdrn, uint32_t options, tain const *stamp)
+{
+  char fmt[128] ;
+  size_t m = buffer_putnoflush(b, fmt, tipidee_response_header_date(fmt, 128, stamp)) ;
+  if (options & 1) m += buffer_putsnoflush(b, "Connection: close\r\n") ;
+  for (uint32_t i = 0 ; i < rhdrn ; i++)
+  {
+    m += buffer_putsnoflush(b, rhdr[i].key) ;
+    m += buffer_putnoflush(b, ": ", 2) ;
+    m += buffer_putsnoflush(b, rhdr[i].value) ;
+    m += buffer_putnoflush(b, "\r\n", 2) ;
+  }
+  return m ;
+}
diff --git a/src/libtipidee/tipidee_response_header_writemerge.c b/src/libtipidee/tipidee_response_header_writemerge.c
new file mode 100644
index 0000000..b8b1e10
--- /dev/null
+++ b/src/libtipidee/tipidee_response_header_writemerge.c
@@ -0,0 +1,54 @@
+/* ISC license. */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <skalibs/buffer.h>
+
+#include <tipidee/headers.h>
+#include <tipidee/response.h>
+
+static int tipidee_response_header_cmp (void const *a, void const *b)
+{
+  return strcasecmp((char const *)a, ((tipidee_response_header const *)b)->key) ;
+}
+
+size_t tipidee_response_header_writemerge (buffer *b, tipidee_response_header const *rhdr, uint32_t rhdrn, tipidee_headers const *hdr, uint32_t options, tain const *stamp)
+{
+  static char const *const nope_table[] =
+  {
+    "Connection",
+    "Content-Length",
+    "Date",
+    "Status"
+  } ;
+  char fmt[128] ;
+  size_t m = buffer_putnoflush(b, fmt, tipidee_response_header_date(fmt, 128, stamp)) ;
+  if (options & 1) m += buffer_putsnoflush(b, "Connection: close\r\n") ;
+
+  for (uint32_t i = 0 ; i < rhdrn ; i++)
+  {
+    if (rhdr[i].options & 1 && tipidee_headers_search(hdr, rhdr[i].key)) continue ;
+    m += buffer_putsnoflush(b, rhdr[i].key) ;
+    m += buffer_putnoflush(b, ": ", 2) ;
+    m += buffer_putsnoflush(b, rhdr[i].value) ;
+    m += buffer_putnoflush(b, "\r\n", 2) ;
+  }
+
+  for (uint32_t i = 0 ; i < hdr->n ; i++)
+  {
+    tipidee_response_header const *p ;
+    char const *key = hdr->buf + hdr->list[i].left ;
+    if (!strncasecmp(key, "X-CGI-", 6)) continue ;
+    if (bsearch(key, nope_table, sizeof(nope_table) / sizeof(char const *const), sizeof(char const *const), (int (*)(void const *, void const *))&strcasecmp)) continue ;
+    p = bsearch(key, rhdr, rhdrn, sizeof(tipidee_response_header), &tipidee_response_header_cmp) ;
+    if (p && !(p->options & 1)) continue ;
+    m += buffer_putsnoflush(b, key) ;
+    m += buffer_putnoflush(b, ": ", 2) ;
+    m += buffer_putsnoflush(b, hdr->buf + hdr->list[i].right) ;
+    m += buffer_putnoflush(b, "\r\n", 2) ;
+  }
+
+  return m ;
+}
diff --git a/src/tipideed/cgi.c b/src/tipideed/cgi.c
index 0d7e104..be969c8 100644
--- a/src/tipideed/cgi.c
+++ b/src/tipideed/cgi.c
@@ -255,36 +255,6 @@ static inline int local_redirect (tipidee_rql *rql, char const *docroot, char co
   return 1 ;
 }
 
-static inline void print_cgi_headers (tipidee_headers const *hdr, size_t rbodylen)
-{
-  static char const *const nope_table[] =
-  {
-    "Connection",
-    "Content-Length",
-    "Date",
-    "Status",
-    0
-  } ;
-  char fmt[SIZE_FMT] ;
-  for (size_t i = 0 ; i < hdr->n ; i++)
-  {
-    char const *key = hdr->buf + hdr->list[i].left ;
-    char const *const *p = nope_table ;
-    if (tipidee_response_header_builtin_search(key)) continue ;
-    if (str_start(key, "X-CGI-")) continue ;
-    for (; *p ; p++) if (!strcasecmp(key, *p)) break ;
-    if (*p) continue ;
-    buffer_putsnoflush(buffer_1, key) ;
-    buffer_putnoflush(buffer_1, ": ", 2) ;
-    buffer_putsnoflush(buffer_1, hdr->buf + hdr->list[i].right) ;
-    buffer_putnoflush(buffer_1, "\r\n", 2) ;
-  }
-  fmt[size_fmt(fmt, rbodylen)] = 0 ;
-  buffer_putsnoflush(buffer_1, "Content-Length: ") ;
-  buffer_putsnoflush(buffer_1, fmt) ;
-  buffer_putnoflush(buffer_1, "\r\n", 2) ;
-}
-
 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") ;
@@ -353,8 +323,14 @@ static inline int process_cgi_output (tipidee_rql *rql, char const *docroot, tip
   }
 
   tipidee_response_status(buffer_1, rql, status, reason) ;
-  tipidee_response_header_common_put_g(buffer_1, !g.cont) ;
-  print_cgi_headers(hdr, rbodylen) ;
+  tipidee_response_header_writemerge_g(buffer_1, g.rhdr, g.rhdrn, hdr, !g.cont) ;
+  {
+    char fmt[SIZE_FMT] ;
+    fmt[size_fmt(fmt, rbodylen)] = 0 ;
+    buffer_putsnoflush(buffer_1, "Content-Length: ") ;
+    buffer_putsnoflush(buffer_1, fmt) ;
+    buffer_putnoflush(buffer_1, "\r\n", 2) ;
+  }
   if (buffer_timed_put_g(buffer_1, "\r\n", 2, &deadline) < 2)
     strerr_diefu1sys(111, "write to stdout") ;
   tipidee_log_answer(g.logv, rql, status, rbodylen) ;
@@ -372,9 +348,9 @@ static inline int do_cgi (tipidee_rql *rql, char const *docroot, char const *con
 {
   static stralloc sa = STRALLOC_ZERO ;
   tipidee_headers hdr ;
-  char hdrbuf[2048] ;
+  char hdrbuf[4096] ;
   sa.len = 0 ;
-  tipidee_headers_init(&hdr, hdrbuf, 2048) ;
+  tipidee_headers_init(&hdr, hdrbuf, 4096) ;
   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]) ;
 }
diff --git a/src/tipideed/options.c b/src/tipideed/options.c
index a023401..ce25a81 100644
--- a/src/tipideed/options.c
+++ b/src/tipideed/options.c
@@ -15,7 +15,7 @@ int respond_options (tipidee_rql const *rql, uint32_t flags)
 {
   tain deadline ;
   tipidee_response_status(buffer_1, rql, 200, "OK") ;
-  tipidee_response_header_common_put_g(buffer_1, 0) ;
+  tipidee_response_header_writeall_g(buffer_1, g.rhdr, g.rhdrn, 0) ;
   buffer_putsnoflush(buffer_1, "Content-Length: 0\r\nAllow: GET, HEAD") ;
   if (flags & 1) buffer_putsnoflush(buffer_1, ", POST") ;
   buffer_putnoflush(buffer_1, "\r\n\r\n", 4) ;
diff --git a/src/tipideed/regular.c b/src/tipideed/regular.c
index aa937ad..a075cc0 100644
--- a/src/tipideed/regular.c
+++ b/src/tipideed/regular.c
@@ -22,7 +22,7 @@ int respond_regular (tipidee_rql const *rql, char const *docroot, char const *fn
   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_response_file_g(buffer_1, rql, 200, "OK", st, ra->content_type, g.rhdr, g.rhdrn, 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))
@@ -40,7 +40,7 @@ int respond_regular (tipidee_rql const *rql, char const *docroot, char const *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_response_file_g(buffer_1, rql, 200, "OK", st, ra->content_type, g.rhdr, g.rhdrn, 2 | !g.cont) ;
     tipidee_log_answer(g.logv, rql, 200, st->st_size) ;
     send_file(fd, st->st_size, fn) ;
     fd_close(fd) ;
@@ -53,7 +53,7 @@ int respond_304 (tipidee_rql const *rql, char const *fn, struct stat const *st)
   tain deadline ;
   char fmt[128] ;
   size_t n = tipidee_response_status(buffer_1, rql, 304, "Not Modified") ;
-  n += tipidee_response_header_common_put_g(buffer_1, !g.cont) ;
+  n += tipidee_response_header_writeall_g(buffer_1, g.rhdr, g.rhdrn, !g.cont) ;
   {
     size_t l = tipidee_response_header_lastmodified(fmt, 128, st) ;
     if (l) n += buffer_putnoflush(buffer_1, fmt, l) ;
diff --git a/src/tipideed/responses.c b/src/tipideed/responses.c
index 81b8315..8155b55 100644
--- a/src/tipideed/responses.c
+++ b/src/tipideed/responses.c
@@ -23,7 +23,7 @@
 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_nofile_g(buffer_1, rql, status, reason, text, options & 1 || !g.cont) ;
+  tipidee_response_error_nofile_g(buffer_1, rql, status, reason, text, g.rhdr, g.rhdrn, options & 1 || !g.cont) ;
   tain_add_g(&deadline, &g.writetto) ;
   if (!buffer_timed_flush_g(buffer_1, &deadline))
     strerr_diefu1sys(111, "write to stdout") ;
@@ -79,7 +79,7 @@ void response_error (tipidee_rql const *rql, char const *docroot, unsigned int s
       }
       else
       {
-        tipidee_response_file_g(buffer_1, rql, status, dt.reason, &st, tipidee_conf_get_content_type(&g.conf, g.sa.s + salen + g.cwdlen + 1), options) ;
+        tipidee_response_file_g(buffer_1, rql, status, dt.reason, &st, tipidee_conf_get_content_type(&g.conf, g.sa.s + salen + g.cwdlen + 1), g.rhdr, g.rhdrn, options) ;
         tipidee_log_answer(g.logv, rql, status, st.st_size) ;
         send_file(fd, st.st_size, g.sa.s + salen + g.cwdlen + 1) ;
         fd_close(fd) ;
@@ -88,7 +88,7 @@ void response_error (tipidee_rql const *rql, char const *docroot, unsigned int s
     }
   }
 
-  tipidee_response_error_nofile_g(buffer_1, rql, status, dt.reason, dt.text, options & 1 || !g.cont) ;
+  tipidee_response_error_nofile_g(buffer_1, rql, status, dt.reason, dt.text, g.rhdr, g.rhdrn, options & 1 || !g.cont) ;
   tipidee_log_answer(g.logv, rql, status, 0) ;
   tain_add_g(&deadline, &g.writetto) ;
   if (!buffer_timed_flush_g(buffer_1, &deadline))
@@ -112,7 +112,7 @@ void exit_405_ (tipidee_rql const *rql, uint32_t options)
 {
   tain deadline ;
   tipidee_response_status(buffer_1, rql, 405, "Method Not Allowed") ;
-  tipidee_response_header_common_put_g(buffer_1, 1) ;
+  tipidee_response_header_writeall_g(buffer_1, g.rhdr, g.rhdrn, 1) ;
   buffer_putsnoflush(buffer_1, "Allow: GET, HEAD") ;
   if (options & 1) buffer_putsnoflush(buffer_1, ", POST") ;
   buffer_putnoflush(buffer_1, "\r\n\r\n", 4) ;
@@ -129,7 +129,7 @@ void respond_30x (tipidee_rql const *rql, tipidee_redirection const *rd)
   static char const *const reason[4] = { "Temporary Redirect", "Permanent Redirect", "Found", "Moved Permanently" } ;
   tain deadline ;
   tipidee_response_status(buffer_1, rql, status[rd->type], reason[rd->type]) ;
-  tipidee_response_header_common_put_g(buffer_1, 0) ;
+  tipidee_response_header_writeall_g(buffer_1, g.rhdr, g.rhdrn, 0) ;
   buffer_putsnoflush(buffer_1, "Content-Length: 0\r\nLocation: ") ;
   buffer_putsnoflush(buffer_1, rd->location) ;
   if (rd->sub) buffer_putsnoflush(buffer_1, rd->sub) ;
diff --git a/src/tipideed/tipideed-internal.h b/src/tipideed/tipideed-internal.h
index 3629f84..344840c 100644
--- a/src/tipideed/tipideed-internal.h
+++ b/src/tipideed/tipideed-internal.h
@@ -32,6 +32,7 @@ struct global_s
   char const *indexnames[16] ;
   tipidee_response_header const *rhdr ;
   int p[2] ;
+  uint32_t rhdrn ;
   uint32_t logv ;
   uint32_t maxrqbody ;
   uint32_t maxcgibody ;
@@ -54,6 +55,7 @@ struct global_s
   .indexnames = { 0 }, \
   .rhdr = 0, \
   .p = { -1, -1 }, \
+  .rhdrn = 0, \
   .logv = TIPIDEE_LOG_DEFAULT, \
   .maxrqbody = 0, \
   .maxcgibody = 0, \
diff --git a/src/tipideed/tipideed.c b/src/tipideed/tipideed.c
index f4d18a6..cf961db 100644
--- a/src/tipideed/tipideed.c
+++ b/src/tipideed/tipideed.c
@@ -352,7 +352,7 @@ int main (int argc, char const *const *argv, char const *const *envp)
   stralloc bodysa = STRALLOC_ZERO ;
   size_t remoteip, remotehost ;
   char const *x ;
-  uint32_t n, rhlen ;
+  uint32_t n ;
   char progstr[14 + PID_FMT] = "tipideed: pid " ;
   progstr[14 + pid_fmt(progstr + 14, getpid())] = 0 ;
   PROG = progstr ;
@@ -397,11 +397,11 @@ int main (int argc, char const *const *argv, char const *const *envp)
   if (!n) strerr_dief3x(102, "bad", " config value for ", "G:index_file") ;
   g.indexn = n-1 ;
 
-  x = tipidee_conf_get_responseheaders(&g.conf, "G:response_headers", &rhlen, &n) ;
+  x = tipidee_conf_get_responseheaders(&g.conf, "G:response_headers", &n, &g.rhdrn) ;
   if (!x) strerr_diefu3sys(102, "get", " config value for ", "G:response_headers") ;
 
   tipidee_response_header rhdr[n ? n : 1] ;  /* should start a block but that's a lot of editing */
-  if (!tipidee_response_header_preparebuiltin(rhdr, n, x, rhlen))
+  if (!tipidee_response_header_preparebuiltin(rhdr, g.rhdrn, x, n))
     strerr_dief3x(102, "bad", " config value for ", "G:response_headers") ;
   g.rhdr = rhdr ;
 
diff --git a/src/tipideed/trace.c b/src/tipideed/trace.c
index 122d269..d1aed09 100644
--- a/src/tipideed/trace.c
+++ b/src/tipideed/trace.c
@@ -19,7 +19,7 @@ int respond_trace (char const *buf, tipidee_rql const *rql, tipidee_headers cons
   size_t cl = 0 ;
   char fmt[SIZE_FMT] ;
   tipidee_response_status(buffer_1, rql, 200, "OK") ;
-  tipidee_response_header_common_put_g(buffer_1, 0) ;
+  tipidee_response_header_writeall_g(buffer_1, g.rhdr, g.rhdrn, 0) ;
   buffer_putsnoflush(buffer_1, "Content-Type: message/http\r\nContent-Length: ") ;
   cl += strlen(tipidee_method_tostr(rql->m)) + 1;
   if (rql->uri.host) cl += 7 + rql->uri.https + strlen(rql->uri.host) ;