diff options
author | Maxim Dounin <mdounin@mdounin.ru> | 2022-05-30 21:25:49 +0300 |
---|---|---|
committer | Maxim Dounin <mdounin@mdounin.ru> | 2022-05-30 21:25:49 +0300 |
commit | b8815c797a3e33ae1249886f9fa80b2188eadd0b (patch) | |
tree | 8d6977d66aa2966799ce728343e7e3ee0e421bc9 | |
parent | d22157fade0c3dc05b860be8d7e3eff4a56cb7d3 (diff) | |
download | nginx-b8815c797a3e33ae1249886f9fa80b2188eadd0b.tar.gz |
Upstream: duplicate headers ignored or properly linked.
Most of the known duplicate upstream response headers are now ignored
with a warning.
If syntax permits multiple headers, these are now properly linked to
the lists, notably Vary and WWW-Authenticate. This makes it possible
to further handle such lists where it makes sense.
-rw-r--r-- | src/http/ngx_http_upstream.c | 112 | ||||
-rw-r--r-- | src/http/ngx_http_upstream.h | 1 |
2 files changed, 104 insertions, 9 deletions
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 8cc4ea5ad..7482bc9bd 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -101,6 +101,9 @@ static void ngx_http_upstream_finalize_request(ngx_http_request_t *r, static ngx_int_t ngx_http_upstream_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t + ngx_http_upstream_process_multi_header_lines(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_upstream_process_content_length(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_upstream_process_last_modified(ngx_http_request_t *r, @@ -226,7 +229,7 @@ static ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = { offsetof(ngx_http_headers_out_t, server), 0 }, { ngx_string("WWW-Authenticate"), - ngx_http_upstream_process_header_line, + ngx_http_upstream_process_multi_header_lines, offsetof(ngx_http_upstream_headers_in_t, www_authenticate), ngx_http_upstream_copy_header_line, 0, 0 }, @@ -236,7 +239,8 @@ static ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = { ngx_http_upstream_rewrite_location, 0, 0 }, { ngx_string("Refresh"), - ngx_http_upstream_ignore_header_line, 0, + ngx_http_upstream_process_header_line, + offsetof(ngx_http_upstream_headers_in_t, refresh), ngx_http_upstream_rewrite_refresh, 0, 0 }, { ngx_string("Set-Cookie"), @@ -2804,6 +2808,10 @@ ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u) i = 0; } + if (h[i].hash == 0) { + continue; + } + hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash, h[i].lowcase_key, h[i].key.len); @@ -2857,6 +2865,10 @@ ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u) i = 0; } + if (h[i].hash == 0) { + continue; + } + if (ngx_hash_find(&u->conf->hide_headers_hash, h[i].hash, h[i].lowcase_key, h[i].key.len)) { @@ -4608,11 +4620,36 @@ ngx_http_upstream_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, ph = (ngx_table_elt_t **) ((char *) &r->upstream->headers_in + offset); - if (*ph == NULL) { - *ph = h; - h->next = NULL; + if (*ph) { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "upstream sent duplicate header line: \"%V: %V\", " + "previous value: \"%V: %V\", ignored", + &h->key, &h->value, + &(*ph)->key, &(*ph)->value); + h->hash = 0; + return NGX_OK; } + *ph = h; + h->next = NULL; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_process_multi_header_lines(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset) +{ + ngx_table_elt_t **ph; + + ph = (ngx_table_elt_t **) ((char *) &r->upstream->headers_in + offset); + + while (*ph) { ph = &(*ph)->next; } + + *ph = h; + h->next = NULL; + return NGX_OK; } @@ -4673,6 +4710,17 @@ ngx_http_upstream_process_last_modified(ngx_http_request_t *r, u = r->upstream; + if (u->headers_in.last_modified) { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "upstream sent duplicate header line: \"%V: %V\", " + "previous value: \"%V: %V\", ignored", + &h->key, &h->value, + &u->headers_in.last_modified->key, + &u->headers_in.last_modified->value); + h->hash = 0; + return NGX_OK; + } + h->next = NULL; u->headers_in.last_modified = h; u->headers_in.last_modified_time = ngx_parse_http_time(h->value.data, @@ -4842,6 +4890,18 @@ ngx_http_upstream_process_expires(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_http_upstream_t *u; u = r->upstream; + + if (u->headers_in.expires) { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "upstream sent duplicate header line: \"%V: %V\", " + "previous value: \"%V: %V\", ignored", + &h->key, &h->value, + &u->headers_in.expires->key, + &u->headers_in.expires->value); + h->hash = 0; + return NGX_OK; + } + u->headers_in.expires = h; h->next = NULL; @@ -4883,6 +4943,18 @@ ngx_http_upstream_process_accel_expires(ngx_http_request_t *r, ngx_http_upstream_t *u; u = r->upstream; + + if (u->headers_in.x_accel_expires) { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "upstream sent duplicate header line: \"%V: %V\", " + "previous value: \"%V: %V\", ignored", + &h->key, &h->value, + &u->headers_in.x_accel_expires->key, + &u->headers_in.x_accel_expires->value); + h->hash = 0; + return NGX_OK; + } + u->headers_in.x_accel_expires = h; h->next = NULL; @@ -4943,6 +5015,18 @@ ngx_http_upstream_process_limit_rate(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_http_upstream_t *u; u = r->upstream; + + if (u->headers_in.x_accel_limit_rate) { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "upstream sent duplicate header line: \"%V: %V\", " + "previous value: \"%V: %V\", ignored", + &h->key, &h->value, + &u->headers_in.x_accel_limit_rate->key, + &u->headers_in.x_accel_limit_rate->value); + h->hash = 0; + return NGX_OK; + } + u->headers_in.x_accel_limit_rate = h; h->next = NULL; @@ -5021,10 +5105,15 @@ static ngx_int_t ngx_http_upstream_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { - ngx_http_upstream_t *u; + ngx_table_elt_t **ph; + ngx_http_upstream_t *u; u = r->upstream; - u->headers_in.connection = h; + ph = &u->headers_in.connection; + + while (*ph) { ph = &(*ph)->next; } + + *ph = h; h->next = NULL; if (ngx_strlcasestrn(h->value.data, h->value.data + h->value.len, @@ -5086,10 +5175,15 @@ static ngx_int_t ngx_http_upstream_process_vary(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { - ngx_http_upstream_t *u; + ngx_table_elt_t **ph; + ngx_http_upstream_t *u; u = r->upstream; - u->headers_in.vary = h; + ph = &u->headers_in.vary; + + while (*ph) { ph = &(*ph)->next; } + + *ph = h; h->next = NULL; #if (NGX_HTTP_CACHE) diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h index 1ccfb8f92..28d1cfbed 100644 --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -280,6 +280,7 @@ typedef struct { ngx_table_elt_t *last_modified; ngx_table_elt_t *location; + ngx_table_elt_t *refresh; ngx_table_elt_t *www_authenticate; ngx_table_elt_t *transfer_encoding; ngx_table_elt_t *vary; |