about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2023-10-24 09:59:08 +0000
committerLaurent Bercot <ska@appnovation.com>2023-10-24 09:59:08 +0000
commit37d2f8cb438f68eaa1da8a56ea9ce5023091f128 (patch)
tree81672ad4254ea18e7d240230ba47ef6743d491ad /src
parent907f1c64369095b5b2d5f6fb23a8b937720d94cc (diff)
downloadtipidee-37d2f8cb438f68eaa1da8a56ea9ce5023091f128.tar.gz
tipidee-37d2f8cb438f68eaa1da8a56ea9ce5023091f128.tar.xz
tipidee-37d2f8cb438f68eaa1da8a56ea9ce5023091f128.zip
Full custom header support, switch not made yet
Signed-off-by: Laurent Bercot <ska@appnovation.com>
Diffstat (limited to 'src')
-rw-r--r--src/config/headers.c30
-rw-r--r--src/config/lexparse.c27
-rw-r--r--src/config/tipidee-config-internal.h4
-rw-r--r--src/include/tipidee/conf.h4
-rw-r--r--src/include/tipidee/response.h10
-rw-r--r--src/libtipidee/deps-lib/tipidee2
-rw-r--r--src/libtipidee/tipidee_conf_get_argv.c7
-rw-r--r--src/libtipidee/tipidee_conf_get_responseheaders.c22
-rw-r--r--src/libtipidee/tipidee_response_header_preparebuiltin.c28
-rw-r--r--src/tipideed/tipideed-internal.h2
-rw-r--r--src/tipideed/tipideed.c60
11 files changed, 157 insertions, 39 deletions
diff --git a/src/config/headers.c b/src/config/headers.c
index b080390..351b938 100644
--- a/src/config/headers.c
+++ b/src/config/headers.c
@@ -1,8 +1,10 @@
 /* ISC license. */
 
+#include <stdint.h>
 #include <string.h>
 #include <ctype.h>
 
+#include <skalibs/uint32.h>
 #include <skalibs/strerr.h>
 #include <skalibs/genalloc.h>
 #include <skalibs/avltree.h>
@@ -47,7 +49,7 @@ int header_allowed (char const *key)
   return !p || p->overridable ;
 }
 
-void header_canonize (char *key)
+void header_canonicalize (char *key)
 {
   int h = 1 ;
   size_t len = strlen(key) ;
@@ -63,17 +65,25 @@ node const *headers_search (char const *key)
   return repo_search(&headers, key) ;
 }
 
-void headers_add (char const *key, char const *value, uint8_t options, size_t filepos, uint32_t line)
+void headers_addv (char const *key, uint8_t options, char const *s, size_t const *word, size_t n, size_t filepos, uint32_t line)
 {
   node node ;
+  if (!n) return ;
   node_start(&headers_storage, &node, key, filepos, line) ;
   node_add(&headers_storage, &node, options & 1 ? "\1" : "", 1) ;
-  node_add(&headers_storage, &node, value, strlen(value) + 1) ;
+  node_add(&headers_storage, &node, s + word[0], strlen(s + word[0])) ;
+  for (size_t i = 1 ; i < n ; i++)
+  {
+    node_add(&headers_storage, &node, " ", 1) ;
+    node_add(&headers_storage, &node, s + word[i], strlen(s + word[i])) ;
+  }
+  node_add(&headers_storage, &node, "", 1) ;
   repo_add(&headers, &node) ;
 }
 
-static void headers_defaults (node *node)
+static uint32_t headers_defaults (node *node)
 {
+  uint32_t n = 0 ;
   for (size_t i = 0 ; i < sizeof(builtinheaders) / sizeof(struct builtinheaders_s) ; i++)
   {
     struct builtinheaders_s const *p = builtinheaders + i ;
@@ -82,7 +92,9 @@ static void headers_defaults (node *node)
     confnode_add(node, p->key, strlen(p->key) + 1) ;
     confnode_add(node, p->overridable ? "\1" : "", 1) ;
     confnode_add(node, p->value, strlen(p->value) + 1) ;
+    n++ ;
   }
+  return n ;
 }
 
 static int header_write (uint32_t d, unsigned int h, void *data)
