~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Nginx/http/modules/ngx_http_proxy_module.c

Version: ~ [ nginx-1.4.1 ] ~ [ nginx-1.5.0 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.