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.
This commit is contained in:
Maxim Dounin 2022-05-30 21:25:49 +03:00
parent 47e9ce390d
commit 027b46b7ea
2 changed files with 104 additions and 9 deletions

View File

@ -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)

View File

@ -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;