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