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 
13 typedef struct {
14     ngx_array_t                    caches;  /* ngx_http_file_cache_t * */
15 } ngx_http_proxy_main_conf_t;
16 
17 
18 typedef struct ngx_http_proxy_rewrite_s  ngx_http_proxy_rewrite_t;
19 
20 typedef ngx_int_t (*ngx_http_proxy_rewrite_pt)(ngx_http_request_t *r,
21     ngx_table_elt_t *h, size_t prefix, size_t len,
22     ngx_http_proxy_rewrite_t *pr);
23 
24 struct ngx_http_proxy_rewrite_s {
25     ngx_http_proxy_rewrite_pt      handler;
26 
27     union {
28         ngx_http_complex_value_t   complex;
29 #if (NGX_PCRE)
30         ngx_http_regex_t          *regex;
31 #endif
32     } pattern;
33 
34     ngx_http_complex_value_t       replacement;
35 };
36 
37 
38 typedef struct {
39     ngx_str_t                      key_start;
40     ngx_str_t                      schema;
41     ngx_str_t                      host_header;
42     ngx_str_t                      port;
43     ngx_str_t                      uri;
44 } ngx_http_proxy_vars_t;
45 
46 
47 typedef struct {
48     ngx_array_t                   *flushes;
49     ngx_array_t                   *lengths;
50     ngx_array_t                   *values;
51     ngx_hash_t                     hash;
52 } ngx_http_proxy_headers_t;
53 
54 
55 typedef struct {
56     ngx_http_upstream_conf_t       upstream;
57 
58     ngx_array_t                   *body_flushes;
59     ngx_array_t                   *body_lengths;
60     ngx_array_t                   *body_values;
61     ngx_str_t                      body_source;
62 
63     ngx_http_proxy_headers_t       headers;
64 #if (NGX_HTTP_CACHE)
65     ngx_http_proxy_headers_t       headers_cache;
66 #endif
67     ngx_array_t                   *headers_source;
68 
69     ngx_array_t                   *proxy_lengths;
70     ngx_array_t                   *proxy_values;
71 
72     ngx_array_t                   *redirects;
73     ngx_array_t                   *cookie_domains;
74     ngx_array_t                   *cookie_paths;
75 
76     ngx_http_complex_value_t      *method;
77     ngx_str_t                      location;
78     ngx_str_t                      url;
79 
80 #if (NGX_HTTP_CACHE)
81     ngx_http_complex_value_t       cache_key;
82 #endif
83 
84     ngx_http_proxy_vars_t          vars;
85 
86     ngx_flag_t                     redirect;
87 
88     ngx_uint_t                     http_version;
89 
90     ngx_uint_t                     headers_hash_max_size;
91     ngx_uint_t                     headers_hash_bucket_size;
92 
93 #if (NGX_HTTP_SSL)
94     ngx_uint_t                     ssl;
95     ngx_uint_t                     ssl_protocols;
96     ngx_str_t                      ssl_ciphers;
97     ngx_uint_t                     ssl_verify_depth;
98     ngx_str_t                      ssl_trusted_certificate;
99     ngx_str_t                      ssl_crl;
100     ngx_str_t                      ssl_certificate;
101     ngx_str_t                      ssl_certificate_key;
102     ngx_array_t                   *ssl_passwords;
103 #endif
104 
105 #if (NGX_HAVE_FSTACK)
106     ngx_flag_t                     kernel_network_stack;
107 #endif
108 } ngx_http_proxy_loc_conf_t;
109 
110 
111 typedef struct {
112     ngx_http_status_t              status;
113     ngx_http_chunked_t             chunked;
114     ngx_http_proxy_vars_t          vars;
115     off_t                          internal_body_length;
116 
117     ngx_chain_t                   *free;
118     ngx_chain_t                   *busy;
119 
120     unsigned                       head:1;
121     unsigned                       internal_chunked:1;
122     unsigned                       header_sent:1;
123 } ngx_http_proxy_ctx_t;
124 
125 
126 static ngx_int_t ngx_http_proxy_eval(ngx_http_request_t *r,
127     ngx_http_proxy_ctx_t *ctx, ngx_http_proxy_loc_conf_t *plcf);
128 #if (NGX_HTTP_CACHE)
129 static ngx_int_t ngx_http_proxy_create_key(ngx_http_request_t *r);
130 #endif
131 static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r);
132 static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r);
133 static ngx_int_t ngx_http_proxy_body_output_filter(void *data, ngx_chain_t *in);
134 static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r);
135 static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r);
136 static ngx_int_t ngx_http_proxy_input_filter_init(void *data);
137 static ngx_int_t ngx_http_proxy_copy_filter(ngx_event_pipe_t *p,
138     ngx_buf_t *buf);
139 static ngx_int_t ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p,
140     ngx_buf_t *buf);
141 static ngx_int_t ngx_http_proxy_non_buffered_copy_filter(void *data,
142     ssize_t bytes);
143 static ngx_int_t ngx_http_proxy_non_buffered_chunked_filter(void *data,
144     ssize_t bytes);
145 static void ngx_http_proxy_abort_request(ngx_http_request_t *r);
146 static void ngx_http_proxy_finalize_request(ngx_http_request_t *r,
147     ngx_int_t rc);
148 
149 static ngx_int_t ngx_http_proxy_host_variable(ngx_http_request_t *r,
150     ngx_http_variable_value_t *v, uintptr_t data);
151 static ngx_int_t ngx_http_proxy_port_variable(ngx_http_request_t *r,
152     ngx_http_variable_value_t *v, uintptr_t data);
153 static ngx_int_t
154     ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
155     ngx_http_variable_value_t *v, uintptr_t data);
156 static ngx_int_t
157     ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
158     ngx_http_variable_value_t *v, uintptr_t data);
159 static ngx_int_t ngx_http_proxy_internal_chunked_variable(ngx_http_request_t *r,
160     ngx_http_variable_value_t *v, uintptr_t data);
161 static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r,
162     ngx_table_elt_t *h, size_t prefix);
163 static ngx_int_t ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r,
164     ngx_table_elt_t *h);
165 static ngx_int_t ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r,
166     ngx_table_elt_t *h, u_char *value, ngx_array_t *rewrites);
167 static ngx_int_t ngx_http_proxy_rewrite(ngx_http_request_t *r,
168     ngx_table_elt_t *h, size_t prefix, size_t len, ngx_str_t *replacement);
169 
170 static ngx_int_t ngx_http_proxy_add_variables(ngx_conf_t *cf);
171 static void *ngx_http_proxy_create_main_conf(ngx_conf_t *cf);
172 static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf);
173 static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf,
174     void *parent, void *child);
175 static ngx_int_t ngx_http_proxy_init_headers(ngx_conf_t *cf,
176     ngx_http_proxy_loc_conf_t *conf, ngx_http_proxy_headers_t *headers,
177     ngx_keyval_t *default_headers);
178 
179 static char *ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd,
180     void *conf);
181 static char *ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd,
182     void *conf);
183 static char *ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd,
184     void *conf);
185 static char *ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd,
186     void *conf);
187 static char *ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd,
188     void *conf);
189 #if (NGX_HTTP_CACHE)
190 static char *ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd,
191     void *conf);
192 static char *ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd,
193     void *conf);
194 #endif
195 #if (NGX_HTTP_SSL)
196 static char *ngx_http_proxy_ssl_password_file(ngx_conf_t *cf,
197     ngx_command_t *cmd, void *conf);
198 #endif
199 
200 static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data);
201 
202 static ngx_int_t ngx_http_proxy_rewrite_regex(ngx_conf_t *cf,
203     ngx_http_proxy_rewrite_t *pr, ngx_str_t *regex, ngx_uint_t caseless);
204 
205 #if (NGX_HTTP_SSL)
206 static ngx_int_t ngx_http_proxy_set_ssl(ngx_conf_t *cf,
207     ngx_http_proxy_loc_conf_t *plcf);
208 #endif
209 static void ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v);
210 
211 
212 static ngx_conf_post_t  ngx_http_proxy_lowat_post =
213     { ngx_http_proxy_lowat_check };
214 
215 
216 static ngx_conf_bitmask_t  ngx_http_proxy_next_upstream_masks[] = {
217     { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
218     { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
219     { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
220     { ngx_string("non_idempotent"), NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT },
221     { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
222     { ngx_string("http_502"), NGX_HTTP_UPSTREAM_FT_HTTP_502 },
223     { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
224     { ngx_string("http_504"), NGX_HTTP_UPSTREAM_FT_HTTP_504 },
225     { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 },
226     { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
227     { ngx_string("http_429"), NGX_HTTP_UPSTREAM_FT_HTTP_429 },
228     { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING },
229     { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
230     { ngx_null_string, 0 }
231 };
232 
233 
234 #if (NGX_HTTP_SSL)
235 
236 static ngx_conf_bitmask_t  ngx_http_proxy_ssl_protocols[] = {
237     { ngx_string("SSLv2"), NGX_SSL_SSLv2 },
238     { ngx_string("SSLv3"), NGX_SSL_SSLv3 },
239     { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
240     { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 },
241     { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 },
242     { ngx_string("TLSv1.3"), NGX_SSL_TLSv1_3 },
243     { ngx_null_string, 0 }
244 };
245 
246 #endif
247 
248 
249 static ngx_conf_enum_t  ngx_http_proxy_http_version[] = {
250     { ngx_string("1.0"), NGX_HTTP_VERSION_10 },
251     { ngx_string("1.1"), NGX_HTTP_VERSION_11 },
252     { ngx_null_string, 0 }
253 };
254 
255 
256 ngx_module_t  ngx_http_proxy_module;
257 
258 
259 static ngx_command_t  ngx_http_proxy_commands[] = {
260 
261     { ngx_string("proxy_pass"),
262       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE1,
263       ngx_http_proxy_pass,
264       NGX_HTTP_LOC_CONF_OFFSET,
265       0,
266       NULL },
267 
268     { ngx_string("proxy_redirect"),
269       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
270       ngx_http_proxy_redirect,
271       NGX_HTTP_LOC_CONF_OFFSET,
272       0,
273       NULL },
274 
275     { ngx_string("proxy_cookie_domain"),
276       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
277       ngx_http_proxy_cookie_domain,
278       NGX_HTTP_LOC_CONF_OFFSET,
279       0,
280       NULL },
281 
282     { ngx_string("proxy_cookie_path"),
283       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
284       ngx_http_proxy_cookie_path,
285       NGX_HTTP_LOC_CONF_OFFSET,
286       0,
287       NULL },
288 
289     { ngx_string("proxy_store"),
290       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
291       ngx_http_proxy_store,
292       NGX_HTTP_LOC_CONF_OFFSET,
293       0,
294       NULL },
295 
296     { ngx_string("proxy_store_access"),
297       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
298       ngx_conf_set_access_slot,
299       NGX_HTTP_LOC_CONF_OFFSET,
300       offsetof(ngx_http_proxy_loc_conf_t, upstream.store_access),
301       NULL },
302 
303     { ngx_string("proxy_buffering"),
304       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
305       ngx_conf_set_flag_slot,
306       NGX_HTTP_LOC_CONF_OFFSET,
307       offsetof(ngx_http_proxy_loc_conf_t, upstream.buffering),
308       NULL },
309 
310     { ngx_string("proxy_request_buffering"),
311       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
312       ngx_conf_set_flag_slot,
313       NGX_HTTP_LOC_CONF_OFFSET,
314       offsetof(ngx_http_proxy_loc_conf_t, upstream.request_buffering),
315       NULL },
316 
317     { ngx_string("proxy_ignore_client_abort"),
318       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
319       ngx_conf_set_flag_slot,
320       NGX_HTTP_LOC_CONF_OFFSET,
321       offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_client_abort),
322       NULL },
323 
324     { ngx_string("proxy_bind"),
325       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
326       ngx_http_upstream_bind_set_slot,
327       NGX_HTTP_LOC_CONF_OFFSET,
328       offsetof(ngx_http_proxy_loc_conf_t, upstream.local),
329       NULL },
330 
331     { ngx_string("proxy_socket_keepalive"),
332       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
333       ngx_conf_set_flag_slot,
334       NGX_HTTP_LOC_CONF_OFFSET,
335       offsetof(ngx_http_proxy_loc_conf_t, upstream.socket_keepalive),
336       NULL },
337 
338     { ngx_string("proxy_connect_timeout"),
339       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
340       ngx_conf_set_msec_slot,
341       NGX_HTTP_LOC_CONF_OFFSET,
342       offsetof(ngx_http_proxy_loc_conf_t, upstream.connect_timeout),
343       NULL },
344 
345     { ngx_string("proxy_send_timeout"),
346       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
347       ngx_conf_set_msec_slot,
348       NGX_HTTP_LOC_CONF_OFFSET,
349       offsetof(ngx_http_proxy_loc_conf_t, upstream.send_timeout),
350       NULL },
351 
352     { ngx_string("proxy_send_lowat"),
353       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
354       ngx_conf_set_size_slot,
355       NGX_HTTP_LOC_CONF_OFFSET,
356       offsetof(ngx_http_proxy_loc_conf_t, upstream.send_lowat),
357       &ngx_http_proxy_lowat_post },
358 
359     { ngx_string("proxy_intercept_errors"),
360       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
361       ngx_conf_set_flag_slot,
362       NGX_HTTP_LOC_CONF_OFFSET,
363       offsetof(ngx_http_proxy_loc_conf_t, upstream.intercept_errors),
364       NULL },
365 
366     { ngx_string("proxy_set_header"),
367       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
368       ngx_conf_set_keyval_slot,
369       NGX_HTTP_LOC_CONF_OFFSET,
370       offsetof(ngx_http_proxy_loc_conf_t, headers_source),
371       NULL },
372 
373     { ngx_string("proxy_headers_hash_max_size"),
374       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
375       ngx_conf_set_num_slot,
376       NGX_HTTP_LOC_CONF_OFFSET,
377       offsetof(ngx_http_proxy_loc_conf_t, headers_hash_max_size),
378       NULL },
379 
380     { ngx_string("proxy_headers_hash_bucket_size"),
381       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
382       ngx_conf_set_num_slot,
383       NGX_HTTP_LOC_CONF_OFFSET,
384       offsetof(ngx_http_proxy_loc_conf_t, headers_hash_bucket_size),
385       NULL },
386 
387     { ngx_string("proxy_set_body"),
388       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
389       ngx_conf_set_str_slot,
390       NGX_HTTP_LOC_CONF_OFFSET,
391       offsetof(ngx_http_proxy_loc_conf_t, body_source),
392       NULL },
393 
394     { ngx_string("proxy_method"),
395       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
396       ngx_http_set_complex_value_slot,
397       NGX_HTTP_LOC_CONF_OFFSET,
398       offsetof(ngx_http_proxy_loc_conf_t, method),
399       NULL },
400 
401     { ngx_string("proxy_pass_request_headers"),
402       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
403       ngx_conf_set_flag_slot,
404       NGX_HTTP_LOC_CONF_OFFSET,
405       offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_headers),
406       NULL },
407 
408     { ngx_string("proxy_pass_request_body"),
409       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
410       ngx_conf_set_flag_slot,
411       NGX_HTTP_LOC_CONF_OFFSET,
412       offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_body),
413       NULL },
414 
415     { ngx_string("proxy_buffer_size"),
416       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
417       ngx_conf_set_size_slot,
418       NGX_HTTP_LOC_CONF_OFFSET,
419       offsetof(ngx_http_proxy_loc_conf_t, upstream.buffer_size),
420       NULL },
421 
422     { ngx_string("proxy_read_timeout"),
423       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
424       ngx_conf_set_msec_slot,
425       NGX_HTTP_LOC_CONF_OFFSET,
426       offsetof(ngx_http_proxy_loc_conf_t, upstream.read_timeout),
427       NULL },
428 
429     { ngx_string("proxy_buffers"),
430       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
431       ngx_conf_set_bufs_slot,
432       NGX_HTTP_LOC_CONF_OFFSET,
433       offsetof(ngx_http_proxy_loc_conf_t, upstream.bufs),
434       NULL },
435 
436     { ngx_string("proxy_busy_buffers_size"),
437       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
438       ngx_conf_set_size_slot,
439       NGX_HTTP_LOC_CONF_OFFSET,
440       offsetof(ngx_http_proxy_loc_conf_t, upstream.busy_buffers_size_conf),
441       NULL },
442 
443     { ngx_string("proxy_force_ranges"),
444       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
445       ngx_conf_set_flag_slot,
446       NGX_HTTP_LOC_CONF_OFFSET,
447       offsetof(ngx_http_proxy_loc_conf_t, upstream.force_ranges),
448       NULL },
449 
450     { ngx_string("proxy_limit_rate"),
451       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
452       ngx_conf_set_size_slot,
453       NGX_HTTP_LOC_CONF_OFFSET,
454       offsetof(ngx_http_proxy_loc_conf_t, upstream.limit_rate),
455       NULL },
456 
457 #if (NGX_HTTP_CACHE)
458 
459     { ngx_string("proxy_cache"),
460       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
461       ngx_http_proxy_cache,
462       NGX_HTTP_LOC_CONF_OFFSET,
463       0,
464       NULL },
465 
466     { ngx_string("proxy_cache_key"),
467       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
468       ngx_http_proxy_cache_key,
469       NGX_HTTP_LOC_CONF_OFFSET,
470       0,
471       NULL },
472 
473     { ngx_string("proxy_cache_path"),
474       NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
475       ngx_http_file_cache_set_slot,
476       NGX_HTTP_MAIN_CONF_OFFSET,
477       offsetof(ngx_http_proxy_main_conf_t, caches),
478       &ngx_http_proxy_module },
479 
480     { ngx_string("proxy_cache_bypass"),
481       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
482       ngx_http_set_predicate_slot,
483       NGX_HTTP_LOC_CONF_OFFSET,
484       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_bypass),
485       NULL },
486 
487     { ngx_string("proxy_no_cache"),
488       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
489       ngx_http_set_predicate_slot,
490       NGX_HTTP_LOC_CONF_OFFSET,
491       offsetof(ngx_http_proxy_loc_conf_t, upstream.no_cache),
492       NULL },
493 
494     { ngx_string("proxy_cache_valid"),
495       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
496       ngx_http_file_cache_valid_set_slot,
497       NGX_HTTP_LOC_CONF_OFFSET,
498       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_valid),
499       NULL },
500 
501     { ngx_string("proxy_cache_min_uses"),
502       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
503       ngx_conf_set_num_slot,
504       NGX_HTTP_LOC_CONF_OFFSET,
505       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_min_uses),
506       NULL },
507 
508     { ngx_string("proxy_cache_max_range_offset"),
509       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
510       ngx_conf_set_off_slot,
511       NGX_HTTP_LOC_CONF_OFFSET,
512       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_max_range_offset),
513       NULL },
514 
515     { ngx_string("proxy_cache_use_stale"),
516       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
517       ngx_conf_set_bitmask_slot,
518       NGX_HTTP_LOC_CONF_OFFSET,
519       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_use_stale),
520       &ngx_http_proxy_next_upstream_masks },
521 
522     { ngx_string("proxy_cache_methods"),
523       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
524       ngx_conf_set_bitmask_slot,
525       NGX_HTTP_LOC_CONF_OFFSET,
526       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_methods),
527       &ngx_http_upstream_cache_method_mask },
528 
529     { ngx_string("proxy_cache_lock"),
530       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
531       ngx_conf_set_flag_slot,
532       NGX_HTTP_LOC_CONF_OFFSET,
533       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock),
534       NULL },
535 
536     { ngx_string("proxy_cache_lock_timeout"),
537       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
538       ngx_conf_set_msec_slot,
539       NGX_HTTP_LOC_CONF_OFFSET,
540       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock_timeout),
541       NULL },
542 
543     { ngx_string("proxy_cache_lock_age"),
544       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
545       ngx_conf_set_msec_slot,
546       NGX_HTTP_LOC_CONF_OFFSET,
547       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_lock_age),
548       NULL },
549 
550     { ngx_string("proxy_cache_revalidate"),
551       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
552       ngx_conf_set_flag_slot,
553       NGX_HTTP_LOC_CONF_OFFSET,
554       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_revalidate),
555       NULL },
556 
557     { ngx_string("proxy_cache_convert_head"),
558       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
559       ngx_conf_set_flag_slot,
560       NGX_HTTP_LOC_CONF_OFFSET,
561       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_convert_head),
562       NULL },
563 
564     { ngx_string("proxy_cache_background_update"),
565       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
566       ngx_conf_set_flag_slot,
567       NGX_HTTP_LOC_CONF_OFFSET,
568       offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_background_update),
569       NULL },
570 
571 #endif
572 
573     { ngx_string("proxy_temp_path"),
574       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
575       ngx_conf_set_path_slot,
576       NGX_HTTP_LOC_CONF_OFFSET,
577       offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_path),
578       NULL },
579 
580     { ngx_string("proxy_max_temp_file_size"),
581       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
582       ngx_conf_set_size_slot,
583       NGX_HTTP_LOC_CONF_OFFSET,
584       offsetof(ngx_http_proxy_loc_conf_t, upstream.max_temp_file_size_conf),
585       NULL },
586 
587     { ngx_string("proxy_temp_file_write_size"),
588       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
589       ngx_conf_set_size_slot,
590       NGX_HTTP_LOC_CONF_OFFSET,
591       offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_file_write_size_conf),
592       NULL },
593 
594     { ngx_string("proxy_next_upstream"),
595       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
596       ngx_conf_set_bitmask_slot,
597       NGX_HTTP_LOC_CONF_OFFSET,
598       offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream),
599       &ngx_http_proxy_next_upstream_masks },
600 
601     { ngx_string("proxy_next_upstream_tries"),
602       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
603       ngx_conf_set_num_slot,
604       NGX_HTTP_LOC_CONF_OFFSET,
605       offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream_tries),
606       NULL },
607 
608     { ngx_string("proxy_next_upstream_timeout"),
609       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
610       ngx_conf_set_msec_slot,
611       NGX_HTTP_LOC_CONF_OFFSET,
612       offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream_timeout),
613       NULL },
614 
615     { ngx_string("proxy_pass_header"),
616       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
617       ngx_conf_set_str_array_slot,
618       NGX_HTTP_LOC_CONF_OFFSET,
619       offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_headers),
620       NULL },
621 
622     { ngx_string("proxy_hide_header"),
623       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
624       ngx_conf_set_str_array_slot,
625       NGX_HTTP_LOC_CONF_OFFSET,
626       offsetof(ngx_http_proxy_loc_conf_t, upstream.hide_headers),
627       NULL },
628 
629     { ngx_string("proxy_ignore_headers"),
630       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
631       ngx_conf_set_bitmask_slot,
632       NGX_HTTP_LOC_CONF_OFFSET,
633       offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_headers),
634       &ngx_http_upstream_ignore_headers_masks },
635 
636     { ngx_string("proxy_http_version"),
637       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
638       ngx_conf_set_enum_slot,
639       NGX_HTTP_LOC_CONF_OFFSET,
640       offsetof(ngx_http_proxy_loc_conf_t, http_version),
641       &ngx_http_proxy_http_version },
642 
643 #if (NGX_HTTP_SSL)
644 
645     { ngx_string("proxy_ssl_session_reuse"),
646       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
647       ngx_conf_set_flag_slot,
648       NGX_HTTP_LOC_CONF_OFFSET,
649       offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_session_reuse),
650       NULL },
651 
652     { ngx_string("proxy_ssl_protocols"),
653       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
654       ngx_conf_set_bitmask_slot,
655       NGX_HTTP_LOC_CONF_OFFSET,
656       offsetof(ngx_http_proxy_loc_conf_t, ssl_protocols),
657       &ngx_http_proxy_ssl_protocols },
658 
659     { ngx_string("proxy_ssl_ciphers"),
660       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
661       ngx_conf_set_str_slot,
662       NGX_HTTP_LOC_CONF_OFFSET,
663       offsetof(ngx_http_proxy_loc_conf_t, ssl_ciphers),
664       NULL },
665 
666     { ngx_string("proxy_ssl_name"),
667       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
668       ngx_http_set_complex_value_slot,
669       NGX_HTTP_LOC_CONF_OFFSET,
670       offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_name),
671       NULL },
672 
673     { ngx_string("proxy_ssl_server_name"),
674       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
675       ngx_conf_set_flag_slot,
676       NGX_HTTP_LOC_CONF_OFFSET,
677       offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_server_name),
678       NULL },
679 
680     { ngx_string("proxy_ssl_verify"),
681       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
682       ngx_conf_set_flag_slot,
683       NGX_HTTP_LOC_CONF_OFFSET,
684       offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_verify),
685       NULL },
686 
687     { ngx_string("proxy_ssl_verify_depth"),
688       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
689       ngx_conf_set_num_slot,
690       NGX_HTTP_LOC_CONF_OFFSET,
691       offsetof(ngx_http_proxy_loc_conf_t, ssl_verify_depth),
692       NULL },
693 
694     { ngx_string("proxy_ssl_trusted_certificate"),
695       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
696       ngx_conf_set_str_slot,
697       NGX_HTTP_LOC_CONF_OFFSET,
698       offsetof(ngx_http_proxy_loc_conf_t, ssl_trusted_certificate),
699       NULL },
700 
701     { ngx_string("proxy_ssl_crl"),
702       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
703       ngx_conf_set_str_slot,
704       NGX_HTTP_LOC_CONF_OFFSET,
705       offsetof(ngx_http_proxy_loc_conf_t, ssl_crl),
706       NULL },
707 
708     { ngx_string("proxy_ssl_certificate"),
709       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
710       ngx_conf_set_str_slot,
711       NGX_HTTP_LOC_CONF_OFFSET,
712       offsetof(ngx_http_proxy_loc_conf_t, ssl_certificate),
713       NULL },
714 
715     { ngx_string("proxy_ssl_certificate_key"),
716       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
717       ngx_conf_set_str_slot,
718       NGX_HTTP_LOC_CONF_OFFSET,
719       offsetof(ngx_http_proxy_loc_conf_t, ssl_certificate_key),
720       NULL },
721 
722     { ngx_string("proxy_ssl_password_file"),
723       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
724       ngx_http_proxy_ssl_password_file,
725       NGX_HTTP_LOC_CONF_OFFSET,
726       0,
727       NULL },
728 
729 #endif
730 
731 #if (NGX_HAVE_FSTACK)
732 
733           { ngx_string("proxy_kernel_network_stack"),
734             NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
735             ngx_conf_set_flag_slot,
736             NGX_HTTP_LOC_CONF_OFFSET,
737             offsetof(ngx_http_proxy_loc_conf_t, kernel_network_stack),
738             NULL },
739 
740 #endif
741 
742       ngx_null_command
743 };
744 
745 
746 static ngx_http_module_t  ngx_http_proxy_module_ctx = {
747     ngx_http_proxy_add_variables,          /* preconfiguration */
748     NULL,                                  /* postconfiguration */
749 
750     ngx_http_proxy_create_main_conf,       /* create main configuration */
751     NULL,                                  /* init main configuration */
752 
753     NULL,                                  /* create server configuration */
754     NULL,                                  /* merge server configuration */
755 
756     ngx_http_proxy_create_loc_conf,        /* create location configuration */
757     ngx_http_proxy_merge_loc_conf          /* merge location configuration */
758 };
759 
760 
761 ngx_module_t  ngx_http_proxy_module = {
762     NGX_MODULE_V1,
763     &ngx_http_proxy_module_ctx,            /* module context */
764     ngx_http_proxy_commands,               /* module directives */
765     NGX_HTTP_MODULE,                       /* module type */
766     NULL,                                  /* init master */
767     NULL,                                  /* init module */
768     NULL,                                  /* init process */
769     NULL,                                  /* init thread */
770     NULL,                                  /* exit thread */
771     NULL,                                  /* exit process */
772     NULL,                                  /* exit master */
773     NGX_MODULE_V1_PADDING
774 };
775 
776 
777 static char  ngx_http_proxy_version[] = " HTTP/1.0" CRLF;
778 static char  ngx_http_proxy_version_11[] = " HTTP/1.1" CRLF;
779 
780 
781 static ngx_keyval_t  ngx_http_proxy_headers[] = {
782     { ngx_string("Host"), ngx_string("$proxy_host") },
783     { ngx_string("Connection"), ngx_string("close") },
784     { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
785     { ngx_string("Transfer-Encoding"), ngx_string("$proxy_internal_chunked") },
786     { ngx_string("TE"), ngx_string("") },
787     { ngx_string("Keep-Alive"), ngx_string("") },
788     { ngx_string("Expect"), ngx_string("") },
789     { ngx_string("Upgrade"), ngx_string("") },
790     { ngx_null_string, ngx_null_string }
791 };
792 
793 
794 static ngx_str_t  ngx_http_proxy_hide_headers[] = {
795     ngx_string("Date"),
796     ngx_string("Server"),
797     ngx_string("X-Pad"),
798     ngx_string("X-Accel-Expires"),
799     ngx_string("X-Accel-Redirect"),
800     ngx_string("X-Accel-Limit-Rate"),
801     ngx_string("X-Accel-Buffering"),
802     ngx_string("X-Accel-Charset"),
803     ngx_null_string
804 };
805 
806 
807 #if (NGX_HTTP_CACHE)
808 
809 static ngx_keyval_t  ngx_http_proxy_cache_headers[] = {
810     { ngx_string("Host"), ngx_string("$proxy_host") },
811     { ngx_string("Connection"), ngx_string("close") },
812     { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
813     { ngx_string("Transfer-Encoding"), ngx_string("$proxy_internal_chunked") },
814     { ngx_string("TE"), ngx_string("") },
815     { ngx_string("Keep-Alive"), ngx_string("") },
816     { ngx_string("Expect"), ngx_string("") },
817     { ngx_string("Upgrade"), ngx_string("") },
818     { ngx_string("If-Modified-Since"),
819       ngx_string("$upstream_cache_last_modified") },
820     { ngx_string("If-Unmodified-Since"), ngx_string("") },
821     { ngx_string("If-None-Match"), ngx_string("$upstream_cache_etag") },
822     { ngx_string("If-Match"), ngx_string("") },
823     { ngx_string("Range"), ngx_string("") },
824     { ngx_string("If-Range"), ngx_string("") },
825     { ngx_null_string, ngx_null_string }
826 };
827 
828 #endif
829 
830 
831 static ngx_http_variable_t  ngx_http_proxy_vars[] = {
832 
833     { ngx_string("proxy_host"), NULL, ngx_http_proxy_host_variable, 0,
834       NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
835 
836     { ngx_string("proxy_port"), NULL, ngx_http_proxy_port_variable, 0,
837       NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
838 
839     { ngx_string("proxy_add_x_forwarded_for"), NULL,
840       ngx_http_proxy_add_x_forwarded_for_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
841 
842 #if 0
843     { ngx_string("proxy_add_via"), NULL, NULL, 0, NGX_HTTP_VAR_NOHASH, 0 },
844 #endif
845 
846     { ngx_string("proxy_internal_body_length"), NULL,
847       ngx_http_proxy_internal_body_length_variable, 0,
848       NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
849 
850     { ngx_string("proxy_internal_chunked"), NULL,
851       ngx_http_proxy_internal_chunked_variable, 0,
852       NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
853 
854       ngx_http_null_variable
855 };
856 
857 
858 static ngx_path_init_t  ngx_http_proxy_temp_path = {
859     ngx_string(NGX_HTTP_PROXY_TEMP_PATH), { 1, 2, 0 }
860 };
861 
862 
863 static ngx_int_t
ngx_http_proxy_handler(ngx_http_request_t * r)864 ngx_http_proxy_handler(ngx_http_request_t *r)
865 {
866     ngx_int_t                    rc;
867     ngx_http_upstream_t         *u;
868     ngx_http_proxy_ctx_t        *ctx;
869     ngx_http_proxy_loc_conf_t   *plcf;
870 #if (NGX_HTTP_CACHE)
871     ngx_http_proxy_main_conf_t  *pmcf;
872 #endif
873 
874     if (ngx_http_upstream_create(r) != NGX_OK) {
875         return NGX_HTTP_INTERNAL_SERVER_ERROR;
876     }
877 
878     ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t));
879     if (ctx == NULL) {
880         return NGX_HTTP_INTERNAL_SERVER_ERROR;
881     }
882 
883     ngx_http_set_ctx(r, ctx, ngx_http_proxy_module);
884 
885     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
886 
887     u = r->upstream;
888 
889     if (plcf->proxy_lengths == NULL) {
890         ctx->vars = plcf->vars;
891         u->schema = plcf->vars.schema;
892 #if (NGX_HTTP_SSL)
893         u->ssl = (plcf->upstream.ssl != NULL);
894 #endif
895 
896     } else {
897         if (ngx_http_proxy_eval(r, ctx, plcf) != NGX_OK) {
898             return NGX_HTTP_INTERNAL_SERVER_ERROR;
899         }
900     }
901 
902     u->output.tag = (ngx_buf_tag_t) &ngx_http_proxy_module;
903 
904     u->conf = &plcf->upstream;
905 
906 #if (NGX_HTTP_CACHE)
907     pmcf = ngx_http_get_module_main_conf(r, ngx_http_proxy_module);
908 
909     u->caches = &pmcf->caches;
910     u->create_key = ngx_http_proxy_create_key;
911 #endif
912 
913     u->create_request = ngx_http_proxy_create_request;
914     u->reinit_request = ngx_http_proxy_reinit_request;
915     u->process_header = ngx_http_proxy_process_status_line;
916     u->abort_request = ngx_http_proxy_abort_request;
917     u->finalize_request = ngx_http_proxy_finalize_request;
918     r->state = 0;
919 
920     if (plcf->redirects) {
921         u->rewrite_redirect = ngx_http_proxy_rewrite_redirect;
922     }
923 
924     if (plcf->cookie_domains || plcf->cookie_paths) {
925         u->rewrite_cookie = ngx_http_proxy_rewrite_cookie;
926     }
927 
928     u->buffering = plcf->upstream.buffering;
929 
930     u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
931     if (u->pipe == NULL) {
932         return NGX_HTTP_INTERNAL_SERVER_ERROR;
933     }
934 
935     u->pipe->input_filter = ngx_http_proxy_copy_filter;
936     u->pipe->input_ctx = r;
937 
938     u->input_filter_init = ngx_http_proxy_input_filter_init;
939     u->input_filter = ngx_http_proxy_non_buffered_copy_filter;
940     u->input_filter_ctx = r;
941 
942     u->accel = 1;
943 
944 #if (NGX_HAVE_FSTACK)
945     u->peer.belong_to_host = plcf->kernel_network_stack;
946 #endif
947 
948 
949     if (!plcf->upstream.request_buffering
950         && plcf->body_values == NULL && plcf->upstream.pass_request_body
951         && (!r->headers_in.chunked
952             || plcf->http_version == NGX_HTTP_VERSION_11))
953     {
954         r->request_body_no_buffering = 1;
955     }
956 
957     rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
958 
959     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
960         return rc;
961     }
962 
963     return NGX_DONE;
964 }
965 
966 
967 static ngx_int_t
ngx_http_proxy_eval(ngx_http_request_t * r,ngx_http_proxy_ctx_t * ctx,ngx_http_proxy_loc_conf_t * plcf)968 ngx_http_proxy_eval(ngx_http_request_t *r, ngx_http_proxy_ctx_t *ctx,
969     ngx_http_proxy_loc_conf_t *plcf)
970 {
971     u_char               *p;
972     size_t                add;
973     u_short               port;
974     ngx_str_t             proxy;
975     ngx_url_t             url;
976     ngx_http_upstream_t  *u;
977 
978     if (ngx_http_script_run(r, &proxy, plcf->proxy_lengths->elts, 0,
979                             plcf->proxy_values->elts)
980         == NULL)
981     {
982         return NGX_ERROR;
983     }
984 
985     if (proxy.len > 7
986         && ngx_strncasecmp(proxy.data, (u_char *) "http://", 7) == 0)
987     {
988         add = 7;
989         port = 80;
990 
991 #if (NGX_HTTP_SSL)
992 
993     } else if (proxy.len > 8
994                && ngx_strncasecmp(proxy.data, (u_char *) "https://", 8) == 0)
995     {
996         add = 8;
997         port = 443;
998         r->upstream->ssl = 1;
999 
1000 #endif
1001 
1002     } else {
1003         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1004                       "invalid URL prefix in \"%V\"", &proxy);
1005         return NGX_ERROR;
1006     }
1007 
1008     u = r->upstream;
1009 
1010     u->schema.len = add;
1011     u->schema.data = proxy.data;
1012 
1013     ngx_memzero(&url, sizeof(ngx_url_t));
1014 
1015     url.url.len = proxy.len - add;
1016     url.url.data = proxy.data + add;
1017     url.default_port = port;
1018     url.uri_part = 1;
1019     url.no_resolve = 1;
1020 
1021     if (ngx_parse_url(r->pool, &url) != NGX_OK) {
1022         if (url.err) {
1023             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1024                           "%s in upstream \"%V\"", url.err, &url.url);
1025         }
1026 
1027         return NGX_ERROR;
1028     }
1029 
1030     if (url.uri.len) {
1031         if (url.uri.data[0] == '?') {
1032             p = ngx_pnalloc(r->pool, url.uri.len + 1);
1033             if (p == NULL) {
1034                 return NGX_ERROR;
1035             }
1036 
1037             *p++ = '/';
1038             ngx_memcpy(p, url.uri.data, url.uri.len);
1039 
1040             url.uri.len++;
1041             url.uri.data = p - 1;
1042         }
1043     }
1044 
1045     ctx->vars.key_start = u->schema;
1046 
1047     ngx_http_proxy_set_vars(&url, &ctx->vars);
1048 
1049     u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
1050     if (u->resolved == NULL) {
1051         return NGX_ERROR;
1052     }
1053 
1054     if (url.addrs) {
1055         u->resolved->sockaddr = url.addrs[0].sockaddr;
1056         u->resolved->socklen = url.addrs[0].socklen;
1057         u->resolved->name = url.addrs[0].name;
1058         u->resolved->naddrs = 1;
1059     }
1060 
1061     u->resolved->host = url.host;
1062     u->resolved->port = (in_port_t) (url.no_port ? port : url.port);
1063     u->resolved->no_port = url.no_port;
1064 
1065     return NGX_OK;
1066 }
1067 
1068 
1069 #if (NGX_HTTP_CACHE)
1070 
1071 static ngx_int_t
ngx_http_proxy_create_key(ngx_http_request_t * r)1072 ngx_http_proxy_create_key(ngx_http_request_t *r)
1073 {
1074     size_t                      len, loc_len;
1075     u_char                     *p;
1076     uintptr_t                   escape;
1077     ngx_str_t                  *key;
1078     ngx_http_upstream_t        *u;
1079     ngx_http_proxy_ctx_t       *ctx;
1080     ngx_http_proxy_loc_conf_t  *plcf;
1081 
1082     u = r->upstream;
1083 
1084     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
1085 
1086     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1087 
1088     key = ngx_array_push(&r->cache->keys);
1089     if (key == NULL) {
1090         return NGX_ERROR;
1091     }
1092 
1093     if (plcf->cache_key.value.data) {
1094 
1095         if (ngx_http_complex_value(r, &plcf->cache_key, key) != NGX_OK) {
1096             return NGX_ERROR;
1097         }
1098 
1099         return NGX_OK;
1100     }
1101 
1102     *key = ctx->vars.key_start;
1103 
1104     key = ngx_array_push(&r->cache->keys);
1105     if (key == NULL) {
1106         return NGX_ERROR;
1107     }
1108 
1109     if (plcf->proxy_lengths && ctx->vars.uri.len) {
1110 
1111         *key = ctx->vars.uri;
1112         u->uri = ctx->vars.uri;
1113 
1114         return NGX_OK;
1115 
1116     } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri) {
1117         *key = r->unparsed_uri;
1118         u->uri = r->unparsed_uri;
1119 
1120         return NGX_OK;
1121     }
1122 
1123     loc_len = (r->valid_location && ctx->vars.uri.len) ? plcf->location.len : 0;
1124 
1125     if (r->quoted_uri || r->space_in_uri || r->internal) {
1126         escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
1127                                     r->uri.len - loc_len, NGX_ESCAPE_URI);
1128     } else {
1129         escape = 0;
1130     }
1131 
1132     len = ctx->vars.uri.len + r->uri.len - loc_len + escape
1133           + sizeof("?") - 1 + r->args.len;
1134 
1135     p = ngx_pnalloc(r->pool, len);
1136     if (p == NULL) {
1137         return NGX_ERROR;
1138     }
1139 
1140     key->data = p;
1141 
1142     if (r->valid_location) {
1143         p = ngx_copy(p, ctx->vars.uri.data, ctx->vars.uri.len);
1144     }
1145 
1146     if (escape) {
1147         ngx_escape_uri(p, r->uri.data + loc_len,
1148                        r->uri.len - loc_len, NGX_ESCAPE_URI);
1149         p += r->uri.len - loc_len + escape;
1150 
1151     } else {
1152         p = ngx_copy(p, r->uri.data + loc_len, r->uri.len - loc_len);
1153     }
1154 
1155     if (r->args.len > 0) {
1156         *p++ = '?';
1157         p = ngx_copy(p, r->args.data, r->args.len);
1158     }
1159 
1160     key->len = p - key->data;
1161     u->uri = *key;
1162 
1163     return NGX_OK;
1164 }
1165 
1166 #endif
1167 
1168 
1169 static ngx_int_t
ngx_http_proxy_create_request(ngx_http_request_t * r)1170 ngx_http_proxy_create_request(ngx_http_request_t *r)
1171 {
1172     size_t                        len, uri_len, loc_len, body_len,
1173                                   key_len, val_len;
1174     uintptr_t                     escape;
1175     ngx_buf_t                    *b;
1176     ngx_str_t                     method;
1177     ngx_uint_t                    i, unparsed_uri;
1178     ngx_chain_t                  *cl, *body;
1179     ngx_list_part_t              *part;
1180     ngx_table_elt_t              *header;
1181     ngx_http_upstream_t          *u;
1182     ngx_http_proxy_ctx_t         *ctx;
1183     ngx_http_script_code_pt       code;
1184     ngx_http_proxy_headers_t     *headers;
1185     ngx_http_script_engine_t      e, le;
1186     ngx_http_proxy_loc_conf_t    *plcf;
1187     ngx_http_script_len_code_pt   lcode;
1188 
1189     u = r->upstream;
1190 
1191     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
1192 
1193 #if (NGX_HTTP_CACHE)
1194     headers = u->cacheable ? &plcf->headers_cache : &plcf->headers;
1195 #else
1196     headers = &plcf->headers;
1197 #endif
1198 
1199     if (u->method.len) {
1200         /* HEAD was changed to GET to cache response */
1201         method = u->method;
1202 
1203     } else if (plcf->method) {
1204         if (ngx_http_complex_value(r, plcf->method, &method) != NGX_OK) {
1205             return NGX_ERROR;
1206         }
1207 
1208     } else {
1209         method = r->method_name;
1210     }
1211 
1212     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1213 
1214     if (method.len == 4
1215         && ngx_strncasecmp(method.data, (u_char *) "HEAD", 4) == 0)
1216     {
1217         ctx->head = 1;
1218     }
1219 
1220     len = method.len + 1 + sizeof(ngx_http_proxy_version) - 1
1221           + sizeof(CRLF) - 1;
1222 
1223     escape = 0;
1224     loc_len = 0;
1225     unparsed_uri = 0;
1226 
1227     if (plcf->proxy_lengths && ctx->vars.uri.len) {
1228         uri_len = ctx->vars.uri.len;
1229 
1230     } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri) {
1231         unparsed_uri = 1;
1232         uri_len = r->unparsed_uri.len;
1233 
1234     } else {
1235         loc_len = (r->valid_location && ctx->vars.uri.len) ?
1236                       plcf->location.len : 0;
1237 
1238         if (r->quoted_uri || r->space_in_uri || r->internal) {
1239             escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
1240                                         r->uri.len - loc_len, NGX_ESCAPE_URI);
1241         }
1242 
1243         uri_len = ctx->vars.uri.len + r->uri.len - loc_len + escape
1244                   + sizeof("?") - 1 + r->args.len;
1245     }
1246 
1247     if (uri_len == 0) {
1248         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1249                       "zero length URI to proxy");
1250         return NGX_ERROR;
1251     }
1252 
1253     len += uri_len;
1254 
1255     ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
1256 
1257     ngx_http_script_flush_no_cacheable_variables(r, plcf->body_flushes);
1258     ngx_http_script_flush_no_cacheable_variables(r, headers->flushes);
1259 
1260     if (plcf->body_lengths) {
1261         le.ip = plcf->body_lengths->elts;
1262         le.request = r;
1263         le.flushed = 1;
1264         body_len = 0;
1265 
1266         while (*(uintptr_t *) le.ip) {
1267             lcode = *(ngx_http_script_len_code_pt *) le.ip;
1268             body_len += lcode(&le);
1269         }
1270 
1271         ctx->internal_body_length = body_len;
1272         len += body_len;
1273 
1274     } else if (r->headers_in.chunked && r->reading_body) {
1275         ctx->internal_body_length = -1;
1276         ctx->internal_chunked = 1;
1277 
1278     } else {
1279         ctx->internal_body_length = r->headers_in.content_length_n;
1280     }
1281 
1282     le.ip = headers->lengths->elts;
1283     le.request = r;
1284     le.flushed = 1;
1285 
1286     while (*(uintptr_t *) le.ip) {
1287 
1288         lcode = *(ngx_http_script_len_code_pt *) le.ip;
1289         key_len = lcode(&le);
1290 
1291         for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
1292             lcode = *(ngx_http_script_len_code_pt *) le.ip;
1293         }
1294         le.ip += sizeof(uintptr_t);
1295 
1296         if (val_len == 0) {
1297             continue;
1298         }
1299 
1300         len += key_len + sizeof(": ") - 1 + val_len + sizeof(CRLF) - 1;
1301     }
1302 
1303 
1304     if (plcf->upstream.pass_request_headers) {
1305         part = &r->headers_in.headers.part;
1306         header = part->elts;
1307 
1308         for (i = 0; /* void */; i++) {
1309 
1310             if (i >= part->nelts) {
1311                 if (part->next == NULL) {
1312                     break;
1313                 }
1314 
1315                 part = part->next;
1316                 header = part->elts;
1317                 i = 0;
1318             }
1319 
1320             if (ngx_hash_find(&headers->hash, header[i].hash,
1321                               header[i].lowcase_key, header[i].key.len))
1322             {
1323                 continue;
1324             }
1325 
1326             len += header[i].key.len + sizeof(": ") - 1
1327                 + header[i].value.len + sizeof(CRLF) - 1;
1328         }
1329     }
1330 
1331 
1332     b = ngx_create_temp_buf(r->pool, len);
1333     if (b == NULL) {
1334         return NGX_ERROR;
1335     }
1336 
1337     cl = ngx_alloc_chain_link(r->pool);
1338     if (cl == NULL) {
1339         return NGX_ERROR;
1340     }
1341 
1342     cl->buf = b;
1343 
1344 
1345     /* the request line */
1346 
1347     b->last = ngx_copy(b->last, method.data, method.len);
1348     *b->last++ = ' ';
1349 
1350     u->uri.data = b->last;
1351 
1352     if (plcf->proxy_lengths && ctx->vars.uri.len) {
1353         b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
1354 
1355     } else if (unparsed_uri) {
1356         b->last = ngx_copy(b->last, r->unparsed_uri.data, r->unparsed_uri.len);
1357 
1358     } else {
1359         if (r->valid_location) {
1360             b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
1361         }
1362 
1363         if (escape) {
1364             ngx_escape_uri(b->last, r->uri.data + loc_len,
1365                            r->uri.len - loc_len, NGX_ESCAPE_URI);
1366             b->last += r->uri.len - loc_len + escape;
1367 
1368         } else {
1369             b->last = ngx_copy(b->last, r->uri.data + loc_len,
1370                                r->uri.len - loc_len);
1371         }
1372 
1373         if (r->args.len > 0) {
1374             *b->last++ = '?';
1375             b->last = ngx_copy(b->last, r->args.data, r->args.len);
1376         }
1377     }
1378 
1379     u->uri.len = b->last - u->uri.data;
1380 
1381     if (plcf->http_version == NGX_HTTP_VERSION_11) {
1382         b->last = ngx_cpymem(b->last, ngx_http_proxy_version_11,
1383                              sizeof(ngx_http_proxy_version_11) - 1);
1384 
1385     } else {
1386         b->last = ngx_cpymem(b->last, ngx_http_proxy_version,
1387                              sizeof(ngx_http_proxy_version) - 1);
1388     }
1389 
1390     ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
1391 
1392     e.ip = headers->values->elts;
1393     e.pos = b->last;
1394     e.request = r;
1395     e.flushed = 1;
1396 
1397     le.ip = headers->lengths->elts;
1398 
1399     while (*(uintptr_t *) le.ip) {
1400 
1401         lcode = *(ngx_http_script_len_code_pt *) le.ip;
1402         (void) lcode(&le);
1403 
1404         for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
1405             lcode = *(ngx_http_script_len_code_pt *) le.ip;
1406         }
1407         le.ip += sizeof(uintptr_t);
1408 
1409         if (val_len == 0) {
1410             e.skip = 1;
1411 
1412             while (*(uintptr_t *) e.ip) {
1413                 code = *(ngx_http_script_code_pt *) e.ip;
1414                 code((ngx_http_script_engine_t *) &e);
1415             }
1416             e.ip += sizeof(uintptr_t);
1417 
1418             e.skip = 0;
1419 
1420             continue;
1421         }
1422 
1423         code = *(ngx_http_script_code_pt *) e.ip;
1424         code((ngx_http_script_engine_t *) &e);
1425 
1426         *e.pos++ = ':'; *e.pos++ = ' ';
1427 
1428         while (*(uintptr_t *) e.ip) {
1429             code = *(ngx_http_script_code_pt *) e.ip;
1430             code((ngx_http_script_engine_t *) &e);
1431         }
1432         e.ip += sizeof(uintptr_t);
1433 
1434         *e.pos++ = CR; *e.pos++ = LF;
1435     }
1436 
1437     b->last = e.pos;
1438 
1439 
1440     if (plcf->upstream.pass_request_headers) {
1441         part = &r->headers_in.headers.part;
1442         header = part->elts;
1443 
1444         for (i = 0; /* void */; i++) {
1445 
1446             if (i >= part->nelts) {
1447                 if (part->next == NULL) {
1448                     break;
1449                 }
1450 
1451                 part = part->next;
1452                 header = part->elts;
1453                 i = 0;
1454             }
1455 
1456             if (ngx_hash_find(&headers->hash, header[i].hash,
1457                               header[i].lowcase_key, header[i].key.len))
1458             {
1459                 continue;
1460             }
1461 
1462             b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len);
1463 
1464             *b->last++ = ':'; *b->last++ = ' ';
1465 
1466             b->last = ngx_copy(b->last, header[i].value.data,
1467                                header[i].value.len);
1468 
1469             *b->last++ = CR; *b->last++ = LF;
1470 
1471             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1472                            "http proxy header: \"%V: %V\"",
1473                            &header[i].key, &header[i].value);
1474         }
1475     }
1476 
1477 
1478     /* add "\r\n" at the header end */
1479     *b->last++ = CR; *b->last++ = LF;
1480 
1481     if (plcf->body_values) {
1482         e.ip = plcf->body_values->elts;
1483         e.pos = b->last;
1484         e.skip = 0;
1485 
1486         while (*(uintptr_t *) e.ip) {
1487             code = *(ngx_http_script_code_pt *) e.ip;
1488             code((ngx_http_script_engine_t *) &e);
1489         }
1490 
1491         b->last = e.pos;
1492     }
1493 
1494     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1495                    "http proxy header:%N\"%*s\"",
1496                    (size_t) (b->last - b->pos), b->pos);
1497 
1498     if (r->request_body_no_buffering) {
1499 
1500         u->request_bufs = cl;
1501 
1502         if (ctx->internal_chunked) {
1503             u->output.output_filter = ngx_http_proxy_body_output_filter;
1504             u->output.filter_ctx = r;
1505         }
1506 
1507     } else if (plcf->body_values == NULL && plcf->upstream.pass_request_body) {
1508 
1509         body = u->request_bufs;
1510         u->request_bufs = cl;
1511 
1512         while (body) {
1513             b = ngx_alloc_buf(r->pool);
1514             if (b == NULL) {
1515                 return NGX_ERROR;
1516             }
1517 
1518             ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
1519 
1520             cl->next = ngx_alloc_chain_link(r->pool);
1521             if (cl->next == NULL) {
1522                 return NGX_ERROR;
1523             }
1524 
1525             cl = cl->next;
1526             cl->buf = b;
1527 
1528             body = body->next;
1529         }
1530 
1531     } else {
1532         u->request_bufs = cl;
1533     }
1534 
1535     b->flush = 1;
1536     cl->next = NULL;
1537 
1538     return NGX_OK;
1539 }
1540 
1541 
1542 static ngx_int_t
ngx_http_proxy_reinit_request(ngx_http_request_t * r)1543 ngx_http_proxy_reinit_request(ngx_http_request_t *r)
1544 {
1545     ngx_http_proxy_ctx_t  *ctx;
1546 
1547     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1548 
1549     if (ctx == NULL) {
1550         return NGX_OK;
1551     }
1552 
1553     ctx->status.code = 0;
1554     ctx->status.count = 0;
1555     ctx->status.start = NULL;
1556     ctx->status.end = NULL;
1557     ctx->chunked.state = 0;
1558 
1559     r->upstream->process_header = ngx_http_proxy_process_status_line;
1560     r->upstream->pipe->input_filter = ngx_http_proxy_copy_filter;
1561     r->upstream->input_filter = ngx_http_proxy_non_buffered_copy_filter;
1562     r->state = 0;
1563 
1564     return NGX_OK;
1565 }
1566 
1567 
1568 static ngx_int_t
ngx_http_proxy_body_output_filter(void * data,ngx_chain_t * in)1569 ngx_http_proxy_body_output_filter(void *data, ngx_chain_t *in)
1570 {
1571     ngx_http_request_t  *r = data;
1572 
1573     off_t                  size;
1574     u_char                *chunk;
1575     ngx_int_t              rc;
1576     ngx_buf_t             *b;
1577     ngx_chain_t           *out, *cl, *tl, **ll, **fl;
1578     ngx_http_proxy_ctx_t  *ctx;
1579 
1580     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1581                    "proxy output filter");
1582 
1583     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1584 
1585     if (in == NULL) {
1586         out = in;
1587         goto out;
1588     }
1589 
1590     out = NULL;
1591     ll = &out;
1592 
1593     if (!ctx->header_sent) {
1594         /* first buffer contains headers, pass it unmodified */
1595 
1596         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1597                        "proxy output header");
1598 
1599         ctx->header_sent = 1;
1600 
1601         tl = ngx_alloc_chain_link(r->pool);
1602         if (tl == NULL) {
1603             return NGX_ERROR;
1604         }
1605 
1606         tl->buf = in->buf;
1607         *ll = tl;
1608         ll = &tl->next;
1609 
1610         in = in->next;
1611 
1612         if (in == NULL) {
1613             tl->next = NULL;
1614             goto out;
1615         }
1616     }
1617 
1618     size = 0;
1619     cl = in;
1620     fl = ll;
1621 
1622     for ( ;; ) {
1623         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1624                        "proxy output chunk: %O", ngx_buf_size(cl->buf));
1625 
1626         size += ngx_buf_size(cl->buf);
1627 
1628         if (cl->buf->flush
1629             || cl->buf->sync
1630             || ngx_buf_in_memory(cl->buf)
1631             || cl->buf->in_file)
1632         {
1633             tl = ngx_alloc_chain_link(r->pool);
1634             if (tl == NULL) {
1635                 return NGX_ERROR;
1636             }
1637 
1638             tl->buf = cl->buf;
1639             *ll = tl;
1640             ll = &tl->next;
1641         }
1642 
1643         if (cl->next == NULL) {
1644             break;
1645         }
1646 
1647         cl = cl->next;
1648     }
1649 
1650     if (size) {
1651         tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
1652         if (tl == NULL) {
1653             return NGX_ERROR;
1654         }
1655 
1656         b = tl->buf;
1657         chunk = b->start;
1658 
1659         if (chunk == NULL) {
1660             /* the "0000000000000000" is 64-bit hexadecimal string */
1661 
1662             chunk = ngx_palloc(r->pool, sizeof("0000000000000000" CRLF) - 1);
1663             if (chunk == NULL) {
1664                 return NGX_ERROR;
1665             }
1666 
1667             b->start = chunk;
1668             b->end = chunk + sizeof("0000000000000000" CRLF) - 1;
1669         }
1670 
1671         b->tag = (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter;
1672         b->memory = 0;
1673         b->temporary = 1;
1674         b->pos = chunk;
1675         b->last = ngx_sprintf(chunk, "%xO" CRLF, size);
1676 
1677         tl->next = *fl;
1678         *fl = tl;
1679     }
1680 
1681     if (cl->buf->last_buf) {
1682         tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
1683         if (tl == NULL) {
1684             return NGX_ERROR;
1685         }
1686 
1687         b = tl->buf;
1688 
1689         b->tag = (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter;
1690         b->temporary = 0;
1691         b->memory = 1;
1692         b->last_buf = 1;
1693         b->pos = (u_char *) CRLF "0" CRLF CRLF;
1694         b->last = b->pos + 7;
1695 
1696         cl->buf->last_buf = 0;
1697 
1698         *ll = tl;
1699 
1700         if (size == 0) {
1701             b->pos += 2;
1702         }
1703 
1704     } else if (size > 0) {
1705         tl = ngx_chain_get_free_buf(r->pool, &ctx->free);
1706         if (tl == NULL) {
1707             return NGX_ERROR;
1708         }
1709 
1710         b = tl->buf;
1711 
1712         b->tag = (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter;
1713         b->temporary = 0;
1714         b->memory = 1;
1715         b->pos = (u_char *) CRLF;
1716         b->last = b->pos + 2;
1717 
1718         *ll = tl;
1719 
1720     } else {
1721         *ll = NULL;
1722     }
1723 
1724 out:
1725 
1726     rc = ngx_chain_writer(&r->upstream->writer, out);
1727 
1728     ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &out,
1729                             (ngx_buf_tag_t) &ngx_http_proxy_body_output_filter);
1730 
1731     return rc;
1732 }
1733 
1734 
1735 static ngx_int_t
ngx_http_proxy_process_status_line(ngx_http_request_t * r)1736 ngx_http_proxy_process_status_line(ngx_http_request_t *r)
1737 {
1738     size_t                 len;
1739     ngx_int_t              rc;
1740     ngx_http_upstream_t   *u;
1741     ngx_http_proxy_ctx_t  *ctx;
1742 
1743     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1744 
1745     if (ctx == NULL) {
1746         return NGX_ERROR;
1747     }
1748 
1749     u = r->upstream;
1750 
1751     rc = ngx_http_parse_status_line(r, &u->buffer, &ctx->status);
1752 
1753     if (rc == NGX_AGAIN) {
1754         return rc;
1755     }
1756 
1757     if (rc == NGX_ERROR) {
1758 
1759 #if (NGX_HTTP_CACHE)
1760 
1761         if (r->cache) {
1762             r->http_version = NGX_HTTP_VERSION_9;
1763             return NGX_OK;
1764         }
1765 
1766 #endif
1767 
1768         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1769                       "upstream sent no valid HTTP/1.0 header");
1770 
1771 #if 0
1772         if (u->accel) {
1773             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1774         }
1775 #endif
1776 
1777         r->http_version = NGX_HTTP_VERSION_9;
1778         u->state->status = NGX_HTTP_OK;
1779         u->headers_in.connection_close = 1;
1780 
1781         return NGX_OK;
1782     }
1783 
1784     if (u->state && u->state->status == 0) {
1785         u->state->status = ctx->status.code;
1786     }
1787 
1788     u->headers_in.status_n = ctx->status.code;
1789 
1790     len = ctx->status.end - ctx->status.start;
1791     u->headers_in.status_line.len = len;
1792 
1793     u->headers_in.status_line.data = ngx_pnalloc(r->pool, len);
1794     if (u->headers_in.status_line.data == NULL) {
1795         return NGX_ERROR;
1796     }
1797 
1798     ngx_memcpy(u->headers_in.status_line.data, ctx->status.start, len);
1799 
1800     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1801                    "http proxy status %ui \"%V\"",
1802                    u->headers_in.status_n, &u->headers_in.status_line);
1803 
1804     if (ctx->status.http_version < NGX_HTTP_VERSION_11) {
1805         u->headers_in.connection_close = 1;
1806     }
1807 
1808     u->process_header = ngx_http_proxy_process_header;
1809 
1810     return ngx_http_proxy_process_header(r);
1811 }
1812 
1813 
1814 static ngx_int_t
ngx_http_proxy_process_header(ngx_http_request_t * r)1815 ngx_http_proxy_process_header(ngx_http_request_t *r)
1816 {
1817     ngx_int_t                       rc;
1818     ngx_table_elt_t                *h;
1819     ngx_http_upstream_t            *u;
1820     ngx_http_proxy_ctx_t           *ctx;
1821     ngx_http_upstream_header_t     *hh;
1822     ngx_http_upstream_main_conf_t  *umcf;
1823 
1824     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
1825 
1826     for ( ;; ) {
1827 
1828         rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);
1829 
1830         if (rc == NGX_OK) {
1831 
1832             /* a header line has been parsed successfully */
1833 
1834             h = ngx_list_push(&r->upstream->headers_in.headers);
1835             if (h == NULL) {
1836                 return NGX_ERROR;
1837             }
1838 
1839             h->hash = r->header_hash;
1840 
1841             h->key.len = r->header_name_end - r->header_name_start;
1842             h->value.len = r->header_end - r->header_start;
1843 
1844             h->key.data = ngx_pnalloc(r->pool,
1845                                h->key.len + 1 + h->value.len + 1 + h->key.len);
1846             if (h->key.data == NULL) {
1847                 h->hash = 0;
1848                 return NGX_ERROR;
1849             }
1850 
1851             h->value.data = h->key.data + h->key.len + 1;
1852             h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;
1853 
1854             ngx_memcpy(h->key.data, r->header_name_start, h->key.len);
1855             h->key.data[h->key.len] = '\0';
1856             ngx_memcpy(h->value.data, r->header_start, h->value.len);
1857             h->value.data[h->value.len] = '\0';
1858 
1859             if (h->key.len == r->lowcase_index) {
1860                 ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
1861 
1862             } else {
1863                 ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
1864             }
1865 
1866             hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
1867                                h->lowcase_key, h->key.len);
1868 
1869             if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1870                 return NGX_ERROR;
1871             }
1872 
1873             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1874                            "http proxy header: \"%V: %V\"",
1875                            &h->key, &h->value);
1876 
1877             continue;
1878         }
1879 
1880         if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
1881 
1882             /* a whole header has been parsed successfully */
1883 
1884             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1885                            "http proxy header done");
1886 
1887             /*
1888              * if no "Server" and "Date" in header line,
1889              * then add the special empty headers
1890              */
1891 
1892             if (r->upstream->headers_in.server == NULL) {
1893                 h = ngx_list_push(&r->upstream->headers_in.headers);
1894                 if (h == NULL) {
1895                     return NGX_ERROR;
1896                 }
1897 
1898                 h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(
1899                                     ngx_hash('s', 'e'), 'r'), 'v'), 'e'), 'r');
1900 
1901                 ngx_str_set(&h->key, "Server");
1902                 ngx_str_null(&h->value);
1903                 h->lowcase_key = (u_char *) "server";
1904             }
1905 
1906             if (r->upstream->headers_in.date == NULL) {
1907                 h = ngx_list_push(&r->upstream->headers_in.headers);
1908                 if (h == NULL) {
1909                     return NGX_ERROR;
1910                 }
1911 
1912                 h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e');
1913 
1914                 ngx_str_set(&h->key, "Date");
1915                 ngx_str_null(&h->value);
1916                 h->lowcase_key = (u_char *) "date";
1917             }
1918 
1919             /* clear content length if response is chunked */
1920 
1921             u = r->upstream;
1922 
1923             if (u->headers_in.chunked) {
1924                 u->headers_in.content_length_n = -1;
1925             }
1926 
1927             /*
1928              * set u->keepalive if response has no body; this allows to keep
1929              * connections alive in case of r->header_only or X-Accel-Redirect
1930              */
1931 
1932             ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1933 
1934             if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
1935                 || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
1936                 || ctx->head
1937                 || (!u->headers_in.chunked
1938                     && u->headers_in.content_length_n == 0))
1939             {
1940                 u->keepalive = !u->headers_in.connection_close;
1941             }
1942 
1943             if (u->headers_in.status_n == NGX_HTTP_SWITCHING_PROTOCOLS) {
1944                 u->keepalive = 0;
1945 
1946                 if (r->headers_in.upgrade) {
1947                     u->upgrade = 1;
1948                 }
1949             }
1950 
1951             return NGX_OK;
1952         }
1953 
1954         if (rc == NGX_AGAIN) {
1955             return NGX_AGAIN;
1956         }
1957 
1958         /* there was error while a header line parsing */
1959 
1960         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1961                       "upstream sent invalid header");
1962 
1963         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1964     }
1965 }
1966 
1967 
1968 static ngx_int_t
ngx_http_proxy_input_filter_init(void * data)1969 ngx_http_proxy_input_filter_init(void *data)
1970 {
1971     ngx_http_request_t    *r = data;
1972     ngx_http_upstream_t   *u;
1973     ngx_http_proxy_ctx_t  *ctx;
1974 
1975     u = r->upstream;
1976     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1977 
1978     if (ctx == NULL) {
1979         return NGX_ERROR;
1980     }
1981 
1982     ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1983                    "http proxy filter init s:%ui h:%d c:%d l:%O",
1984                    u->headers_in.status_n, ctx->head, u->headers_in.chunked,
1985                    u->headers_in.content_length_n);
1986 
1987     /* as per RFC2616, 4.4 Message Length */
1988 
1989     if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
1990         || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
1991         || ctx->head)
1992     {
1993         /* 1xx, 204, and 304 and replies to HEAD requests */
1994         /* no 1xx since we don't send Expect and Upgrade */
1995 
1996         u->pipe->length = 0;
1997         u->length = 0;
1998         u->keepalive = !u->headers_in.connection_close;
1999 
2000     } else if (u->headers_in.chunked) {
2001         /* chunked */
2002 
2003         u->pipe->input_filter = ngx_http_proxy_chunked_filter;
2004         u->pipe->length = 3; /* "0" LF LF */
2005 
2006         u->input_filter = ngx_http_proxy_non_buffered_chunked_filter;
2007         u->length = 1;
2008 
2009     } else if (u->headers_in.content_length_n == 0) {
2010         /* empty body: special case as filter won't be called */
2011 
2012         u->pipe->length = 0;
2013         u->length = 0;
2014         u->keepalive = !u->headers_in.connection_close;
2015 
2016     } else {
2017         /* content length or connection close */
2018 
2019         u->pipe->length = u->headers_in.content_length_n;
2020         u->length = u->headers_in.content_length_n;
2021     }
2022 
2023     return NGX_OK;
2024 }
2025 
2026 
2027 static ngx_int_t
ngx_http_proxy_copy_filter(ngx_event_pipe_t * p,ngx_buf_t * buf)2028 ngx_http_proxy_copy_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
2029 {
2030     ngx_buf_t           *b;
2031     ngx_chain_t         *cl;
2032     ngx_http_request_t  *r;
2033 
2034     if (buf->pos == buf->last) {
2035         return NGX_OK;
2036     }
2037 
2038     cl = ngx_chain_get_free_buf(p->pool, &p->free);
2039     if (cl == NULL) {
2040         return NGX_ERROR;
2041     }
2042 
2043     b = cl->buf;
2044 
2045     ngx_memcpy(b, buf, sizeof(ngx_buf_t));
2046     b->shadow = buf;
2047     b->tag = p->tag;
2048     b->last_shadow = 1;
2049     b->recycled = 1;
2050     buf->shadow = b;
2051 
2052     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num);
2053 
2054     if (p->in) {
2055         *p->last_in = cl;
2056     } else {
2057         p->in = cl;
2058     }
2059     p->last_in = &cl->next;
2060 
2061     if (p->length == -1) {
2062         return NGX_OK;
2063     }
2064 
2065     p->length -= b->last - b->pos;
2066 
2067     if (p->length == 0) {
2068         r = p->input_ctx;
2069         p->upstream_done = 1;
2070         r->upstream->keepalive = !r->upstream->headers_in.connection_close;
2071 
2072     } else if (p->length < 0) {
2073         r = p->input_ctx;
2074         p->upstream_done = 1;
2075 
2076         ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
2077                       "upstream sent more data than specified in "
2078                       "\"Content-Length\" header");
2079     }
2080 
2081     return NGX_OK;
2082 }
2083 
2084 
2085 static ngx_int_t
ngx_http_proxy_chunked_filter(ngx_event_pipe_t * p,ngx_buf_t * buf)2086 ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
2087 {
2088     ngx_int_t              rc;
2089     ngx_buf_t             *b, **prev;
2090     ngx_chain_t           *cl;
2091     ngx_http_request_t    *r;
2092     ngx_http_proxy_ctx_t  *ctx;
2093 
2094     if (buf->pos == buf->last) {
2095         return NGX_OK;
2096     }
2097 
2098     r = p->input_ctx;
2099     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2100 
2101     if (ctx == NULL) {
2102         return NGX_ERROR;
2103     }
2104 
2105     b = NULL;
2106     prev = &buf->shadow;
2107 
2108     for ( ;; ) {
2109 
2110         rc = ngx_http_parse_chunked(r, buf, &ctx->chunked);
2111 
2112         if (rc == NGX_OK) {
2113 
2114             /* a chunk has been parsed successfully */
2115 
2116             cl = ngx_chain_get_free_buf(p->pool, &p->free);
2117             if (cl == NULL) {
2118                 return NGX_ERROR;
2119             }
2120 
2121             b = cl->buf;
2122 
2123             ngx_memzero(b, sizeof(ngx_buf_t));
2124 
2125             b->pos = buf->pos;
2126             b->start = buf->start;
2127             b->end = buf->end;
2128             b->tag = p->tag;
2129             b->temporary = 1;
2130             b->recycled = 1;
2131 
2132             *prev = b;
2133             prev = &b->shadow;
2134 
2135             if (p->in) {
2136                 *p->last_in = cl;
2137             } else {
2138                 p->in = cl;
2139             }
2140             p->last_in = &cl->next;
2141 
2142             /* STUB */ b->num = buf->num;
2143 
2144             ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
2145                            "input buf #%d %p", b->num, b->pos);
2146 
2147             if (buf->last - buf->pos >= ctx->chunked.size) {
2148 
2149                 buf->pos += (size_t) ctx->chunked.size;
2150                 b->last = buf->pos;
2151                 ctx->chunked.size = 0;
2152 
2153                 continue;
2154             }
2155 
2156             ctx->chunked.size -= buf->last - buf->pos;
2157             buf->pos = buf->last;
2158             b->last = buf->last;
2159 
2160             continue;
2161         }
2162 
2163         if (rc == NGX_DONE) {
2164 
2165             /* a whole response has been parsed successfully */
2166 
2167             p->upstream_done = 1;
2168             r->upstream->keepalive = !r->upstream->headers_in.connection_close;
2169 
2170             break;
2171         }
2172 
2173         if (rc == NGX_AGAIN) {
2174 
2175             /* set p->length, minimal amount of data we want to see */
2176 
2177             p->length = ctx->chunked.length;
2178 
2179             break;
2180         }
2181 
2182         /* invalid response */
2183 
2184         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2185                       "upstream sent invalid chunked response");
2186 
2187         return NGX_ERROR;
2188     }
2189 
2190     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2191                    "http proxy chunked state %ui, length %O",
2192                    ctx->chunked.state, p->length);
2193 
2194     if (b) {
2195         b->shadow = buf;
2196         b->last_shadow = 1;
2197 
2198         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
2199                        "input buf %p %z", b->pos, b->last - b->pos);
2200 
2201         return NGX_OK;
2202     }
2203 
2204     /* there is no data record in the buf, add it to free chain */
2205 
2206     if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) {
2207         return NGX_ERROR;
2208     }
2209 
2210     return NGX_OK;
2211 }
2212 
2213 
2214 static ngx_int_t
ngx_http_proxy_non_buffered_copy_filter(void * data,ssize_t bytes)2215 ngx_http_proxy_non_buffered_copy_filter(void *data, ssize_t bytes)
2216 {
2217     ngx_http_request_t   *r = data;
2218 
2219     ngx_buf_t            *b;
2220     ngx_chain_t          *cl, **ll;
2221     ngx_http_upstream_t  *u;
2222 
2223     u = r->upstream;
2224 
2225     for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
2226         ll = &cl->next;
2227     }
2228 
2229     cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
2230     if (cl == NULL) {
2231         return NGX_ERROR;
2232     }
2233 
2234     *ll = cl;
2235 
2236     cl->buf->flush = 1;
2237     cl->buf->memory = 1;
2238 
2239     b = &u->buffer;
2240 
2241     cl->buf->pos = b->last;
2242     b->last += bytes;
2243     cl->buf->last = b->last;
2244     cl->buf->tag = u->output.tag;
2245 
2246     if (u->length == -1) {
2247         return NGX_OK;
2248     }
2249 
2250     u->length -= bytes;
2251 
2252     if (u->length == 0) {
2253         u->keepalive = !u->headers_in.connection_close;
2254     }
2255 
2256     return NGX_OK;
2257 }
2258 
2259 
2260 static ngx_int_t
ngx_http_proxy_non_buffered_chunked_filter(void * data,ssize_t bytes)2261 ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes)
2262 {
2263     ngx_http_request_t   *r = data;
2264 
2265     ngx_int_t              rc;
2266     ngx_buf_t             *b, *buf;
2267     ngx_chain_t           *cl, **ll;
2268     ngx_http_upstream_t   *u;
2269     ngx_http_proxy_ctx_t  *ctx;
2270 
2271     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2272 
2273     if (ctx == NULL) {
2274         return NGX_ERROR;
2275     }
2276 
2277     u = r->upstream;
2278     buf = &u->buffer;
2279 
2280     buf->pos = buf->last;
2281     buf->last += bytes;
2282 
2283     for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
2284         ll = &cl->next;
2285     }
2286 
2287     for ( ;; ) {
2288 
2289         rc = ngx_http_parse_chunked(r, buf, &ctx->chunked);
2290 
2291         if (rc == NGX_OK) {
2292 
2293             /* a chunk has been parsed successfully */
2294 
2295             cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
2296             if (cl == NULL) {
2297                 return NGX_ERROR;
2298             }
2299 
2300             *ll = cl;
2301             ll = &cl->next;
2302 
2303             b = cl->buf;
2304 
2305             b->flush = 1;
2306             b->memory = 1;
2307 
2308             b->pos = buf->pos;
2309             b->tag = u->output.tag;
2310 
2311             if (buf->last - buf->pos >= ctx->chunked.size) {
2312                 buf->pos += (size_t) ctx->chunked.size;
2313                 b->last = buf->pos;
2314                 ctx->chunked.size = 0;
2315 
2316             } else {
2317                 ctx->chunked.size -= buf->last - buf->pos;
2318                 buf->pos = buf->last;
2319                 b->last = buf->last;
2320             }
2321 
2322             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2323                            "http proxy out buf %p %z",
2324                            b->pos, b->last - b->pos);
2325 
2326             continue;
2327         }
2328 
2329         if (rc == NGX_DONE) {
2330 
2331             /* a whole response has been parsed successfully */
2332 
2333             u->keepalive = !u->headers_in.connection_close;
2334             u->length = 0;
2335 
2336             break;
2337         }
2338 
2339         if (rc == NGX_AGAIN) {
2340             break;
2341         }
2342 
2343         /* invalid response */
2344 
2345         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2346                       "upstream sent invalid chunked response");
2347 
2348         return NGX_ERROR;
2349     }
2350 
2351     return NGX_OK;
2352 }
2353 
2354 
2355 static void
ngx_http_proxy_abort_request(ngx_http_request_t * r)2356 ngx_http_proxy_abort_request(ngx_http_request_t *r)
2357 {
2358     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2359                    "abort http proxy request");
2360 
2361     return;
2362 }
2363 
2364 
2365 static void
ngx_http_proxy_finalize_request(ngx_http_request_t * r,ngx_int_t rc)2366 ngx_http_proxy_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
2367 {
2368     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2369                    "finalize http proxy request");
2370 
2371     return;
2372 }
2373 
2374 
2375 static ngx_int_t
ngx_http_proxy_host_variable(ngx_http_request_t * r,ngx_http_variable_value_t * v,uintptr_t data)2376 ngx_http_proxy_host_variable(ngx_http_request_t *r,
2377     ngx_http_variable_value_t *v, uintptr_t data)
2378 {
2379     ngx_http_proxy_ctx_t  *ctx;
2380 
2381     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2382 
2383     if (ctx == NULL) {
2384         v->not_found = 1;
2385         return NGX_OK;
2386     }
2387 
2388     v->len = ctx->vars.host_header.len;
2389     v->valid = 1;
2390     v->no_cacheable = 0;
2391     v->not_found = 0;
2392     v->data = ctx->vars.host_header.data;
2393 
2394     return NGX_OK;
2395 }
2396 
2397 
2398 static ngx_int_t
ngx_http_proxy_port_variable(ngx_http_request_t * r,ngx_http_variable_value_t * v,uintptr_t data)2399 ngx_http_proxy_port_variable(ngx_http_request_t *r,
2400     ngx_http_variable_value_t *v, uintptr_t data)
2401 {
2402     ngx_http_proxy_ctx_t  *ctx;
2403 
2404     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2405 
2406     if (ctx == NULL) {
2407         v->not_found = 1;
2408         return NGX_OK;
2409     }
2410 
2411     v->len = ctx->vars.port.len;
2412     v->valid = 1;
2413     v->no_cacheable = 0;
2414     v->not_found = 0;
2415     v->data = ctx->vars.port.data;
2416 
2417     return NGX_OK;
2418 }
2419 
2420 
2421 static ngx_int_t
ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t * r,ngx_http_variable_value_t * v,uintptr_t data)2422 ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
2423     ngx_http_variable_value_t *v, uintptr_t data)
2424 {
2425     size_t             len;
2426     u_char            *p;
2427     ngx_uint_t         i, n;
2428     ngx_table_elt_t  **h;
2429 
2430     v->valid = 1;
2431     v->no_cacheable = 0;
2432     v->not_found = 0;
2433 
2434     n = r->headers_in.x_forwarded_for.nelts;
2435     h = r->headers_in.x_forwarded_for.elts;
2436 
2437     len = 0;
2438 
2439     for (i = 0; i < n; i++) {
2440         len += h[i]->value.len + sizeof(", ") - 1;
2441     }
2442 
2443     if (len == 0) {
2444         v->len = r->connection->addr_text.len;
2445         v->data = r->connection->addr_text.data;
2446         return NGX_OK;
2447     }
2448 
2449     len += r->connection->addr_text.len;
2450 
2451     p = ngx_pnalloc(r->pool, len);
2452     if (p == NULL) {
2453         return NGX_ERROR;
2454     }
2455 
2456     v->len = len;
2457     v->data = p;
2458 
2459     for (i = 0; i < n; i++) {
2460         p = ngx_copy(p, h[i]->value.data, h[i]->value.len);
2461         *p++ = ','; *p++ = ' ';
2462     }
2463 
2464     ngx_memcpy(p, r->connection->addr_text.data, r->connection->addr_text.len);
2465 
2466     return NGX_OK;
2467 }
2468 
2469 
2470 static ngx_int_t
ngx_http_proxy_internal_body_length_variable(ngx_http_request_t * r,ngx_http_variable_value_t * v,uintptr_t data)2471 ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
2472     ngx_http_variable_value_t *v, uintptr_t data)
2473 {
2474     ngx_http_proxy_ctx_t  *ctx;
2475 
2476     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2477 
2478     if (ctx == NULL || ctx->internal_body_length < 0) {
2479         v->not_found = 1;
2480         return NGX_OK;
2481     }
2482 
2483     v->valid = 1;
2484     v->no_cacheable = 0;
2485     v->not_found = 0;
2486 
2487     v->data = ngx_pnalloc(r->pool, NGX_OFF_T_LEN);
2488 
2489     if (v->data == NULL) {
2490         return NGX_ERROR;
2491     }
2492 
2493     v->len = ngx_sprintf(v->data, "%O", ctx->internal_body_length) - v->data;
2494 
2495     return NGX_OK;
2496 }
2497 
2498 
2499 static ngx_int_t
ngx_http_proxy_internal_chunked_variable(ngx_http_request_t * r,ngx_http_variable_value_t * v,uintptr_t data)2500 ngx_http_proxy_internal_chunked_variable(ngx_http_request_t *r,
2501     ngx_http_variable_value_t *v, uintptr_t data)
2502 {
2503     ngx_http_proxy_ctx_t  *ctx;
2504 
2505     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
2506 
2507     if (ctx == NULL || !ctx->internal_chunked) {
2508         v->not_found = 1;
2509         return NGX_OK;
2510     }
2511 
2512     v->valid = 1;
2513     v->no_cacheable = 0;
2514     v->not_found = 0;
2515 
2516     v->data = (u_char *) "chunked";
2517     v->len = sizeof("chunked") - 1;
2518 
2519     return NGX_OK;
2520 }
2521 
2522 
2523 static ngx_int_t
ngx_http_proxy_rewrite_redirect(ngx_http_request_t * r,ngx_table_elt_t * h,size_t prefix)2524 ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h,
2525     size_t prefix)
2526 {
2527     size_t                      len;
2528     ngx_int_t                   rc;
2529     ngx_uint_t                  i;
2530     ngx_http_proxy_rewrite_t   *pr;
2531     ngx_http_proxy_loc_conf_t  *plcf;
2532 
2533     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
2534 
2535     pr = plcf->redirects->elts;
2536 
2537     if (pr == NULL) {
2538         return NGX_DECLINED;
2539     }
2540 
2541     len = h->value.len - prefix;
2542 
2543     for (i = 0; i < plcf->redirects->nelts; i++) {
2544         rc = pr[i].handler(r, h, prefix, len, &pr[i]);
2545 
2546         if (rc != NGX_DECLINED) {
2547             return rc;
2548         }
2549     }
2550 
2551     return NGX_DECLINED;
2552 }
2553 
2554 
2555 static ngx_int_t
ngx_http_proxy_rewrite_cookie(ngx_http_request_t * r,ngx_table_elt_t * h)2556 ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, ngx_table_elt_t *h)
2557 {
2558     size_t                      prefix;
2559     u_char                     *p;
2560     ngx_int_t                   rc, rv;
2561     ngx_http_proxy_loc_conf_t  *plcf;
2562 
2563     p = (u_char *) ngx_strchr(h->value.data, ';');
2564     if (p == NULL) {
2565         return NGX_DECLINED;
2566     }
2567 
2568     prefix = p + 1 - h->value.data;
2569 
2570     rv = NGX_DECLINED;
2571 
2572     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
2573 
2574     if (plcf->cookie_domains) {
2575         p = ngx_strcasestrn(h->value.data + prefix, "domain=", 7 - 1);
2576 
2577         if (p) {
2578             rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 7,
2579                                                      plcf->cookie_domains);
2580             if (rc == NGX_ERROR) {
2581                 return NGX_ERROR;
2582             }
2583 
2584             if (rc != NGX_DECLINED) {
2585                 rv = rc;
2586             }
2587         }
2588     }
2589 
2590     if (plcf->cookie_paths) {
2591         p = ngx_strcasestrn(h->value.data + prefix, "path=", 5 - 1);
2592 
2593         if (p) {
2594             rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 5,
2595                                                      plcf->cookie_paths);
2596             if (rc == NGX_ERROR) {
2597                 return NGX_ERROR;
2598             }
2599 
2600             if (rc != NGX_DECLINED) {
2601                 rv = rc;
2602             }
2603         }
2604     }
2605 
2606     return rv;
2607 }
2608 
2609 
2610 static ngx_int_t
ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t * r,ngx_table_elt_t * h,u_char * value,ngx_array_t * rewrites)2611 ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, ngx_table_elt_t *h,
2612     u_char *value, ngx_array_t *rewrites)
2613 {
2614     size_t                     len, prefix;
2615     u_char                    *p;
2616     ngx_int_t                  rc;
2617     ngx_uint_t                 i;
2618     ngx_http_proxy_rewrite_t  *pr;
2619 
2620     prefix = value - h->value.data;
2621 
2622     p = (u_char *) ngx_strchr(value, ';');
2623 
2624     len = p ? (size_t) (p - value) : (h->value.len - prefix);
2625 
2626     pr = rewrites->elts;
2627 
2628     for (i = 0; i < rewrites->nelts; i++) {
2629         rc = pr[i].handler(r, h, prefix, len, &pr[i]);
2630 
2631         if (rc != NGX_DECLINED) {
2632             return rc;
2633         }
2634     }
2635 
2636     return NGX_DECLINED;
2637 }
2638 
2639 
2640 static ngx_int_t
ngx_http_proxy_rewrite_complex_handler(ngx_http_request_t * r,ngx_table_elt_t * h,size_t prefix,size_t len,ngx_http_proxy_rewrite_t * pr)2641 ngx_http_proxy_rewrite_complex_handler(ngx_http_request_t *r,
2642     ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
2643 {
2644     ngx_str_t  pattern, replacement;
2645 
2646     if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) {
2647         return NGX_ERROR;
2648     }
2649 
2650     if (pattern.len > len
2651         || ngx_rstrncmp(h->value.data + prefix, pattern.data,
2652                         pattern.len) != 0)
2653     {
2654         return NGX_DECLINED;
2655     }
2656 
2657     if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
2658         return NGX_ERROR;
2659     }
2660 
2661     return ngx_http_proxy_rewrite(r, h, prefix, pattern.len, &replacement);
2662 }
2663 
2664 
2665 #if (NGX_PCRE)
2666 
2667 static ngx_int_t
ngx_http_proxy_rewrite_regex_handler(ngx_http_request_t * r,ngx_table_elt_t * h,size_t prefix,size_t len,ngx_http_proxy_rewrite_t * pr)2668 ngx_http_proxy_rewrite_regex_handler(ngx_http_request_t *r, ngx_table_elt_t *h,
2669     size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
2670 {
2671     ngx_str_t  pattern, replacement;
2672 
2673     pattern.len = len;
2674     pattern.data = h->value.data + prefix;
2675 
2676     if (ngx_http_regex_exec(r, pr->pattern.regex, &pattern) != NGX_OK) {
2677         return NGX_DECLINED;
2678     }
2679 
2680     if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
2681         return NGX_ERROR;
2682     }
2683 
2684     if (prefix == 0 && h->value.len == len) {
2685         h->value = replacement;
2686         return NGX_OK;
2687     }
2688 
2689     return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement);
2690 }
2691 
2692 #endif
2693 
2694 
2695 static ngx_int_t
ngx_http_proxy_rewrite_domain_handler(ngx_http_request_t * r,ngx_table_elt_t * h,size_t prefix,size_t len,ngx_http_proxy_rewrite_t * pr)2696 ngx_http_proxy_rewrite_domain_handler(ngx_http_request_t *r,
2697     ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
2698 {
2699     u_char     *p;
2700     ngx_str_t   pattern, replacement;
2701 
2702     if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) {
2703         return NGX_ERROR;
2704     }
2705 
2706     p = h->value.data + prefix;
2707 
2708     if (p[0] == '.') {
2709         p++;
2710         prefix++;
2711         len--;
2712     }
2713 
2714     if (pattern.len != len || ngx_rstrncasecmp(pattern.data, p, len) != 0) {
2715         return NGX_DECLINED;
2716     }
2717 
2718     if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) {
2719         return NGX_ERROR;
2720     }
2721 
2722     return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement);
2723 }
2724 
2725 
2726 static ngx_int_t
ngx_http_proxy_rewrite(ngx_http_request_t * r,ngx_table_elt_t * h,size_t prefix,size_t len,ngx_str_t * replacement)2727 ngx_http_proxy_rewrite(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix,
2728     size_t len, ngx_str_t *replacement)
2729 {
2730     u_char  *p, *data;
2731     size_t   new_len;
2732 
2733     new_len = replacement->len + h->value.len - len;
2734 
2735     if (replacement->len > len) {
2736 
2737         data = ngx_pnalloc(r->pool, new_len + 1);
2738         if (data == NULL) {
2739             return NGX_ERROR;
2740         }
2741 
2742         p = ngx_copy(data, h->value.data, prefix);
2743         p = ngx_copy(p, replacement->data, replacement->len);
2744 
2745         ngx_memcpy(p, h->value.data + prefix + len,
2746                    h->value.len - len - prefix + 1);
2747 
2748         h->value.data = data;
2749 
2750     } else {
2751         p = ngx_copy(h->value.data + prefix, replacement->data,
2752                      replacement->len);
2753 
2754         ngx_memmove(p, h->value.data + prefix + len,
2755                     h->value.len - len - prefix + 1);
2756     }
2757 
2758     h->value.len = new_len;
2759 
2760     return NGX_OK;
2761 }
2762 
2763 
2764 static ngx_int_t
ngx_http_proxy_add_variables(ngx_conf_t * cf)2765 ngx_http_proxy_add_variables(ngx_conf_t *cf)
2766 {
2767     ngx_http_variable_t  *var, *v;
2768 
2769     for (v = ngx_http_proxy_vars; v->name.len; v++) {
2770         var = ngx_http_add_variable(cf, &v->name, v->flags);
2771         if (var == NULL) {
2772             return NGX_ERROR;
2773         }
2774 
2775         var->get_handler = v->get_handler;
2776         var->data = v->data;
2777     }
2778 
2779     return NGX_OK;
2780 }
2781 
2782 
2783 static void *
ngx_http_proxy_create_main_conf(ngx_conf_t * cf)2784 ngx_http_proxy_create_main_conf(ngx_conf_t *cf)
2785 {
2786     ngx_http_proxy_main_conf_t  *conf;
2787 
2788     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_main_conf_t));
2789     if (conf == NULL) {
2790         return NULL;
2791     }
2792 
2793 #if (NGX_HTTP_CACHE)
2794     if (ngx_array_init(&conf->caches, cf->pool, 4,
2795                        sizeof(ngx_http_file_cache_t *))
2796         != NGX_OK)
2797     {
2798         return NULL;
2799     }
2800 #endif
2801 
2802     return conf;
2803 }
2804 
2805 
2806 static void *
ngx_http_proxy_create_loc_conf(ngx_conf_t * cf)2807 ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
2808 {
2809     ngx_http_proxy_loc_conf_t  *conf;
2810 
2811     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t));
2812     if (conf == NULL) {
2813         return NULL;
2814     }
2815 
2816     /*
2817      * set by ngx_pcalloc():
2818      *
2819      *     conf->upstream.bufs.num = 0;
2820      *     conf->upstream.ignore_headers = 0;
2821      *     conf->upstream.next_upstream = 0;
2822      *     conf->upstream.cache_zone = NULL;
2823      *     conf->upstream.cache_use_stale = 0;
2824      *     conf->upstream.cache_methods = 0;
2825      *     conf->upstream.temp_path = NULL;
2826      *     conf->upstream.hide_headers_hash = { NULL, 0 };
2827      *     conf->upstream.store_lengths = NULL;
2828      *     conf->upstream.store_values = NULL;
2829      *     conf->upstream.ssl_name = NULL;
2830      *
2831      *     conf->method = NULL;
2832      *     conf->location = NULL;
2833      *     conf->url = { 0, NULL };
2834      *     conf->headers_source = NULL;
2835      *     conf->headers.lengths = NULL;
2836      *     conf->headers.values = NULL;
2837      *     conf->headers.hash = { NULL, 0 };
2838      *     conf->headers_cache.lengths = NULL;
2839      *     conf->headers_cache.values = NULL;
2840      *     conf->headers_cache.hash = { NULL, 0 };
2841      *     conf->body_lengths = NULL;
2842      *     conf->body_values = NULL;
2843      *     conf->body_source = { 0, NULL };
2844      *     conf->redirects = NULL;
2845      *     conf->ssl = 0;
2846      *     conf->ssl_protocols = 0;
2847      *     conf->ssl_ciphers = { 0, NULL };
2848      *     conf->ssl_trusted_certificate = { 0, NULL };
2849      *     conf->ssl_crl = { 0, NULL };
2850      *     conf->ssl_certificate = { 0, NULL };
2851      *     conf->ssl_certificate_key = { 0, NULL };
2852      */
2853 
2854     conf->upstream.store = NGX_CONF_UNSET;
2855     conf->upstream.store_access = NGX_CONF_UNSET_UINT;
2856     conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
2857     conf->upstream.buffering = NGX_CONF_UNSET;
2858     conf->upstream.request_buffering = NGX_CONF_UNSET;
2859     conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
2860     conf->upstream.force_ranges = NGX_CONF_UNSET;
2861 
2862     conf->upstream.local = NGX_CONF_UNSET_PTR;
2863     conf->upstream.socket_keepalive = NGX_CONF_UNSET;
2864 
2865     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
2866     conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
2867     conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
2868     conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC;
2869 
2870     conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
2871     conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
2872     conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE;
2873 
2874     conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
2875     conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
2876     conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;
2877 
2878     conf->upstream.pass_request_headers = NGX_CONF_UNSET;
2879     conf->upstream.pass_request_body = NGX_CONF_UNSET;
2880 
2881 #if (NGX_HTTP_CACHE)
2882     conf->upstream.cache = NGX_CONF_UNSET;
2883     conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
2884     conf->upstream.cache_max_range_offset = NGX_CONF_UNSET;
2885     conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
2886     conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
2887     conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
2888     conf->upstream.cache_lock = NGX_CONF_UNSET;
2889     conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
2890     conf->upstream.cache_lock_age = NGX_CONF_UNSET_MSEC;
2891     conf->upstream.cache_revalidate = NGX_CONF_UNSET;
2892     conf->upstream.cache_convert_head = NGX_CONF_UNSET;
2893     conf->upstream.cache_background_update = NGX_CONF_UNSET;
2894 #endif
2895 
2896     conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
2897     conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
2898 
2899     conf->upstream.intercept_errors = NGX_CONF_UNSET;
2900 
2901 #if (NGX_HTTP_SSL)
2902     conf->upstream.ssl_session_reuse = NGX_CONF_UNSET;
2903     conf->upstream.ssl_server_name = NGX_CONF_UNSET;
2904     conf->upstream.ssl_verify = NGX_CONF_UNSET;
2905     conf->ssl_verify_depth = NGX_CONF_UNSET_UINT;
2906     conf->ssl_passwords = NGX_CONF_UNSET_PTR;
2907 #endif
2908 
2909     /* "proxy_cyclic_temp_file" is disabled */
2910     conf->upstream.cyclic_temp_file = 0;
2911 
2912     conf->redirect = NGX_CONF_UNSET;
2913     conf->upstream.change_buffering = 1;
2914 
2915     conf->cookie_domains = NGX_CONF_UNSET_PTR;
2916     conf->cookie_paths = NGX_CONF_UNSET_PTR;
2917 
2918     conf->http_version = NGX_CONF_UNSET_UINT;
2919 
2920     conf->headers_hash_max_size = NGX_CONF_UNSET_UINT;
2921     conf->headers_hash_bucket_size = NGX_CONF_UNSET_UINT;
2922 
2923     ngx_str_set(&conf->upstream.module, "proxy");
2924 
2925 #if (NGX_HAVE_FSTACK)
2926     conf->kernel_network_stack = NGX_CONF_UNSET;
2927 #endif
2928 
2929     return conf;
2930 }
2931 
2932 
2933 static char *
ngx_http_proxy_merge_loc_conf(ngx_conf_t * cf,void * parent,void * child)2934 ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
2935 {
2936     ngx_http_proxy_loc_conf_t *prev = parent;
2937     ngx_http_proxy_loc_conf_t *conf = child;
2938 
2939     u_char                     *p;
2940     size_t                      size;
2941     ngx_int_t                   rc;
2942     ngx_hash_init_t             hash;
2943     ngx_http_core_loc_conf_t   *clcf;
2944     ngx_http_proxy_rewrite_t   *pr;
2945     ngx_http_script_compile_t   sc;
2946 
2947 #if (NGX_HTTP_CACHE)
2948 
2949     if (conf->upstream.store > 0) {
2950         conf->upstream.cache = 0;
2951     }
2952 
2953     if (conf->upstream.cache > 0) {
2954         conf->upstream.store = 0;
2955     }
2956 
2957 #endif
2958 
2959     if (conf->upstream.store == NGX_CONF_UNSET) {
2960         ngx_conf_merge_value(conf->upstream.store,
2961                               prev->upstream.store, 0);
2962 
2963         conf->upstream.store_lengths = prev->upstream.store_lengths;
2964         conf->upstream.store_values = prev->upstream.store_values;
2965     }
2966 
2967     ngx_conf_merge_uint_value(conf->upstream.store_access,
2968                               prev->upstream.store_access, 0600);
2969 
2970     ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
2971                               prev->upstream.next_upstream_tries, 0);
2972 
2973     ngx_conf_merge_value(conf->upstream.buffering,
2974                               prev->upstream.buffering, 1);
2975 
2976     ngx_conf_merge_value(conf->upstream.request_buffering,
2977                               prev->upstream.request_buffering, 1);
2978 
2979     ngx_conf_merge_value(conf->upstream.ignore_client_abort,
2980                               prev->upstream.ignore_client_abort, 0);
2981 
2982     ngx_conf_merge_value(conf->upstream.force_ranges,
2983                               prev->upstream.force_ranges, 0);
2984 
2985     ngx_conf_merge_ptr_value(conf->upstream.local,
2986                               prev->upstream.local, NULL);
2987 
2988     ngx_conf_merge_value(conf->upstream.socket_keepalive,
2989                               prev->upstream.socket_keepalive, 0);
2990 
2991     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
2992                               prev->upstream.connect_timeout, 60000);
2993 
2994     ngx_conf_merge_msec_value(conf->upstream.send_timeout,
2995                               prev->upstream.send_timeout, 60000);
2996 
2997     ngx_conf_merge_msec_value(conf->upstream.read_timeout,
2998                               prev->upstream.read_timeout, 60000);
2999 
3000     ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
3001                               prev->upstream.next_upstream_timeout, 0);
3002 
3003     ngx_conf_merge_size_value(conf->upstream.send_lowat,
3004                               prev->upstream.send_lowat, 0);
3005 
3006     ngx_conf_merge_size_value(conf->upstream.buffer_size,
3007                               prev->upstream.buffer_size,
3008                               (size_t) ngx_pagesize);
3009 
3010     ngx_conf_merge_size_value(conf->upstream.limit_rate,
3011                               prev->upstream.limit_rate, 0);
3012 
3013     ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
3014                               8, ngx_pagesize);
3015 
3016     if (conf->upstream.bufs.num < 2) {
3017         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3018                            "there must be at least 2 \"proxy_buffers\"");
3019         return NGX_CONF_ERROR;
3020     }
3021 
3022 
3023     size = conf->upstream.buffer_size;
3024     if (size < conf->upstream.bufs.size) {
3025         size = conf->upstream.bufs.size;
3026     }
3027 
3028 
3029     ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
3030                               prev->upstream.busy_buffers_size_conf,
3031                               NGX_CONF_UNSET_SIZE);
3032 
3033     if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
3034         conf->upstream.busy_buffers_size = 2 * size;
3035     } else {
3036         conf->upstream.busy_buffers_size =
3037                                          conf->upstream.busy_buffers_size_conf;
3038     }
3039 
3040     if (conf->upstream.busy_buffers_size < size) {
3041         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3042              "\"proxy_busy_buffers_size\" must be equal to or greater than "
3043              "the maximum of the value of \"proxy_buffer_size\" and "
3044              "one of the \"proxy_buffers\"");
3045 
3046         return NGX_CONF_ERROR;
3047     }
3048 
3049     if (conf->upstream.busy_buffers_size
3050         > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
3051     {
3052         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3053              "\"proxy_busy_buffers_size\" must be less than "
3054              "the size of all \"proxy_buffers\" minus one buffer");
3055 
3056         return NGX_CONF_ERROR;
3057     }
3058 
3059 
3060     ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf,
3061                               prev->upstream.temp_file_write_size_conf,
3062                               NGX_CONF_UNSET_SIZE);
3063 
3064     if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
3065         conf->upstream.temp_file_write_size = 2 * size;
3066     } else {
3067         conf->upstream.temp_file_write_size =
3068                                       conf->upstream.temp_file_write_size_conf;
3069     }
3070 
3071     if (conf->upstream.temp_file_write_size < size) {
3072         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3073              "\"proxy_temp_file_write_size\" must be equal to or greater "
3074              "than the maximum of the value of \"proxy_buffer_size\" and "
3075              "one of the \"proxy_buffers\"");
3076 
3077         return NGX_CONF_ERROR;
3078     }
3079 
3080     ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf,
3081                               prev->upstream.max_temp_file_size_conf,
3082                               NGX_CONF_UNSET_SIZE);
3083 
3084     if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
3085         conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
3086     } else {
3087         conf->upstream.max_temp_file_size =
3088                                         conf->upstream.max_temp_file_size_conf;
3089     }
3090 
3091     if (conf->upstream.max_temp_file_size != 0
3092         && conf->upstream.max_temp_file_size < size)
3093     {
3094         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3095              "\"proxy_max_temp_file_size\" must be equal to zero to disable "
3096              "temporary files usage or must be equal to or greater than "
3097              "the maximum of the value of \"proxy_buffer_size\" and "
3098              "one of the \"proxy_buffers\"");
3099 
3100         return NGX_CONF_ERROR;
3101     }
3102 
3103 
3104     ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
3105                               prev->upstream.ignore_headers,
3106                               NGX_CONF_BITMASK_SET);
3107 
3108 
3109     ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
3110                               prev->upstream.next_upstream,
3111                               (NGX_CONF_BITMASK_SET
3112                                |NGX_HTTP_UPSTREAM_FT_ERROR
3113                                |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
3114 
3115     if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
3116         conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
3117                                        |NGX_HTTP_UPSTREAM_FT_OFF;
3118     }
3119 
3120     if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
3121                               prev->upstream.temp_path,
3122                               &ngx_http_proxy_temp_path)
3123         != NGX_OK)
3124     {
3125         return NGX_CONF_ERROR;
3126     }
3127 
3128 
3129 #if (NGX_HTTP_CACHE)
3130 
3131     if (conf->upstream.cache == NGX_CONF_UNSET) {
3132         ngx_conf_merge_value(conf->upstream.cache,
3133                               prev->upstream.cache, 0);
3134 
3135         conf->upstream.cache_zone = prev->upstream.cache_zone;
3136         conf->upstream.cache_value = prev->upstream.cache_value;
3137     }
3138 
3139     if (conf->upstream.cache_zone && conf->upstream.cache_zone->data == NULL) {
3140         ngx_shm_zone_t  *shm_zone;
3141 
3142         shm_zone = conf->upstream.cache_zone;
3143 
3144         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3145                            "\"proxy_cache\" zone \"%V\" is unknown",
3146                            &shm_zone->shm.name);
3147 
3148         return NGX_CONF_ERROR;
3149     }
3150 
3151     ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
3152                               prev->upstream.cache_min_uses, 1);
3153 
3154     ngx_conf_merge_off_value(conf->upstream.cache_max_range_offset,
3155                               prev->upstream.cache_max_range_offset,
3156                               NGX_MAX_OFF_T_VALUE);
3157 
3158     ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
3159                               prev->upstream.cache_use_stale,
3160                               (NGX_CONF_BITMASK_SET
3161                                |NGX_HTTP_UPSTREAM_FT_OFF));
3162 
3163     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
3164         conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
3165                                          |NGX_HTTP_UPSTREAM_FT_OFF;
3166     }
3167 
3168     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
3169         conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
3170     }
3171 
3172     if (conf->upstream.cache_methods == 0) {
3173         conf->upstream.cache_methods = prev->upstream.cache_methods;
3174     }
3175 
3176     conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD;
3177 
3178     ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
3179                              prev->upstream.cache_bypass, NULL);
3180 
3181     ngx_conf_merge_ptr_value(conf->upstream.no_cache,
3182                              prev->upstream.no_cache, NULL);
3183 
3184     ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
3185                              prev->upstream.cache_valid, NULL);
3186 
3187     if (conf->cache_key.value.data == NULL) {
3188         conf->cache_key = prev->cache_key;
3189     }
3190 
3191     ngx_conf_merge_value(conf->upstream.cache_lock,
3192                               prev->upstream.cache_lock, 0);
3193 
3194     ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
3195                               prev->upstream.cache_lock_timeout, 5000);
3196 
3197     ngx_conf_merge_msec_value(conf->upstream.cache_lock_age,
3198                               prev->upstream.cache_lock_age, 5000);
3199 
3200     ngx_conf_merge_value(conf->upstream.cache_revalidate,
3201                               prev->upstream.cache_revalidate, 0);
3202 
3203     ngx_conf_merge_value(conf->upstream.cache_convert_head,
3204                               prev->upstream.cache_convert_head, 1);
3205 
3206     ngx_conf_merge_value(conf->upstream.cache_background_update,
3207                               prev->upstream.cache_background_update, 0);
3208 
3209 #endif
3210 
3211     if (conf->method == NULL) {
3212         conf->method = prev->method;
3213     }
3214 
3215     ngx_conf_merge_value(conf->upstream.pass_request_headers,
3216                               prev->upstream.pass_request_headers, 1);
3217     ngx_conf_merge_value(conf->upstream.pass_request_body,
3218                               prev->upstream.pass_request_body, 1);
3219 
3220     ngx_conf_merge_value(conf->upstream.intercept_errors,
3221                               prev->upstream.intercept_errors, 0);
3222 
3223 #if (NGX_HTTP_SSL)
3224 
3225     ngx_conf_merge_value(conf->upstream.ssl_session_reuse,
3226                               prev->upstream.ssl_session_reuse, 1);
3227 
3228     ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols,
3229                                  (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1
3230                                   |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2));
3231 
3232     ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers,
3233                              "DEFAULT");
3234 
3235     if (conf->upstream.ssl_name == NULL) {
3236         conf->upstream.ssl_name = prev->upstream.ssl_name;
3237     }
3238 
3239     ngx_conf_merge_value(conf->upstream.ssl_server_name,
3240                               prev->upstream.ssl_server_name, 0);
3241     ngx_conf_merge_value(conf->upstream.ssl_verify,
3242                               prev->upstream.ssl_verify, 0);
3243     ngx_conf_merge_uint_value(conf->ssl_verify_depth,
3244                               prev->ssl_verify_depth, 1);
3245     ngx_conf_merge_str_value(conf->ssl_trusted_certificate,
3246                               prev->ssl_trusted_certificate, "");
3247     ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, "");
3248 
3249     ngx_conf_merge_str_value(conf->ssl_certificate,
3250                               prev->ssl_certificate, "");
3251     ngx_conf_merge_str_value(conf->ssl_certificate_key,
3252                               prev->ssl_certificate_key, "");
3253     ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL);
3254 
3255     if (conf->ssl && ngx_http_proxy_set_ssl(cf, conf) != NGX_OK) {
3256         return NGX_CONF_ERROR;
3257     }
3258 
3259 #endif
3260 
3261     ngx_conf_merge_value(conf->redirect, prev->redirect, 1);
3262 
3263     if (conf->redirect) {
3264 
3265         if (conf->redirects == NULL) {
3266             conf->redirects = prev->redirects;
3267         }
3268 
3269         if (conf->redirects == NULL && conf->url.data) {
3270 
3271             conf->redirects = ngx_array_create(cf->pool, 1,
3272                                              sizeof(ngx_http_proxy_rewrite_t));
3273             if (conf->redirects == NULL) {
3274                 return NGX_CONF_ERROR;
3275             }
3276 
3277             pr = ngx_array_push(conf->redirects);
3278             if (pr == NULL) {
3279                 return NGX_CONF_ERROR;
3280             }
3281 
3282             ngx_memzero(&pr->pattern.complex,
3283                         sizeof(ngx_http_complex_value_t));
3284 
3285             ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t));
3286 
3287             pr->handler = ngx_http_proxy_rewrite_complex_handler;
3288 
3289             if (conf->vars.uri.len) {
3290                 pr->pattern.complex.value = conf->url;
3291                 pr->replacement.value = conf->location;
3292 
3293             } else {
3294                 pr->pattern.complex.value.len = conf->url.len
3295                                                 + sizeof("/") - 1;
3296 
3297                 p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len);
3298                 if (p == NULL) {
3299                     return NGX_CONF_ERROR;
3300                 }
3301 
3302                 pr->pattern.complex.value.data = p;
3303 
3304                 p = ngx_cpymem(p, conf->url.data, conf->url.len);
3305                 *p = '/';
3306 
3307                 ngx_str_set(&pr->replacement.value, "/");
3308             }
3309         }
3310     }
3311 
3312     ngx_conf_merge_ptr_value(conf->cookie_domains, prev->cookie_domains, NULL);
3313 
3314     ngx_conf_merge_ptr_value(conf->cookie_paths, prev->cookie_paths, NULL);
3315 
3316     ngx_conf_merge_uint_value(conf->http_version, prev->http_version,
3317                               NGX_HTTP_VERSION_10);
3318 
3319     ngx_conf_merge_uint_value(conf->headers_hash_max_size,
3320                               prev->headers_hash_max_size, 512);
3321 
3322     ngx_conf_merge_uint_value(conf->headers_hash_bucket_size,
3323                               prev->headers_hash_bucket_size, 64);
3324 
3325     conf->headers_hash_bucket_size = ngx_align(conf->headers_hash_bucket_size,
3326                                                ngx_cacheline_size);
3327 
3328     hash.max_size = conf->headers_hash_max_size;
3329     hash.bucket_size = conf->headers_hash_bucket_size;
3330     hash.name = "proxy_headers_hash";
3331 
3332     if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
3333             &prev->upstream, ngx_http_proxy_hide_headers, &hash)
3334         != NGX_OK)
3335     {
3336         return NGX_CONF_ERROR;
3337     }
3338 
3339     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
3340 
3341     if (clcf->noname
3342         && conf->upstream.upstream == NULL && conf->proxy_lengths == NULL)
3343     {
3344         conf->upstream.upstream = prev->upstream.upstream;
3345         conf->location = prev->location;
3346         conf->vars = prev->vars;
3347 
3348         conf->proxy_lengths = prev->proxy_lengths;
3349         conf->proxy_values = prev->proxy_values;
3350 
3351 #if (NGX_HTTP_SSL)
3352         conf->upstream.ssl = prev->upstream.ssl;
3353 #endif
3354     }
3355 
3356     if (clcf->lmt_excpt && clcf->handler == NULL
3357         && (conf->upstream.upstream || conf->proxy_lengths))
3358     {
3359         clcf->handler = ngx_http_proxy_handler;
3360     }
3361 
3362     if (conf->body_source.data == NULL) {
3363         conf->body_flushes = prev->body_flushes;
3364         conf->body_source = prev->body_source;
3365         conf->body_lengths = prev->body_lengths;
3366         conf->body_values = prev->body_values;
3367     }
3368 
3369     if (conf->body_source.data && conf->body_lengths == NULL) {
3370 
3371         ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3372 
3373         sc.cf = cf;
3374         sc.source = &conf->body_source;
3375         sc.flushes = &conf->body_flushes;
3376         sc.lengths = &conf->body_lengths;
3377         sc.values = &conf->body_values;
3378         sc.complete_lengths = 1;
3379         sc.complete_values = 1;
3380 
3381         if (ngx_http_script_compile(&sc) != NGX_OK) {
3382             return NGX_CONF_ERROR;
3383         }
3384     }
3385 
3386     if (conf->headers_source == NULL) {
3387         conf->headers = prev->headers;
3388 #if (NGX_HTTP_CACHE)
3389         conf->headers_cache = prev->headers_cache;
3390 #endif
3391         conf->headers_source = prev->headers_source;
3392     }
3393 
3394     rc = ngx_http_proxy_init_headers(cf, conf, &conf->headers,
3395                                      ngx_http_proxy_headers);
3396     if (rc != NGX_OK) {
3397         return NGX_CONF_ERROR;
3398     }
3399 
3400 #if (NGX_HTTP_CACHE)
3401 
3402     if (conf->upstream.cache) {
3403         rc = ngx_http_proxy_init_headers(cf, conf, &conf->headers_cache,
3404                                          ngx_http_proxy_cache_headers);
3405         if (rc != NGX_OK) {
3406             return NGX_CONF_ERROR;
3407         }
3408     }
3409 
3410 #endif
3411 
3412     /*
3413      * special handling to preserve conf->headers in the "http" section
3414      * to inherit it to all servers
3415      */
3416 
3417     if (prev->headers.hash.buckets == NULL
3418         && conf->headers_source == prev->headers_source)
3419     {
3420         prev->headers = conf->headers;
3421 #if (NGX_HTTP_CACHE)
3422         prev->headers_cache = conf->headers_cache;
3423 #endif
3424     }
3425 
3426 #if (NGX_HAVE_FSTACK)
3427     /* By default, we set up a proxy on fstack */
3428     ngx_conf_merge_value(conf->kernel_network_stack,
3429                               prev->kernel_network_stack, 0);
3430 #endif
3431 
3432     return NGX_CONF_OK;
3433 }
3434 
3435 
3436 static ngx_int_t
ngx_http_proxy_init_headers(ngx_conf_t * cf,ngx_http_proxy_loc_conf_t * conf,ngx_http_proxy_headers_t * headers,ngx_keyval_t * default_headers)3437 ngx_http_proxy_init_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf,
3438     ngx_http_proxy_headers_t *headers, ngx_keyval_t *default_headers)
3439 {
3440     u_char                       *p;
3441     size_t                        size;
3442     uintptr_t                    *code;
3443     ngx_uint_t                    i;
3444     ngx_array_t                   headers_names, headers_merged;
3445     ngx_keyval_t                 *src, *s, *h;
3446     ngx_hash_key_t               *hk;
3447     ngx_hash_init_t               hash;
3448     ngx_http_script_compile_t     sc;
3449     ngx_http_script_copy_code_t  *copy;
3450 
3451     if (headers->hash.buckets) {
3452         return NGX_OK;
3453     }
3454 
3455     if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
3456         != NGX_OK)
3457     {
3458         return NGX_ERROR;
3459     }
3460 
3461     if (ngx_array_init(&headers_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t))
3462         != NGX_OK)
3463     {
3464         return NGX_ERROR;
3465     }
3466 
3467     headers->lengths = ngx_array_create(cf->pool, 64, 1);
3468     if (headers->lengths == NULL) {
3469         return NGX_ERROR;
3470     }
3471 
3472     headers->values = ngx_array_create(cf->pool, 512, 1);
3473     if (headers->values == NULL) {
3474         return NGX_ERROR;
3475     }
3476 
3477     if (conf->headers_source) {
3478 
3479         src = conf->headers_source->elts;
3480         for (i = 0; i < conf->headers_source->nelts; i++) {
3481 
3482             s = ngx_array_push(&headers_merged);
3483             if (s == NULL) {
3484                 return NGX_ERROR;
3485             }
3486 
3487             *s = src[i];
3488         }
3489     }
3490 
3491     h = default_headers;
3492 
3493     while (h->key.len) {
3494 
3495         src = headers_merged.elts;
3496         for (i = 0; i < headers_merged.nelts; i++) {
3497             if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
3498                 goto next;
3499             }
3500         }
3501 
3502         s = ngx_array_push(&headers_merged);
3503         if (s == NULL) {
3504             return NGX_ERROR;
3505         }
3506 
3507         *s = *h;
3508 
3509     next:
3510 
3511         h++;
3512     }
3513 
3514 
3515     src = headers_merged.elts;
3516     for (i = 0; i < headers_merged.nelts; i++) {
3517 
3518         hk = ngx_array_push(&headers_names);
3519         if (hk == NULL) {
3520             return NGX_ERROR;
3521         }
3522 
3523         hk->key = src[i].key;
3524         hk->key_hash = ngx_hash_key_lc(src[i].key.data, src[i].key.len);
3525         hk->value = (void *) 1;
3526 
3527         if (src[i].value.len == 0) {
3528             continue;
3529         }
3530 
3531         copy = ngx_array_push_n(headers->lengths,
3532                                 sizeof(ngx_http_script_copy_code_t));
3533         if (copy == NULL) {
3534             return NGX_ERROR;
3535         }
3536 
3537         copy->code = (ngx_http_script_code_pt) (void *)
3538                                                  ngx_http_script_copy_len_code;
3539         copy->len = src[i].key.len;
3540 
3541         size = (sizeof(ngx_http_script_copy_code_t)
3542                 + src[i].key.len + sizeof(uintptr_t) - 1)
3543                & ~(sizeof(uintptr_t) - 1);
3544 
3545         copy = ngx_array_push_n(headers->values, size);
3546         if (copy == NULL) {
3547             return NGX_ERROR;
3548         }
3549 
3550         copy->code = ngx_http_script_copy_code;
3551         copy->len = src[i].key.len;
3552 
3553         p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
3554         ngx_memcpy(p, src[i].key.data, src[i].key.len);
3555 
3556         ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3557 
3558         sc.cf = cf;
3559         sc.source = &src[i].value;
3560         sc.flushes = &headers->flushes;
3561         sc.lengths = &headers->lengths;
3562         sc.values = &headers->values;
3563 
3564         if (ngx_http_script_compile(&sc) != NGX_OK) {
3565             return NGX_ERROR;
3566         }
3567 
3568         code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t));
3569         if (code == NULL) {
3570             return NGX_ERROR;
3571         }
3572 
3573         *code = (uintptr_t) NULL;
3574 
3575         code = ngx_array_push_n(headers->values, sizeof(uintptr_t));
3576         if (code == NULL) {
3577             return NGX_ERROR;
3578         }
3579 
3580         *code = (uintptr_t) NULL;
3581     }
3582 
3583     code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t));
3584     if (code == NULL) {
3585         return NGX_ERROR;
3586     }
3587 
3588     *code = (uintptr_t) NULL;
3589 
3590 
3591     hash.hash = &headers->hash;
3592     hash.key = ngx_hash_key_lc;
3593     hash.max_size = conf->headers_hash_max_size;
3594     hash.bucket_size = conf->headers_hash_bucket_size;
3595     hash.name = "proxy_headers_hash";
3596     hash.pool = cf->pool;
3597     hash.temp_pool = NULL;
3598 
3599     return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
3600 }
3601 
3602 
3603 static char *
ngx_http_proxy_pass(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)3604 ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3605 {
3606     ngx_http_proxy_loc_conf_t *plcf = conf;
3607 
3608     size_t                      add;
3609     u_short                     port;
3610     ngx_str_t                  *value, *url;
3611     ngx_url_t                   u;
3612     ngx_uint_t                  n;
3613     ngx_http_core_loc_conf_t   *clcf;
3614     ngx_http_script_compile_t   sc;
3615 
3616     if (plcf->upstream.upstream || plcf->proxy_lengths) {
3617         return "is duplicate";
3618     }
3619 
3620     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
3621 
3622     clcf->handler = ngx_http_proxy_handler;
3623 
3624     if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') {
3625         clcf->auto_redirect = 1;
3626     }
3627 
3628     value = cf->args->elts;
3629 
3630     url = &value[1];
3631 
3632     n = ngx_http_script_variables_count(url);
3633 
3634     if (n) {
3635 
3636         ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3637 
3638         sc.cf = cf;
3639         sc.source = url;
3640         sc.lengths = &plcf->proxy_lengths;
3641         sc.values = &plcf->proxy_values;
3642         sc.variables = n;
3643         sc.complete_lengths = 1;
3644         sc.complete_values = 1;
3645 
3646         if (ngx_http_script_compile(&sc) != NGX_OK) {
3647             return NGX_CONF_ERROR;
3648         }
3649 
3650 #if (NGX_HTTP_SSL)
3651         plcf->ssl = 1;
3652 #endif
3653 
3654         return NGX_CONF_OK;
3655     }
3656 
3657     if (ngx_strncasecmp(url->data, (u_char *) "http://", 7) == 0) {
3658         add = 7;
3659         port = 80;
3660 
3661     } else if (ngx_strncasecmp(url->data, (u_char *) "https://", 8) == 0) {
3662 
3663 #if (NGX_HTTP_SSL)
3664         plcf->ssl = 1;
3665 
3666         add = 8;
3667         port = 443;
3668 #else
3669         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3670                            "https protocol requires SSL support");
3671         return NGX_CONF_ERROR;
3672 #endif
3673 
3674     } else {
3675         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid URL prefix");
3676         return NGX_CONF_ERROR;
3677     }
3678 
3679     ngx_memzero(&u, sizeof(ngx_url_t));
3680 
3681     u.url.len = url->len - add;
3682     u.url.data = url->data + add;
3683     u.default_port = port;
3684     u.uri_part = 1;
3685     u.no_resolve = 1;
3686 
3687     plcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
3688     if (plcf->upstream.upstream == NULL) {
3689         return NGX_CONF_ERROR;
3690     }
3691 
3692     plcf->vars.schema.len = add;
3693     plcf->vars.schema.data = url->data;
3694     plcf->vars.key_start = plcf->vars.schema;
3695 
3696     ngx_http_proxy_set_vars(&u, &plcf->vars);
3697 
3698     plcf->location = clcf->name;
3699 
3700     if (clcf->named
3701 #if (NGX_PCRE)
3702         || clcf->regex
3703 #endif
3704         || clcf->noname)
3705     {
3706         if (plcf->vars.uri.len) {
3707             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3708                                "\"proxy_pass\" cannot have URI part in "
3709                                "location given by regular expression, "
3710                                "or inside named location, "
3711                                "or inside \"if\" statement, "
3712                                "or inside \"limit_except\" block");
3713             return NGX_CONF_ERROR;
3714         }
3715 
3716         plcf->location.len = 0;
3717     }
3718 
3719     plcf->url = *url;
3720 
3721     return NGX_CONF_OK;
3722 }
3723 
3724 
3725 static char *
ngx_http_proxy_redirect(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)3726 ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3727 {
3728     ngx_http_proxy_loc_conf_t *plcf = conf;
3729 
3730     u_char                            *p;
3731     ngx_str_t                         *value;
3732     ngx_http_proxy_rewrite_t          *pr;
3733     ngx_http_compile_complex_value_t   ccv;
3734 
3735     if (plcf->redirect == 0) {
3736         return NGX_CONF_OK;
3737     }
3738 
3739     plcf->redirect = 1;
3740 
3741     value = cf->args->elts;
3742 
3743     if (cf->args->nelts == 2) {
3744         if (ngx_strcmp(value[1].data, "off") == 0) {
3745             plcf->redirect = 0;
3746             plcf->redirects = NULL;
3747             return NGX_CONF_OK;
3748         }
3749 
3750         if (ngx_strcmp(value[1].data, "false") == 0) {
3751             ngx_conf_log_error(NGX_LOG_ERR, cf, 0,
3752                            "invalid parameter \"false\", use \"off\" instead");
3753             plcf->redirect = 0;
3754             plcf->redirects = NULL;
3755             return NGX_CONF_OK;
3756         }
3757 
3758         if (ngx_strcmp(value[1].data, "default") != 0) {
3759             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3760                                "invalid parameter \"%V\"", &value[1]);
3761             return NGX_CONF_ERROR;
3762         }
3763     }
3764 
3765     if (plcf->redirects == NULL) {
3766         plcf->redirects = ngx_array_create(cf->pool, 1,
3767                                            sizeof(ngx_http_proxy_rewrite_t));
3768         if (plcf->redirects == NULL) {
3769             return NGX_CONF_ERROR;
3770         }
3771     }
3772 
3773     pr = ngx_array_push(plcf->redirects);
3774     if (pr == NULL) {
3775         return NGX_CONF_ERROR;
3776     }
3777 
3778     if (ngx_strcmp(value[1].data, "default") == 0) {
3779         if (plcf->proxy_lengths) {
3780             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3781                                "\"proxy_redirect default\" cannot be used "
3782                                "with \"proxy_pass\" directive with variables");
3783             return NGX_CONF_ERROR;
3784         }
3785 
3786         if (plcf->url.data == NULL) {
3787             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3788                                "\"proxy_redirect default\" should be placed "
3789                                "after the \"proxy_pass\" directive");
3790             return NGX_CONF_ERROR;
3791         }
3792 
3793         pr->handler = ngx_http_proxy_rewrite_complex_handler;
3794 
3795         ngx_memzero(&pr->pattern.complex, sizeof(ngx_http_complex_value_t));
3796 
3797         ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t));
3798 
3799         if (plcf->vars.uri.len) {
3800             pr->pattern.complex.value = plcf->url;
3801             pr->replacement.value = plcf->location;
3802 
3803         } else {
3804             pr->pattern.complex.value.len = plcf->url.len + sizeof("/") - 1;
3805 
3806             p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len);
3807             if (p == NULL) {
3808                 return NGX_CONF_ERROR;
3809             }
3810 
3811             pr->pattern.complex.value.data = p;
3812 
3813             p = ngx_cpymem(p, plcf->url.data, plcf->url.len);
3814             *p = '/';
3815 
3816             ngx_str_set(&pr->replacement.value, "/");
3817         }
3818 
3819         return NGX_CONF_OK;
3820     }
3821 
3822 
3823     if (value[1].data[0] == '~') {
3824         value[1].len--;
3825         value[1].data++;
3826 
3827         if (value[1].data[0] == '*') {
3828             value[1].len--;
3829             value[1].data++;
3830 
3831             if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
3832                 return NGX_CONF_ERROR;
3833             }
3834 
3835         } else {
3836             if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) {
3837                 return NGX_CONF_ERROR;
3838             }
3839         }
3840 
3841     } else {
3842 
3843         ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3844 
3845         ccv.cf = cf;
3846         ccv.value = &value[1];
3847         ccv.complex_value = &pr->pattern.complex;
3848 
3849         if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3850             return NGX_CONF_ERROR;
3851         }
3852 
3853         pr->handler = ngx_http_proxy_rewrite_complex_handler;
3854     }
3855 
3856 
3857     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3858 
3859     ccv.cf = cf;
3860     ccv.value = &value[2];
3861     ccv.complex_value = &pr->replacement;
3862 
3863     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3864         return NGX_CONF_ERROR;
3865     }
3866 
3867     return NGX_CONF_OK;
3868 }
3869 
3870 
3871 static char *
ngx_http_proxy_cookie_domain(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)3872 ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3873 {
3874     ngx_http_proxy_loc_conf_t *plcf = conf;
3875 
3876     ngx_str_t                         *value;
3877     ngx_http_proxy_rewrite_t          *pr;
3878     ngx_http_compile_complex_value_t   ccv;
3879 
3880     if (plcf->cookie_domains == NULL) {
3881         return NGX_CONF_OK;
3882     }
3883 
3884     value = cf->args->elts;
3885 
3886     if (cf->args->nelts == 2) {
3887 
3888         if (ngx_strcmp(value[1].data, "off") == 0) {
3889             plcf->cookie_domains = NULL;
3890             return NGX_CONF_OK;
3891         }
3892 
3893         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3894                            "invalid parameter \"%V\"", &value[1]);
3895         return NGX_CONF_ERROR;
3896     }
3897 
3898     if (plcf->cookie_domains == NGX_CONF_UNSET_PTR) {
3899         plcf->cookie_domains = ngx_array_create(cf->pool, 1,
3900                                      sizeof(ngx_http_proxy_rewrite_t));
3901         if (plcf->cookie_domains == NULL) {
3902             return NGX_CONF_ERROR;
3903         }
3904     }
3905 
3906     pr = ngx_array_push(plcf->cookie_domains);
3907     if (pr == NULL) {
3908         return NGX_CONF_ERROR;
3909     }
3910 
3911     if (value[1].data[0] == '~') {
3912         value[1].len--;
3913         value[1].data++;
3914 
3915         if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
3916             return NGX_CONF_ERROR;
3917         }
3918 
3919     } else {
3920 
3921         if (value[1].data[0] == '.') {
3922             value[1].len--;
3923             value[1].data++;
3924         }
3925 
3926         ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3927 
3928         ccv.cf = cf;
3929         ccv.value = &value[1];
3930         ccv.complex_value = &pr->pattern.complex;
3931 
3932         if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3933             return NGX_CONF_ERROR;
3934         }
3935 
3936         pr->handler = ngx_http_proxy_rewrite_domain_handler;
3937 
3938         if (value[2].data[0] == '.') {
3939             value[2].len--;
3940             value[2].data++;
3941         }
3942     }
3943 
3944     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3945 
3946     ccv.cf = cf;
3947     ccv.value = &value[2];
3948     ccv.complex_value = &pr->replacement;
3949 
3950     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3951         return NGX_CONF_ERROR;
3952     }
3953 
3954     return NGX_CONF_OK;
3955 }
3956 
3957 
3958 static char *
ngx_http_proxy_cookie_path(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)3959 ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3960 {
3961     ngx_http_proxy_loc_conf_t *plcf = conf;
3962 
3963     ngx_str_t                         *value;
3964     ngx_http_proxy_rewrite_t          *pr;
3965     ngx_http_compile_complex_value_t   ccv;
3966 
3967     if (plcf->cookie_paths == NULL) {
3968         return NGX_CONF_OK;
3969     }
3970 
3971     value = cf->args->elts;
3972 
3973     if (cf->args->nelts == 2) {
3974 
3975         if (ngx_strcmp(value[1].data, "off") == 0) {
3976             plcf->cookie_paths = NULL;
3977             return NGX_CONF_OK;
3978         }
3979 
3980         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3981                            "invalid parameter \"%V\"", &value[1]);
3982         return NGX_CONF_ERROR;
3983     }
3984 
3985     if (plcf->cookie_paths == NGX_CONF_UNSET_PTR) {
3986         plcf->cookie_paths = ngx_array_create(cf->pool, 1,
3987                                      sizeof(ngx_http_proxy_rewrite_t));
3988         if (plcf->cookie_paths == NULL) {
3989             return NGX_CONF_ERROR;
3990         }
3991     }
3992 
3993     pr = ngx_array_push(plcf->cookie_paths);
3994     if (pr == NULL) {
3995         return NGX_CONF_ERROR;
3996     }
3997 
3998     if (value[1].data[0] == '~') {
3999         value[1].len--;
4000         value[1].data++;
4001 
4002         if (value[1].data[0] == '*') {
4003             value[1].len--;
4004             value[1].data++;
4005 
4006             if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) {
4007                 return NGX_CONF_ERROR;
4008             }
4009 
4010         } else {
4011             if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) {
4012                 return NGX_CONF_ERROR;
4013             }
4014         }
4015 
4016     } else {
4017 
4018         ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
4019 
4020         ccv.cf = cf;
4021         ccv.value = &value[1];
4022         ccv.complex_value = &pr->pattern.complex;
4023 
4024         if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
4025             return NGX_CONF_ERROR;
4026         }
4027 
4028         pr->handler = ngx_http_proxy_rewrite_complex_handler;
4029     }
4030 
4031     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
4032 
4033     ccv.cf = cf;
4034     ccv.value = &value[2];
4035     ccv.complex_value = &pr->replacement;
4036 
4037     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
4038         return NGX_CONF_ERROR;
4039     }
4040 
4041     return NGX_CONF_OK;
4042 }
4043 
4044 
4045 static ngx_int_t
ngx_http_proxy_rewrite_regex(ngx_conf_t * cf,ngx_http_proxy_rewrite_t * pr,ngx_str_t * regex,ngx_uint_t caseless)4046 ngx_http_proxy_rewrite_regex(ngx_conf_t *cf, ngx_http_proxy_rewrite_t *pr,
4047     ngx_str_t *regex, ngx_uint_t caseless)
4048 {
4049 #if (NGX_PCRE)
4050     u_char               errstr[NGX_MAX_CONF_ERRSTR];
4051     ngx_regex_compile_t  rc;
4052 
4053     ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
4054 
4055     rc.pattern = *regex;
4056     rc.err.len = NGX_MAX_CONF_ERRSTR;
4057     rc.err.data = errstr;
4058 
4059     if (caseless) {
4060         rc.options = NGX_REGEX_CASELESS;
4061     }
4062 
4063     pr->pattern.regex = ngx_http_regex_compile(cf, &rc);
4064     if (pr->pattern.regex == NULL) {
4065         return NGX_ERROR;
4066     }
4067 
4068     pr->handler = ngx_http_proxy_rewrite_regex_handler;
4069 
4070     return NGX_OK;
4071 
4072 #else
4073 
4074     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
4075                        "using regex \"%V\" requires PCRE library", regex);
4076     return NGX_ERROR;
4077 
4078 #endif
4079 }
4080 
4081 
4082 static char *
ngx_http_proxy_store(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)4083 ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
4084 {
4085     ngx_http_proxy_loc_conf_t *plcf = conf;
4086 
4087     ngx_str_t                  *value;
4088     ngx_http_script_compile_t   sc;
4089 
4090     if (plcf->upstream.store != NGX_CONF_UNSET) {
4091         return "is duplicate";
4092     }
4093 
4094     value = cf->args->elts;
4095 
4096     if (ngx_strcmp(value[1].data, "off") == 0) {
4097         plcf->upstream.store = 0;
4098         return NGX_CONF_OK;
4099     }
4100 
4101 #if (NGX_HTTP_CACHE)
4102     if (plcf->upstream.cache > 0) {
4103         return "is incompatible with \"proxy_cache\"";
4104     }
4105 #endif
4106 
4107     plcf->upstream.store = 1;
4108 
4109     if (ngx_strcmp(value[1].data, "on") == 0) {
4110         return NGX_CONF_OK;
4111     }
4112 
4113     /* include the terminating '\0' into script */
4114     value[1].len++;
4115 
4116     ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
4117 
4118     sc.cf = cf;
4119     sc.source = &value[1];
4120     sc.lengths = &plcf->upstream.store_lengths;
4121     sc.values = &plcf->upstream.store_values;
4122     sc.variables = ngx_http_script_variables_count(&value[1]);
4123     sc.complete_lengths = 1;
4124     sc.complete_values = 1;
4125 
4126     if (ngx_http_script_compile(&sc) != NGX_OK) {
4127         return NGX_CONF_ERROR;
4128     }
4129 
4130     return NGX_CONF_OK;
4131 }
4132 
4133 
4134 #if (NGX_HTTP_CACHE)
4135 
4136 static char *
ngx_http_proxy_cache(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)4137 ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
4138 {
4139     ngx_http_proxy_loc_conf_t *plcf = conf;
4140 
4141     ngx_str_t                         *value;
4142     ngx_http_complex_value_t           cv;
4143     ngx_http_compile_complex_value_t   ccv;
4144 
4145     value = cf->args->elts;
4146 
4147     if (plcf->upstream.cache != NGX_CONF_UNSET) {
4148         return "is duplicate";
4149     }
4150 
4151     if (ngx_strcmp(value[1].data, "off") == 0) {
4152         plcf->upstream.cache = 0;
4153         return NGX_CONF_OK;
4154     }
4155 
4156     if (plcf->upstream.store > 0) {
4157         return "is incompatible with \"proxy_store\"";
4158     }
4159 
4160     plcf->upstream.cache = 1;
4161 
4162     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
4163 
4164     ccv.cf = cf;
4165     ccv.value = &value[1];
4166     ccv.complex_value = &cv;
4167 
4168     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
4169         return NGX_CONF_ERROR;
4170     }
4171 
4172     if (cv.lengths != NULL) {
4173 
4174         plcf->upstream.cache_value = ngx_palloc(cf->pool,
4175                                              sizeof(ngx_http_complex_value_t));
4176         if (plcf->upstream.cache_value == NULL) {
4177             return NGX_CONF_ERROR;
4178         }
4179 
4180         *plcf->upstream.cache_value = cv;
4181 
4182         return NGX_CONF_OK;
4183     }
4184 
4185     plcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0,
4186                                                       &ngx_http_proxy_module);
4187     if (plcf->upstream.cache_zone == NULL) {
4188         return NGX_CONF_ERROR;
4189     }
4190 
4191     return NGX_CONF_OK;
4192 }
4193 
4194 
4195 static char *
ngx_http_proxy_cache_key(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)4196 ngx_http_proxy_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
4197 {
4198     ngx_http_proxy_loc_conf_t *plcf = conf;
4199 
4200     ngx_str_t                         *value;
4201     ngx_http_compile_complex_value_t   ccv;
4202 
4203     value = cf->args->elts;
4204 
4205     if (plcf->cache_key.value.data) {
4206         return "is duplicate";
4207     }
4208 
4209     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
4210 
4211     ccv.cf = cf;
4212     ccv.value = &value[1];
4213     ccv.complex_value = &plcf->cache_key;
4214 
4215     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
4216         return NGX_CONF_ERROR;
4217     }
4218 
4219     return NGX_CONF_OK;
4220 }
4221 
4222 #endif
4223 
4224 
4225 #if (NGX_HTTP_SSL)
4226 
4227 static char *
ngx_http_proxy_ssl_password_file(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)4228 ngx_http_proxy_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
4229 {
4230     ngx_http_proxy_loc_conf_t *plcf = conf;
4231 
4232     ngx_str_t  *value;
4233 
4234     if (plcf->ssl_passwords != NGX_CONF_UNSET_PTR) {
4235         return "is duplicate";
4236     }
4237 
4238     value = cf->args->elts;
4239 
4240     plcf->ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]);
4241 
4242     if (plcf->ssl_passwords == NULL) {
4243         return NGX_CONF_ERROR;
4244     }
4245 
4246     return NGX_CONF_OK;
4247 }
4248 
4249 #endif
4250 
4251 
4252 static char *
ngx_http_proxy_lowat_check(ngx_conf_t * cf,void * post,void * data)4253 ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data)
4254 {
4255 #if (NGX_FREEBSD)
4256     ssize_t *np = data;
4257 
4258     if ((u_long) *np >= ngx_freebsd_net_inet_tcp_sendspace) {
4259         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
4260                            "\"proxy_send_lowat\" must be less than %d "
4261                            "(sysctl net.inet.tcp.sendspace)",
4262                            ngx_freebsd_net_inet_tcp_sendspace);
4263 
4264         return NGX_CONF_ERROR;
4265     }
4266 
4267 #elif !(NGX_HAVE_SO_SNDLOWAT)
4268     ssize_t *np = data;
4269 
4270     ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
4271                        "\"proxy_send_lowat\" is not supported, ignored");
4272 
4273     *np = 0;
4274 
4275 #endif
4276 
4277     return NGX_CONF_OK;
4278 }
4279 
4280 
4281 #if (NGX_HTTP_SSL)
4282 
4283 static ngx_int_t
ngx_http_proxy_set_ssl(ngx_conf_t * cf,ngx_http_proxy_loc_conf_t * plcf)4284 ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf)
4285 {
4286     ngx_pool_cleanup_t  *cln;
4287 
4288     plcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));
4289     if (plcf->upstream.ssl == NULL) {
4290         return NGX_ERROR;
4291     }
4292 
4293     plcf->upstream.ssl->log = cf->log;
4294 
4295     if (ngx_ssl_create(plcf->upstream.ssl, plcf->ssl_protocols, NULL)
4296         != NGX_OK)
4297     {
4298         return NGX_ERROR;
4299     }
4300 
4301     cln = ngx_pool_cleanup_add(cf->pool, 0);
4302     if (cln == NULL) {
4303         ngx_ssl_cleanup_ctx(plcf->upstream.ssl);
4304         return NGX_ERROR;
4305     }
4306 
4307     cln->handler = ngx_ssl_cleanup_ctx;
4308     cln->data = plcf->upstream.ssl;
4309 
4310     if (plcf->ssl_certificate.len) {
4311 
4312         if (plcf->ssl_certificate_key.len == 0) {
4313             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
4314                           "no \"proxy_ssl_certificate_key\" is defined "
4315                           "for certificate \"%V\"", &plcf->ssl_certificate);
4316             return NGX_ERROR;
4317         }
4318 
4319         if (ngx_ssl_certificate(cf, plcf->upstream.ssl, &plcf->ssl_certificate,
4320                                 &plcf->ssl_certificate_key, plcf->ssl_passwords)
4321             != NGX_OK)
4322         {
4323             return NGX_ERROR;
4324         }
4325     }
4326 
4327     if (ngx_ssl_ciphers(cf, plcf->upstream.ssl, &plcf->ssl_ciphers, 0)
4328         != NGX_OK)
4329     {
4330         return NGX_ERROR;
4331     }
4332 
4333     if (plcf->upstream.ssl_verify) {
4334         if (plcf->ssl_trusted_certificate.len == 0) {
4335             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
4336                       "no proxy_ssl_trusted_certificate for proxy_ssl_verify");
4337             return NGX_ERROR;
4338         }
4339 
4340         if (ngx_ssl_trusted_certificate(cf, plcf->upstream.ssl,
4341                                         &plcf->ssl_trusted_certificate,
4342                                         plcf->ssl_verify_depth)
4343             != NGX_OK)
4344         {
4345             return NGX_ERROR;
4346         }
4347 
4348         if (ngx_ssl_crl(cf, plcf->upstream.ssl, &plcf->ssl_crl) != NGX_OK) {
4349             return NGX_ERROR;
4350         }
4351     }
4352 
4353     if (ngx_ssl_client_session_cache(cf, plcf->upstream.ssl,
4354                                      plcf->upstream.ssl_session_reuse)
4355         != NGX_OK)
4356     {
4357         return NGX_ERROR;
4358     }
4359 
4360     return NGX_OK;
4361 }
4362 
4363 #endif
4364 
4365 
4366 static void
ngx_http_proxy_set_vars(ngx_url_t * u,ngx_http_proxy_vars_t * v)4367 ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v)
4368 {
4369     if (u->family != AF_UNIX) {
4370 
4371         if (u->no_port || u->port == u->default_port) {
4372 
4373             v->host_header = u->host;
4374 
4375             if (u->default_port == 80) {
4376                 ngx_str_set(&v->port, "80");
4377 
4378             } else {
4379                 ngx_str_set(&v->port, "443");
4380             }
4381 
4382         } else {
4383             v->host_header.len = u->host.len + 1 + u->port_text.len;
4384             v->host_header.data = u->host.data;
4385             v->port = u->port_text;
4386         }
4387 
4388         v->key_start.len += v->host_header.len;
4389 
4390     } else {
4391         ngx_str_set(&v->host_header, "localhost");
4392         ngx_str_null(&v->port);
4393         v->key_start.len += sizeof("unix:") - 1 + u->host.len + 1;
4394     }
4395 
4396     v->uri = u->uri;
4397 }
4398