@@ -91,16 +103,20 @@ static int header_write (uint32_t d, unsigned int h, void *data)
   node *const header = genalloc_s(node, &headers.ga) + d ;
   (void)h ;
   confnode_add(confnode, headers_storage.s + header->key, header->keylen + 1) ;
-  confnode_add(confnode, headers_storage.s + header->data, header->datalen + 1) ;
+  confnode_add(confnode, headers_storage.s + header->data, header->datalen) ;
   return 1 ;
 }
 
 void headers_finish (void)
 {
+  uint32_t n ;
+  char pack[4] ;
   node node ;
-  confnode_start(&node, "G:response-headers", 0, 0) ;
-  headers_defaults(&node) ;
+  confnode_start(&node, "G:response_headers", 0, 0) ;
+  n = avltree_len(&headers.tree) + headers_defaults(&node) ;
   (void)avltree_iter(&headers.tree, &header_write, &node) ;
+  uint32_pack_big(pack, n) ;
+  confnode_add(&node, pack, 4) ;
   conftree_add(&node) ;
   avltree_free(&headers.tree) ;
   genalloc_free(node, &headers.ga) ;
diff --git a/src/config/lexparse.c b/src/config/lexparse.c
index 27a62df..783e39f 100644
--- a/src/config/lexparse.c
+++ b/src/config/lexparse.c
@@ -45,6 +45,7 @@ enum token_e
   T_GLOBAL,
   T_LOG,
   T_CONTENTTYPE,
+  T_CUSTOMHEADER,
   T_DOMAIN,
   T_NPHPREFIX,
   T_REDIRECT,
@@ -195,6 +196,27 @@ static inline void parse_contenttype (char const *s, size_t const *word, size_t
   }
 }
 
