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