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