# UNDF: UNDF-2026-000000185 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -2871,38 +2871,50 @@ ngx_http_link_multi_headers(ngx_http_request_t *r) { - ngx_uint_t i, j; - ngx_list_part_t *part, *ppart; - ngx_table_elt_t *header, *pheader, **ph; + ngx_uint_t i; + ngx_list_part_t *part; + ngx_table_elt_t *header, **ph; + ngx_hash_t name_map; + ngx_hash_init_t hash; + ngx_hash_key_t *keys; + ngx_uint_t nkeys; if (r->headers_in.multi_linked) { return NGX_OK; } r->headers_in.multi_linked = 1; part = &r->headers_in.headers.part; header = part->elts; - for (i = 0; /* void */; i++) { - - if (i >= part->nelts) { - if (part->next == NULL) { - break; - } - - part = part->next; - header = part->elts; - i = 0; - } - - header[i].next = NULL; - - ppart = &r->headers_in.headers.part; - pheader = ppart->elts; - - for (j = 0; /* void */; j++) { - - if (j >= ppart->nelts) { - if (ppart->next == NULL) { - break; - } - - ppart = ppart->next; - pheader = ppart->elts; - j = 0; - } - - if (part == ppart && i == j) { - break; - } - - if (header[i].key.len == pheader[j].key.len - && ngx_strncasecmp(header[i].key.data, pheader[j].key.data, - header[i].key.len) - == 0) - { - ph = &pheader[j].next; - while (*ph) { ph = &(*ph)->next; } - *ph = &header[i]; - - r->headers_in.multi = 1; - - break; - } - } - } + /* + * Build a hash table mapping lowercased header name → first ngx_table_elt_t *. + * Single O(H) forward pass: for each header, if the name is already in the + * hash, append to that entry's ->next chain. No backward re-scan needed. + * Replaces the O(H²) double-traversal that compared every (i,j) pair. + */ + ngx_hash_keys_array_t ha; + if (ngx_hash_keys_array_init(&ha, NGX_HASH_SMALL, r->pool) != NGX_OK) { + return NGX_ERROR; + } + + for (i = 0; /* void */; i++) { + if (i >= part->nelts) { + if (part->next == NULL) break; + part = part->next; + header = part->elts; + i = 0; + } + + header[i].next = NULL; + + ngx_table_elt_t **existing = ngx_hash_find(&name_map, + header[i].lowcase_key ? + ngx_hash_key(header[i].lowcase_key, header[i].key.len) : + ngx_hash_key_lc(header[i].key.data, header[i].key.len), + header[i].key.data, + header[i].key.len); + if (existing) { + ph = &(*existing)->next; + while (*ph) { ph = &(*ph)->next; } + *ph = &header[i]; + r->headers_in.multi = 1; + } else { + ngx_hash_add_key(&ha, &header[i].key, &header[i], NGX_HASH_READONLY_KEY); + } + }