From 2e0676fd6dbab9da6b838f8f803bfc5dec11b346 Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Fri, 11 Sep 2020 17:25:43 -0400 Subject: [PATCH] [core] extend (data_string *) to store header id (optional addition to (data_string *), used by http_header.[ch]) extend (data_string *) instead of creating another data_* TYPE_* (new data type would probably have (data_string *) as base class) (might revisit choice in the future) HTTP_HEADER_UNSPECIFIED has been removed. It was used in select locations as an optimization to avoid looking up enum header_header_e before checking the array, but the ordering in the array now relies on having the id. Having the id allows for a quick check if a common header is present or not in the htags bitmask, before checking the array, and allows for integer comparison in the log(n) search of the array, instead of strncasecmp(). With HTTP_HEADER_UNSPECIFIED removed, add optimization to set bit in htags for HTTP_HEADER_OTHER when an "other" header is added, but do not clear the bit, as there might be addtl "other" headers --- src/array.c | 58 ++++++++++++++++++++++++++ src/array.h | 8 +++- src/configfile-glue.c | 2 +- src/configfile.h | 1 + src/configparser.y | 5 +++ src/http_header.c | 96 ++++++++++++++++++++++++++----------------- src/http_header.h | 3 +- src/mod_accesslog.c | 7 +++- src/mod_extforward.c | 14 ++++++- src/mod_magnet.c | 4 +- src/mod_setenv.c | 47 ++++++++++----------- 11 files changed, 174 insertions(+), 71 deletions(-) diff --git a/src/array.c b/src/array.c index 38e110d4..f45fb013 100644 --- a/src/array.c +++ b/src/array.c @@ -115,6 +115,50 @@ static int array_keycmp(const char * const a, const uint32_t alen, const char * return alen < blen ? -1 : alen > blen ? 1 : array_caseless_compare(a, b, blen); } +__attribute_cold__ +__attribute_pure__ +static int array_keycmpb(const char * const k, const uint32_t klen, const buffer * const b) { + /* key is non-empty (0==b->used), though possibly blank (1==b->used) + * if inserted into key-value array */ + /*force_assert(b && b->used);*/ + return array_keycmp(k, klen, b->ptr, b->used-1); + /*return array_keycmp(k, klen, CONST_BUF_LEN(b));*/ +} + +/* returns pos into a->sorted[] which contains copy of data (ptr) in a->data[] + * if pos >= 0, or returns -pos-1 if that is the position-1 in a->sorted[] + * where the key needs to be inserted (-1 to avoid -0) + */ +__attribute_hot__ +__attribute_pure__ +static int32_t array_get_index_ext(const array * const a, const int ext, const char * const k, const uint32_t klen) { + /* invariant: [lower-1] < probe < [upper] + * invariant: 0 <= lower <= upper <= a->used + */ + uint32_t lower = 0, upper = a->used; + while (lower != upper) { + const uint32_t probe = (lower + upper) / 2; + const int x = ((data_string *)a->sorted[probe])->ext; + /* (compare strings only if ext is 0 for both)*/ + const int e = (ext|x) + ? ext + : array_keycmpb(k, klen, &a->sorted[probe]->key); + if (e < x) /* e < [probe] */ + upper = probe; /* still: lower <= upper */ + else if (e > x) /* e > [probe] */ + lower = probe + 1; /* still: lower <= upper */ + else /*(e == x)*/ /* found */ + return (int32_t)probe; + } + /* not found: [lower-1] < key < [upper] = [lower] ==> insert at [lower] */ + return -(int)lower - 1; +} + +data_unset *array_get_element_klen_ext(const array * const a, const int ext, const char *key, const uint32_t klen) { + const int32_t ipos = array_get_index_ext(a, ext, key, klen); + return ipos >= 0 ? a->sorted[ipos] : NULL; +} + /* returns pos into a->sorted[] which contains copy of data (ptr) in a->data[] * if pos >= 0, or returns -pos-1 if that is the position-1 in a->sorted[] * where the key needs to be inserted (-1 to avoid -0) @@ -209,6 +253,7 @@ static data_unset *array_get_unused_element(array * const a, const data_type_t t #endif } +__attribute_hot__ static void array_insert_data_at_pos(array * const a, data_unset * const entry, const uint32_t pos) { /* This data structure should not be used for nearly so many entries */ force_assert(a->used + 1 <= INT32_MAX); @@ -242,6 +287,7 @@ static data_integer * array_insert_integer_at_pos(array * const a, const uint32_ return di; } +__attribute_hot__ static data_string * array_insert_string_at_pos(array * const a, const uint32_t pos) { data_string *ds = (data_string *)array_get_unused_element(a, TYPE_STRING); if (NULL == ds) ds = data_string_init(); @@ -249,6 +295,18 @@ static data_string * array_insert_string_at_pos(array * const a, const uint32_t return ds; } +__attribute_hot__ +buffer * array_get_buf_ptr_ext(array * const a, const int ext, const char * const k, const uint32_t klen) { + int32_t ipos = array_get_index_ext(a, ext, k, klen); + if (ipos >= 0) return &((data_string *)a->sorted[ipos])->value; + + data_string * const ds = array_insert_string_at_pos(a, (uint32_t)(-ipos-1)); + ds->ext = ext; + buffer_copy_string_len(&ds->key, k, klen); + buffer_clear(&ds->value); + return &ds->value; +} + int * array_get_int_ptr(array * const a, const char * const k, const uint32_t klen) { int32_t ipos = array_get_index(a, k, klen); if (ipos >= 0) return &((data_integer *)a->sorted[ipos])->value; diff --git a/src/array.h b/src/array.h index 1a06b613..706ee4df 100644 --- a/src/array.h +++ b/src/array.h @@ -33,7 +33,7 @@ typedef struct { typedef struct { DATA_UNSET; - + int ext; /*(fits in space due to alignment in 64-bit; extends 32-bit)*/ buffer value; } data_string; @@ -91,6 +91,9 @@ __attribute_cold__ __attribute_pure__ int array_is_kvstring(const array *a); +__attribute_pure__ +data_unset *array_get_element_klen_ext(const array *a, int ext, const char *key, uint32_t klen); + __attribute_pure__ data_unset *array_get_element_klen(const array *a, const char *key, uint32_t klen); @@ -104,6 +107,9 @@ data_unset *array_extract_element_klen(array *a, const char *key, uint32_t klen) __attribute_returns_nonnull__ int * array_get_int_ptr(array *a, const char *k, uint32_t klen); +__attribute_returns_nonnull__ +buffer * array_get_buf_ptr_ext(array *a, int ext, const char *k, uint32_t klen); + __attribute_returns_nonnull__ buffer * array_get_buf_ptr(array *a, const char *k, uint32_t klen); diff --git a/src/configfile-glue.c b/src/configfile-glue.c index b53e8995..c8aca54b 100644 --- a/src/configfile-glue.c +++ b/src/configfile-glue.c @@ -572,7 +572,7 @@ static cond_result_t config_check_cond_nocache(request_st * const r, const data_ break; case COMP_HTTP_REQUEST_HEADER: - *((const buffer **)&l) = http_header_request_get(r, HTTP_HEADER_UNSPECIFIED, CONST_BUF_LEN(dc->comp_tag)); + *((const buffer **)&l) = http_header_request_get(r, dc->ext, CONST_BUF_LEN(dc->comp_tag)); if (NULL == l) l = (buffer *)&empty_string; break; case COMP_HTTP_REQUEST_METHOD: diff --git a/src/configfile.h b/src/configfile.h index 45fe3c7b..911ce952 100644 --- a/src/configfile.h +++ b/src/configfile.h @@ -37,6 +37,7 @@ struct data_config { void *regex; struct pcre_extra *regex_study; #endif + int ext; buffer *comp_tag; buffer *comp_key; const char *op; diff --git a/src/configparser.y b/src/configparser.y index eae39f88..a00e5554 100644 --- a/src/configparser.y +++ b/src/configparser.y @@ -8,6 +8,7 @@ #include "configfile.h" #include "buffer.h" #include "array.h" +#include "http_header.h" /* http_header_hkey_get() */ #include "request.h" /* http_request_host_normalize() */ #include @@ -693,6 +694,10 @@ context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expressio } } + if (COMP_HTTP_REQUEST_HEADER == dc->comp) { + dc->ext = http_header_hkey_get(CONST_BUF_LEN(dc->comp_tag)); + } + buffer_copy_buffer(&dc->string, rvalue); if (ctx->ok) switch(E) { diff --git a/src/http_header.c b/src/http_header.c index 5880eb09..8c321efe 100644 --- a/src/http_header.c +++ b/src/http_header.c @@ -159,23 +159,29 @@ static inline void http_header_token_append_cookie(buffer * const vb, const char } __attribute_pure__ -static inline buffer * http_header_generic_get_ifnotempty(const array * const a, const char * const k, const uint32_t klen) { +static inline buffer * http_header_generic_get_ifnotempty(const array * const a, const enum http_header_e id, const char * const k, const uint32_t klen) { data_string * const ds = - (data_string *)array_get_element_klen(a, k, klen); + (data_string *)array_get_element_klen_ext(a, id, k, klen); return ds && !buffer_string_is_empty(&ds->value) ? &ds->value : NULL; } +static inline void http_header_set_key_value(array * const a, enum http_header_e id, const char * const k, const size_t klen, const char * const v, const size_t vlen) { + buffer_copy_string_len(array_get_buf_ptr_ext(a, id, k, klen), v, vlen); +} + buffer * http_header_response_get(const request_st * const r, enum http_header_e id, const char *k, uint32_t klen) { - return (id <= HTTP_HEADER_OTHER || light_btst(r->resp_htags, id)) - ? http_header_generic_get_ifnotempty(&r->resp_headers, k, klen) + return light_btst(r->resp_htags, id) + ? http_header_generic_get_ifnotempty(&r->resp_headers, id, k, klen) : NULL; } void http_header_response_unset(request_st * const r, enum http_header_e id, const char *k, uint32_t klen) { - if (id <= HTTP_HEADER_OTHER || light_btst(r->resp_htags, id)) { + if (light_btst(r->resp_htags, id)) { + /* (do not clear bit for HTTP_HEADER_OTHER, + * as there might be addtl "other" headers) */ if (id > HTTP_HEADER_OTHER) light_bclr(r->resp_htags, id); - array_set_key_value(&r->resp_headers, k, klen, CONST_STR_LEN("")); + http_header_set_key_value(&r->resp_headers,id,k,klen,CONST_STR_LEN("")); } } @@ -183,50 +189,59 @@ void http_header_response_set(request_st * const r, enum http_header_e id, const /* set value, including setting blank value if 0 == vlen * (note: if 0 == vlen, header is still inserted with blank value, * which is used to indicate a "removed" header) - */ - if (id > HTTP_HEADER_OTHER) - (vlen) ? light_bset(r->resp_htags, id) : light_bclr(r->resp_htags, id); - array_set_key_value(&r->resp_headers, k, klen, v, vlen); + * (do not clear bit for HTTP_HEADER_OTHER if 0 == vlen, + * as there might be addtl "other" headers) */ + (vlen) + ? light_bset(r->resp_htags, id) + : (id > HTTP_HEADER_OTHER ? light_bclr(r->resp_htags, id) : 0); + http_header_set_key_value(&r->resp_headers, id, k, klen, v, vlen); } void http_header_response_append(request_st * const r, enum http_header_e id, const char *k, uint32_t klen, const char *v, uint32_t vlen) { if (0 == vlen) return; - if (id > HTTP_HEADER_OTHER) light_bset(r->resp_htags, id); - buffer * const vb = array_get_buf_ptr(&r->resp_headers, k, klen); + light_bset(r->resp_htags, id); + buffer * const vb = array_get_buf_ptr_ext(&r->resp_headers, id, k, klen); http_header_token_append(vb, v, vlen); } +__attribute_cold__ +static void http_header_response_insert_addtl(request_st * const r, enum http_header_e id, const char *k, uint32_t klen, buffer * const vb, uint32_t vlen) { + UNUSED(id); + buffer_append_string_len(vb, CONST_STR_LEN("\r\n")); + if (r->http_version >= HTTP_VERSION_2) { + r->resp_header_repeated = 1; + char * const h = buffer_string_prepare_append(vb, klen + vlen + 2); + for (uint32_t i = 0; i < klen; ++i) + h[i] = !light_isupper(k[i]) ? k[i] : (k[i] | 0x20); + buffer_commit(vb, klen); + } + else + buffer_append_string_len(vb, k, klen); + buffer_append_string_len(vb, CONST_STR_LEN(": ")); +} + void http_header_response_insert(request_st * const r, enum http_header_e id, const char *k, uint32_t klen, const char *v, uint32_t vlen) { if (0 == vlen) return; - if (id > HTTP_HEADER_OTHER) light_bset(r->resp_htags, id); - buffer * const vb = array_get_buf_ptr(&r->resp_headers, k, klen); - if (!buffer_string_is_empty(vb)) { /* append value */ - buffer_append_string_len(vb, CONST_STR_LEN("\r\n")); - if (r->http_version >= HTTP_VERSION_2) { - r->resp_header_repeated = 1; - char * const h = buffer_string_prepare_append(vb, klen + vlen + 2); - for (uint32_t i = 0; i < klen; ++i) - h[i] = !light_isupper(k[i]) ? k[i] : (k[i] | 0x20); - buffer_commit(vb, klen); - } - else - buffer_append_string_len(vb, k, klen); - buffer_append_string_len(vb, CONST_STR_LEN(": ")); - } + light_bset(r->resp_htags, id); + buffer * const vb = array_get_buf_ptr_ext(&r->resp_headers, id, k, klen); + if (!buffer_string_is_empty(vb)) /*append repeated field-name on new line*/ + http_header_response_insert_addtl(r, id, k, klen, vb, vlen); buffer_append_string_len(vb, v, vlen); } buffer * http_header_request_get(const request_st * const r, enum http_header_e id, const char *k, uint32_t klen) { - return (id <= HTTP_HEADER_OTHER || light_btst(r->rqst_htags, id)) - ? http_header_generic_get_ifnotempty(&r->rqst_headers, k, klen) + return light_btst(r->rqst_htags, id) + ? http_header_generic_get_ifnotempty(&r->rqst_headers, id, k, klen) : NULL; } void http_header_request_unset(request_st * const r, enum http_header_e id, const char *k, uint32_t klen) { - if (id <= HTTP_HEADER_OTHER || light_btst(r->rqst_htags, id)) { + if (light_btst(r->rqst_htags, id)) { + /* (do not clear bit for HTTP_HEADER_OTHER, + * as there might be addtl "other" headers) */ if (id > HTTP_HEADER_OTHER) light_bclr(r->rqst_htags, id); - array_set_key_value(&r->rqst_headers, k, klen, CONST_STR_LEN("")); + http_header_set_key_value(&r->rqst_headers,id,k,klen,CONST_STR_LEN("")); } } @@ -234,16 +249,18 @@ void http_header_request_set(request_st * const r, enum http_header_e id, const /* set value, including setting blank value if 0 == vlen * (note: if 0 == vlen, header is still inserted with blank value, * which is used to indicate a "removed" header) - */ - if (id > HTTP_HEADER_OTHER) - (vlen) ? light_bset(r->rqst_htags, id) : light_bclr(r->rqst_htags, id); - array_set_key_value(&r->rqst_headers, k, klen, v, vlen); + * (do not clear bit for HTTP_HEADER_OTHER if 0 == vlen, + * as there might be addtl "other" headers) */ + (vlen) + ? light_bset(r->rqst_htags, id) + : (id > HTTP_HEADER_OTHER ? light_bclr(r->rqst_htags, id) : 0); + http_header_set_key_value(&r->rqst_headers, id, k, klen, v, vlen); } void http_header_request_append(request_st * const r, enum http_header_e id, const char *k, uint32_t klen, const char *v, uint32_t vlen) { if (0 == vlen) return; - if (id > HTTP_HEADER_OTHER) light_bset(r->rqst_htags, id); - buffer * const vb = array_get_buf_ptr(&r->rqst_headers, k, klen); + light_bset(r->rqst_htags, id); + buffer * const vb = array_get_buf_ptr_ext(&r->rqst_headers, id, k, klen); if (id != HTTP_HEADER_COOKIE) http_header_token_append(vb, v, vlen); else @@ -252,7 +269,10 @@ void http_header_request_append(request_st * const r, enum http_header_e id, con buffer * http_header_env_get(const request_st * const r, const char *k, uint32_t klen) { - return http_header_generic_get_ifnotempty(&r->env, k, klen); + /* similar to http_header_generic_get_ifnotempty() but without id */ + data_string * const ds = + (data_string *)array_get_element_klen(&r->env, k, klen); + return ds && !buffer_string_is_empty(&ds->value) ? &ds->value : NULL; } void http_header_env_set(request_st * const r, const char *k, uint32_t klen, const char *v, uint32_t vlen) { diff --git a/src/http_header.h b/src/http_header.h index 17f6be89..a9bff769 100644 --- a/src/http_header.h +++ b/src/http_header.h @@ -8,8 +8,7 @@ /* Note: must be kept in sync with http_header.c http_headers[] */ /* Note: when adding new items, must replace OTHER in existing code for item */ enum http_header_e { - HTTP_HEADER_UNSPECIFIED = -1 - ,HTTP_HEADER_OTHER = 0 + HTTP_HEADER_OTHER = 0 ,HTTP_HEADER_ACCEPT_ENCODING ,HTTP_HEADER_AUTHORIZATION ,HTTP_HEADER_CACHE_CONTROL diff --git a/src/mod_accesslog.c b/src/mod_accesslog.c index b4fc21b7..6f744cdd 100644 --- a/src/mod_accesslog.c +++ b/src/mod_accesslog.c @@ -722,6 +722,9 @@ static format_fields * mod_accesslog_process_format(const char * const format, c mod_accesslog_free_format_fields(parsed_format); return NULL; } + } else if (FORMAT_HEADER == f->field + || FORMAT_RESPONSE_HEADER == f->field) { + f->opt = http_header_hkey_get(CONST_BUF_LEN(fstr)); } } @@ -994,14 +997,14 @@ static int log_access_record (const request_st * const r, buffer * const b, form break; } case FORMAT_HEADER: - if (NULL != (vb = http_header_request_get(r, HTTP_HEADER_UNSPECIFIED, CONST_BUF_LEN(&f->string)))) { + if (NULL != (vb = http_header_request_get(r, f->opt, CONST_BUF_LEN(&f->string)))) { accesslog_append_escaped(b, vb); } else { buffer_append_string_len(b, CONST_STR_LEN("-")); } break; case FORMAT_RESPONSE_HEADER: - if (NULL != (vb = http_header_response_get(r, HTTP_HEADER_UNSPECIFIED, CONST_BUF_LEN(&f->string)))) { + if (NULL != (vb = http_header_response_get(r, f->opt, CONST_BUF_LEN(&f->string)))) { accesslog_append_escaped(b, vb); } else { buffer_append_string_len(b, CONST_STR_LEN("-")); diff --git a/src/mod_extforward.c b/src/mod_extforward.c index 00d19c4d..1a6829c2 100644 --- a/src/mod_extforward.c +++ b/src/mod_extforward.c @@ -375,6 +375,15 @@ SETDEFAULTS_FUNC(mod_extforward_set_defaults) { cpv->vtype = T_CONFIG_LOCAL; break; case 1: /* extforward.headers */ + if (cpv->v.a->used) { + array *a; + *(const array **)&a = cpv->v.a; + for (uint32_t j = 0; j < a->used; ++j) { + data_string * const ds = (data_string *)a->data[j]; + ds->ext = + http_header_hkey_get(CONST_BUF_LEN(&ds->value)); + } + } break; case 2: /* extforward.params */ cpv->v.u = mod_extforward_parse_opts(srv, cpv->v.a); @@ -1105,8 +1114,9 @@ URIHANDLER_FUNC(mod_extforward_uri_handler) { return HANDLER_GO_ON; for (uint32_t k = 0; k < p->conf.headers->used; ++k) { - buffer *hdr = &((data_string *)p->conf.headers->data[k])->value; - forwarded = http_header_request_get(r, HTTP_HEADER_UNSPECIFIED, CONST_BUF_LEN(hdr)); + const data_string * const ds = (data_string *)p->conf.headers->data[k]; + const buffer * const hdr = &ds->value; + forwarded = http_header_request_get(r, ds->ext, CONST_BUF_LEN(hdr)); if (forwarded) { is_forwarded_header = buffer_is_equal_caseless_string(hdr, CONST_STR_LEN("Forwarded")); break; diff --git a/src/mod_magnet.c b/src/mod_magnet.c index 05a6a0c0..f5aa758b 100644 --- a/src/mod_magnet.c +++ b/src/mod_magnet.c @@ -368,8 +368,8 @@ static int magnet_reqhdr_get(lua_State *L) { size_t klen; const char * const k = luaL_checklstring(L, 2, &klen); request_st * const r = magnet_get_request(L); - const buffer * const vb = - http_header_request_get(r, HTTP_HEADER_UNSPECIFIED, k, klen); + const int id = http_header_hkey_get(k, (uint32_t)klen); + const buffer * const vb = http_header_request_get(r, id, k, klen); magnet_push_buffer(L, NULL != vb ? vb : NULL); return 1; } diff --git a/src/mod_setenv.c b/src/mod_setenv.c index cd47821e..bb8b2c4e 100644 --- a/src/mod_setenv.c +++ b/src/mod_setenv.c @@ -84,6 +84,15 @@ static void mod_setenv_patch_config(request_st * const r, plugin_data * const p, } } +static void mod_setenv_prep_ext (const array * const ac) { + array *a; + *(const array **)&a = ac; + for (uint32_t i = 0; i < a->used; ++i) { + data_string * const ds = (data_string *)a->data[i]; + ds->ext = http_header_hkey_get(CONST_BUF_LEN(&ds->key)); + } +} + SETDEFAULTS_FUNC(mod_setenv_set_defaults) { static const config_plugin_keys_t cpk[] = { { CONST_STR_LEN("setenv.add-request-header"), @@ -113,11 +122,6 @@ SETDEFAULTS_FUNC(mod_setenv_set_defaults) { if (!config_plugin_values_init(srv, p, cpk, "mod_setenv")) return HANDLER_ERROR; - /* future: might create custom data structures here - * then look up and store http_header_e at config time - * enum http_header_e id = http_header_hkey_get(CONST_BUF_LEN(&ds->key)); - */ - /* process and validate config directives * (init i to 0 if global context; to 1 to skip empty global context) */ for (int i = !p->cvlist[0].v.u2[1]; i < p->nconfig; ++i) { @@ -126,9 +130,14 @@ SETDEFAULTS_FUNC(mod_setenv_set_defaults) { switch (cpv->k_id) { case 0: /* setenv.add-request-header */ case 1: /* setenv.add-response-header */ + mod_setenv_prep_ext(cpv->v.a); + break; case 2: /* setenv.add-environment */ + break; case 3: /* setenv.set-request-header */ case 4: /* setenv.set-response-header */ + mod_setenv_prep_ext(cpv->v.a); + break; case 5: /* setenv.set-environment */ break; default:/* should not happen */ @@ -164,22 +173,18 @@ URIHANDLER_FUNC(mod_setenv_uri_handler) { if (aa) { for (uint32_t k = 0; k < aa->used; ++k) { const data_string * const ds = (const data_string *)aa->data[k]; - const enum http_header_e id = - http_header_hkey_get(CONST_BUF_LEN(&ds->key)); - http_header_request_append(r, id, CONST_BUF_LEN(&ds->key), - CONST_BUF_LEN(&ds->value)); + http_header_request_append(r, ds->ext, CONST_BUF_LEN(&ds->key), + CONST_BUF_LEN(&ds->value)); } } if (as) { for (uint32_t k = 0; k < as->used; ++k) { const data_string * const ds = (const data_string *)as->data[k]; - const enum http_header_e id = - http_header_hkey_get(CONST_BUF_LEN(&ds->key)); !buffer_string_is_empty(&ds->value) - ? http_header_request_set(r, id, CONST_BUF_LEN(&ds->key), - CONST_BUF_LEN(&ds->value)) - : http_header_request_unset(r, id, CONST_BUF_LEN(&ds->key)); + ? http_header_request_set(r, ds->ext, CONST_BUF_LEN(&ds->key), + CONST_BUF_LEN(&ds->value)) + : http_header_request_unset(r, ds->ext, CONST_BUF_LEN(&ds->key)); } } @@ -226,22 +231,18 @@ REQUEST_FUNC(mod_setenv_handle_response_start) { if (aa) { for (uint32_t k = 0; k < aa->used; ++k) { const data_string * const ds = (const data_string *)aa->data[k]; - const enum http_header_e id = - http_header_hkey_get(CONST_BUF_LEN(&ds->key)); - http_header_response_insert(r, id, CONST_BUF_LEN(&ds->key), - CONST_BUF_LEN(&ds->value)); + http_header_response_insert(r, ds->ext, CONST_BUF_LEN(&ds->key), + CONST_BUF_LEN(&ds->value)); } } if (as) { for (uint32_t k = 0; k < as->used; ++k) { const data_string * const ds = (const data_string *)as->data[k]; - const enum http_header_e id = - http_header_hkey_get(CONST_BUF_LEN(&ds->key)); !buffer_string_is_empty(&ds->value) - ? http_header_response_set(r, id, CONST_BUF_LEN(&ds->key), - CONST_BUF_LEN(&ds->value)) - : http_header_response_unset(r, id, CONST_BUF_LEN(&ds->key)); + ? http_header_response_set(r, ds->ext, CONST_BUF_LEN(&ds->key), + CONST_BUF_LEN(&ds->value)) + : http_header_response_unset(r, ds->ext, CONST_BUF_LEN(&ds->key)); } }