109 lines
3.4 KiB
Diff
109 lines
3.4 KiB
Diff
# 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);
|
|
+ }
|
|
+ }
|