Groonga 3.0.9 Source Code Document
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ngx_http_proxy_module.c
Go to the documentation of this file.
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_http.h>
11 
12 
14 
16  ngx_table_elt_t *h, size_t prefix, size_t len,
18 
21 
22  union {
24 #if (NGX_PCRE)
25  ngx_http_regex_t *regex;
26 #endif
27  } pattern;
28 
30 };
31 
32 
33 typedef struct {
40 
41 
42 typedef struct {
44 
51 
53 
56 
60 
62 
66 
67 #if (NGX_HTTP_CACHE)
68  ngx_http_complex_value_t cache_key;
69 #endif
70 
72 
74 
76 
80 
81 
82 typedef struct {
87 
88  ngx_uint_t head; /* unsigned head:1 */
90 
91 
92 static ngx_int_t ngx_http_proxy_eval(ngx_http_request_t *r,
94 #if (NGX_HTTP_CACHE)
95 static ngx_int_t ngx_http_proxy_create_key(ngx_http_request_t *r);
96 #endif
97 static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r);
98 static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r);
99 static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r);
100 static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r);
101 static ngx_int_t ngx_http_proxy_input_filter_init(void *data);
102 static ngx_int_t ngx_http_proxy_copy_filter(ngx_event_pipe_t *p,
103  ngx_buf_t *buf);
104 static ngx_int_t ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p,
105  ngx_buf_t *buf);
106 static ngx_int_t ngx_http_proxy_non_buffered_copy_filter(void *data,
107  ssize_t bytes);
108 static ngx_int_t ngx_http_proxy_non_buffered_chunked_filter(void *data,
109  ssize_t bytes);
110 static void ngx_http_proxy_abort_request(ngx_http_request_t *r);
111 static void ngx_http_proxy_finalize_request(ngx_http_request_t *r,
112  ngx_int_t rc);
113 
114 static ngx_int_t ngx_http_proxy_host_variable(ngx_http_request_t *r,
115  ngx_http_variable_value_t *v, uintptr_t data);
116 static ngx_int_t ngx_http_proxy_port_variable(ngx_http_request_t *r,
117  ngx_http_variable_value_t *v, uintptr_t data);
118 static ngx_int_t
119  ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
120  ngx_http_variable_value_t *v, uintptr_t data);
121 static ngx_int_t
122  ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
123  ngx_http_variable_value_t *v, uintptr_t data);
124 static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r,
125  ngx_table_elt_t *h, size_t prefix);
126 static ngx_int_t ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r,
127  ngx_table_elt_t *h);
128 static ngx_int_t ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r,
129  ngx_table_elt_t *h, u_char *value, ngx_array_t *rewrites);
130 static ngx_int_t ngx_http_proxy_rewrite(ngx_http_request_t *r,
131  ngx_table_elt_t *h, size_t prefix, size_t len, ngx_str_t *replacement);
132 
133 static ngx_int_t ngx_http_proxy_add_variables(ngx_conf_t *cf);
134 static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf);
135 static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf,
136  void *parent, void *child);
137 static ngx_int_t ngx_http_proxy_merge_headers(ngx_conf_t *cf,
139 
140 static char *ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd,
141  void *conf);
142 static char *ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd,
143  void *conf);
144 static char *ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd,
145  void *conf);
146 static char *ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd,
147  void *conf);
148 static char *ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd,
149  void *conf);
150 #if (NGX_HTTP_CACHE)
151 static char *ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd,
152  void *conf);
153 static char *ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd,
154  void *conf);
155 #endif
156 
157 static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data);
158 
159 static ngx_int_t ngx_http_proxy_rewrite_regex(ngx_conf_t *cf,
160  ngx_http_proxy_rewrite_t *pr, ngx_str_t *regex, ngx_uint_t caseless);
161 
162 #if (NGX_HTTP_SSL)
163 static ngx_int_t ngx_http_proxy_set_ssl(ngx_conf_t *cf,
165 #endif
166 static void ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v);
167 
168 
169 static ngx_conf_post_t ngx_http_proxy_lowat_post =
170  { ngx_http_proxy_lowat_check };
171 
172 
173 static ngx_conf_bitmask_t ngx_http_proxy_next_upstream_masks[] = {
176  { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
177  { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
178  { ngx_string("http_502"), NGX_HTTP_UPSTREAM_FT_HTTP_502 },
179  { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
180  { ngx_string("http_504"), NGX_HTTP_UPSTREAM_FT_HTTP_504 },
181  { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
182  { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING },
184  { ngx_null_string, 0 }
185 };
186 
187 
188 static ngx_conf_enum_t ngx_http_proxy_http_version[] = {
189  { ngx_string("1.0"), NGX_HTTP_VERSION_10 },
190  { ngx_string("1.1"), NGX_HTTP_VERSION_11 },
191  { ngx_null_string, 0 }
192 };
193 
194 
196 
197 
198 static ngx_command_t ngx_http_proxy_commands[] = {
199 
200  { ngx_string("proxy_pass"),
202  ngx_http_proxy_pass,
204  0,
205  NULL },
206 
207  { ngx_string("proxy_redirect"),
209  ngx_http_proxy_redirect,
211  0,
212  NULL },
213 
214  { ngx_string("proxy_cookie_domain"),
216  ngx_http_proxy_cookie_domain,
218  0,
219  NULL },
220 
221  { ngx_string("proxy_cookie_path"),
223  ngx_http_proxy_cookie_path,
225  0,
226  NULL },
227 
228  { ngx_string("proxy_store"),
230  ngx_http_proxy_store,
232  0,
233  NULL },
234 
235  { ngx_string("proxy_store_access"),
239  offsetof(ngx_http_proxy_loc_conf_t, upstream.store_access),
240  NULL },
241 
242  { ngx_string("proxy_buffering"),
246  offsetof(ngx_http_proxy_loc_conf_t, upstream.buffering),
247  NULL },
248 
249  { ngx_string("proxy_ignore_client_abort"),
253  offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_client_abort),
254  NULL },
255 
256  { ngx_string("proxy_bind"),
260  offsetof(ngx_http_proxy_loc_conf_t, upstream.local),
261  NULL },
262 
263  { ngx_string("proxy_connect_timeout"),
267  offsetof(ngx_http_proxy_loc_conf_t, upstream.connect_timeout),
268  NULL },
269 
270  { ngx_string("proxy_send_timeout"),
274  offsetof(ngx_http_proxy_loc_conf_t, upstream.send_timeout),
275  NULL },
276 
277  { ngx_string("proxy_send_lowat"),
281  offsetof(ngx_http_proxy_loc_conf_t, upstream.send_lowat),
282  &ngx_http_proxy_lowat_post },
283 
284  { ngx_string("proxy_intercept_errors"),
288  offsetof(ngx_http_proxy_loc_conf_t, upstream.intercept_errors),
289  NULL },
290 
291  { ngx_string("proxy_set_header"),
295  offsetof(ngx_http_proxy_loc_conf_t, headers_source),
296  NULL },
297 
298  { ngx_string("proxy_headers_hash_max_size"),
302  offsetof(ngx_http_proxy_loc_conf_t, headers_hash_max_size),
303  NULL },
304 
305  { ngx_string("proxy_headers_hash_bucket_size"),
309  offsetof(ngx_http_proxy_loc_conf_t, headers_hash_bucket_size),
310  NULL },
311 
312  { ngx_string("proxy_set_body"),
316  offsetof(ngx_http_proxy_loc_conf_t, body_source),
317  NULL },
318 
319  { ngx_string("proxy_method"),
323  offsetof(ngx_http_proxy_loc_conf_t, method),
324  NULL },
325 
326  { ngx_string("proxy_pass_request_headers"),
330  offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_headers),
331  NULL },
332 
333  { ngx_string("proxy_pass_request_body"),
337  offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_body),
338  NULL },
339 
340  { ngx_string("proxy_buffer_size"),
344  offsetof(ngx_http_proxy_loc_conf_t, upstream.buffer_size),
345  NULL },
346 
347  { ngx_string("proxy_read_timeout"),
351  offsetof(ngx_http_proxy_loc_conf_t, upstream.read_timeout),
352  NULL },
353 
354  { ngx_string("proxy_buffers"),
358  offsetof(ngx_http_proxy_loc_conf_t, upstream.bufs),
359  NULL },
360 
361  { ngx_string("proxy_busy_buffers_size"),
365  offsetof(ngx_http_proxy_loc_conf_t, upstream.busy_buffers_size_conf),
366  NULL },
367 
368 #if (NGX_HTTP_CACHE)
369 
370  { ngx_string("proxy_cache"),
372  ngx_http_proxy_cache,
374  0,
375  NULL },
376 
377  { ngx_string("proxy_cache_key"),
379  ngx_http_proxy_cache_key,
381  0,
382  NULL },
383 
384  { ngx_string("proxy_cache_path"),
387  0,
388  0,
389  &ngx_http_proxy_module },
390 
391  { ngx_string("proxy_cache_bypass"),
395  offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_bypass),
396  NULL },
397 
398  { ngx_string("proxy_no_cache"),
402  offsetof(ngx_http_proxy_loc_conf_t, upstream.no_cache),
403  NULL },
404 
405  { ngx_string("proxy_cache_valid"),
409  offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_valid),
410  NULL },
411 
412  { ngx_string("proxy_cache_min_uses"),
416  offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_min_uses),
417  NULL },
418 
419  { ngx_string("proxy_cache_use_stale"),
423  offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_use_stale),
424  &ngx_http_proxy_next_upstream_masks },
425 
426  { ngx_string("proxy_cache_methods"),
430  offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_methods),
432 
433  { ngx_string("proxy_cache_lock"),
437  offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock),
438  NULL },
439 
440  { ngx_string("proxy_cache_lock_timeout"),
444  offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock_timeout),
445  NULL },
446 
447 #endif
448 
449  { ngx_string("proxy_temp_path"),
453  offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_path),
454  NULL },
455 
456  { ngx_string("proxy_max_temp_file_size"),
460  offsetof(ngx_http_proxy_loc_conf_t, upstream.max_temp_file_size_conf),
461  NULL },
462 
463  { ngx_string("proxy_temp_file_write_size"),
467  offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_file_write_size_conf),
468  NULL },
469 
470  { ngx_string("proxy_next_upstream"),
474  offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream),
475  &ngx_http_proxy_next_upstream_masks },
476 
477  { ngx_string("proxy_pass_header"),
481  offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_headers),
482  NULL },
483 
484  { ngx_string("proxy_hide_header"),
488  offsetof(ngx_http_proxy_loc_conf_t, upstream.hide_headers),
489  NULL },
490 
491  { ngx_string("proxy_ignore_headers"),
495  offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_headers),
497 
498  { ngx_string("proxy_http_version"),
502  offsetof(ngx_http_proxy_loc_conf_t, http_version),
503  &ngx_http_proxy_http_version },
504 
505 #if (NGX_HTTP_SSL)
506 
507  { ngx_string("proxy_ssl_session_reuse"),
511  offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_session_reuse),
512  NULL },
513 
514 #endif
515 
517 };
518 
519 
520 static ngx_http_module_t ngx_http_proxy_module_ctx = {
521  ngx_http_proxy_add_variables, /* preconfiguration */
522  NULL, /* postconfiguration */
523 
524  NULL, /* create main configuration */
525  NULL, /* init main configuration */
526 
527  NULL, /* create server configuration */
528  NULL, /* merge server configuration */
529 
530  ngx_http_proxy_create_loc_conf, /* create location configuration */
531  ngx_http_proxy_merge_loc_conf /* merge location configuration */
532 };
533 
534 
535 ngx_module_t ngx_http_proxy_module = {
537  &ngx_http_proxy_module_ctx, /* module context */
538  ngx_http_proxy_commands, /* module directives */
539  NGX_HTTP_MODULE, /* module type */
540  NULL, /* init master */
541  NULL, /* init module */
542  NULL, /* init process */
543  NULL, /* init thread */
544  NULL, /* exit thread */
545  NULL, /* exit process */
546  NULL, /* exit master */
548 };
549 
550 
551 static char ngx_http_proxy_version[] = " HTTP/1.0" CRLF;
552 static char ngx_http_proxy_version_11[] = " HTTP/1.1" CRLF;
553 
554 
555 static ngx_keyval_t ngx_http_proxy_headers[] = {
556  { ngx_string("Host"), ngx_string("$proxy_host") },
557  { ngx_string("Connection"), ngx_string("close") },
558  { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
559  { ngx_string("Transfer-Encoding"), ngx_string("") },
560  { ngx_string("Keep-Alive"), ngx_string("") },
561  { ngx_string("Expect"), ngx_string("") },
562  { ngx_string("Upgrade"), ngx_string("") },
564 };
565 
566 
567 static ngx_str_t ngx_http_proxy_hide_headers[] = {
568  ngx_string("Date"),
569  ngx_string("Server"),
570  ngx_string("X-Pad"),
571  ngx_string("X-Accel-Expires"),
572  ngx_string("X-Accel-Redirect"),
573  ngx_string("X-Accel-Limit-Rate"),
574  ngx_string("X-Accel-Buffering"),
575  ngx_string("X-Accel-Charset"),
577 };
578 
579 
580 #if (NGX_HTTP_CACHE)
581 
582 static ngx_keyval_t ngx_http_proxy_cache_headers[] = {
583  { ngx_string("Host"), ngx_string("$proxy_host") },
584  { ngx_string("Connection"), ngx_string("close") },
585  { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
586  { ngx_string("Transfer-Encoding"), ngx_string("") },
587  { ngx_string("Keep-Alive"), ngx_string("") },
588  { ngx_string("Expect"), ngx_string("") },
589  { ngx_string("Upgrade"), ngx_string("") },
590  { ngx_string("If-Modified-Since"), ngx_string("") },
591  { ngx_string("If-Unmodified-Since"), ngx_string("") },
592  { ngx_string("If-None-Match"), ngx_string("") },
593  { ngx_string("If-Match"), ngx_string("") },
594  { ngx_string("Range"), ngx_string("") },
595  { ngx_string("If-Range"), ngx_string("") },
597 };
598 
599 #endif
600 
601 
602 static ngx_http_variable_t ngx_http_proxy_vars[] = {
603 
604  { ngx_string("proxy_host"), NULL, ngx_http_proxy_host_variable, 0,
606 
607  { ngx_string("proxy_port"), NULL, ngx_http_proxy_port_variable, 0,
609 
610  { ngx_string("proxy_add_x_forwarded_for"), NULL,
611  ngx_http_proxy_add_x_forwarded_for_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
612 
613 #if 0
614  { ngx_string("proxy_add_via"), NULL, NULL, 0, NGX_HTTP_VAR_NOHASH, 0 },
615 #endif
616 
617  { ngx_string("proxy_internal_body_length"), NULL,
618  ngx_http_proxy_internal_body_length_variable, 0,
620 
621  { ngx_null_string, NULL, NULL, 0, 0, 0 }
622 };
623 
624 
625 static ngx_path_init_t ngx_http_proxy_temp_path = {
627 };
628 
629 
630 static ngx_int_t
631 ngx_http_proxy_handler(ngx_http_request_t *r)
632 {
633  ngx_int_t rc;
637 
638  if (ngx_http_upstream_create(r) != NGX_OK) {
640  }
641 
642  ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t));
643  if (ctx == NULL) {
644  return NGX_ERROR;
645  }
646 
647  ngx_http_set_ctx(r, ctx, ngx_http_proxy_module);
648 
649  plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
650 
651  u = r->upstream;
652 
653  if (plcf->proxy_lengths == NULL) {
654  ctx->vars = plcf->vars;
655  u->schema = plcf->vars.schema;
656 #if (NGX_HTTP_SSL)
657  u->ssl = (plcf->upstream.ssl != NULL);
658 #endif
659 
660  } else {
661  if (ngx_http_proxy_eval(r, ctx, plcf) != NGX_OK) {
663  }
664  }
665 
666  u->output.tag = (ngx_buf_tag_t) &ngx_http_proxy_module;
667 
668  u->conf = &plcf->upstream;
669 
670 #if (NGX_HTTP_CACHE)
671  u->create_key = ngx_http_proxy_create_key;
672 #endif
673  u->create_request = ngx_http_proxy_create_request;
674  u->reinit_request = ngx_http_proxy_reinit_request;
675  u->process_header = ngx_http_proxy_process_status_line;
676  u->abort_request = ngx_http_proxy_abort_request;
677  u->finalize_request = ngx_http_proxy_finalize_request;
678  r->state = 0;
679 
680  if (plcf->redirects) {
681  u->rewrite_redirect = ngx_http_proxy_rewrite_redirect;
682  }
683 
684  if (plcf->cookie_domains || plcf->cookie_paths) {
685  u->rewrite_cookie = ngx_http_proxy_rewrite_cookie;
686  }
687 
688  u->buffering = plcf->upstream.buffering;
689 
690  u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
691  if (u->pipe == NULL) {
693  }
694 
695  u->pipe->input_filter = ngx_http_proxy_copy_filter;
696  u->pipe->input_ctx = r;
697 
698  u->input_filter_init = ngx_http_proxy_input_filter_init;
699  u->input_filter = ngx_http_proxy_non_buffered_copy_filter;
700  u->input_filter_ctx = r;
701 
702  u->accel = 1;
703 
705 
706  if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
707  return rc;
708  }
709 
710  return NGX_DONE;
711 }
712 
713 
714 static ngx_int_t
715 ngx_http_proxy_eval(ngx_http_request_t *r, ngx_http_proxy_ctx_t *ctx,
717 {
718  u_char *p;
719  size_t add;
720  u_short port;
721  ngx_str_t proxy;
722  ngx_url_t url;
724 
725  if (ngx_http_script_run(r, &proxy, plcf->proxy_lengths->elts, 0,
726  plcf->proxy_values->elts)
727  == NULL)
728  {
729  return NGX_ERROR;
730  }
731 
732  if (proxy.len > 7
733  && ngx_strncasecmp(proxy.data, (u_char *) "http://", 7) == 0)
734  {
735  add = 7;
736  port = 80;
737 
738 #if (NGX_HTTP_SSL)
739 
740  } else if (proxy.len > 8
741  && ngx_strncasecmp(proxy.data, (u_char *) "https://", 8) == 0)
742  {
743  add = 8;
744  port = 443;
745  r->upstream->ssl = 1;
746 
747 #endif
748 
749  } else {
751  "invalid URL prefix in \"%V\"", &proxy);
752  return NGX_ERROR;
753  }
754 
755  u = r->upstream;
756 
757  u->schema.len = add;
758  u->schema.data = proxy.data;
759 
760  ngx_memzero(&url, sizeof(ngx_url_t));
761 
762  url.url.len = proxy.len - add;
763  url.url.data = proxy.data + add;
764  url.default_port = port;
765  url.uri_part = 1;
766  url.no_resolve = 1;
767 
768  if (ngx_parse_url(r->pool, &url) != NGX_OK) {
769  if (url.err) {
771  "%s in upstream \"%V\"", url.err, &url.url);
772  }
773 
774  return NGX_ERROR;
775  }
776 
777  if (url.uri.len) {
778  if (url.uri.data[0] == '?') {
779  p = ngx_pnalloc(r->pool, url.uri.len + 1);
780  if (p == NULL) {
781  return NGX_ERROR;
782  }
783 
784  *p++ = '/';
785  ngx_memcpy(p, url.uri.data, url.uri.len);
786 
787  url.uri.len++;
788  url.uri.data = p - 1;
789  }
790  }
791 
792  ctx->vars.key_start = u->schema;
793 
794  ngx_http_proxy_set_vars(&url, &ctx->vars);
795 
797  if (u->resolved == NULL) {
798  return NGX_ERROR;
799  }
800 
801  if (url.addrs && url.addrs[0].sockaddr) {
802  u->resolved->sockaddr = url.addrs[0].sockaddr;
803  u->resolved->socklen = url.addrs[0].socklen;
804  u->resolved->naddrs = 1;
805  u->resolved->host = url.addrs[0].name;
806 
807  } else {
808  u->resolved->host = url.host;
809  u->resolved->port = (in_port_t) (url.no_port ? port : url.port);
810  u->resolved->no_port = url.no_port;
811  }
812 
813  return NGX_OK;
814 }
815 
816 
817 #if (NGX_HTTP_CACHE)
818 
819 static ngx_int_t
820 ngx_http_proxy_create_key(ngx_http_request_t *r)
821 {
822  size_t len, loc_len;
823  u_char *p;
824  uintptr_t escape;
825  ngx_str_t *key;
829 
830  u = r->upstream;
831 
832  plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
833 
834  ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
835 
836  key = ngx_array_push(&r->cache->keys);
837  if (key == NULL) {
838  return NGX_ERROR;
839  }
840 
841  if (plcf->cache_key.value.data) {
842 
843  if (ngx_http_complex_value(r, &plcf->cache_key, key) != NGX_OK) {
844  return NGX_ERROR;
845  }
846 
847  return NGX_OK;
848  }
849 
850  *key = ctx->vars.key_start;
851 
852  key = ngx_array_push(&r->cache->keys);
853  if (key == NULL) {
854  return NGX_ERROR;
855  }
856 
857  if (plcf->proxy_lengths && ctx->vars.uri.len) {
858 
859  *key = ctx->vars.uri;
860  u->uri = ctx->vars.uri;
861 
862  return NGX_OK;
863 
864  } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main)
865  {
866  *key = r->unparsed_uri;
867  u->uri = r->unparsed_uri;
868 
869  return NGX_OK;
870  }
871 
872  loc_len = (r->valid_location && ctx->vars.uri.len) ? plcf->location.len : 0;
873 
874  if (r->quoted_uri || r->internal) {
875  escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
876  r->uri.len - loc_len, NGX_ESCAPE_URI);
877  } else {
878  escape = 0;
879  }
880 
881  len = ctx->vars.uri.len + r->uri.len - loc_len + escape
882  + sizeof("?") - 1 + r->args.len;
883 
884  p = ngx_pnalloc(r->pool, len);
885  if (p == NULL) {
886  return NGX_ERROR;
887  }
888 
889  key->data = p;
890 
891  if (r->valid_location) {
892  p = ngx_copy(p, ctx->vars.uri.data, ctx->vars.uri.len);
893  }
894 
895  if (escape) {
896  ngx_escape_uri(p, r->uri.data + loc_len,
897  r->uri.len - loc_len, NGX_ESCAPE_URI);
898  p += r->uri.len - loc_len + escape;
899 
900  } else {
901  p = ngx_copy(p, r->uri.data + loc_len, r->uri.len - loc_len);
902  }
903 
904  if (r->args.len > 0) {
905  *p++ = '?';
906  p = ngx_copy(p, r->args.data, r->args.len);
907  }
908 
909  key->len = p - key->data;
910  u->uri = *key;
911 
912  return NGX_OK;
913 }
914 
915 #endif
916 
917 
918 static ngx_int_t
919 ngx_http_proxy_create_request(ngx_http_request_t *r)
920 {
921  size_t len, uri_len, loc_len, body_len;
922  uintptr_t escape;
923  ngx_buf_t *b;
924  ngx_str_t method;
925  ngx_uint_t i, unparsed_uri;
926  ngx_chain_t *cl, *body;
927  ngx_list_part_t *part;
928  ngx_table_elt_t *header;
935 
936  u = r->upstream;
937 
938  plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
939 
940  if (u->method.len) {
941  /* HEAD was changed to GET to cache response */
942  method = u->method;
943  method.len++;
944 
945  } else if (plcf->method.len) {
946  method = plcf->method;
947 
948  } else {
949  method = r->method_name;
950  method.len++;
951  }
952 
953  ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
954 
955  if (method.len == 5
956  && ngx_strncasecmp(method.data, (u_char *) "HEAD ", 5) == 0)
957  {
958  ctx->head = 1;
959  }
960 
961  len = method.len + sizeof(ngx_http_proxy_version) - 1 + sizeof(CRLF) - 1;
962 
963  escape = 0;
964  loc_len = 0;
965  unparsed_uri = 0;
966 
967  if (plcf->proxy_lengths && ctx->vars.uri.len) {
968  uri_len = ctx->vars.uri.len;
969 
970  } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main)
971  {
972  unparsed_uri = 1;
973  uri_len = r->unparsed_uri.len;
974 
975  } else {
976  loc_len = (r->valid_location && ctx->vars.uri.len) ?
977  plcf->location.len : 0;
978 
979  if (r->quoted_uri || r->space_in_uri || r->internal) {
980  escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
981  r->uri.len - loc_len, NGX_ESCAPE_URI);
982  }
983 
984  uri_len = ctx->vars.uri.len + r->uri.len - loc_len + escape
985  + sizeof("?") - 1 + r->args.len;
986  }
987 
988  if (uri_len == 0) {
990  "zero length URI to proxy");
991  return NGX_ERROR;
992  }
993 
994  len += uri_len;
995 
997 
998  if (plcf->body_set_len) {
999  le.ip = plcf->body_set_len->elts;
1000  le.request = r;
1001  le.flushed = 1;
1002  body_len = 0;
1003 
1004  while (*(uintptr_t *) le.ip) {
1005  lcode = *(ngx_http_script_len_code_pt *) le.ip;
1006  body_len += lcode(&le);
1007  }
1008 
1009  ctx->internal_body_length = body_len;
1010  len += body_len;
1011 
1012  } else {
1014  }
1015 
1016  le.ip = plcf->headers_set_len->elts;
1017  le.request = r;
1018  le.flushed = 1;
1019 
1020  while (*(uintptr_t *) le.ip) {
1021  while (*(uintptr_t *) le.ip) {
1022  lcode = *(ngx_http_script_len_code_pt *) le.ip;
1023  len += lcode(&le);
1024  }
1025  le.ip += sizeof(uintptr_t);
1026  }
1027 
1028 
1029  if (plcf->upstream.pass_request_headers) {
1030  part = &r->headers_in.headers.part;
1031  header = part->elts;
1032 
1033  for (i = 0; /* void */; i++) {
1034 
1035  if (i >= part->nelts) {
1036  if (part->next == NULL) {
1037  break;
1038  }
1039 
1040  part = part->next;
1041  header = part->elts;
1042  i = 0;
1043  }
1044 
1045  if (ngx_hash_find(&plcf->headers_set_hash, header[i].hash,
1046  header[i].lowcase_key, header[i].key.len))
1047  {
1048  continue;
1049  }
1050 
1051  len += header[i].key.len + sizeof(": ") - 1
1052  + header[i].value.len + sizeof(CRLF) - 1;
1053  }
1054  }
1055 
1056 
1057  b = ngx_create_temp_buf(r->pool, len);
1058  if (b == NULL) {
1059  return NGX_ERROR;
1060  }
1061 
1062  cl = ngx_alloc_chain_link(r->pool);
1063  if (cl == NULL) {
1064  return NGX_ERROR;
1065  }
1066 
1067  cl->buf = b;
1068 
1069 
1070  /* the request line */
1071 
1072  b->last = ngx_copy(b->last, method.data, method.len);
1073 
1074  u->uri.data = b->last;
1075 
1076  if (plcf->proxy_lengths && ctx->vars.uri.len) {
1077  b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
1078 
1079  } else if (unparsed_uri) {
1080  b->last = ngx_copy(b->last, r->unparsed_uri.data, r->unparsed_uri.len);
1081 
1082  } else {
1083  if (r->valid_location) {
1084  b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
1085  }
1086 
1087  if (escape) {
1088  ngx_escape_uri(b->last, r->uri.data + loc_len,
1089  r->uri.len - loc_len, NGX_ESCAPE_URI);
1090  b->last += r->uri.len - loc_len + escape;
1091 
1092  } else {
1093  b->last = ngx_copy(b->last, r->uri.data + loc_len,
1094  r->uri.len - loc_len);
1095  }
1096 
1097  if (r->args.len > 0) {
1098  *b->last++ = '?';
1099  b->last = ngx_copy(b->last, r->args.data, r->args.len);
1100  }
1101  }
1102 
1103  u->uri.len = b->last - u->uri.data;
1104 
1105  if (plcf->http_version == NGX_HTTP_VERSION_11) {
1106  b->last = ngx_cpymem(b->last, ngx_http_proxy_version_11,
1107  sizeof(ngx_http_proxy_version_11) - 1);
1108 
1109  } else {
1110  b->last = ngx_cpymem(b->last, ngx_http_proxy_version,
1111  sizeof(ngx_http_proxy_version) - 1);
1112  }
1113 
1115 
1116  e.ip = plcf->headers_set->elts;
1117  e.pos = b->last;
1118  e.request = r;
1119  e.flushed = 1;
1120 
1121  le.ip = plcf->headers_set_len->elts;
1122 
1123  while (*(uintptr_t *) le.ip) {
1124  lcode = *(ngx_http_script_len_code_pt *) le.ip;
1125 
1126  /* skip the header line name length */
1127  (void) lcode(&le);
1128 
1129  if (*(ngx_http_script_len_code_pt *) le.ip) {
1130 
1131  for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) {
1132  lcode = *(ngx_http_script_len_code_pt *) le.ip;
1133  }
1134 
1135  e.skip = (len == sizeof(CRLF) - 1) ? 1 : 0;
1136 
1137  } else {
1138  e.skip = 0;
1139  }
1140 
1141  le.ip += sizeof(uintptr_t);
1142 
1143  while (*(uintptr_t *) e.ip) {
1144  code = *(ngx_http_script_code_pt *) e.ip;
1145  code((ngx_http_script_engine_t *) &e);
1146  }
1147  e.ip += sizeof(uintptr_t);
1148  }
1149 
1150  b->last = e.pos;
1151 
1152 
1153  if (plcf->upstream.pass_request_headers) {
1154  part = &r->headers_in.headers.part;
1155  header = part->elts;
1156 
1157  for (i = 0; /* void */; i++) {
1158 
1159  if (i >= part->nelts) {
1160  if (part->next == NULL) {
1161  break;
1162  }
1163 
1164  part = part->next;
1165  header = part->elts;
1166  i = 0;
1167  }
1168 
1169  if (ngx_hash_find(&plcf->headers_set_hash, header[i].hash,
1170  header[i].lowcase_key, header[i].key.len))
1171  {
1172  continue;
1173  }
1174 
1175  b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len);
1176 
1177  *b->last++ = ':'; *b->last++ = ' ';
1178 
1179  b->last = ngx_copy(b->last, header[i].value.data,
1180  header[i].value.len);
1181 
1182  *b->last++ = CR; *b->last++ = LF;
1183 
1185  "http proxy header: \"%V: %V\"",
1186  &header[i].key, &header[i].value);
1187  }
1188  }
1189 
1190 
1191  /* add "\r\n" at the header end */
1192  *b->last++ = CR; *b->last++ = LF;
1193 
1194  if (plcf->body_set) {
1195  e.ip = plcf->body_set->elts;
1196  e.pos = b->last;
1197 
1198  while (*(uintptr_t *) e.ip) {
1199  code = *(ngx_http_script_code_pt *) e.ip;
1200  code((ngx_http_script_engine_t *) &e);
1201  }
1202 
1203  b->last = e.pos;
1204  }
1205 
1207  "http proxy header:\n\"%*s\"",
1208  (size_t) (b->last - b->pos), b->pos);
1209 
1210  if (plcf->body_set == NULL && plcf->upstream.pass_request_body) {
1211 
1212  body = u->request_bufs;
1213  u->request_bufs = cl;
1214 
1215  while (body) {
1216  b = ngx_alloc_buf(r->pool);
1217  if (b == NULL) {
1218  return NGX_ERROR;
1219  }
1220 
1221  ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
1222 
1223  cl->next = ngx_alloc_chain_link(r->pool);
1224  if (cl->next == NULL) {
1225  return NGX_ERROR;
1226  }
1227 
1228  cl = cl->next;
1229  cl->buf = b;
1230 
1231  body = body->next;
1232  }
1233 
1234  } else {
1235  u->request_bufs = cl;
1236  }
1237 
1238  b->flush = 1;
1239  cl->next = NULL;
1240 
1241  return NGX_OK;
1242 }
1243 
1244 
1245 static ngx_int_t
1246 ngx_http_proxy_reinit_request(ngx_http_request_t *r)
1247 {
1248  ngx_http_proxy_ctx_t *ctx;
1249 
1250  ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1251 
1252  if (ctx == NULL) {
1253  return NGX_OK;
1254  }
1255 
1256  ctx->status.code = 0;
1257  ctx->status.count = 0;
1258  ctx->status.start = NULL;
1259  ctx->status.end = NULL;
1260  ctx->chunked.state = 0;
1261 
1262  r->upstream->process_header = ngx_http_proxy_process_status_line;
1263  r->upstream->pipe->input_filter = ngx_http_proxy_copy_filter;
1264  r->upstream->input_filter = ngx_http_proxy_non_buffered_copy_filter;
1265  r->state = 0;
1266 
1267  return NGX_OK;
1268 }
1269 
1270 
1271 static ngx_int_t
1272 ngx_http_proxy_process_status_line(ngx_http_request_t *r)
1273 {
1274  size_t len;
1275  ngx_int_t rc;
1277  ngx_http_proxy_ctx_t *ctx;
1278 
1279  ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1280 
1281  if (ctx == NULL) {
1282  return NGX_ERROR;
1283  }
1284 
1285  u = r->upstream;
1286 
1287  rc = ngx_http_parse_status_line(r, &u->buffer, &ctx->status);
1288 
1289  if (rc == NGX_AGAIN) {
1290  return rc;
1291  }
1292 
1293  if (rc == NGX_ERROR) {
1294 
1295 #if (NGX_HTTP_CACHE)
1296 
1297  if (r->cache) {
1299  return NGX_OK;
1300  }
1301 
1302 #endif
1303 
1305  "upstream sent no valid HTTP/1.0 header");
1306 
1307 #if 0
1308  if (u->accel) {
1310  }
1311 #endif
1312 
1314  u->state->status = NGX_HTTP_OK;
1316 
1317  return NGX_OK;
1318  }
1319 
1320  if (u->state) {
1321  u->state->status = ctx->status.code;
1322  }
1323 
1324  u->headers_in.status_n = ctx->status.code;
1325 
1326  len = ctx->status.end - ctx->status.start;
1327  u->headers_in.status_line.len = len;
1328 
1329  u->headers_in.status_line.data = ngx_pnalloc(r->pool, len);
1330  if (u->headers_in.status_line.data == NULL) {
1331  return NGX_ERROR;
1332  }
1333 
1335 
1337  "http proxy status %ui \"%V\"",
1339 
1342  }
1343 
1344  u->process_header = ngx_http_proxy_process_header;
1345 
1346  return ngx_http_proxy_process_header(r);
1347 }
1348 
1349 
1350 static ngx_int_t
1351 ngx_http_proxy_process_header(ngx_http_request_t *r)
1352 {
1353  ngx_int_t rc;
1354  ngx_table_elt_t *h;
1356  ngx_http_proxy_ctx_t *ctx;
1359 
1361 
1362  for ( ;; ) {
1363 
1364  rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);
1365 
1366  if (rc == NGX_OK) {
1367 
1368  /* a header line has been parsed successfully */
1369 
1371  if (h == NULL) {
1372  return NGX_ERROR;
1373  }
1374 
1375  h->hash = r->header_hash;
1376 
1378  h->value.len = r->header_end - r->header_start;
1379 
1380  h->key.data = ngx_pnalloc(r->pool,
1381  h->key.len + 1 + h->value.len + 1 + h->key.len);
1382  if (h->key.data == NULL) {
1383  return NGX_ERROR;
1384  }
1385 
1386  h->value.data = h->key.data + h->key.len + 1;
1387  h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;
1388 
1390  h->key.data[h->key.len] = '\0';
1391  ngx_memcpy(h->value.data, r->header_start, h->value.len);
1392  h->value.data[h->value.len] = '\0';
1393 
1394  if (h->key.len == r->lowcase_index) {
1396 
1397  } else {
1398  ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
1399  }
1400 
1401  hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
1402  h->lowcase_key, h->key.len);
1403 
1404  if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1405  return NGX_ERROR;
1406  }
1407 
1409  "http proxy header: \"%V: %V\"",
1410  &h->key, &h->value);
1411 
1412  continue;
1413  }
1414 
1415  if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
1416 
1417  /* a whole header has been parsed successfully */
1418 
1420  "http proxy header done");
1421 
1422  /*
1423  * if no "Server" and "Date" in header line,
1424  * then add the special empty headers
1425  */
1426 
1427  if (r->upstream->headers_in.server == NULL) {
1429  if (h == NULL) {
1430  return NGX_ERROR;
1431  }
1432 
1434  ngx_hash('s', 'e'), 'r'), 'v'), 'e'), 'r');
1435 
1436  ngx_str_set(&h->key, "Server");
1437  ngx_str_null(&h->value);
1438  h->lowcase_key = (u_char *) "server";
1439  }
1440 
1441  if (r->upstream->headers_in.date == NULL) {
1443  if (h == NULL) {
1444  return NGX_ERROR;
1445  }
1446 
1447  h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e');
1448 
1449  ngx_str_set(&h->key, "Date");
1450  ngx_str_null(&h->value);
1451  h->lowcase_key = (u_char *) "date";
1452  }
1453 
1454  /* clear content length if response is chunked */
1455 
1456  u = r->upstream;
1457 
1458  if (u->headers_in.chunked) {
1459  u->headers_in.content_length_n = -1;
1460  }
1461 
1462  /*
1463  * set u->keepalive if response has no body; this allows to keep
1464  * connections alive in case of r->header_only or X-Accel-Redirect
1465  */
1466 
1467  ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1468 
1471  || ctx->head
1472  || (!u->headers_in.chunked
1473  && u->headers_in.content_length_n == 0))
1474  {
1476  }
1477 
1479  u->keepalive = 0;
1480 
1481  if (r->headers_in.upgrade) {
1482  u->upgrade = 1;
1483  }
1484  }
1485 
1486  return NGX_OK;
1487  }
1488 
1489  if (rc == NGX_AGAIN) {
1490  return NGX_AGAIN;
1491  }
1492 
1493  /* there was error while a header line parsing */
1494 
1496  "upstream sent invalid header");
1497 
1499  }
1500 }
1501 
1502 
1503 static ngx_int_t
1504 ngx_http_proxy_input_filter_init(void *data)
1505 {
1506  ngx_http_request_t *r = data;
1508  ngx_http_proxy_ctx_t *ctx;
1509 
1510  u = r->upstream;
1511  ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1512 
1513  if (ctx == NULL) {
1514  return NGX_ERROR;
1515  }
1516 
1518  "http proxy filter init s:%d h:%d c:%d l:%O",
1519  u->headers_in.status_n, ctx->head, u->headers_in.chunked,
1521 
1522  /* as per RFC2616, 4.4 Message Length */
1523 
1526  || ctx->head)
1527  {
1528  /* 1xx, 204, and 304 and replies to HEAD requests */
1529  /* no 1xx since we don't send Expect and Upgrade */
1530 
1531  u->pipe->length = 0;
1532  u->length = 0;
1534 
1535  } else if (u->headers_in.chunked) {
1536  /* chunked */
1537 
1538  u->pipe->input_filter = ngx_http_proxy_chunked_filter;
1539  u->pipe->length = 3; /* "0" LF LF */
1540 
1541  u->input_filter = ngx_http_proxy_non_buffered_chunked_filter;
1542  u->length = -1;
1543 
1544  } else if (u->headers_in.content_length_n == 0) {
1545  /* empty body: special case as filter won't be called */
1546 
1547  u->pipe->length = 0;
1548  u->length = 0;
1550 
1551  } else {
1552  /* content length or connection close */
1553 
1556  }
1557 
1558  return NGX_OK;
1559 }
1560 
1561 
1562 static ngx_int_t
1563 ngx_http_proxy_copy_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
1564 {
1565  ngx_buf_t *b;
1566  ngx_chain_t *cl;
1567  ngx_http_request_t *r;
1568 
1569  if (buf->pos == buf->last) {
1570  return NGX_OK;
1571  }
1572 
1573  if (p->free) {
1574  cl = p->free;
1575  b = cl->buf;
1576  p->free = cl->next;
1577  ngx_free_chain(p->pool, cl);
1578 
1579  } else {
1580  b = ngx_alloc_buf(p->pool);
1581  if (b == NULL) {
1582  return NGX_ERROR;
1583  }
1584  }
1585 
1586  ngx_memcpy(b, buf, sizeof(ngx_buf_t));
1587  b->shadow = buf;
1588  b->tag = p->tag;
1589  b->last_shadow = 1;
1590  b->recycled = 1;
1591  buf->shadow = b;
1592 
1593  cl = ngx_alloc_chain_link(p->pool);
1594  if (cl == NULL) {
1595  return NGX_ERROR;
1596  }
1597 
1598  cl->buf = b;
1599  cl->next = NULL;
1600 
1601  ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num);
1602 
1603  if (p->in) {
1604  *p->last_in = cl;
1605  } else {
1606  p->in = cl;
1607  }
1608  p->last_in = &cl->next;
1609 
1610  if (p->length == -1) {
1611  return NGX_OK;
1612  }
1613 
1614  p->length -= b->last - b->pos;
1615 
1616  if (p->length == 0) {
1617  r = p->input_ctx;
1618  p->upstream_done = 1;
1620 
1621  } else if (p->length < 0) {
1622  r = p->input_ctx;
1623  p->upstream_done = 1;
1624 
1626  "upstream sent more data than specified in "
1627  "\"Content-Length\" header");
1628  }
1629 
1630  return NGX_OK;
1631 }
1632 
1633 
1634 static ngx_int_t
1635 ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
1636 {
1637  ngx_int_t rc;
1638  ngx_buf_t *b, **prev;
1639  ngx_chain_t *cl;
1640  ngx_http_request_t *r;
1641  ngx_http_proxy_ctx_t *ctx;
1642 
1643  if (buf->pos == buf->last) {
1644  return NGX_OK;
1645  }
1646 
1647  r = p->input_ctx;
1648  ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1649 
1650  if (ctx == NULL) {
1651  return NGX_ERROR;
1652  }
1653 
1654  b = NULL;
1655  prev = &buf->shadow;
1656 
1657  for ( ;; ) {
1658 
1659  rc = ngx_http_parse_chunked(r, buf, &ctx->chunked);
1660 
1661  if (rc == NGX_OK) {
1662 
1663  /* a chunk has been parsed successfully */
1664 
1665  if (p->free) {
1666  cl = p->free;
1667  b = cl->buf;
1668  p->free = cl->next;
1669  ngx_free_chain(p->pool, cl);
1670 
1671  } else {
1672  b = ngx_alloc_buf(p->pool);
1673  if (b == NULL) {
1674  return NGX_ERROR;
1675  }
1676  }
1677 
1678  ngx_memzero(b, sizeof(ngx_buf_t));
1679 
1680  b->pos = buf->pos;
1681  b->start = buf->start;
1682  b->end = buf->end;
1683  b->tag = p->tag;
1684  b->temporary = 1;
1685  b->recycled = 1;
1686 
1687  *prev = b;
1688  prev = &b->shadow;
1689 
1690  cl = ngx_alloc_chain_link(p->pool);
1691  if (cl == NULL) {
1692  return NGX_ERROR;
1693  }
1694 
1695  cl->buf = b;
1696  cl->next = NULL;
1697 
1698  if (p->in) {
1699  *p->last_in = cl;
1700  } else {
1701  p->in = cl;
1702  }
1703  p->last_in = &cl->next;
1704 
1705  /* STUB */ b->num = buf->num;
1706 
1708  "input buf #%d %p", b->num, b->pos);
1709 
1710  if (buf->last - buf->pos >= ctx->chunked.size) {
1711 
1712  buf->pos += ctx->chunked.size;
1713  b->last = buf->pos;
1714  ctx->chunked.size = 0;
1715 
1716  continue;
1717  }
1718 
1719  ctx->chunked.size -= buf->last - buf->pos;
1720  buf->pos = buf->last;
1721  b->last = buf->last;
1722 
1723  continue;
1724  }
1725 
1726  if (rc == NGX_DONE) {
1727 
1728  /* a whole response has been parsed successfully */
1729 
1730  p->upstream_done = 1;
1732 
1733  break;
1734  }
1735 
1736  if (rc == NGX_AGAIN) {
1737 
1738  /* set p->length, minimal amount of data we want to see */
1739 
1740  p->length = ctx->chunked.length;
1741 
1742  break;
1743  }
1744 
1745  /* invalid response */
1746 
1748  "upstream sent invalid chunked response");
1749 
1750  return NGX_ERROR;
1751  }
1752 
1754  "http proxy chunked state %d, length %d",
1755  ctx->chunked.state, p->length);
1756 
1757  if (b) {
1758  b->shadow = buf;
1759  b->last_shadow = 1;
1760 
1762  "input buf %p %z", b->pos, b->last - b->pos);
1763 
1764  return NGX_OK;
1765  }
1766 
1767  /* there is no data record in the buf, add it to free chain */
1768 
1769  if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) {
1770  return NGX_ERROR;
1771  }
1772 
1773  return NGX_OK;
1774 }
1775 
1776 
1777 static ngx_int_t
1778 ngx_http_proxy_non_buffered_copy_filter(void *data, ssize_t bytes)
1779 {
1780  ngx_http_request_t *r = data;
1781 
1782  ngx_buf_t *b;
1783  ngx_chain_t *cl, **ll;
1785 
1786  u = r->upstream;
1787 
1788  for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
1789  ll = &cl->next;
1790  }
1791 
1792  cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
1793  if (cl == NULL) {
1794  return NGX_ERROR;
1795  }
1796 
1797  *ll = cl;
1798 
1799  cl->buf->flush = 1;
1800  cl->buf->memory = 1;
1801 
1802  b = &u->buffer;
1803 
1804  cl->buf->pos = b->last;
1805  b->last += bytes;
1806  cl->buf->last = b->last;
1807  cl->buf->tag = u->output.tag;
1808 
1809  if (u->length == -1) {
1810  return NGX_OK;
1811  }
1812 
1813  u->length -= bytes;
1814 
1815  if (u->length == 0) {
1817  }
1818 
1819  return NGX_OK;
1820 }
1821 
1822 
1823 static ngx_int_t
1824 ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes)
1825 {
1826  ngx_http_request_t *r = data;
1827 
1828  ngx_int_t rc;
1829  ngx_buf_t *b, *buf;
1830  ngx_chain_t *cl, **ll;
1832  ngx_http_proxy_ctx_t *ctx;
1833 
1834  ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1835 
1836  if (ctx == NULL) {
1837  return NGX_ERROR;
1838  }
1839 
1840  u = r->upstream;
1841  buf = &u->buffer;
1842 
1843  buf->pos = buf->last;
1844  buf->last += bytes;
1845 
1846  for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
1847  ll = &cl->next;
1848  }
1849 
1850  for ( ;; ) {
1851 
1852  rc = ngx_http_parse_chunked(r, buf, &ctx->chunked);
1853 
1854  if (rc == NGX_OK) {
1855 
1856  /* a chunk has been parsed successfully */
1857 
1858  cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
1859  if (cl == NULL) {
1860  return NGX_ERROR;
1861  }
1862 
1863  *ll = cl;
1864  ll = &cl->next;
1865 
1866  b = cl->buf;
1867 
1868  b->flush = 1;
1869  b->memory = 1;
1870 
1871  b->pos = buf->pos;
1872  b->tag = u->output.tag;
1873 
1874  if (buf->last - buf->pos >= ctx->chunked.size) {
1875  buf->pos += ctx->chunked.size;
1876  b->last = buf->pos;
1877  ctx->chunked.size = 0;
1878 
1879  } else {
1880  ctx->chunked.size -= buf->last - buf->pos;
1881  buf->pos = buf->last;
1882  b->last = buf->last;
1883  }
1884 
1886  "http proxy out buf %p %z",
1887  b->pos, b->last - b->pos);
1888 
1889  continue;
1890  }
1891 
1892  if (rc == NGX_DONE) {
1893 
1894  /* a whole response has been parsed successfully */
1895 
1897  u->length = 0;
1898 
1899  break;
1900  }
1901 
1902  if (rc == NGX_AGAIN) {
1903  break;
1904  }
1905 
1906  /* invalid response */
1907 
1909  "upstream sent invalid chunked response");
1910 
1911  return NGX_ERROR;
1912  }
1913 
1914  /* provide continuous buffer for subrequests in memory */
1915 
1916  if (r->subrequest_in_memory) {
1917 
1918  cl = u->out_bufs;
1919 
1920  if (cl) {
1921  buf->pos = cl->buf->pos;
1922  }
1923 
1924  buf->last = buf->pos;
1925 
1926  for (cl = u->out_bufs; cl; cl = cl->next) {
1928  "http proxy in memory %p-%p %uz",
1929  cl->buf->pos, cl->buf->last, ngx_buf_size(cl->buf));
1930 
1931  if (buf->last == cl->buf->pos) {
1932  buf->last = cl->buf->last;
1933  continue;
1934  }
1935 
1936  buf->last = ngx_movemem(buf->last, cl->buf->pos,
1937  cl->buf->last - cl->buf->pos);
1938 
1939  cl->buf->pos = buf->last - (cl->buf->last - cl->buf->pos);
1940  cl->buf->last = buf->last;
1941  }
1942  }
1943 
1944  return NGX_OK;
1945 }
1946 
1947 
1948 static void
1949 ngx_http_proxy_abort_request(ngx_http_request_t *r)
1950 {
1952  "abort http proxy request");
1953 
1954  return;
1955 }
1956 
1957 
1958 static void
1959 ngx_http_proxy_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
1960 {
1962  "finalize http proxy request");
1963 
1964  return;
1965 }
1966 
1967 
1968 static ngx_int_t
1969 ngx_http_proxy_host_variable(ngx_http_request_t *r,
1970  ngx_http_variable_value_t *v, uintptr_t data)
1971 {
1972  ngx_http_proxy_ctx_t *ctx;
1973 
1974  ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1975 
1976  if (ctx == NULL) {
1977  v->not_found = 1;
1978  return NGX_OK;
1979  }
1980 
1981  v->len = ctx->vars.host_header.len;
1982  v->valid = 1;
1983  v->no_cacheable = 0;
1984  v->not_found = 0;
1985  v->data = ctx->vars.host_header.data;
1986 
1987  return NGX_OK;
1988 }
1989 
1990 
1991 static ngx_int_t
1992 ngx_http_proxy_port_variable(ngx_http_request_t *r,
1993  ngx_http_variable_value_t *v, uintptr_t data)
1994 {
1995  ngx_http_proxy_ctx_t *ctx;
1996 
1997  ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1998 
1999  if (ctx == NULL) {
2000  v->not_found = 1;
2001  return NGX_OK;
2002  }
2003 
2004  v->len = ctx->vars.port.len;
2005  v->valid = 1;
2006  v->no_cacheable = 0;
2007  v->not_found = 0;
2008  v->data = ctx->vars.port.data;
2009 
2010  return NGX_OK;
2011 }
2012 
2013 
2014 static ngx_int_t
2015 ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
2016  ngx_http_variable_value_t *v, uintptr_t data)
2017 {
2018  size_t len;
2019  u_char *p;
2020  ngx_uint_t i, n;
2021  ngx_table_elt_t **h;
2022 
2023  v->valid = 1;
2024  v->no_cacheable = 0;
2025  v->not_found = 0;
2026 
2027  n = r->headers_in.x_forwarded_for.nelts;
2028  h = r->headers_in.x_forwarded_for.elts;
2029 
2030  len = 0;
2031 
2032  for (i = 0; i < n; i++) {
2033  len += h[i]->value.len + sizeof(", ") - 1;
2034  }
2035 
2036  if (len == 0) {
2037  v->len = r->connection->addr_text.len;
2038  v->data = r->connection->addr_text.data;
2039  return NGX_OK;
2040  }
2041 
2042  len += r->connection->addr_text.len;
2043 
2044  p = ngx_pnalloc(r->pool, len);
2045  if (p == NULL) {
2046  return NGX_ERROR;
2047  }
2048 
2049  v->len = len;
2050  v->data = p;
2051 
2052  for (i = 0; i < n; i++) {
2053  p = ngx_copy(p, h[i]->value.data, h[i]->value.len);
2054  *p++ = ','; *p++ = ' ';
2055  }
2056 
2058 
2059  return NGX_OK;
2060 }
2061 
2062 
2063 static ngx_int_t
2064 ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
2065  ngx_http_variable_value_t *v, uintptr_t data)
2066 {
2067  ngx_http_proxy_ctx_t *ctx;
2068 
2069  ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2070 
2071  if (ctx == NULL || ctx->internal_body_length < 0) {
2072  v->not_found = 1;
2073  return NGX_OK;
2074  }
2075 
2076  v->valid = 1;
2077  v->no_cacheable = 0;
2078  v->not_found = 0;
2079 
2081 
2082  if (v->data == NULL) {
2083  return NGX_ERROR;
2084  }
2085 
2086  v->len = ngx_sprintf(v->data, "%O", ctx->internal_body_length) - v->data;
2087 
2088  return NGX_OK;
2089 }
2090 
2091 
2092 static ngx_int_t
2093 ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h,
2094  size_t prefix)
2095 {
2096  size_t len;
2097  ngx_int_t rc;
2098  ngx_uint_t i;
2101 
2102  plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
2103 
2104  pr = plcf->redirects->elts;
2105 
2106  if (pr == NULL) {
2107  return NGX_DECLINED;
2108  }
2109 
2110  len = h->value.len - prefix;
2111 
2112  for (i = 0; i < plcf->redirects->nelts; i++) {
2113  rc = pr[i].handler(r, h, prefix, len, &pr[i]);
2114 
2115  if (rc != NGX_DECLINED) {
2116  return rc;
2117  }
2118  }
2119 
2120  return NGX_DECLINED;
2121 }
2122 
2123 
2124 static ngx_int_t
2125 ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, ngx_table_elt_t *h)
2126 {
2127  size_t prefix;
2128  u_char *p;
2129  ngx_int_t rc, rv;
2131 
2132  p = (u_char *) ngx_strchr(h->value.data, ';');
2133  if (p == NULL) {
2134  return NGX_DECLINED;
2135  }
2136 
2137  prefix = p + 1 - h->value.data;
2138 
2139  rv = NGX_DECLINED;
2140 
2141  plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
2142 
2143  if (plcf->cookie_domains) {
2144  p = ngx_strcasestrn(h->value.data + prefix, "domain=", 7 - 1);
2145 
2146  if (p) {
2147  rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 7,
2148  plcf->cookie_domains);
2149  if (rc == NGX_ERROR) {
2150  return NGX_ERROR;
2151  }
2152 
2153  if (rc != NGX_DECLINED) {
2154  rv = rc;
2155  }
2156  }
2157  }
2158 
2159  if (plcf->cookie_paths) {
2160  p = ngx_strcasestrn(h->value.data + prefix, "path=", 5 - 1);
2161 
2162  if (p) {
2163  rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 5,
2164  plcf->cookie_paths);
2165  if (rc == NGX_ERROR) {
2166  return NGX_ERROR;
2167  }
2168 
2169  if (rc != NGX_DECLINED) {
2170  rv = rc;
2171  }
2172  }
2173  }
2174 
2175  return rv;
2176 }
2177 
2178 
2179 static ngx_int_t
2180 ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, ngx_table_elt_t *h,
2181  u_char *value, ngx_array_t *rewrites)
2182 {
2183  size_t len, prefix;
2184  u_char *p;
2185  ngx_int_t rc;
2186  ngx_uint_t i;
2188 
2189  prefix = value - h->value.data;
2190 
2191  p = (u_char *) ngx_strchr(value, ';');
2192 
2193  len = p ? (size_t) (p - value) : (h->value.len - prefix);
2194 
2195  pr = rewrites->elts;
2196 
2197  for (i = 0; i < rewrites->nelts; i++) {
2198  rc = pr[i].handler(r, h, prefix, len, &pr[i]);
2199 
2200  if (rc != NGX_DECLINED) {
2201  return rc;
2202  }
2203  }
2204 
2205  return NGX_DECLINED;
2206 }
2207 
2208 
2209 static ngx_int_t
2210 ngx_http_proxy_rewrite_complex_handler(ngx_http_request_t *r,
2211  ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
2212 {
2213  ngx_str_t pattern, replacement;
2214 
2215  if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) {
2216  return NGX_ERROR;
2217  }
2218 
2219  if (pattern.len > len
2220  || ngx_rstrncmp(h->value.data + prefix, pattern.data,
2221  pattern.len) != 0)
2222  {
2223  return NGX_DECLINED;
2224  }
2225 
2226  if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
2227  return NGX_ERROR;
2228  }
2229 
2230  return ngx_http_proxy_rewrite(r, h, prefix, pattern.len, &replacement);
2231 }
2232 
2233 
2234 #if (NGX_PCRE)
2235 
2236 static ngx_int_t
2237 ngx_http_proxy_rewrite_regex_handler(ngx_http_request_t *r, ngx_table_elt_t *h,
2238  size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
2239 {
2240  ngx_str_t pattern, replacement;
2241 
2242  pattern.len = len;
2243  pattern.data = h->value.data + prefix;
2244 
2245  if (ngx_http_regex_exec(r, pr->pattern.regex, &pattern) != NGX_OK) {
2246  return NGX_DECLINED;
2247  }
2248 
2249  if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
2250  return NGX_ERROR;
2251  }
2252 
2253  if (prefix == 0 && h->value.len == len) {
2254  h->value = replacement;
2255  return NGX_OK;
2256  }
2257 
2258  return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement);
2259 }
2260 
2261 #endif
2262 
2263 
2264 static ngx_int_t
2265 ngx_http_proxy_rewrite_domain_handler(ngx_http_request_t *r,
2266  ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
2267 {
2268  u_char *p;
2269  ngx_str_t pattern, replacement;
2270 
2271  if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) {
2272  return NGX_ERROR;
2273  }
2274 
2275  p = h->value.data + prefix;
2276 
2277  if (p[0] == '.') {
2278  p++;
2279  prefix++;
2280  len--;
2281  }
2282 
2283  if (pattern.len != len || ngx_rstrncasecmp(pattern.data, p, len) != 0) {
2284  return NGX_DECLINED;
2285  }
2286 
2287  if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
2288  return NGX_ERROR;
2289  }
2290 
2291  return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement);
2292 }
2293 
2294 
2295 static ngx_int_t
2296 ngx_http_proxy_rewrite(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix,
2297  size_t len, ngx_str_t *replacement)
2298 {
2299  u_char *p, *data;
2300  size_t new_len;
2301 
2302  new_len = replacement->len + h->value.len - len;
2303 
2304  if (replacement->len > len) {
2305 
2306  data = ngx_pnalloc(r->pool, new_len);
2307  if (data == NULL) {
2308  return NGX_ERROR;
2309  }
2310 
2311  p = ngx_copy(data, h->value.data, prefix);
2312  p = ngx_copy(p, replacement->data, replacement->len);
2313 
2314  ngx_memcpy(p, h->value.data + prefix + len,
2315  h->value.len - len - prefix);
2316 
2317  h->value.data = data;
2318 
2319  } else {
2320  p = ngx_copy(h->value.data + prefix, replacement->data,
2321  replacement->len);
2322 
2323  ngx_memmove(p, h->value.data + prefix + len,
2324  h->value.len - len - prefix);
2325  }
2326 
2327  h->value.len = new_len;
2328 
2329  return NGX_OK;
2330 }
2331 
2332 
2333 static ngx_int_t
2334 ngx_http_proxy_add_variables(ngx_conf_t *cf)
2335 {
2336  ngx_http_variable_t *var, *v;
2337 
2338  for (v = ngx_http_proxy_vars; v->name.len; v++) {
2339  var = ngx_http_add_variable(cf, &v->name, v->flags);
2340  if (var == NULL) {
2341  return NGX_ERROR;
2342  }
2343 
2344  var->get_handler = v->get_handler;
2345  var->data = v->data;
2346  }
2347 
2348  return NGX_OK;
2349 }
2350 
2351 
2352 static void *
2353 ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
2354 {
2356 
2357  conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t));
2358  if (conf == NULL) {
2359  return NULL;
2360  }
2361 
2362  /*
2363  * set by ngx_pcalloc():
2364  *
2365  * conf->upstream.bufs.num = 0;
2366  * conf->upstream.ignore_headers = 0;
2367  * conf->upstream.next_upstream = 0;
2368  * conf->upstream.cache_use_stale = 0;
2369  * conf->upstream.cache_methods = 0;
2370  * conf->upstream.temp_path = NULL;
2371  * conf->upstream.hide_headers_hash = { NULL, 0 };
2372  * conf->upstream.uri = { 0, NULL };
2373  * conf->upstream.location = NULL;
2374  * conf->upstream.store_lengths = NULL;
2375  * conf->upstream.store_values = NULL;
2376  *
2377  * conf->method = { 0, NULL };
2378  * conf->headers_source = NULL;
2379  * conf->headers_set_len = NULL;
2380  * conf->headers_set = NULL;
2381  * conf->headers_set_hash = NULL;
2382  * conf->body_set_len = NULL;
2383  * conf->body_set = NULL;
2384  * conf->body_source = { 0, NULL };
2385  * conf->redirects = NULL;
2386  */
2387 
2388  conf->upstream.store = NGX_CONF_UNSET;
2392 
2394 
2398 
2401 
2405 
2408 
2409 #if (NGX_HTTP_CACHE)
2410  conf->upstream.cache = NGX_CONF_UNSET_PTR;
2411  conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
2412  conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
2413  conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
2414  conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
2415  conf->upstream.cache_lock = NGX_CONF_UNSET;
2416  conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
2417 #endif
2418 
2421 
2423 #if (NGX_HTTP_SSL)
2424  conf->upstream.ssl_session_reuse = NGX_CONF_UNSET;
2425 #endif
2426 
2427  /* "proxy_cyclic_temp_file" is disabled */
2428  conf->upstream.cyclic_temp_file = 0;
2429 
2430  conf->redirect = NGX_CONF_UNSET;
2431  conf->upstream.change_buffering = 1;
2432 
2435 
2437 
2440 
2441  ngx_str_set(&conf->upstream.module, "proxy");
2442 
2443  return conf;
2444 }
2445 
2446 
2447 static char *
2448 ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
2449 {
2450  ngx_http_proxy_loc_conf_t *prev = parent;
2451  ngx_http_proxy_loc_conf_t *conf = child;
2452 
2453  u_char *p;
2454  size_t size;
2455  ngx_hash_init_t hash;
2459 
2460  if (conf->upstream.store != 0) {
2462  prev->upstream.store, 0);
2463 
2464  if (conf->upstream.store_lengths == NULL) {
2467  }
2468  }
2469 
2471  prev->upstream.store_access, 0600);
2472 
2474  prev->upstream.buffering, 1);
2475 
2477  prev->upstream.ignore_client_abort, 0);
2478 
2480  prev->upstream.local, NULL);
2481 
2483  prev->upstream.connect_timeout, 60000);
2484 
2486  prev->upstream.send_timeout, 60000);
2487 
2489  prev->upstream.read_timeout, 60000);
2490 
2492  prev->upstream.send_lowat, 0);
2493 
2495  prev->upstream.buffer_size,
2496  (size_t) ngx_pagesize);
2497 
2499  8, ngx_pagesize);
2500 
2501  if (conf->upstream.bufs.num < 2) {
2503  "there must be at least 2 \"proxy_buffers\"");
2504  return NGX_CONF_ERROR;
2505  }
2506 
2507 
2508  size = conf->upstream.buffer_size;
2509  if (size < conf->upstream.bufs.size) {
2510  size = conf->upstream.bufs.size;
2511  }
2512 
2513 
2517 
2519  conf->upstream.busy_buffers_size = 2 * size;
2520  } else {
2521  conf->upstream.busy_buffers_size =
2523  }
2524 
2525  if (conf->upstream.busy_buffers_size < size) {
2527  "\"proxy_busy_buffers_size\" must be equal to or greater than "
2528  "the maximum of the value of \"proxy_buffer_size\" and "
2529  "one of the \"proxy_buffers\"");
2530 
2531  return NGX_CONF_ERROR;
2532  }
2533 
2534  if (conf->upstream.busy_buffers_size
2535  > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
2536  {
2538  "\"proxy_busy_buffers_size\" must be less than "
2539  "the size of all \"proxy_buffers\" minus one buffer");
2540 
2541  return NGX_CONF_ERROR;
2542  }
2543 
2544 
2548 
2550  conf->upstream.temp_file_write_size = 2 * size;
2551  } else {
2554  }
2555 
2556  if (conf->upstream.temp_file_write_size < size) {
2558  "\"proxy_temp_file_write_size\" must be equal to or greater "
2559  "than the maximum of the value of \"proxy_buffer_size\" and "
2560  "one of the \"proxy_buffers\"");
2561 
2562  return NGX_CONF_ERROR;
2563  }
2564 
2568 
2570  conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
2571  } else {
2574  }
2575 
2576  if (conf->upstream.max_temp_file_size != 0
2577  && conf->upstream.max_temp_file_size < size)
2578  {
2580  "\"proxy_max_temp_file_size\" must be equal to zero to disable "
2581  "temporary files usage or must be equal to or greater than "
2582  "the maximum of the value of \"proxy_buffer_size\" and "
2583  "one of the \"proxy_buffers\"");
2584 
2585  return NGX_CONF_ERROR;
2586  }
2587 
2588 
2590  prev->upstream.ignore_headers,
2592 
2593 
2595  prev->upstream.next_upstream,
2599 
2603  }
2604 
2606  prev->upstream.temp_path,
2607  &ngx_http_proxy_temp_path)
2608  != NGX_OK)
2609  {
2610  return NGX_CONF_ERROR;
2611  }
2612 
2613 
2614 #if (NGX_HTTP_CACHE)
2615 
2616  ngx_conf_merge_ptr_value(conf->upstream.cache,
2617  prev->upstream.cache, NULL);
2618 
2619  if (conf->upstream.cache && conf->upstream.cache->data == NULL) {
2620  ngx_shm_zone_t *shm_zone;
2621 
2622  shm_zone = conf->upstream.cache;
2623 
2625  "\"proxy_cache\" zone \"%V\" is unknown",
2626  &shm_zone->shm.name);
2627 
2628  return NGX_CONF_ERROR;
2629  }
2630 
2631  ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
2632  prev->upstream.cache_min_uses, 1);
2633 
2634  ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
2635  prev->upstream.cache_use_stale,
2638 
2639  if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
2640  conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
2642  }
2643 
2644  if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
2645  conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
2646  }
2647 
2648  if (conf->upstream.cache_methods == 0) {
2649  conf->upstream.cache_methods = prev->upstream.cache_methods;
2650  }
2651 
2652  conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD;
2653 
2654  ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
2655  prev->upstream.cache_bypass, NULL);
2656 
2657  ngx_conf_merge_ptr_value(conf->upstream.no_cache,
2658  prev->upstream.no_cache, NULL);
2659 
2660  if (conf->upstream.no_cache && conf->upstream.cache_bypass == NULL) {
2661  ngx_log_error(NGX_LOG_WARN, cf->log, 0,
2662  "\"proxy_no_cache\" functionality has been changed in 0.8.46, "
2663  "now it should be used together with \"proxy_cache_bypass\"");
2664  }
2665 
2666  ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
2667  prev->upstream.cache_valid, NULL);
2668 
2669  if (conf->cache_key.value.data == NULL) {
2670  conf->cache_key = prev->cache_key;
2671  }
2672 
2673  ngx_conf_merge_value(conf->upstream.cache_lock,
2674  prev->upstream.cache_lock, 0);
2675 
2676  ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
2677  prev->upstream.cache_lock_timeout, 5000);
2678 
2679 #endif
2680 
2681  ngx_conf_merge_str_value(conf->method, prev->method, "");
2682 
2683  if (conf->method.len
2684  && conf->method.data[conf->method.len - 1] != ' ')
2685  {
2686  conf->method.data[conf->method.len] = ' ';
2687  conf->method.len++;
2688  }
2689 
2691  prev->upstream.pass_request_headers, 1);
2693  prev->upstream.pass_request_body, 1);
2694 
2696  prev->upstream.intercept_errors, 0);
2697 
2698 #if (NGX_HTTP_SSL)
2699  ngx_conf_merge_value(conf->upstream.ssl_session_reuse,
2700  prev->upstream.ssl_session_reuse, 1);
2701 #endif
2702 
2703  ngx_conf_merge_value(conf->redirect, prev->redirect, 1);
2704 
2705  if (conf->redirect) {
2706 
2707  if (conf->redirects == NULL) {
2708  conf->redirects = prev->redirects;
2709  }
2710 
2711  if (conf->redirects == NULL && conf->url.data) {
2712 
2713  conf->redirects = ngx_array_create(cf->pool, 1,
2714  sizeof(ngx_http_proxy_rewrite_t));
2715  if (conf->redirects == NULL) {
2716  return NGX_CONF_ERROR;
2717  }
2718 
2719  pr = ngx_array_push(conf->redirects);
2720  if (pr == NULL) {
2721  return NGX_CONF_ERROR;
2722  }
2723 
2725  sizeof(ngx_http_complex_value_t));
2726 
2728 
2729  pr->handler = ngx_http_proxy_rewrite_complex_handler;
2730 
2731  if (conf->vars.uri.len) {
2732  pr->pattern.complex.value = conf->url;
2733  pr->replacement.value = conf->location;
2734 
2735  } else {
2736  pr->pattern.complex.value.len = conf->url.len
2737  + sizeof("/") - 1;
2738 
2739  p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len);
2740  if (p == NULL) {
2741  return NGX_CONF_ERROR;
2742  }
2743 
2744  pr->pattern.complex.value.data = p;
2745 
2746  p = ngx_cpymem(p, conf->url.data, conf->url.len);
2747  *p = '/';
2748 
2749  ngx_str_set(&pr->replacement.value, "/");
2750  }
2751  }
2752  }
2753 
2755 
2757 
2758 #if (NGX_HTTP_SSL)
2759  if (conf->upstream.ssl == NULL) {
2760  conf->upstream.ssl = prev->upstream.ssl;
2761  }
2762 #endif
2763 
2766 
2768  prev->headers_hash_max_size, 512);
2769 
2771  prev->headers_hash_bucket_size, 64);
2772 
2775 
2776  hash.max_size = conf->headers_hash_max_size;
2778  hash.name = "proxy_headers_hash";
2779 
2781  &prev->upstream, ngx_http_proxy_hide_headers, &hash)
2782  != NGX_OK)
2783  {
2784  return NGX_CONF_ERROR;
2785  }
2786 
2787  if (conf->upstream.upstream == NULL) {
2788  conf->upstream.upstream = prev->upstream.upstream;
2789  conf->vars = prev->vars;
2790  }
2791 
2792  if (conf->proxy_lengths == NULL) {
2793  conf->proxy_lengths = prev->proxy_lengths;
2794  conf->proxy_values = prev->proxy_values;
2795  }
2796 
2797  if (conf->upstream.upstream || conf->proxy_lengths) {
2799  if (clcf->handler == NULL && clcf->lmt_excpt) {
2800  clcf->handler = ngx_http_proxy_handler;
2801  conf->location = prev->location;
2802  }
2803  }
2804 
2805  if (conf->body_source.data == NULL) {
2806  conf->body_source = prev->body_source;
2807  conf->body_set_len = prev->body_set_len;
2808  conf->body_set = prev->body_set;
2809  }
2810 
2811  if (conf->body_source.data && conf->body_set_len == NULL) {
2812 
2813  ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
2814 
2815  sc.cf = cf;
2816  sc.source = &conf->body_source;
2817  sc.flushes = &conf->flushes;
2818  sc.lengths = &conf->body_set_len;
2819  sc.values = &conf->body_set;
2820  sc.complete_lengths = 1;
2821  sc.complete_values = 1;
2822 
2823  if (ngx_http_script_compile(&sc) != NGX_OK) {
2824  return NGX_CONF_ERROR;
2825  }
2826  }
2827 
2828  if (ngx_http_proxy_merge_headers(cf, conf, prev) != NGX_OK) {
2829  return NGX_CONF_ERROR;
2830  }
2831 
2832  return NGX_CONF_OK;
2833 }
2834 
2835 
2836 static ngx_int_t
2837 ngx_http_proxy_merge_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf,
2839 {
2840  u_char *p;
2841  size_t size;
2842  uintptr_t *code;
2843  ngx_uint_t i;
2844  ngx_array_t headers_names, headers_merged;
2845  ngx_keyval_t *src, *s, *h;
2846  ngx_hash_key_t *hk;
2847  ngx_hash_init_t hash;
2850 
2851  if (conf->headers_source == NULL) {
2852  conf->flushes = prev->flushes;
2853  conf->headers_set_len = prev->headers_set_len;
2854  conf->headers_set = prev->headers_set;
2855  conf->headers_set_hash = prev->headers_set_hash;
2856  conf->headers_source = prev->headers_source;
2857  }
2858 
2859  if (conf->headers_set_hash.buckets
2860 #if (NGX_HTTP_CACHE)
2861  && ((conf->upstream.cache == NULL) == (prev->upstream.cache == NULL))
2862 #endif
2863  )
2864  {
2865  return NGX_OK;
2866  }
2867 
2868 
2869  if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
2870  != NGX_OK)
2871  {
2872  return NGX_ERROR;
2873  }
2874 
2875  if (ngx_array_init(&headers_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t))
2876  != NGX_OK)
2877  {
2878  return NGX_ERROR;
2879  }
2880 
2881  if (conf->headers_source == NULL) {
2882  conf->headers_source = ngx_array_create(cf->pool, 4,
2883  sizeof(ngx_keyval_t));
2884  if (conf->headers_source == NULL) {
2885  return NGX_ERROR;
2886  }
2887  }
2888 
2889  conf->headers_set_len = ngx_array_create(cf->pool, 64, 1);
2890  if (conf->headers_set_len == NULL) {
2891  return NGX_ERROR;
2892  }
2893 
2894  conf->headers_set = ngx_array_create(cf->pool, 512, 1);
2895  if (conf->headers_set == NULL) {
2896  return NGX_ERROR;
2897  }
2898 
2899 
2900 #if (NGX_HTTP_CACHE)
2901 
2902  h = conf->upstream.cache ? ngx_http_proxy_cache_headers:
2903  ngx_http_proxy_headers;
2904 #else
2905 
2906  h = ngx_http_proxy_headers;
2907 
2908 #endif
2909 
2910  src = conf->headers_source->elts;
2911  for (i = 0; i < conf->headers_source->nelts; i++) {
2912 
2913  s = ngx_array_push(&headers_merged);
2914  if (s == NULL) {
2915  return NGX_ERROR;
2916  }
2917 
2918  *s = src[i];
2919  }
2920 
2921  while (h->key.len) {
2922 
2923  src = headers_merged.elts;
2924  for (i = 0; i < headers_merged.nelts; i++) {
2925  if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
2926  goto next;
2927  }
2928  }
2929 
2930  s = ngx_array_push(&headers_merged);
2931  if (s == NULL) {
2932  return NGX_ERROR;
2933  }
2934 
2935  *s = *h;
2936 
2937  next:
2938 
2939  h++;
2940  }
2941 
2942 
2943  src = headers_merged.elts;
2944  for (i = 0; i < headers_merged.nelts; i++) {
2945 
2946  hk = ngx_array_push(&headers_names);
2947  if (hk == NULL) {
2948  return NGX_ERROR;
2949  }
2950 
2951  hk->key = src[i].key;
2952  hk->key_hash = ngx_hash_key_lc(src[i].key.data, src[i].key.len);
2953  hk->value = (void *) 1;
2954 
2955  if (src[i].value.len == 0) {
2956  continue;
2957  }
2958 
2959  if (ngx_http_script_variables_count(&src[i].value) == 0) {
2960  copy = ngx_array_push_n(conf->headers_set_len,
2961  sizeof(ngx_http_script_copy_code_t));
2962  if (copy == NULL) {
2963  return NGX_ERROR;
2964  }
2965 
2966  copy->code = (ngx_http_script_code_pt)
2968  copy->len = src[i].key.len + sizeof(": ") - 1
2969  + src[i].value.len + sizeof(CRLF) - 1;
2970 
2971 
2972  size = (sizeof(ngx_http_script_copy_code_t)
2973  + src[i].key.len + sizeof(": ") - 1
2974  + src[i].value.len + sizeof(CRLF) - 1
2975  + sizeof(uintptr_t) - 1)
2976  & ~(sizeof(uintptr_t) - 1);
2977 
2978  copy = ngx_array_push_n(conf->headers_set, size);
2979  if (copy == NULL) {
2980  return NGX_ERROR;
2981  }
2982 
2984  copy->len = src[i].key.len + sizeof(": ") - 1
2985  + src[i].value.len + sizeof(CRLF) - 1;
2986 
2987  p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
2988 
2989  p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
2990  *p++ = ':'; *p++ = ' ';
2991  p = ngx_cpymem(p, src[i].value.data, src[i].value.len);
2992  *p++ = CR; *p = LF;
2993 
2994  } else {
2995  copy = ngx_array_push_n(conf->headers_set_len,
2996  sizeof(ngx_http_script_copy_code_t));
2997  if (copy == NULL) {
2998  return NGX_ERROR;
2999  }
3000 
3001  copy->code = (ngx_http_script_code_pt)
3003  copy->len = src[i].key.len + sizeof(": ") - 1;
3004 
3005 
3006  size = (sizeof(ngx_http_script_copy_code_t)
3007  + src[i].key.len + sizeof(": ") - 1 + sizeof(uintptr_t) - 1)
3008  & ~(sizeof(uintptr_t) - 1);
3009 
3010  copy = ngx_array_push_n(conf->headers_set, size);
3011  if (copy == NULL) {
3012  return NGX_ERROR;
3013  }
3014 
3016  copy->len = src[i].key.len + sizeof(": ") - 1;
3017 
3018  p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
3019  p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
3020  *p++ = ':'; *p = ' ';
3021 
3022 
3023  ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3024 
3025  sc.cf = cf;
3026  sc.source = &src[i].value;
3027  sc.flushes = &conf->flushes;
3028  sc.lengths = &conf->headers_set_len;
3029  sc.values = &conf->headers_set;
3030 
3031  if (ngx_http_script_compile(&sc) != NGX_OK) {
3032  return NGX_ERROR;
3033  }
3034 
3035 
3036  copy = ngx_array_push_n(conf->headers_set_len,
3037  sizeof(ngx_http_script_copy_code_t));
3038  if (copy == NULL) {
3039  return NGX_ERROR;
3040  }
3041 
3042  copy->code = (ngx_http_script_code_pt)
3044  copy->len = sizeof(CRLF) - 1;
3045 
3046 
3047  size = (sizeof(ngx_http_script_copy_code_t)
3048  + sizeof(CRLF) - 1 + sizeof(uintptr_t) - 1)
3049  & ~(sizeof(uintptr_t) - 1);
3050 
3051  copy = ngx_array_push_n(conf->headers_set, size);
3052  if (copy == NULL) {
3053  return NGX_ERROR;
3054  }
3055 
3057  copy->len = sizeof(CRLF) - 1;
3058 
3059  p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
3060  *p++ = CR; *p = LF;
3061  }
3062 
3063  code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t));
3064  if (code == NULL) {
3065  return NGX_ERROR;
3066  }
3067 
3068  *code = (uintptr_t) NULL;
3069 
3070  code = ngx_array_push_n(conf->headers_set, sizeof(uintptr_t));
3071  if (code == NULL) {
3072  return NGX_ERROR;
3073  }
3074 
3075  *code = (uintptr_t) NULL;
3076  }
3077 
3078  code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t));
3079  if (code == NULL) {
3080  return NGX_ERROR;
3081  }
3082 
3083  *code = (uintptr_t) NULL;
3084 
3085 
3086  hash.hash = &conf->headers_set_hash;
3087  hash.key = ngx_hash_key_lc;
3088  hash.max_size = conf->headers_hash_max_size;
3090  hash.name = "proxy_headers_hash";
3091  hash.pool = cf->pool;
3092  hash.temp_pool = NULL;
3093 
3094  return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
3095 }
3096 
3097 
3098 static char *
3099 ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3100 {
3101  ngx_http_proxy_loc_conf_t *plcf = conf;
3102 
3103  size_t add;
3104  u_short port;
3105  ngx_str_t *value, *url;
3106  ngx_url_t u;
3107  ngx_uint_t n;
3110 
3111  if (plcf->upstream.upstream || plcf->proxy_lengths) {
3112  return "is duplicate";
3113  }
3114 
3116 
3117  clcf->handler = ngx_http_proxy_handler;
3118 
3119  if (clcf->name.data[clcf->name.len - 1] == '/') {
3120  clcf->auto_redirect = 1;
3121  }
3122 
3123  value = cf->args->elts;
3124 
3125  url = &value[1];
3126 
3128 
3129  if (n) {
3130 
3131  ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3132 
3133  sc.cf = cf;
3134  sc.source = url;
3135  sc.lengths = &plcf->proxy_lengths;
3136  sc.values = &plcf->proxy_values;
3137  sc.variables = n;
3138  sc.complete_lengths = 1;
3139  sc.complete_values = 1;
3140 
3141  if (ngx_http_script_compile(&sc) != NGX_OK) {
3142  return NGX_CONF_ERROR;
3143  }
3144 
3145 #if (NGX_HTTP_SSL)
3146  if (ngx_http_proxy_set_ssl(cf, plcf) != NGX_OK) {
3147  return NGX_CONF_ERROR;
3148  }
3149 #endif
3150 
3151  return NGX_CONF_OK;
3152  }
3153 
3154  if (ngx_strncasecmp(url->data, (u_char *) "http://", 7) == 0) {
3155  add = 7;
3156  port = 80;
3157 
3158  } else if (ngx_strncasecmp(url->data, (u_char *) "https://", 8) == 0) {
3159 
3160 #if (NGX_HTTP_SSL)
3161  if (ngx_http_proxy_set_ssl(cf, plcf) != NGX_OK) {
3162  return NGX_CONF_ERROR;
3163  }
3164 
3165  add = 8;
3166  port = 443;
3167 #else
3169  "https protocol requires SSL support");
3170  return NGX_CONF_ERROR;
3171 #endif
3172 
3173  } else {
3174  ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid URL prefix");
3175  return NGX_CONF_ERROR;
3176  }
3177 
3178  ngx_memzero(&u, sizeof(ngx_url_t));
3179 
3180  u.url.len = url->len - add;
3181  u.url.data = url->data + add;
3182  u.default_port = port;
3183  u.uri_part = 1;
3184  u.no_resolve = 1;
3185 
3186  plcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
3187  if (plcf->upstream.upstream == NULL) {
3188  return NGX_CONF_ERROR;
3189  }
3190 
3191  plcf->vars.schema.len = add;
3192  plcf->vars.schema.data = url->data;
3193  plcf->vars.key_start = plcf->vars.schema;
3194 
3195  ngx_http_proxy_set_vars(&u, &plcf->vars);
3196 
3197  plcf->location = clcf->name;
3198 
3199  if (clcf->named
3200 #if (NGX_PCRE)
3201  || clcf->regex
3202 #endif
3203  || clcf->noname)
3204  {
3205  if (plcf->vars.uri.len) {
3207  "\"proxy_pass\" cannot have URI part in "
3208  "location given by regular expression, "
3209  "or inside named location, "
3210  "or inside \"if\" statement, "
3211  "or inside \"limit_except\" block");
3212  return NGX_CONF_ERROR;
3213  }
3214 
3215  plcf->location.len = 0;
3216  }
3217 
3218  plcf->url = *url;
3219 
3220  return NGX_CONF_OK;
3221 }
3222 
3223 
3224 static char *
3225 ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3226 {
3227  ngx_http_proxy_loc_conf_t *plcf = conf;
3228 
3229  u_char *p;
3230  ngx_str_t *value;
3233 
3234  if (plcf->redirect == 0) {
3235  return NGX_CONF_OK;
3236  }
3237 
3238  plcf->redirect = 1;
3239 
3240  value = cf->args->elts;
3241 
3242  if (cf->args->nelts == 2) {
3243  if (ngx_strcmp(value[1].data, "off") == 0) {
3244  plcf->redirect = 0;
3245  plcf->redirects = NULL;
3246  return NGX_CONF_OK;
3247  }
3248 
3249  if (ngx_strcmp(value[1].data, "false") == 0) {
3251  "invalid parameter \"false\", use \"off\" instead");
3252  plcf->redirect = 0;
3253  plcf->redirects = NULL;
3254  return NGX_CONF_OK;
3255  }
3256 
3257  if (ngx_strcmp(value[1].data, "default") != 0) {
3259  "invalid parameter \"%V\"", &value[1]);
3260  return NGX_CONF_ERROR;
3261  }
3262  }
3263 
3264  if (plcf->redirects == NULL) {
3265  plcf->redirects = ngx_array_create(cf->pool, 1,
3266  sizeof(ngx_http_proxy_rewrite_t));
3267  if (plcf->redirects == NULL) {
3268  return NGX_CONF_ERROR;
3269  }
3270  }
3271 
3272  pr = ngx_array_push(plcf->redirects);
3273  if (pr == NULL) {
3274  return NGX_CONF_ERROR;
3275  }
3276 
3277  if (ngx_strcmp(value[1].data, "default") == 0) {
3278  if (plcf->proxy_lengths) {
3280  "\"proxy_redirect default\" cannot be used "
3281  "with \"proxy_pass\" directive with variables");
3282  return NGX_CONF_ERROR;
3283  }
3284 
3285  if (plcf->url.data == NULL) {
3287  "\"proxy_redirect default\" should be placed "
3288  "after the \"proxy_pass\" directive");
3289  return NGX_CONF_ERROR;
3290  }
3291 
3292  pr->handler = ngx_http_proxy_rewrite_complex_handler;
3293 
3295 
3297 
3298  if (plcf->vars.uri.len) {
3299  pr->pattern.complex.value = plcf->url;
3300  pr->replacement.value = plcf->location;
3301 
3302  } else {
3303  pr->pattern.complex.value.len = plcf->url.len + sizeof("/") - 1;
3304 
3305  p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len);
3306  if (p == NULL) {
3307  return NGX_CONF_ERROR;
3308  }
3309 
3310  pr->pattern.complex.value.data = p;
3311 
3312  p = ngx_cpymem(p, plcf->url.data, plcf->url.len);
3313  *p = '/';
3314 
3315  ngx_str_set(&pr->replacement.value, "/");
3316  }
3317 
3318  return NGX_CONF_OK;
3319  }
3320 
3321 
3322  if (value[1].data[0] == '~') {
3323  value[1].len--;
3324  value[1].data++;
3325 
3326  if (value[1].data[0] == '*') {
3327  value[1].len--;
3328  value[1].data++;
3329 
3330  if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
3331  return NGX_CONF_ERROR;
3332  }
3333 
3334  } else {
3335  if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) {
3336  return NGX_CONF_ERROR;
3337  }
3338  }
3339 
3340  } else {
3341 
3343 
3344  ccv.cf = cf;
3345  ccv.value = &value[1];
3346  ccv.complex_value = &pr->pattern.complex;
3347 
3348  if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3349  return NGX_CONF_ERROR;
3350  }
3351 
3352  pr->handler = ngx_http_proxy_rewrite_complex_handler;
3353  }
3354 
3355 
3357 
3358  ccv.cf = cf;
3359  ccv.value = &value[2];
3360  ccv.complex_value = &pr->replacement;
3361 
3362  if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3363  return NGX_CONF_ERROR;
3364  }
3365 
3366  return NGX_CONF_OK;
3367 }
3368 
3369 
3370 static char *
3371 ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3372 {
3373  ngx_http_proxy_loc_conf_t *plcf = conf;
3374 
3375  ngx_str_t *value;
3378 
3379  if (plcf->cookie_domains == NULL) {
3380  return NGX_CONF_OK;
3381  }
3382 
3383  value = cf->args->elts;
3384 
3385  if (cf->args->nelts == 2) {
3386 
3387  if (ngx_strcmp(value[1].data, "off") == 0) {
3388  plcf->cookie_domains = NULL;
3389  return NGX_CONF_OK;
3390  }
3391 
3393  "invalid parameter \"%V\"", &value[1]);
3394  return NGX_CONF_ERROR;
3395  }
3396 
3397  if (plcf->cookie_domains == NGX_CONF_UNSET_PTR) {
3398  plcf->cookie_domains = ngx_array_create(cf->pool, 1,
3399  sizeof(ngx_http_proxy_rewrite_t));
3400  if (plcf->cookie_domains == NULL) {
3401  return NGX_CONF_ERROR;
3402  }
3403  }
3404 
3405  pr = ngx_array_push(plcf->cookie_domains);
3406  if (pr == NULL) {
3407  return NGX_CONF_ERROR;
3408  }
3409 
3410  if (value[1].data[0] == '~') {
3411  value[1].len--;
3412  value[1].data++;
3413 
3414  if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
3415  return NGX_CONF_ERROR;
3416  }
3417 
3418  } else {
3419 
3420  if (value[1].data[0] == '.') {
3421  value[1].len--;
3422  value[1].data++;
3423  }
3424 
3426 
3427  ccv.cf = cf;
3428  ccv.value = &value[1];
3429  ccv.complex_value = &pr->pattern.complex;
3430 
3431  if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3432  return NGX_CONF_ERROR;
3433  }
3434 
3435  pr->handler = ngx_http_proxy_rewrite_domain_handler;
3436 
3437  if (value[2].data[0] == '.') {
3438  value[2].len--;
3439  value[2].data++;
3440  }
3441  }
3442 
3444 
3445  ccv.cf = cf;
3446  ccv.value = &value[2];
3447  ccv.complex_value = &pr->replacement;
3448 
3449  if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3450  return NGX_CONF_ERROR;
3451  }
3452 
3453  return NGX_CONF_OK;
3454 }
3455 
3456 
3457 static char *
3458 ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3459 {
3460  ngx_http_proxy_loc_conf_t *plcf = conf;
3461 
3462  ngx_str_t *value;
3465 
3466  if (plcf->cookie_paths == NULL) {
3467  return NGX_CONF_OK;
3468  }
3469 
3470  value = cf->args->elts;
3471 
3472  if (cf->args->nelts == 2) {
3473 
3474  if (ngx_strcmp(value[1].data, "off") == 0) {
3475  plcf->cookie_paths = NULL;
3476  return NGX_CONF_OK;
3477  }
3478 
3480  "invalid parameter \"%V\"", &value[1]);
3481  return NGX_CONF_ERROR;
3482  }
3483 
3484  if (plcf->cookie_paths == NGX_CONF_UNSET_PTR) {
3485  plcf->cookie_paths = ngx_array_create(cf->pool, 1,
3486  sizeof(ngx_http_proxy_rewrite_t));
3487  if (plcf->cookie_paths == NULL) {
3488  return NGX_CONF_ERROR;
3489  }
3490  }
3491 
3492  pr = ngx_array_push(plcf->cookie_paths);
3493  if (pr == NULL) {
3494  return NGX_CONF_ERROR;
3495  }
3496 
3497  if (value[1].data[0] == '~') {
3498  value[1].len--;
3499  value[1].data++;
3500 
3501  if (value[1].data[0] == '*') {
3502  value[1].len--;
3503  value[1].data++;
3504 
3505  if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
3506  return NGX_CONF_ERROR;
3507  }
3508 
3509  } else {
3510  if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) {
3511  return NGX_CONF_ERROR;
3512  }
3513  }
3514 
3515  } else {
3516 
3518 
3519  ccv.cf = cf;
3520  ccv.value = &value[1];
3521  ccv.complex_value = &pr->pattern.complex;
3522 
3523  if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3524  return NGX_CONF_ERROR;
3525  }
3526 
3527  pr->handler = ngx_http_proxy_rewrite_complex_handler;
3528  }
3529 
3531 
3532  ccv.cf = cf;
3533  ccv.value = &value[2];
3534  ccv.complex_value = &pr->replacement;
3535 
3536  if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3537  return NGX_CONF_ERROR;
3538  }
3539 
3540  return NGX_CONF_OK;
3541 }
3542 
3543 
3544 static ngx_int_t
3545 ngx_http_proxy_rewrite_regex(ngx_conf_t *cf, ngx_http_proxy_rewrite_t *pr,
3546  ngx_str_t *regex, ngx_uint_t caseless)
3547 {
3548 #if (NGX_PCRE)
3549  u_char errstr[NGX_MAX_CONF_ERRSTR];
3551 
3552  ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
3553 
3554  rc.pattern = *regex;
3556  rc.err.data = errstr;
3557 
3558  if (caseless) {
3560  }
3561 
3562  pr->pattern.regex = ngx_http_regex_compile(cf, &rc);
3563  if (pr->pattern.regex == NULL) {
3564  return NGX_ERROR;
3565  }
3566 
3567  pr->handler = ngx_http_proxy_rewrite_regex_handler;
3568 
3569  return NGX_OK;
3570 
3571 #else
3572 
3574  "using regex \"%V\" requires PCRE library", regex);
3575  return NGX_ERROR;
3576 
3577 #endif
3578 }
3579 
3580 
3581 static char *
3582 ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3583 {
3584  ngx_http_proxy_loc_conf_t *plcf = conf;
3585 
3586  ngx_str_t *value;
3588 
3589  if (plcf->upstream.store != NGX_CONF_UNSET
3590  || plcf->upstream.store_lengths)
3591  {
3592  return "is duplicate";
3593  }
3594 
3595  value = cf->args->elts;
3596 
3597  if (ngx_strcmp(value[1].data, "off") == 0) {
3598  plcf->upstream.store = 0;
3599  return NGX_CONF_OK;
3600  }
3601 
3602 #if (NGX_HTTP_CACHE)
3603 
3604  if (plcf->upstream.cache != NGX_CONF_UNSET_PTR
3605  && plcf->upstream.cache != NULL)
3606  {
3607  return "is incompatible with \"proxy_cache\"";
3608  }
3609 
3610 #endif
3611 
3612  if (ngx_strcmp(value[1].data, "on") == 0) {
3613  plcf->upstream.store = 1;
3614  return NGX_CONF_OK;
3615  }
3616 
3617  /* include the terminating '\0' into script */
3618  value[1].len++;
3619 
3620  ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3621 
3622  sc.cf = cf;
3623  sc.source = &value[1];
3624  sc.lengths = &plcf->upstream.store_lengths;
3625  sc.values = &plcf->upstream.store_values;
3627  sc.complete_lengths = 1;
3628  sc.complete_values = 1;
3629 
3630  if (ngx_http_script_compile(&sc) != NGX_OK) {
3631  return NGX_CONF_ERROR;
3632  }
3633 
3634  return NGX_CONF_OK;
3635 }
3636 
3637 
3638 #if (NGX_HTTP_CACHE)
3639 
3640 static char *
3641 ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3642 {
3643  ngx_http_proxy_loc_conf_t *plcf = conf;
3644 
3645  ngx_str_t *value;
3646 
3647  value = cf->args->elts;
3648 
3649  if (plcf->upstream.cache != NGX_CONF_UNSET_PTR) {
3650  return "is duplicate";
3651  }
3652 
3653  if (ngx_strcmp(value[1].data, "off") == 0) {
3654  plcf->upstream.cache = NULL;
3655  return NGX_CONF_OK;
3656  }
3657 
3658  if (plcf->upstream.store > 0 || plcf->upstream.store_lengths) {
3659  return "is incompatible with \"proxy_store\"";
3660  }
3661 
3662  plcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0,
3663  &ngx_http_proxy_module);
3664  if (plcf->upstream.cache == NULL) {
3665  return NGX_CONF_ERROR;
3666  }
3667 
3668  return NGX_CONF_OK;
3669 }
3670 
3671 
3672 static char *
3673 ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3674 {
3675  ngx_http_proxy_loc_conf_t *plcf = conf;
3676 
3677  ngx_str_t *value;
3679 
3680  value = cf->args->elts;
3681 
3682  if (plcf->cache_key.value.data) {
3683  return "is duplicate";
3684  }
3685 
3687 
3688  ccv.cf = cf;
3689  ccv.value = &value[1];
3690  ccv.complex_value = &plcf->cache_key;
3691 
3692  if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3693  return NGX_CONF_ERROR;
3694  }
3695 
3696  return NGX_CONF_OK;
3697 }
3698 
3699 #endif
3700 
3701 
3702 static char *
3703 ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data)
3704 {
3705 #if (NGX_FREEBSD)
3706  ssize_t *np = data;
3707 
3708  if ((u_long) *np >= ngx_freebsd_net_inet_tcp_sendspace) {
3710  "\"proxy_send_lowat\" must be less than %d "
3711  "(sysctl net.inet.tcp.sendspace)",
3713 
3714  return NGX_CONF_ERROR;
3715  }
3716 
3717 #elif !(NGX_HAVE_SO_SNDLOWAT)
3718  ssize_t *np = data;
3719 
3721  "\"proxy_send_lowat\" is not supported, ignored");
3722 
3723  *np = 0;
3724 
3725 #endif
3726 
3727  return NGX_CONF_OK;
3728 }
3729 
3730 
3731 #if (NGX_HTTP_SSL)
3732 
3733 static ngx_int_t
3734 ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf)
3735 {
3736  ngx_pool_cleanup_t *cln;
3737 
3738  plcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));
3739  if (plcf->upstream.ssl == NULL) {
3740  return NGX_ERROR;
3741  }
3742 
3743  plcf->upstream.ssl->log = cf->log;
3744 
3745  if (ngx_ssl_create(plcf->upstream.ssl,
3748  NULL)
3749  != NGX_OK)
3750  {
3751  return NGX_ERROR;
3752  }
3753 
3754  cln = ngx_pool_cleanup_add(cf->pool, 0);
3755  if (cln == NULL) {
3756  return NGX_ERROR;
3757  }
3758 
3760  cln->data = plcf->upstream.ssl;
3761 
3762  return NGX_OK;
3763 }
3764 
3765 #endif
3766 
3767 
3768 static void
3769 ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v)
3770 {
3771  if (u->family != AF_UNIX) {
3772 
3773  if (u->no_port || u->port == u->default_port) {
3774 
3775  v->host_header = u->host;
3776 
3777  if (u->default_port == 80) {
3778  ngx_str_set(&v->port, "80");
3779 
3780  } else {
3781  ngx_str_set(&v->port, "443");
3782  }
3783 
3784  } else {
3785  v->host_header.len = u->host.len + 1 + u->port_text.len;
3786  v->host_header.data = u->host.data;
3787  v->port = u->port_text;
3788  }
3789 
3790  v->key_start.len += v->host_header.len;
3791 
3792  } else {
3793  ngx_str_set(&v->host_header, "localhost");
3794  ngx_str_null(&v->port);
3795  v->key_start.len += sizeof("unix:") - 1 + u->host.len + 1;
3796  }
3797 
3798  v->uri = u->uri;
3799 }