Mercurial > hg > nginx
comparison src/http/ngx_http_upstream.c @ 8034:413dbda22f7d
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.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 30 May 2022 21:25:49 +0300 |
parents | 2bf7792c262e |
children | cd73509f21e2 |
comparison
equal
deleted
inserted
replaced
8033:2bf7792c262e | 8034:413dbda22f7d |
---|---|
99 static void ngx_http_upstream_finalize_request(ngx_http_request_t *r, | 99 static void ngx_http_upstream_finalize_request(ngx_http_request_t *r, |
100 ngx_http_upstream_t *u, ngx_int_t rc); | 100 ngx_http_upstream_t *u, ngx_int_t rc); |
101 | 101 |
102 static ngx_int_t ngx_http_upstream_process_header_line(ngx_http_request_t *r, | 102 static ngx_int_t ngx_http_upstream_process_header_line(ngx_http_request_t *r, |
103 ngx_table_elt_t *h, ngx_uint_t offset); | 103 ngx_table_elt_t *h, ngx_uint_t offset); |
104 static ngx_int_t | |
105 ngx_http_upstream_process_multi_header_lines(ngx_http_request_t *r, | |
106 ngx_table_elt_t *h, ngx_uint_t offset); | |
104 static ngx_int_t ngx_http_upstream_process_content_length(ngx_http_request_t *r, | 107 static ngx_int_t ngx_http_upstream_process_content_length(ngx_http_request_t *r, |
105 ngx_table_elt_t *h, ngx_uint_t offset); | 108 ngx_table_elt_t *h, ngx_uint_t offset); |
106 static ngx_int_t ngx_http_upstream_process_last_modified(ngx_http_request_t *r, | 109 static ngx_int_t ngx_http_upstream_process_last_modified(ngx_http_request_t *r, |
107 ngx_table_elt_t *h, ngx_uint_t offset); | 110 ngx_table_elt_t *h, ngx_uint_t offset); |
108 static ngx_int_t ngx_http_upstream_process_set_cookie(ngx_http_request_t *r, | 111 static ngx_int_t ngx_http_upstream_process_set_cookie(ngx_http_request_t *r, |
224 offsetof(ngx_http_upstream_headers_in_t, server), | 227 offsetof(ngx_http_upstream_headers_in_t, server), |
225 ngx_http_upstream_copy_header_line, | 228 ngx_http_upstream_copy_header_line, |
226 offsetof(ngx_http_headers_out_t, server), 0 }, | 229 offsetof(ngx_http_headers_out_t, server), 0 }, |
227 | 230 |
228 { ngx_string("WWW-Authenticate"), | 231 { ngx_string("WWW-Authenticate"), |
229 ngx_http_upstream_process_header_line, | 232 ngx_http_upstream_process_multi_header_lines, |
230 offsetof(ngx_http_upstream_headers_in_t, www_authenticate), | 233 offsetof(ngx_http_upstream_headers_in_t, www_authenticate), |
231 ngx_http_upstream_copy_header_line, 0, 0 }, | 234 ngx_http_upstream_copy_header_line, 0, 0 }, |
232 | 235 |
233 { ngx_string("Location"), | 236 { ngx_string("Location"), |
234 ngx_http_upstream_process_header_line, | 237 ngx_http_upstream_process_header_line, |
235 offsetof(ngx_http_upstream_headers_in_t, location), | 238 offsetof(ngx_http_upstream_headers_in_t, location), |
236 ngx_http_upstream_rewrite_location, 0, 0 }, | 239 ngx_http_upstream_rewrite_location, 0, 0 }, |
237 | 240 |
238 { ngx_string("Refresh"), | 241 { ngx_string("Refresh"), |
239 ngx_http_upstream_ignore_header_line, 0, | 242 ngx_http_upstream_process_header_line, |
243 offsetof(ngx_http_upstream_headers_in_t, refresh), | |
240 ngx_http_upstream_rewrite_refresh, 0, 0 }, | 244 ngx_http_upstream_rewrite_refresh, 0, 0 }, |
241 | 245 |
242 { ngx_string("Set-Cookie"), | 246 { ngx_string("Set-Cookie"), |
243 ngx_http_upstream_process_set_cookie, | 247 ngx_http_upstream_process_set_cookie, |
244 offsetof(ngx_http_upstream_headers_in_t, set_cookie), | 248 offsetof(ngx_http_upstream_headers_in_t, set_cookie), |
2802 part = part->next; | 2806 part = part->next; |
2803 h = part->elts; | 2807 h = part->elts; |
2804 i = 0; | 2808 i = 0; |
2805 } | 2809 } |
2806 | 2810 |
2811 if (h[i].hash == 0) { | |
2812 continue; | |
2813 } | |
2814 | |
2807 hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash, | 2815 hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash, |
2808 h[i].lowcase_key, h[i].key.len); | 2816 h[i].lowcase_key, h[i].key.len); |
2809 | 2817 |
2810 if (hh && hh->redirect) { | 2818 if (hh && hh->redirect) { |
2811 if (hh->copy_handler(r, &h[i], hh->conf) != NGX_OK) { | 2819 if (hh->copy_handler(r, &h[i], hh->conf) != NGX_OK) { |
2853 } | 2861 } |
2854 | 2862 |
2855 part = part->next; | 2863 part = part->next; |
2856 h = part->elts; | 2864 h = part->elts; |
2857 i = 0; | 2865 i = 0; |
2866 } | |
2867 | |
2868 if (h[i].hash == 0) { | |
2869 continue; | |
2858 } | 2870 } |
2859 | 2871 |
2860 if (ngx_hash_find(&u->conf->hide_headers_hash, h[i].hash, | 2872 if (ngx_hash_find(&u->conf->hide_headers_hash, h[i].hash, |
2861 h[i].lowcase_key, h[i].key.len)) | 2873 h[i].lowcase_key, h[i].key.len)) |
2862 { | 2874 { |
4606 { | 4618 { |
4607 ngx_table_elt_t **ph; | 4619 ngx_table_elt_t **ph; |
4608 | 4620 |
4609 ph = (ngx_table_elt_t **) ((char *) &r->upstream->headers_in + offset); | 4621 ph = (ngx_table_elt_t **) ((char *) &r->upstream->headers_in + offset); |
4610 | 4622 |
4611 if (*ph == NULL) { | 4623 if (*ph) { |
4612 *ph = h; | 4624 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, |
4613 h->next = NULL; | 4625 "upstream sent duplicate header line: \"%V: %V\", " |
4614 } | 4626 "previous value: \"%V: %V\", ignored", |
4627 &h->key, &h->value, | |
4628 &(*ph)->key, &(*ph)->value); | |
4629 h->hash = 0; | |
4630 return NGX_OK; | |
4631 } | |
4632 | |
4633 *ph = h; | |
4634 h->next = NULL; | |
4635 | |
4636 return NGX_OK; | |
4637 } | |
4638 | |
4639 | |
4640 static ngx_int_t | |
4641 ngx_http_upstream_process_multi_header_lines(ngx_http_request_t *r, | |
4642 ngx_table_elt_t *h, ngx_uint_t offset) | |
4643 { | |
4644 ngx_table_elt_t **ph; | |
4645 | |
4646 ph = (ngx_table_elt_t **) ((char *) &r->upstream->headers_in + offset); | |
4647 | |
4648 while (*ph) { ph = &(*ph)->next; } | |
4649 | |
4650 *ph = h; | |
4651 h->next = NULL; | |
4615 | 4652 |
4616 return NGX_OK; | 4653 return NGX_OK; |
4617 } | 4654 } |
4618 | 4655 |
4619 | 4656 |
4671 { | 4708 { |
4672 ngx_http_upstream_t *u; | 4709 ngx_http_upstream_t *u; |
4673 | 4710 |
4674 u = r->upstream; | 4711 u = r->upstream; |
4675 | 4712 |
4713 if (u->headers_in.last_modified) { | |
4714 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, | |
4715 "upstream sent duplicate header line: \"%V: %V\", " | |
4716 "previous value: \"%V: %V\", ignored", | |
4717 &h->key, &h->value, | |
4718 &u->headers_in.last_modified->key, | |
4719 &u->headers_in.last_modified->value); | |
4720 h->hash = 0; | |
4721 return NGX_OK; | |
4722 } | |
4723 | |
4676 h->next = NULL; | 4724 h->next = NULL; |
4677 u->headers_in.last_modified = h; | 4725 u->headers_in.last_modified = h; |
4678 u->headers_in.last_modified_time = ngx_parse_http_time(h->value.data, | 4726 u->headers_in.last_modified_time = ngx_parse_http_time(h->value.data, |
4679 h->value.len); | 4727 h->value.len); |
4680 | 4728 |
4840 ngx_uint_t offset) | 4888 ngx_uint_t offset) |
4841 { | 4889 { |
4842 ngx_http_upstream_t *u; | 4890 ngx_http_upstream_t *u; |
4843 | 4891 |
4844 u = r->upstream; | 4892 u = r->upstream; |
4893 | |
4894 if (u->headers_in.expires) { | |
4895 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, | |
4896 "upstream sent duplicate header line: \"%V: %V\", " | |
4897 "previous value: \"%V: %V\", ignored", | |
4898 &h->key, &h->value, | |
4899 &u->headers_in.expires->key, | |
4900 &u->headers_in.expires->value); | |
4901 h->hash = 0; | |
4902 return NGX_OK; | |
4903 } | |
4904 | |
4845 u->headers_in.expires = h; | 4905 u->headers_in.expires = h; |
4846 h->next = NULL; | 4906 h->next = NULL; |
4847 | 4907 |
4848 #if (NGX_HTTP_CACHE) | 4908 #if (NGX_HTTP_CACHE) |
4849 { | 4909 { |
4881 ngx_table_elt_t *h, ngx_uint_t offset) | 4941 ngx_table_elt_t *h, ngx_uint_t offset) |
4882 { | 4942 { |
4883 ngx_http_upstream_t *u; | 4943 ngx_http_upstream_t *u; |
4884 | 4944 |
4885 u = r->upstream; | 4945 u = r->upstream; |
4946 | |
4947 if (u->headers_in.x_accel_expires) { | |
4948 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, | |
4949 "upstream sent duplicate header line: \"%V: %V\", " | |
4950 "previous value: \"%V: %V\", ignored", | |
4951 &h->key, &h->value, | |
4952 &u->headers_in.x_accel_expires->key, | |
4953 &u->headers_in.x_accel_expires->value); | |
4954 h->hash = 0; | |
4955 return NGX_OK; | |
4956 } | |
4957 | |
4886 u->headers_in.x_accel_expires = h; | 4958 u->headers_in.x_accel_expires = h; |
4887 h->next = NULL; | 4959 h->next = NULL; |
4888 | 4960 |
4889 #if (NGX_HTTP_CACHE) | 4961 #if (NGX_HTTP_CACHE) |
4890 { | 4962 { |
4941 { | 5013 { |
4942 ngx_int_t n; | 5014 ngx_int_t n; |
4943 ngx_http_upstream_t *u; | 5015 ngx_http_upstream_t *u; |
4944 | 5016 |
4945 u = r->upstream; | 5017 u = r->upstream; |
5018 | |
5019 if (u->headers_in.x_accel_limit_rate) { | |
5020 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, | |
5021 "upstream sent duplicate header line: \"%V: %V\", " | |
5022 "previous value: \"%V: %V\", ignored", | |
5023 &h->key, &h->value, | |
5024 &u->headers_in.x_accel_limit_rate->key, | |
5025 &u->headers_in.x_accel_limit_rate->value); | |
5026 h->hash = 0; | |
5027 return NGX_OK; | |
5028 } | |
5029 | |
4946 u->headers_in.x_accel_limit_rate = h; | 5030 u->headers_in.x_accel_limit_rate = h; |
4947 h->next = NULL; | 5031 h->next = NULL; |
4948 | 5032 |
4949 if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_LIMIT_RATE) { | 5033 if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_LIMIT_RATE) { |
4950 return NGX_OK; | 5034 return NGX_OK; |
5019 | 5103 |
5020 static ngx_int_t | 5104 static ngx_int_t |
5021 ngx_http_upstream_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h, | 5105 ngx_http_upstream_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h, |
5022 ngx_uint_t offset) | 5106 ngx_uint_t offset) |
5023 { | 5107 { |
5024 ngx_http_upstream_t *u; | 5108 ngx_table_elt_t **ph; |
5109 ngx_http_upstream_t *u; | |
5025 | 5110 |
5026 u = r->upstream; | 5111 u = r->upstream; |
5027 u->headers_in.connection = h; | 5112 ph = &u->headers_in.connection; |
5113 | |
5114 while (*ph) { ph = &(*ph)->next; } | |
5115 | |
5116 *ph = h; | |
5028 h->next = NULL; | 5117 h->next = NULL; |
5029 | 5118 |
5030 if (ngx_strlcasestrn(h->value.data, h->value.data + h->value.len, | 5119 if (ngx_strlcasestrn(h->value.data, h->value.data + h->value.len, |
5031 (u_char *) "close", 5 - 1) | 5120 (u_char *) "close", 5 - 1) |
5032 != NULL) | 5121 != NULL) |
5084 | 5173 |
5085 static ngx_int_t | 5174 static ngx_int_t |
5086 ngx_http_upstream_process_vary(ngx_http_request_t *r, | 5175 ngx_http_upstream_process_vary(ngx_http_request_t *r, |
5087 ngx_table_elt_t *h, ngx_uint_t offset) | 5176 ngx_table_elt_t *h, ngx_uint_t offset) |
5088 { | 5177 { |
5089 ngx_http_upstream_t *u; | 5178 ngx_table_elt_t **ph; |
5179 ngx_http_upstream_t *u; | |
5090 | 5180 |
5091 u = r->upstream; | 5181 u = r->upstream; |
5092 u->headers_in.vary = h; | 5182 ph = &u->headers_in.vary; |
5183 | |
5184 while (*ph) { ph = &(*ph)->next; } | |
5185 | |
5186 *ph = h; | |
5093 h->next = NULL; | 5187 h->next = NULL; |
5094 | 5188 |
5095 #if (NGX_HTTP_CACHE) | 5189 #if (NGX_HTTP_CACHE) |
5096 | 5190 |
5097 if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_VARY) { | 5191 if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_VARY) { |