+static inline void parse_customheader (char const *s, size_t const *word, size_t n, mdt const *md)
+{
+  uint8_t options = 0 ;
+  if (n < 3)
+    strerr_dief8x(1, "too ", "few", " arguments to directive ", "custom-header", " in file ", g.storage.s + md->filepos, " line ", md->linefmt) ;
+  if (!strcmp(s + word[0], "weak")) options |= 1 ;
+  else if (!strcmp(s + word[0], "strong")) options &= ~1 ;
+  else strerr_dief7x(1, "type should be weak or strong for", " directive ", "custom-header", " in file ", g.storage.s + md->filepos, " line ", md->linefmt) ;
+  word++ ; n-- ;
+  {
+    size_t len = strlen(s + *word) ;
+    char key[len + 1] ;
+    memcpy(key, s + *word++, len + 1) ; n-- ;
+    header_canonicalize(key) ;
+    if (!header_allowed(key))
+      strerr_dief7x(1, "header ", key, " cannot be customized", " in file ", g.storage.s + md->filepos, " line ", md->linefmt) ;
+    headers_checkunique(key, md) ;
+    headers_addv(key, options, s, word, n, md->filepos, md->line) ;
+  }
+}
+
 static inline void parse_redirect (char const *s, size_t const *word, size_t n, char const *domain, size_t domainlen, mdt const *md)
 {
   static uint32_t const codes[4] = { 307, 308, 302, 301 } ;
@@ -360,6 +382,7 @@ static inline void process_line (char const *s, size_t const *word, size_t n, st
     { .s = "basic-auth", .token = T_BASICAUTH },
     { .s = "cgi", .token = T_CGI },
     { .s = "content-type", .token = T_CONTENTTYPE },
+    { .s = "custom-header", .token = T_CUSTOMHEADER },
     { .s = "custom-response", .token = T_CUSTOMRESPONSE },
     { .s = "domain", .token = T_DOMAIN },
     { .s = "file-type", .token = T_FILETYPE },
@@ -404,6 +427,9 @@ static inline void process_line (char const *s, size_t const *word, size_t n, st
     case T_CONTENTTYPE :
       parse_contenttype(s, word, n, md) ;
       break ;
+    case T_CUSTOMHEADER :
+      parse_customheader(s, word, n, md) ;
+      break ;
     case T_DOMAIN :
       if (n != 1)
         strerr_dief8x(1, "too ", n > 1 ? "many" : "few", " arguments to directive ", "domain", " in file ", g.storage.s + md->filepos, " line ", md->linefmt) ;
@@ -518,4 +544,5 @@ void conf_lexparse (buffer *b, char const *ifile)
   stralloc_free(&domain) ;
   genalloc_free(size_t, &words) ;
   stralloc_free(&sa) ;
+  headers_finish() ;
 }
diff --git a/src/config/tipidee-config-internal.h b/src/config/tipidee-config-internal.h
index 3508771..d3977c0 100644
--- a/src/config/tipidee-config-internal.h
+++ b/src/config/tipidee-config-internal.h
@@ -81,11 +81,11 @@ extern int conftree_write (cdbmaker *) ;
 
  /* headers */
 
-extern void header_canonize (char *) ;
+extern void header_canonicalize (char *) ;
 extern int header_allowed (char const *) ;
 
 extern node const *headers_search (char const *) ;
-extern void headers_add (char const *, char const *, uint8_t, size_t, uint32_t) ;
+extern void headers_addv (char const *, uint8_t, char const *, size_t const *, size_t, size_t, uint32_t) ;
 extern void headers_finish (void) ;
 
 
diff --git a/src/include/tipidee/conf.h b/src/include/tipidee/conf.h
index d0b8fb0..5f3b697 100644
--- a/src/include/tipidee/conf.h
+++ b/src/include/tipidee/conf.h
@@ -35,7 +35,9 @@ extern int tipidee_conf_init (tipidee_conf *, char const *) ;
 extern int tipidee_conf_get (tipidee_conf const *, char const *, cdb_data *) ;
 extern char const *tipidee_conf_get_string (tipidee_conf const *, char const *) ;
 extern int tipidee_conf_get_uint32 (tipidee_conf const *, char const *, uint32_t *) ;
-extern unsigned int tipidee_conf_get_argv (tipidee_conf const *, char const *, char const **, unsigned int, size_t *) ;
+extern uint32_t tipidee_conf_get_argv (tipidee_conf const *, char const *, char const **, uint32_t, size_t *) ;
+
+extern char const *tipidee_conf_get_responseheaders (tipidee_conf const *, char const *, uint32_t *, uint32_t *) ;
 
 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 *) ;
diff --git a/src/include/tipidee/response.h b/src/include/tipidee/response.h
index 3850970..bc83fc6 100644
--- a/src/include/tipidee/response.h
+++ b/src/include/tipidee/response.h
@@ -16,6 +16,14 @@
 
 #include <tipidee/rql.h>
 
+typedef struct tipidee_response_header_s tipidee_response_header, *tipidee_response_header_ref ;
+struct tipidee_response_header_s
+{
+  char const *key ;
+  char const *value ;
+  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
 {
@@ -42,4 +50,6 @@ extern size_t tipidee_response_error_nofile (buffer *, tipidee_rql const *, unsi
 extern tipidee_response_header_builtin const *tipidee_response_header_builtin_table ;
 extern char const *tipidee_response_header_builtin_search (char const *) ;
 
+extern int tipidee_response_header_preparebuiltin (tipidee_response_header *, uint32_t, char const *, size_t) ;
+
 #endif
diff --git a/src/libtipidee/deps-lib/tipidee b/src/libtipidee/deps-lib/tipidee
index 93e261a..d406e5c 100644
--- a/src/libtipidee/deps-lib/tipidee
+++ b/src/libtipidee/deps-lib/tipidee
@@ -4,6 +4,7 @@ tipidee_conf_get_argv.o
 tipidee_conf_get_content_type.o
 tipidee_conf_get_errorfile.o
 tipidee_conf_get_redirection.o
+tipidee_conf_get_responseheaders.o
 tipidee_conf_get_string.o
 tipidee_conf_get_uint32.o
 tipidee_conf_init.o
@@ -24,6 +25,7 @@ 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_status.o
 tipidee_rql_read.o
 tipidee_uri_parse.o
diff --git a/src/libtipidee/tipidee_conf_get_argv.c b/src/libtipidee/tipidee_conf_get_argv.c
index 0dd016e..79c24e6 100644
--- a/src/libtipidee/tipidee_conf_get_argv.c
+++ b/src/libtipidee/tipidee_conf_get_argv.c
@@ -1,6 +1,7 @@
 /* ISC license. */
 
 #include <errno.h>
+#include <stdint.h>
 #include <string.h>
 
 #include <skalibs/cdb.h>
@@ -9,11 +10,11 @@
 
 #include <skalibs/posixishard.h>
 
-unsigned int tipidee_conf_get_argv (tipidee_conf const *conf, char const *key, char const **argv, unsigned int max, size_t *maxlen)
+uint32_t tipidee_conf_get_argv (tipidee_conf const *conf, char const *key, char const **argv, uint32_t max, size_t *maxlen)
 {
   cdb_data data ;
-  size_t curlen = 0 ;
-  unsigned int n = 0, pos = 0 ;
+  size_t curlen = 0, pos = 0 ;
+  uint32_t n = 0 ;
   if (!tipidee_conf_get(conf, key, &data)) return 0 ;
   if (data.s[data.len-1]) return (errno = EPROTO, 0) ;
   while (pos < data.len)
diff --git a/src/libtipidee/tipidee_conf_get_responseheaders.c b/src/libtipidee/tipidee_conf_get_responseheaders.c
new file mode 100644
index 0000000..ee8c786
--- /dev/null
+++ b/src/libtipidee/tipidee_conf_get_responseheaders.c
@@ -0,0 +1,22 @@
+/* ISC license. */
+
+#include <stddef.h>
+#include <errno.h>
+#include <string.h>
+
+#include <skalibs/uint32.h>
+#include <skalibs/cdb.h>
+
+#include <tipidee/conf.h>
+
+#include <skalibs/posixishard.h>
+
+char const *tipidee_conf_get_responseheaders (tipidee_conf const *conf, char const *key, uint32_t *len, uint32_t *n)
+{
+  cdb_data data ;
+  if (!tipidee_conf_get(conf, key, &data)) return NULL ;
+  if (data.len < 4) return (errno = EPROTO, NULL) ;
+  uint32_unpack_big(data.s + data.len - 4, n) ;
+  *len = data.len - 4 ;
+  return data.s ;
+}
diff --git a/src/libtipidee/tipidee_response_header_preparebuiltin.c b/src/libtipidee/tipidee_response_header_preparebuiltin.c
new file mode 100644
index 0000000..a04b666
--- /dev/null
+++ b/src/libtipidee/tipidee_response_header_preparebuiltin.c
@@ -0,0 +1,28 @@
+/* ISC license. */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <tipidee/response.h>
+
+int tipidee_response_header_preparebuiltin (tipidee_response_header *tab, uint32_t n, char const *s, size_t len)
+{
+  size_t pos = 0 ;
+  for (uint32_t i = 0 ; i < n ; i++)
+  {
+    char const *next ;
+    tab[i].key = s + pos ;
+    next = memchr(s + pos, 0, len - pos) ;
+    if (!next) return 0 ;
+    pos = next - s ;
+    if (pos++ >= len) return 0 ;
+    tab[i].options = (uint8_t)s[pos] ;
+    if (pos++ >= len) return 0 ;
+    tab[i].value = s + pos ;
+    next = memchr(s + pos, 0, len - pos) ;
+    if (!next) return 0 ;
+    pos = next - s ;
+    if (pos++ >= len) return 0 ;
+  }
+  return pos == len ;
+}
diff --git a/src/tipideed/tipideed-internal.h b/src/tipideed/tipideed-internal.h
index a4f6d95..3629f84 100644
--- a/src/tipideed/tipideed-internal.h
+++ b/src/tipideed/tipideed-internal.h
@@ -30,6 +30,7 @@ struct global_s
   tain cgitto ;
   char const *defaulthost ;
   char const *indexnames[16] ;
+  tipidee_response_header const *rhdr ;
   int p[2] ;
   uint32_t logv ;
   uint32_t maxrqbody ;
@@ -51,6 +52,7 @@ struct global_s
   .cgitto = TAIN_ZERO, \
   .defaulthost = "@", \
   .indexnames = { 0 }, \
+  .rhdr = 0, \
   .p = { -1, -1 }, \
   .logv = TIPIDEE_LOG_DEFAULT, \
   .maxrqbody = 0, \
diff --git a/src/tipideed/tipideed.c b/src/tipideed/tipideed.c
index b499b2a..f4d18a6 100644
--- a/src/tipideed/tipideed.c
+++ b/src/tipideed/tipideed.c
@@ -350,6 +350,9 @@ static inline int serve (tipidee_rql *rql, char const *docroot, char *uribuf, ti
 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 ;
   char progstr[14 + PID_FMT] = "tipideed: pid " ;
   progstr[14 + pid_fmt(progstr + 14, getpid())] = 0 ;
   PROG = progstr ;
@@ -383,31 +386,37 @@ int main (int argc, char const *const *argv, char const *const *envp)
     tipideed_harden(h) ;
   }
 
-  {
-    size_t remoteip, remotehost ;
-    unsigned int n ;
-    prep_env(&remoteip, &remotehost) ;
-    inittto(&g.readtto, "G:read_timeout") ;
-    inittto(&g.writetto, "G:write_timeout") ;
-    inittto(&g.cgitto, "G:cgi_timeout") ;
-    g.maxrqbody = get_uint32("G:max_request_body_length") ;
-    g.maxcgibody = get_uint32("G:max_cgi_body_length") ;
-    g.logv = get_uint32("G:logv") ;
-    n = tipidee_conf_get_argv(&g.conf, "G:index_file", g.indexnames, 16, &g.indexlen) ;
-    if (!n) strerr_dief3x(102, "bad", " config value for ", "G:index_file") ;
-    g.indexn = n-1 ;
-
-    if (ndelay_on(0) == -1 || ndelay_on(1) == -1)
-      strerr_diefu1sys(111, "set I/O nonblocking") ;
-    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) ;
-  }
+  prep_env(&remoteip, &remotehost) ;
+  inittto(&g.readtto, "G:read_timeout") ;
+  inittto(&g.writetto, "G:write_timeout") ;
+  inittto(&g.cgitto, "G:cgi_timeout") ;
+  g.maxrqbody = get_uint32("G:max_request_body_length") ;
+  g.maxcgibody = get_uint32("G:max_cgi_body_length") ;
+  g.logv = get_uint32("G:logv") ;
+  n = tipidee_conf_get_argv(&g.conf, "G:index_file", g.indexnames, 16, &g.indexlen) ;
+  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) ;
+  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))
+    strerr_dief3x(102, "bad", " config value for ", "G:response_headers") ;
+  g.rhdr = rhdr ;
+
+  if (ndelay_on(0) == -1 || ndelay_on(1) == -1)
+    strerr_diefu1sys(111, "set I/O nonblocking") ;
+  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) ;
 
 
  /* Main loop */
@@ -419,7 +428,6 @@ int main (int argc, char const *const *argv, char const *const *envp)
     tipidee_headers hdr ;
     int e ;
     unsigned int localredirs = 0 ;
-    char const *x ;
     size_t content_length ;
     tipidee_transfercoding tcoding = TIPIDEE_TRANSFERCODING_UNKNOWN ;
     char uribuf[URI_BUFSIZE] ;