From ffd8df879dea5b306b1a1615c2eabe0d463a3a3b Mon Sep 17 00:00:00 2001 From: Laurent Bercot Date: Fri, 27 Oct 2023 14:33:26 +0000 Subject: custom-headers revamp, can be removed now Signed-off-by: Laurent Bercot --- doc/tipidee.conf.html | 26 ++++-- src/config/headers.c | 23 +++--- src/config/lexparse.c | 93 ++++++++++++++-------- .../tipidee_response_header_preparebuiltin.c | 14 ++-- src/libtipidee/tipidee_response_header_writeall.c | 1 + .../tipidee_response_header_writemerge.c | 9 +-- 6 files changed, 101 insertions(+), 65 deletions(-) diff --git a/doc/tipidee.conf.html b/doc/tipidee.conf.html index 7ead60f..685b454 100644 --- a/doc/tipidee.conf.html +++ b/doc/tipidee.conf.html @@ -448,21 +448,31 @@ serving files with uncommon extensions or have specific needs. custom-header is global directive, introduced by the keyword custom-header. It allows the user to define custom headers that are to be added to every response. +It takes a subcommand, that is used to define what should be done with +the header:

- custom-header option key value + custom-header add name value + custom-header always name value + custom-header remove name + custom-header never name

diff --git a/src/config/headers.c b/src/config/headers.c index 829b898..9ea069f 100644 --- a/src/config/headers.c +++ b/src/config/headers.c @@ -68,16 +68,19 @@ node const *headers_search (char const *key) 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 ; + char c = !s << 7 | (options & 1) ; node_start(&headers_storage, &node, key, filepos, line) ; - node_add(&headers_storage, &node, options & 1 ? "\1" : "", 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, &c, 1) ; + if (s) { - node_add(&headers_storage, &node, " ", 1) ; - node_add(&headers_storage, &node, s + word[i], strlen(s + word[i])) ; + 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) ; } - node_add(&headers_storage, &node, "", 1) ; repo_add(&headers, &node) ; } @@ -87,11 +90,11 @@ static inline void headers_defaults (void) { node node ; struct builtinheaders_s const *p = builtinheaders + i ; - if (!p->value) continue ; + char c = (!p->value << 7) | p->overridable ; if (p->overridable && headers_search(p->key)) continue ; node_start(&headers_storage, &node, p->key, 0, 0) ; - node_add(&headers_storage, &node, p->overridable ? "\1" : "", 1) ; - node_add(&headers_storage, &node, p->value, strlen(p->value) + 1) ; + node_add(&headers_storage, &node, &c, 1) ; + if (p->value) node_add(&headers_storage, &node, p->value, strlen(p->value) + 1) ; repo_add(&headers, &node) ; } } diff --git a/src/config/lexparse.c b/src/config/lexparse.c index 650e8a1..b75ccd6 100644 --- a/src/config/lexparse.c +++ b/src/config/lexparse.c @@ -27,13 +27,13 @@ struct mdt_s } ; #define MDT_ZERO { .filepos = 0, .line = 0, .linefmt = "0" } -struct logkey_s +struct namevalue_s { char const *name ; uint32_t value ; } ; -enum token_e +enum directivevalue_e { T_BANG, T_GLOBAL, @@ -54,10 +54,12 @@ enum token_e T_CUSTOMRESPONSE } ; -struct directive_s +enum customheaderoptionvalue_e { - char const *s ; - enum token_e token ; + CHO_ADD, + CHO_ALWAYS, + CHO_REMOVE, + CHO_NEVER } ; static void conftree_checkunique (char const *key, mdt const *md) @@ -134,7 +136,7 @@ static inline void parse_indexfile (char const *s, size_t const *word, size_t n, static inline void parse_log (char const *s, size_t const *word, size_t n, mdt const *md) { - static struct logkey_s const logkeys[] = + static struct namevalue_s const logkeys[] = { { .name = "answer", .value = TIPIDEE_LOG_ANSWER }, { .name = "answer_size", .value = TIPIDEE_LOG_SIZE }, @@ -155,7 +157,7 @@ static inline void parse_log (char const *s, size_t const *word, size_t n, mdt c strerr_dief8x(1, "too ", "few", " arguments to directive ", "log", " in file ", g.storage.s + md->filepos, " line ", md->linefmt) ; for (size_t i = 0 ; i < n ; i++) { - struct logkey_s const *l = BSEARCH(struct logkey_s, s + word[i], logkeys) ; + struct namevalue_s const *l = BSEARCH(struct namevalue_s, s + word[i], logkeys) ; if (!l) strerr_dief6x(1, "unrecognized log setting ", s + word[i], " in file ", g.storage.s + md->filepos, " line ", md->linefmt) ; if (l->value) v |= l->value ; else if (n == 1) v = 0 ; @@ -191,12 +193,20 @@ 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) + static struct namevalue_s const choptions[] = + { + { .name = "add", .value = CHO_ADD }, + { .name = "always", .value = CHO_ALWAYS }, + { .name = "never", .value = CHO_NEVER }, + { .name = "remove", .value = CHO_REMOVE }, + } ; + struct namevalue_s const *p ; + if (n < 2) 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) ; + p = BSEARCH(struct namevalue_s, s + *word, choptions) ; + if (!p) strerr_dief7x(1, "type should be weak or strong for", " directive ", "custom-header", " in file ", g.storage.s + md->filepos, " line ", md->linefmt) ; + if ((p->value == CHO_ADD || p->value == CHO_ALWAYS) == (n == 2)) + strerr_dief10x(1, "too ", n == 2 ? "few" : "many", " arguments to directive ", "custom-header", " ", p->name, " in file ", g.storage.s + md->filepos, " line ", md->linefmt) ; word++ ; n-- ; { size_t len = strlen(s + *word) ; @@ -206,7 +216,22 @@ static inline void parse_customheader (char const *s, size_t const *word, size_t 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) ; + switch (p->value) + { + case CHO_ADD : + headers_addv(key, 1, s, word, n, md->filepos, md->line) ; + break ; + case CHO_ALWAYS : + headers_addv(key, 0, s, word, n, md->filepos, md->line) ; + break ; + case CHO_NEVER : + headers_addv(key, 0, 0, 0, 0, md->filepos, md->line) ; + break ; + case CHO_REMOVE : + headers_addv(key, 1, 0, 0, 0, md->filepos, md->line) ; + break ; + default : strerr_dief1x(101, "can't happen: unknown value in parse_customheader") ; + } } } @@ -369,34 +394,34 @@ static inline void parse_customresponse (char const *s, size_t const *word, size static inline void process_line (char const *s, size_t const *word, size_t n, stralloc *domain, mdt *md) { - static struct directive_s const directives[] = + static struct namevalue_s const directives[] = { - { .s = "!", .token = T_BANG }, - { .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 }, - { .s = "global", .token = T_GLOBAL }, - { .s = "index-file", .token = T_INDEXFILE }, - { .s = "log", .token = T_LOG }, - { .s = "no-auth", .token = T_NOAUTH }, - { .s = "noncgi", .token = T_NONCGI }, - { .s = "nonnph", .token = T_NONNPH }, - { .s = "nph", .token = T_NPH }, - { .s = "nph-prefix", .token = T_NPHPREFIX }, - { .s = "redirect", .token = T_REDIRECT }, + { .name = "!", .value = T_BANG }, + { .name = "basic-auth", .value = T_BASICAUTH }, + { .name = "cgi", .value = T_CGI }, + { .name = "content-type", .value = T_CONTENTTYPE }, + { .name = "custom-header", .value = T_CUSTOMHEADER }, + { .name = "custom-response", .value = T_CUSTOMRESPONSE }, + { .name = "domain", .value = T_DOMAIN }, + { .name = "file-type", .value = T_FILETYPE }, + { .name = "global", .value = T_GLOBAL }, + { .name = "index-file", .value = T_INDEXFILE }, + { .name = "log", .value = T_LOG }, + { .name = "no-auth", .value = T_NOAUTH }, + { .name = "noncgi", .value = T_NONCGI }, + { .name = "nonnph", .value = T_NONNPH }, + { .name = "nph", .value = T_NPH }, + { .name = "nph-prefix", .value = T_NPHPREFIX }, + { .name = "redirect", .value = T_REDIRECT }, } ; - struct directive_s const *directive ; + struct namevalue_s const *directive ; char const *word0 ; if (!n--) return ; word0 = s + *word++ ; - directive = BSEARCH(struct directive_s, word0, directives) ; + directive = BSEARCH(struct namevalue_s, word0, directives) ; if (!directive) strerr_dief6x(1, "unrecognized word ", word0, " in file ", g.storage.s + md->filepos, " line ", md->linefmt) ; - switch (directive->token) + switch (directive->value) { case T_BANG : { diff --git a/src/libtipidee/tipidee_response_header_preparebuiltin.c b/src/libtipidee/tipidee_response_header_preparebuiltin.c index a04b666..56978c7 100644 --- a/src/libtipidee/tipidee_response_header_preparebuiltin.c +++ b/src/libtipidee/tipidee_response_header_preparebuiltin.c @@ -18,11 +18,15 @@ int tipidee_response_header_preparebuiltin (tipidee_response_header *tab, uint32 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 ; + if (tab[i].options & 0x80) tab[i].value = 0 ; + else + { + 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/libtipidee/tipidee_response_header_writeall.c b/src/libtipidee/tipidee_response_header_writeall.c index a61a80d..b94578d 100644 --- a/src/libtipidee/tipidee_response_header_writeall.c +++ b/src/libtipidee/tipidee_response_header_writeall.c @@ -11,6 +11,7 @@ size_t tipidee_response_header_writeall (buffer *b, tipidee_response_header cons if (options & 1) m += buffer_putsnoflush(b, "Connection: close\r\n") ; for (uint32_t i = 0 ; i < rhdrn ; i++) { + if (!rhdr[i].value) continue ; m += buffer_putsnoflush(b, rhdr[i].key) ; m += buffer_putnoflush(b, ": ", 2) ; m += buffer_putsnoflush(b, rhdr[i].value) ; diff --git a/src/libtipidee/tipidee_response_header_writemerge.c b/src/libtipidee/tipidee_response_header_writemerge.c index b8b1e10..d31aadc 100644 --- a/src/libtipidee/tipidee_response_header_writemerge.c +++ b/src/libtipidee/tipidee_response_header_writemerge.c @@ -16,19 +16,13 @@ static int tipidee_response_header_cmp (void const *a, void const *b) 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].value) continue ; 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) ; @@ -41,7 +35,6 @@ size_t tipidee_response_header_writemerge (buffer *b, tipidee_response_header co 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) ; -- cgit v1.2.3