comparison src/http/ngx_http_upstream.c @ 9021:8d0753760546 quic

Merged with the default branch.
author Sergey Kandaurov <pluknet@nginx.com>
date Wed, 22 Jun 2022 18:34:58 +0400
parents 5c86189a1c1b c7e25324be11
children e88cdaa0f1ff
comparison
equal deleted inserted replaced
9020:efbcdb9b37dc 9021:8d0753760546
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,
145 static ngx_int_t ngx_http_upstream_rewrite_set_cookie(ngx_http_request_t *r, 148 static ngx_int_t ngx_http_upstream_rewrite_set_cookie(ngx_http_request_t *r,
146 ngx_table_elt_t *h, ngx_uint_t offset); 149 ngx_table_elt_t *h, ngx_uint_t offset);
147 static ngx_int_t ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r, 150 static ngx_int_t ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r,
148 ngx_table_elt_t *h, ngx_uint_t offset); 151 ngx_table_elt_t *h, ngx_uint_t offset);
149 152
150 #if (NGX_HTTP_GZIP)
151 static ngx_int_t ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r,
152 ngx_table_elt_t *h, ngx_uint_t offset);
153 #endif
154
155 static ngx_int_t ngx_http_upstream_add_variables(ngx_conf_t *cf); 153 static ngx_int_t ngx_http_upstream_add_variables(ngx_conf_t *cf);
156 static ngx_int_t ngx_http_upstream_addr_variable(ngx_http_request_t *r, 154 static ngx_int_t ngx_http_upstream_addr_variable(ngx_http_request_t *r,
157 ngx_http_variable_value_t *v, uintptr_t data); 155 ngx_http_variable_value_t *v, uintptr_t data);
158 static ngx_int_t ngx_http_upstream_status_variable(ngx_http_request_t *r, 156 static ngx_int_t ngx_http_upstream_status_variable(ngx_http_request_t *r,
159 ngx_http_variable_value_t *v, uintptr_t data); 157 ngx_http_variable_value_t *v, uintptr_t data);
229 offsetof(ngx_http_upstream_headers_in_t, server), 227 offsetof(ngx_http_upstream_headers_in_t, server),
230 ngx_http_upstream_copy_header_line, 228 ngx_http_upstream_copy_header_line,
231 offsetof(ngx_http_headers_out_t, server), 0 }, 229 offsetof(ngx_http_headers_out_t, server), 0 },
232 230
233 { ngx_string("WWW-Authenticate"), 231 { ngx_string("WWW-Authenticate"),
234 ngx_http_upstream_process_header_line, 232 ngx_http_upstream_process_multi_header_lines,
235 offsetof(ngx_http_upstream_headers_in_t, www_authenticate), 233 offsetof(ngx_http_upstream_headers_in_t, www_authenticate),
236 ngx_http_upstream_copy_header_line, 0, 0 }, 234 ngx_http_upstream_copy_header_line, 0, 0 },
237 235
238 { ngx_string("Location"), 236 { ngx_string("Location"),
239 ngx_http_upstream_process_header_line, 237 ngx_http_upstream_process_header_line,
240 offsetof(ngx_http_upstream_headers_in_t, location), 238 offsetof(ngx_http_upstream_headers_in_t, location),
241 ngx_http_upstream_rewrite_location, 0, 0 }, 239 ngx_http_upstream_rewrite_location, 0, 0 },
242 240
243 { ngx_string("Refresh"), 241 { ngx_string("Refresh"),
244 ngx_http_upstream_ignore_header_line, 0, 242 ngx_http_upstream_process_header_line,
243 offsetof(ngx_http_upstream_headers_in_t, refresh),
245 ngx_http_upstream_rewrite_refresh, 0, 0 }, 244 ngx_http_upstream_rewrite_refresh, 0, 0 },
246 245
247 { ngx_string("Set-Cookie"), 246 { ngx_string("Set-Cookie"),
248 ngx_http_upstream_process_set_cookie, 247 ngx_http_upstream_process_set_cookie,
249 offsetof(ngx_http_upstream_headers_in_t, cookies), 248 offsetof(ngx_http_upstream_headers_in_t, set_cookie),
250 ngx_http_upstream_rewrite_set_cookie, 0, 1 }, 249 ngx_http_upstream_rewrite_set_cookie, 0, 1 },
251 250
252 { ngx_string("Content-Disposition"), 251 { ngx_string("Content-Disposition"),
253 ngx_http_upstream_ignore_header_line, 0, 252 ngx_http_upstream_ignore_header_line, 0,
254 ngx_http_upstream_copy_header_line, 0, 1 }, 253 ngx_http_upstream_copy_header_line, 0, 1 },
262 ngx_http_upstream_process_expires, 0, 261 ngx_http_upstream_process_expires, 0,
263 ngx_http_upstream_copy_header_line, 262 ngx_http_upstream_copy_header_line,
264 offsetof(ngx_http_headers_out_t, expires), 1 }, 263 offsetof(ngx_http_headers_out_t, expires), 1 },
265 264
266 { ngx_string("Accept-Ranges"), 265 { ngx_string("Accept-Ranges"),
267 ngx_http_upstream_process_header_line, 266 ngx_http_upstream_ignore_header_line, 0,
268 offsetof(ngx_http_upstream_headers_in_t, accept_ranges),
269 ngx_http_upstream_copy_allow_ranges, 267 ngx_http_upstream_copy_allow_ranges,
270 offsetof(ngx_http_headers_out_t, accept_ranges), 1 }, 268 offsetof(ngx_http_headers_out_t, accept_ranges), 1 },
271 269
272 { ngx_string("Content-Range"), 270 { ngx_string("Content-Range"),
273 ngx_http_upstream_ignore_header_line, 0, 271 ngx_http_upstream_ignore_header_line, 0,
314 312
315 { ngx_string("Transfer-Encoding"), 313 { ngx_string("Transfer-Encoding"),
316 ngx_http_upstream_process_transfer_encoding, 0, 314 ngx_http_upstream_process_transfer_encoding, 0,
317 ngx_http_upstream_ignore_header_line, 0, 0 }, 315 ngx_http_upstream_ignore_header_line, 0, 0 },
318 316
319 #if (NGX_HTTP_GZIP)
320 { ngx_string("Content-Encoding"), 317 { ngx_string("Content-Encoding"),
321 ngx_http_upstream_process_header_line, 318 ngx_http_upstream_ignore_header_line, 0,
322 offsetof(ngx_http_upstream_headers_in_t, content_encoding), 319 ngx_http_upstream_copy_header_line,
323 ngx_http_upstream_copy_content_encoding, 0, 0 }, 320 offsetof(ngx_http_headers_out_t, content_encoding), 0 },
324 #endif
325 321
326 { ngx_null_string, NULL, 0, NULL, 0, 0 } 322 { ngx_null_string, NULL, 0, NULL, 0, 0 }
327 }; 323 };
328 324
329 325
1712 NGX_HTTP_INTERNAL_SERVER_ERROR); 1708 NGX_HTTP_INTERNAL_SERVER_ERROR);
1713 return; 1709 return;
1714 } 1710 }
1715 } 1711 }
1716 1712
1717 if (u->conf->ssl_certificate && (u->conf->ssl_certificate->lengths 1713 if (u->conf->ssl_certificate
1718 || u->conf->ssl_certificate_key->lengths)) 1714 && u->conf->ssl_certificate->value.len
1715 && (u->conf->ssl_certificate->lengths
1716 || u->conf->ssl_certificate_key->lengths))
1719 { 1717 {
1720 if (ngx_http_upstream_ssl_certificate(r, u, c) != NGX_OK) { 1718 if (ngx_http_upstream_ssl_certificate(r, u, c) != NGX_OK) {
1721 ngx_http_upstream_finalize_request(r, u, 1719 ngx_http_upstream_finalize_request(r, u,
1722 NGX_HTTP_INTERNAL_SERVER_ERROR); 1720 NGX_HTTP_INTERNAL_SERVER_ERROR);
1723 return; 1721 return;
2669 ngx_http_upstream_intercept_errors(ngx_http_request_t *r, 2667 ngx_http_upstream_intercept_errors(ngx_http_request_t *r,
2670 ngx_http_upstream_t *u) 2668 ngx_http_upstream_t *u)
2671 { 2669 {
2672 ngx_int_t status; 2670 ngx_int_t status;
2673 ngx_uint_t i; 2671 ngx_uint_t i;
2674 ngx_table_elt_t *h; 2672 ngx_table_elt_t *h, *ho, **ph;
2675 ngx_http_err_page_t *err_page; 2673 ngx_http_err_page_t *err_page;
2676 ngx_http_core_loc_conf_t *clcf; 2674 ngx_http_core_loc_conf_t *clcf;
2677 2675
2678 status = u->headers_in.status_n; 2676 status = u->headers_in.status_n;
2679 2677
2698 if (err_page[i].status == status) { 2696 if (err_page[i].status == status) {
2699 2697
2700 if (status == NGX_HTTP_UNAUTHORIZED 2698 if (status == NGX_HTTP_UNAUTHORIZED
2701 && u->headers_in.www_authenticate) 2699 && u->headers_in.www_authenticate)
2702 { 2700 {
2703 h = ngx_list_push(&r->headers_out.headers); 2701 h = u->headers_in.www_authenticate;
2704 2702 ph = &r->headers_out.www_authenticate;
2705 if (h == NULL) { 2703
2706 ngx_http_upstream_finalize_request(r, u, 2704 while (h) {
2705 ho = ngx_list_push(&r->headers_out.headers);
2706
2707 if (ho == NULL) {
2708 ngx_http_upstream_finalize_request(r, u,
2707 NGX_HTTP_INTERNAL_SERVER_ERROR); 2709 NGX_HTTP_INTERNAL_SERVER_ERROR);
2708 return NGX_OK; 2710 return NGX_OK;
2711 }
2712
2713 *ho = *h;
2714 ho->next = NULL;
2715
2716 *ph = ho;
2717 ph = &ho->next;
2718
2719 h = h->next;
2709 } 2720 }
2710
2711 *h = *u->headers_in.www_authenticate;
2712
2713 r->headers_out.www_authenticate = h;
2714 } 2721 }
2715 2722
2716 #if (NGX_HTTP_CACHE) 2723 #if (NGX_HTTP_CACHE)
2717 2724
2718 if (r->cache) { 2725 if (r->cache) {
2726
2727 if (u->headers_in.no_cache || u->headers_in.expired) {
2728 u->cacheable = 0;
2729 }
2719 2730
2720 if (u->cacheable) { 2731 if (u->cacheable) {
2721 time_t valid; 2732 time_t valid;
2722 2733
2723 valid = r->cache->valid_sec; 2734 valid = r->cache->valid_sec;
2809 ngx_http_upstream_header_t *hh; 2820 ngx_http_upstream_header_t *hh;
2810 ngx_http_upstream_main_conf_t *umcf; 2821 ngx_http_upstream_main_conf_t *umcf;
2811 2822
2812 umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); 2823 umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
2813 2824
2825 if (u->headers_in.no_cache || u->headers_in.expired) {
2826 u->cacheable = 0;
2827 }
2828
2814 if (u->headers_in.x_accel_redirect 2829 if (u->headers_in.x_accel_redirect
2815 && !(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT)) 2830 && !(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT))
2816 { 2831 {
2817 ngx_http_upstream_finalize_request(r, u, NGX_DECLINED); 2832 ngx_http_upstream_finalize_request(r, u, NGX_DECLINED);
2818 2833
2827 } 2842 }
2828 2843
2829 part = part->next; 2844 part = part->next;
2830 h = part->elts; 2845 h = part->elts;
2831 i = 0; 2846 i = 0;
2847 }
2848
2849 if (h[i].hash == 0) {
2850 continue;
2832 } 2851 }
2833 2852
2834 hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash, 2853 hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash,
2835 h[i].lowcase_key, h[i].key.len); 2854 h[i].lowcase_key, h[i].key.len);
2836 2855
2880 } 2899 }
2881 2900
2882 part = part->next; 2901 part = part->next;
2883 h = part->elts; 2902 h = part->elts;
2884 i = 0; 2903 i = 0;
2904 }
2905
2906 if (h[i].hash == 0) {
2907 continue;
2885 } 2908 }
2886 2909
2887 if (ngx_hash_find(&u->conf->hide_headers_hash, h[i].hash, 2910 if (ngx_hash_find(&u->conf->hide_headers_hash, h[i].hash,
2888 h[i].lowcase_key, h[i].key.len)) 2911 h[i].lowcase_key, h[i].key.len))
2889 { 2912 {
4633 { 4656 {
4634 ngx_table_elt_t **ph; 4657 ngx_table_elt_t **ph;
4635 4658
4636 ph = (ngx_table_elt_t **) ((char *) &r->upstream->headers_in + offset); 4659 ph = (ngx_table_elt_t **) ((char *) &r->upstream->headers_in + offset);
4637 4660
4638 if (*ph == NULL) { 4661 if (*ph) {
4639 *ph = h; 4662 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
4640 } 4663 "upstream sent duplicate header line: \"%V: %V\", "
4664 "previous value: \"%V: %V\", ignored",
4665 &h->key, &h->value,
4666 &(*ph)->key, &(*ph)->value);
4667 h->hash = 0;
4668 return NGX_OK;
4669 }
4670
4671 *ph = h;
4672 h->next = NULL;
4673
4674 return NGX_OK;
4675 }
4676
4677
4678 static ngx_int_t
4679 ngx_http_upstream_process_multi_header_lines(ngx_http_request_t *r,
4680 ngx_table_elt_t *h, ngx_uint_t offset)
4681 {
4682 ngx_table_elt_t **ph;
4683
4684 ph = (ngx_table_elt_t **) ((char *) &r->upstream->headers_in + offset);
4685
4686 while (*ph) { ph = &(*ph)->next; }
4687
4688 *ph = h;
4689 h->next = NULL;
4641 4690
4642 return NGX_OK; 4691 return NGX_OK;
4643 } 4692 }
4644 4693
4645 4694
4657 { 4706 {
4658 ngx_http_upstream_t *u; 4707 ngx_http_upstream_t *u;
4659 4708
4660 u = r->upstream; 4709 u = r->upstream;
4661 4710
4711 if (u->headers_in.content_length) {
4712 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
4713 "upstream sent duplicate header line: \"%V: %V\", "
4714 "previous value: \"%V: %V\"",
4715 &h->key, &h->value,
4716 &u->headers_in.content_length->key,
4717 &u->headers_in.content_length->value);
4718 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
4719 }
4720
4721 if (u->headers_in.transfer_encoding) {
4722 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
4723 "upstream sent \"Content-Length\" and "
4724 "\"Transfer-Encoding\" headers at the same time");
4725 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
4726 }
4727
4728 h->next = NULL;
4662 u->headers_in.content_length = h; 4729 u->headers_in.content_length = h;
4663 u->headers_in.content_length_n = ngx_atoof(h->value.data, h->value.len); 4730 u->headers_in.content_length_n = ngx_atoof(h->value.data, h->value.len);
4731
4732 if (u->headers_in.content_length_n == NGX_ERROR) {
4733 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
4734 "upstream sent invalid \"Content-Length\" header: "
4735 "\"%V: %V\"", &h->key, &h->value);
4736 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
4737 }
4664 4738
4665 return NGX_OK; 4739 return NGX_OK;
4666 } 4740 }
4667 4741
4668 4742
4672 { 4746 {
4673 ngx_http_upstream_t *u; 4747 ngx_http_upstream_t *u;
4674 4748
4675 u = r->upstream; 4749 u = r->upstream;
4676 4750
4751 if (u->headers_in.last_modified) {
4752 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
4753 "upstream sent duplicate header line: \"%V: %V\", "
4754 "previous value: \"%V: %V\", ignored",
4755 &h->key, &h->value,
4756 &u->headers_in.last_modified->key,
4757 &u->headers_in.last_modified->value);
4758 h->hash = 0;
4759 return NGX_OK;
4760 }
4761
4762 h->next = NULL;
4677 u->headers_in.last_modified = h; 4763 u->headers_in.last_modified = h;
4678 u->headers_in.last_modified_time = ngx_parse_http_time(h->value.data, 4764 u->headers_in.last_modified_time = ngx_parse_http_time(h->value.data,
4679 h->value.len); 4765 h->value.len);
4680 4766
4681 return NGX_OK; 4767 return NGX_OK;
4684 4770
4685 static ngx_int_t 4771 static ngx_int_t
4686 ngx_http_upstream_process_set_cookie(ngx_http_request_t *r, ngx_table_elt_t *h, 4772 ngx_http_upstream_process_set_cookie(ngx_http_request_t *r, ngx_table_elt_t *h,
4687 ngx_uint_t offset) 4773 ngx_uint_t offset)
4688 { 4774 {
4689 ngx_array_t *pa;
4690 ngx_table_elt_t **ph; 4775 ngx_table_elt_t **ph;
4691 ngx_http_upstream_t *u; 4776 ngx_http_upstream_t *u;
4692 4777
4693 u = r->upstream; 4778 u = r->upstream;
4694 pa = &u->headers_in.cookies; 4779 ph = &u->headers_in.set_cookie;
4695 4780
4696 if (pa->elts == NULL) { 4781 while (*ph) { ph = &(*ph)->next; }
4697 if (ngx_array_init(pa, r->pool, 1, sizeof(ngx_table_elt_t *)) != NGX_OK)
4698 {
4699 return NGX_ERROR;
4700 }
4701 }
4702
4703 ph = ngx_array_push(pa);
4704 if (ph == NULL) {
4705 return NGX_ERROR;
4706 }
4707 4782
4708 *ph = h; 4783 *ph = h;
4784 h->next = NULL;
4709 4785
4710 #if (NGX_HTTP_CACHE) 4786 #if (NGX_HTTP_CACHE)
4711 if (!(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_SET_COOKIE)) { 4787 if (!(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_SET_COOKIE)) {
4712 u->cacheable = 0; 4788 u->cacheable = 0;
4713 } 4789 }
4719 4795
4720 static ngx_int_t 4796 static ngx_int_t
4721 ngx_http_upstream_process_cache_control(ngx_http_request_t *r, 4797 ngx_http_upstream_process_cache_control(ngx_http_request_t *r,
4722 ngx_table_elt_t *h, ngx_uint_t offset) 4798 ngx_table_elt_t *h, ngx_uint_t offset)
4723 { 4799 {
4724 ngx_array_t *pa; 4800 ngx_table_elt_t **ph;
4725 ngx_table_elt_t **ph; 4801 ngx_http_upstream_t *u;
4726 ngx_http_upstream_t *u;
4727 4802
4728 u = r->upstream; 4803 u = r->upstream;
4729 pa = &u->headers_in.cache_control; 4804 ph = &u->headers_in.cache_control;
4730 4805
4731 if (pa->elts == NULL) { 4806 while (*ph) { ph = &(*ph)->next; }
4732 if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK)
4733 {
4734 return NGX_ERROR;
4735 }
4736 }
4737
4738 ph = ngx_array_push(pa);
4739 if (ph == NULL) {
4740 return NGX_ERROR;
4741 }
4742 4807
4743 *ph = h; 4808 *ph = h;
4809 h->next = NULL;
4744 4810
4745 #if (NGX_HTTP_CACHE) 4811 #if (NGX_HTTP_CACHE)
4746 { 4812 {
4747 u_char *p, *start, *last; 4813 u_char *p, *start, *last;
4748 ngx_int_t n; 4814 ngx_int_t n;
4753 4819
4754 if (r->cache == NULL) { 4820 if (r->cache == NULL) {
4755 return NGX_OK; 4821 return NGX_OK;
4756 } 4822 }
4757 4823
4758 if (r->cache->valid_sec != 0 && u->headers_in.x_accel_expires != NULL) {
4759 return NGX_OK;
4760 }
4761
4762 start = h->value.data; 4824 start = h->value.data;
4763 last = start + h->value.len; 4825 last = start + h->value.len;
4826
4827 if (r->cache->valid_sec != 0 && u->headers_in.x_accel_expires != NULL) {
4828 goto extensions;
4829 }
4764 4830
4765 if (ngx_strlcasestrn(start, last, (u_char *) "no-cache", 8 - 1) != NULL 4831 if (ngx_strlcasestrn(start, last, (u_char *) "no-cache", 8 - 1) != NULL
4766 || ngx_strlcasestrn(start, last, (u_char *) "no-store", 8 - 1) != NULL 4832 || ngx_strlcasestrn(start, last, (u_char *) "no-store", 8 - 1) != NULL
4767 || ngx_strlcasestrn(start, last, (u_char *) "private", 7 - 1) != NULL) 4833 || ngx_strlcasestrn(start, last, (u_char *) "private", 7 - 1) != NULL)
4768 { 4834 {
4769 u->cacheable = 0; 4835 u->headers_in.no_cache = 1;
4770 return NGX_OK; 4836 return NGX_OK;
4771 } 4837 }
4772 4838
4773 p = ngx_strlcasestrn(start, last, (u_char *) "s-maxage=", 9 - 1); 4839 p = ngx_strlcasestrn(start, last, (u_char *) "s-maxage=", 9 - 1);
4774 offset = 9; 4840 offset = 9;
4794 u->cacheable = 0; 4860 u->cacheable = 0;
4795 return NGX_OK; 4861 return NGX_OK;
4796 } 4862 }
4797 4863
4798 if (n == 0) { 4864 if (n == 0) {
4799 u->cacheable = 0; 4865 u->headers_in.no_cache = 1;
4800 return NGX_OK; 4866 return NGX_OK;
4801 } 4867 }
4802 4868
4803 r->cache->valid_sec = ngx_time() + n; 4869 r->cache->valid_sec = ngx_time() + n;
4804 } 4870 u->headers_in.expired = 0;
4871 }
4872
4873 extensions:
4805 4874
4806 p = ngx_strlcasestrn(start, last, (u_char *) "stale-while-revalidate=", 4875 p = ngx_strlcasestrn(start, last, (u_char *) "stale-while-revalidate=",
4807 23 - 1); 4876 23 - 1);
4808 4877
4809 if (p) { 4878 if (p) {
4860 ngx_uint_t offset) 4929 ngx_uint_t offset)
4861 { 4930 {
4862 ngx_http_upstream_t *u; 4931 ngx_http_upstream_t *u;
4863 4932
4864 u = r->upstream; 4933 u = r->upstream;
4934
4935 if (u->headers_in.expires) {
4936 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
4937 "upstream sent duplicate header line: \"%V: %V\", "
4938 "previous value: \"%V: %V\", ignored",
4939 &h->key, &h->value,
4940 &u->headers_in.expires->key,
4941 &u->headers_in.expires->value);
4942 h->hash = 0;
4943 return NGX_OK;
4944 }
4945
4865 u->headers_in.expires = h; 4946 u->headers_in.expires = h;
4947 h->next = NULL;
4866 4948
4867 #if (NGX_HTTP_CACHE) 4949 #if (NGX_HTTP_CACHE)
4868 { 4950 {
4869 time_t expires; 4951 time_t expires;
4870 4952
4881 } 4963 }
4882 4964
4883 expires = ngx_parse_http_time(h->value.data, h->value.len); 4965 expires = ngx_parse_http_time(h->value.data, h->value.len);
4884 4966
4885 if (expires == NGX_ERROR || expires < ngx_time()) { 4967 if (expires == NGX_ERROR || expires < ngx_time()) {
4886 u->cacheable = 0; 4968 u->headers_in.expired = 1;
4887 return NGX_OK; 4969 return NGX_OK;
4888 } 4970 }
4889 4971
4890 r->cache->valid_sec = expires; 4972 r->cache->valid_sec = expires;
4891 } 4973 }
4900 ngx_table_elt_t *h, ngx_uint_t offset) 4982 ngx_table_elt_t *h, ngx_uint_t offset)
4901 { 4983 {
4902 ngx_http_upstream_t *u; 4984 ngx_http_upstream_t *u;
4903 4985
4904 u = r->upstream; 4986 u = r->upstream;
4987
4988 if (u->headers_in.x_accel_expires) {
4989 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
4990 "upstream sent duplicate header line: \"%V: %V\", "
4991 "previous value: \"%V: %V\", ignored",
4992 &h->key, &h->value,
4993 &u->headers_in.x_accel_expires->key,
4994 &u->headers_in.x_accel_expires->value);
4995 h->hash = 0;
4996 return NGX_OK;
4997 }
4998
4905 u->headers_in.x_accel_expires = h; 4999 u->headers_in.x_accel_expires = h;
5000 h->next = NULL;
4906 5001
4907 #if (NGX_HTTP_CACHE) 5002 #if (NGX_HTTP_CACHE)
4908 { 5003 {
4909 u_char *p; 5004 u_char *p;
4910 size_t len; 5005 size_t len;
4932 case NGX_ERROR: 5027 case NGX_ERROR:
4933 return NGX_OK; 5028 return NGX_OK;
4934 5029
4935 default: 5030 default:
4936 r->cache->valid_sec = ngx_time() + n; 5031 r->cache->valid_sec = ngx_time() + n;
5032 u->headers_in.no_cache = 0;
5033 u->headers_in.expired = 0;
4937 return NGX_OK; 5034 return NGX_OK;
4938 } 5035 }
4939 } 5036 }
4940 5037
4941 p++; 5038 p++;
4943 5040
4944 n = ngx_atoi(p, len); 5041 n = ngx_atoi(p, len);
4945 5042
4946 if (n != NGX_ERROR) { 5043 if (n != NGX_ERROR) {
4947 r->cache->valid_sec = n; 5044 r->cache->valid_sec = n;
5045 u->headers_in.no_cache = 0;
5046 u->headers_in.expired = 0;
4948 } 5047 }
4949 } 5048 }
4950 #endif 5049 #endif
4951 5050
4952 return NGX_OK; 5051 return NGX_OK;
4959 { 5058 {
4960 ngx_int_t n; 5059 ngx_int_t n;
4961 ngx_http_upstream_t *u; 5060 ngx_http_upstream_t *u;
4962 5061
4963 u = r->upstream; 5062 u = r->upstream;
5063
5064 if (u->headers_in.x_accel_limit_rate) {
5065 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
5066 "upstream sent duplicate header line: \"%V: %V\", "
5067 "previous value: \"%V: %V\", ignored",
5068 &h->key, &h->value,
5069 &u->headers_in.x_accel_limit_rate->key,
5070 &u->headers_in.x_accel_limit_rate->value);
5071 h->hash = 0;
5072 return NGX_OK;
5073 }
5074
4964 u->headers_in.x_accel_limit_rate = h; 5075 u->headers_in.x_accel_limit_rate = h;
5076 h->next = NULL;
4965 5077
4966 if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_LIMIT_RATE) { 5078 if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_LIMIT_RATE) {
4967 return NGX_OK; 5079 return NGX_OK;
4968 } 5080 }
4969 5081
5018 5130
5019 static ngx_int_t 5131 static ngx_int_t
5020 ngx_http_upstream_process_charset(ngx_http_request_t *r, ngx_table_elt_t *h, 5132 ngx_http_upstream_process_charset(ngx_http_request_t *r, ngx_table_elt_t *h,
5021 ngx_uint_t offset) 5133 ngx_uint_t offset)
5022 { 5134 {
5023 if (r->upstream->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_CHARSET) { 5135 ngx_http_upstream_t *u;
5136
5137 u = r->upstream;
5138
5139 if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_CHARSET) {
5024 return NGX_OK; 5140 return NGX_OK;
5025 } 5141 }
5026 5142
5027 r->headers_out.override_charset = &h->value; 5143 r->headers_out.override_charset = &h->value;
5028 5144
5032 5148
5033 static ngx_int_t 5149 static ngx_int_t
5034 ngx_http_upstream_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h, 5150 ngx_http_upstream_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h,
5035 ngx_uint_t offset) 5151 ngx_uint_t offset)
5036 { 5152 {
5037 r->upstream->headers_in.connection = h; 5153 ngx_table_elt_t **ph;
5154 ngx_http_upstream_t *u;
5155
5156 u = r->upstream;
5157 ph = &u->headers_in.connection;
5158
5159 while (*ph) { ph = &(*ph)->next; }
5160
5161 *ph = h;
5162 h->next = NULL;
5038 5163
5039 if (ngx_strlcasestrn(h->value.data, h->value.data + h->value.len, 5164 if (ngx_strlcasestrn(h->value.data, h->value.data + h->value.len,
5040 (u_char *) "close", 5 - 1) 5165 (u_char *) "close", 5 - 1)
5041 != NULL) 5166 != NULL)
5042 { 5167 {
5043 r->upstream->headers_in.connection_close = 1; 5168 u->headers_in.connection_close = 1;
5044 } 5169 }
5045 5170
5046 return NGX_OK; 5171 return NGX_OK;
5047 } 5172 }
5048 5173
5049 5174
5050 static ngx_int_t 5175 static ngx_int_t
5051 ngx_http_upstream_process_transfer_encoding(ngx_http_request_t *r, 5176 ngx_http_upstream_process_transfer_encoding(ngx_http_request_t *r,
5052 ngx_table_elt_t *h, ngx_uint_t offset) 5177 ngx_table_elt_t *h, ngx_uint_t offset)
5053 { 5178 {
5054 r->upstream->headers_in.transfer_encoding = h; 5179 ngx_http_upstream_t *u;
5055 5180
5056 if (ngx_strlcasestrn(h->value.data, h->value.data + h->value.len, 5181 u = r->upstream;
5057 (u_char *) "chunked", 7 - 1) 5182
5058 != NULL) 5183 if (u->headers_in.transfer_encoding) {
5184 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
5185 "upstream sent duplicate header line: \"%V: %V\", "
5186 "previous value: \"%V: %V\"",
5187 &h->key, &h->value,
5188 &u->headers_in.transfer_encoding->key,
5189 &u->headers_in.transfer_encoding->value);
5190 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
5191 }
5192
5193 if (u->headers_in.content_length) {
5194 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
5195 "upstream sent \"Content-Length\" and "
5196 "\"Transfer-Encoding\" headers at the same time");
5197 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
5198 }
5199
5200 u->headers_in.transfer_encoding = h;
5201 h->next = NULL;
5202
5203 if (h->value.len == 7
5204 && ngx_strncasecmp(h->value.data, (u_char *) "chunked", 7) == 0)
5059 { 5205 {
5060 r->upstream->headers_in.chunked = 1; 5206 u->headers_in.chunked = 1;
5207
5208 } else {
5209 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
5210 "upstream sent unknown \"Transfer-Encoding\": \"%V\"",
5211 &h->value);
5212 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
5061 } 5213 }
5062 5214
5063 return NGX_OK; 5215 return NGX_OK;
5064 } 5216 }
5065 5217
5066 5218
5067 static ngx_int_t 5219 static ngx_int_t
5068 ngx_http_upstream_process_vary(ngx_http_request_t *r, 5220 ngx_http_upstream_process_vary(ngx_http_request_t *r,
5069 ngx_table_elt_t *h, ngx_uint_t offset) 5221 ngx_table_elt_t *h, ngx_uint_t offset)
5070 { 5222 {
5071 ngx_http_upstream_t *u; 5223 ngx_table_elt_t **ph;
5224 ngx_http_upstream_t *u;
5072 5225
5073 u = r->upstream; 5226 u = r->upstream;
5074 u->headers_in.vary = h; 5227 ph = &u->headers_in.vary;
5228
5229 while (*ph) { ph = &(*ph)->next; }
5230
5231 *ph = h;
5232 h->next = NULL;
5075 5233
5076 #if (NGX_HTTP_CACHE) 5234 #if (NGX_HTTP_CACHE)
5235 {
5236 u_char *p;
5237 size_t len;
5238 ngx_str_t vary;
5077 5239
5078 if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_VARY) { 5240 if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_VARY) {
5079 return NGX_OK; 5241 return NGX_OK;
5080 } 5242 }
5081 5243
5082 if (r->cache == NULL) { 5244 if (r->cache == NULL || !u->cacheable) {
5083 return NGX_OK; 5245 return NGX_OK;
5084 } 5246 }
5085 5247
5086 if (h->value.len > NGX_HTTP_CACHE_VARY_LEN 5248 if (h->value.len == 1 && h->value.data[0] == '*') {
5087 || (h->value.len == 1 && h->value.data[0] == '*'))
5088 {
5089 u->cacheable = 0; 5249 u->cacheable = 0;
5090 } 5250 return NGX_OK;
5091 5251 }
5092 r->cache->vary = h->value; 5252
5093 5253 if (u->headers_in.vary->next) {
5254
5255 len = 0;
5256
5257 for (h = u->headers_in.vary; h; h = h->next) {
5258 len += h->value.len + 2;
5259 }
5260
5261 len -= 2;
5262
5263 p = ngx_pnalloc(r->pool, len);
5264 if (p == NULL) {
5265 return NGX_ERROR;
5266 }
5267
5268 vary.len = len;
5269 vary.data = p;
5270
5271 for (h = u->headers_in.vary; h; h = h->next) {
5272 p = ngx_copy(p, h->value.data, h->value.len);
5273
5274 if (h->next == NULL) {
5275 break;
5276 }
5277
5278 *p++ = ','; *p++ = ' ';
5279 }
5280
5281 } else {
5282 vary = h->value;
5283 }
5284
5285 if (vary.len > NGX_HTTP_CACHE_VARY_LEN) {
5286 u->cacheable = 0;
5287 }
5288
5289 r->cache->vary = vary;
5290 }
5094 #endif 5291 #endif
5095 5292
5096 return NGX_OK; 5293 return NGX_OK;
5097 } 5294 }
5098 5295
5111 *ho = *h; 5308 *ho = *h;
5112 5309
5113 if (offset) { 5310 if (offset) {
5114 ph = (ngx_table_elt_t **) ((char *) &r->headers_out + offset); 5311 ph = (ngx_table_elt_t **) ((char *) &r->headers_out + offset);
5115 *ph = ho; 5312 *ph = ho;
5313 ho->next = NULL;
5116 } 5314 }
5117 5315
5118 return NGX_OK; 5316 return NGX_OK;
5119 } 5317 }
5120 5318
5121 5319
5122 static ngx_int_t 5320 static ngx_int_t
5123 ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r, 5321 ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r,
5124 ngx_table_elt_t *h, ngx_uint_t offset) 5322 ngx_table_elt_t *h, ngx_uint_t offset)
5125 { 5323 {
5126 ngx_array_t *pa;
5127 ngx_table_elt_t *ho, **ph; 5324 ngx_table_elt_t *ho, **ph;
5128
5129 pa = (ngx_array_t *) ((char *) &r->headers_out + offset);
5130
5131 if (pa->elts == NULL) {
5132 if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK)
5133 {
5134 return NGX_ERROR;
5135 }
5136 }
5137 5325
5138 ho = ngx_list_push(&r->headers_out.headers); 5326 ho = ngx_list_push(&r->headers_out.headers);
5139 if (ho == NULL) { 5327 if (ho == NULL) {
5140 return NGX_ERROR; 5328 return NGX_ERROR;
5141 } 5329 }
5142 5330
5143 *ho = *h; 5331 *ho = *h;
5144 5332
5145 ph = ngx_array_push(pa); 5333 ph = (ngx_table_elt_t **) ((char *) &r->headers_out + offset);
5146 if (ph == NULL) { 5334
5147 return NGX_ERROR; 5335 while (*ph) { ph = &(*ph)->next; }
5148 }
5149 5336
5150 *ph = ho; 5337 *ph = ho;
5338 ho->next = NULL;
5151 5339
5152 return NGX_OK; 5340 return NGX_OK;
5153 } 5341 }
5154 5342
5155 5343
5215 if (ho == NULL) { 5403 if (ho == NULL) {
5216 return NGX_ERROR; 5404 return NGX_ERROR;
5217 } 5405 }
5218 5406
5219 *ho = *h; 5407 *ho = *h;
5408 ho->next = NULL;
5220 5409
5221 r->headers_out.last_modified = ho; 5410 r->headers_out.last_modified = ho;
5222 r->headers_out.last_modified_time = 5411 r->headers_out.last_modified_time =
5223 r->upstream->headers_in.last_modified_time; 5412 r->upstream->headers_in.last_modified_time;
5224 5413
5237 if (ho == NULL) { 5426 if (ho == NULL) {
5238 return NGX_ERROR; 5427 return NGX_ERROR;
5239 } 5428 }
5240 5429
5241 *ho = *h; 5430 *ho = *h;
5431 ho->next = NULL;
5242 5432
5243 if (r->upstream->rewrite_redirect) { 5433 if (r->upstream->rewrite_redirect) {
5244 rc = r->upstream->rewrite_redirect(r, ho, 0); 5434 rc = r->upstream->rewrite_redirect(r, ho, 0);
5245 5435
5246 if (rc == NGX_DECLINED) { 5436 if (rc == NGX_DECLINED) {
5282 if (ho == NULL) { 5472 if (ho == NULL) {
5283 return NGX_ERROR; 5473 return NGX_ERROR;
5284 } 5474 }
5285 5475
5286 *ho = *h; 5476 *ho = *h;
5477 ho->next = NULL;
5287 5478
5288 if (r->upstream->rewrite_redirect) { 5479 if (r->upstream->rewrite_redirect) {
5289 5480
5290 p = ngx_strcasestrn(ho->value.data, "url=", 4 - 1); 5481 p = ngx_strcasestrn(ho->value.data, "url=", 4 - 1);
5291 5482
5327 if (ho == NULL) { 5518 if (ho == NULL) {
5328 return NGX_ERROR; 5519 return NGX_ERROR;
5329 } 5520 }
5330 5521
5331 *ho = *h; 5522 *ho = *h;
5523 ho->next = NULL;
5332 5524
5333 if (r->upstream->rewrite_cookie) { 5525 if (r->upstream->rewrite_cookie) {
5334 rc = r->upstream->rewrite_cookie(r, ho); 5526 rc = r->upstream->rewrite_cookie(r, ho);
5335 5527
5336 if (rc == NGX_DECLINED) { 5528 if (rc == NGX_DECLINED) {
5380 if (ho == NULL) { 5572 if (ho == NULL) {
5381 return NGX_ERROR; 5573 return NGX_ERROR;
5382 } 5574 }
5383 5575
5384 *ho = *h; 5576 *ho = *h;
5577 ho->next = NULL;
5385 5578
5386 r->headers_out.accept_ranges = ho; 5579 r->headers_out.accept_ranges = ho;
5387 5580
5388 return NGX_OK; 5581 return NGX_OK;
5389 } 5582 }
5390
5391
5392 #if (NGX_HTTP_GZIP)
5393
5394 static ngx_int_t
5395 ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r,
5396 ngx_table_elt_t *h, ngx_uint_t offset)
5397 {
5398 ngx_table_elt_t *ho;
5399
5400 ho = ngx_list_push(&r->headers_out.headers);
5401 if (ho == NULL) {
5402 return NGX_ERROR;
5403 }
5404
5405 *ho = *h;
5406
5407 r->headers_out.content_encoding = ho;
5408
5409 return NGX_OK;
5410 }
5411
5412 #endif
5413 5583
5414 5584
5415 static ngx_int_t 5585 static ngx_int_t
5416 ngx_http_upstream_add_variables(ngx_conf_t *cf) 5586 ngx_http_upstream_add_variables(ngx_conf_t *cf)
5417 { 5587 {
5721 if (r->upstream == NULL) { 5891 if (r->upstream == NULL) {
5722 v->not_found = 1; 5892 v->not_found = 1;
5723 return NGX_OK; 5893 return NGX_OK;
5724 } 5894 }
5725 5895
5726 return ngx_http_variable_unknown_header(v, (ngx_str_t *) data, 5896 return ngx_http_variable_unknown_header(r, v, (ngx_str_t *) data,
5727 &r->upstream->headers_in.headers.part, 5897 &r->upstream->headers_in.headers.part,
5728 sizeof("upstream_http_") - 1); 5898 sizeof("upstream_http_") - 1);
5729 } 5899 }
5730 5900
5731 5901
5736 if (r->upstream == NULL) { 5906 if (r->upstream == NULL) {
5737 v->not_found = 1; 5907 v->not_found = 1;
5738 return NGX_OK; 5908 return NGX_OK;
5739 } 5909 }
5740 5910
5741 return ngx_http_variable_unknown_header(v, (ngx_str_t *) data, 5911 return ngx_http_variable_unknown_header(r, v, (ngx_str_t *) data,
5742 &r->upstream->headers_in.trailers.part, 5912 &r->upstream->headers_in.trailers.part,
5743 sizeof("upstream_trailer_") - 1); 5913 sizeof("upstream_trailer_") - 1);
5744 } 5914 }
5745 5915
5746 5916
5758 } 5928 }
5759 5929
5760 s.len = name->len - (sizeof("upstream_cookie_") - 1); 5930 s.len = name->len - (sizeof("upstream_cookie_") - 1);
5761 s.data = name->data + sizeof("upstream_cookie_") - 1; 5931 s.data = name->data + sizeof("upstream_cookie_") - 1;
5762 5932
5763 if (ngx_http_parse_set_cookie_lines(&r->upstream->headers_in.cookies, 5933 if (ngx_http_parse_set_cookie_lines(r, r->upstream->headers_in.set_cookie,
5764 &s, &cookie) 5934 &s, &cookie)
5765 == NGX_DECLINED) 5935 == NULL)
5766 { 5936 {
5767 v->not_found = 1; 5937 v->not_found = 1;
5768 return NGX_OK; 5938 return NGX_OK;
5769 } 5939 }
5770 5940