upstream 0.7.33
[nginx.git] / nginx / src / http / modules / ngx_http_proxy_module.c
1
2 /*
3  * Copyright (C) Igor Sysoev
4  */
5
6
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_http.h>
10
11
12 typedef struct ngx_http_proxy_redirect_s  ngx_http_proxy_redirect_t;
13
14 typedef ngx_int_t (*ngx_http_proxy_redirect_pt)(ngx_http_request_t *r,
15     ngx_table_elt_t *h, size_t prefix, ngx_http_proxy_redirect_t *pr);
16
17 struct ngx_http_proxy_redirect_s {
18     ngx_http_proxy_redirect_pt     handler;
19     ngx_str_t                      redirect;
20
21     union {
22         ngx_str_t                  text;
23
24         struct {
25             void                  *lengths;
26             void                  *values;
27         } vars;
28
29         void                      *regex;
30     } replacement;
31 };
32
33
34 typedef struct {
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     ngx_array_t                   *headers_names;
54
55     ngx_array_t                   *proxy_lengths;
56     ngx_array_t                   *proxy_values;
57
58     ngx_array_t                   *redirects;
59
60     ngx_str_t                      body_source;
61
62     ngx_str_t                      method;
63     ngx_str_t                      location;
64     ngx_str_t                      url;
65
66     ngx_http_proxy_vars_t          vars;
67
68     ngx_flag_t                     redirect;
69
70     ngx_uint_t                     headers_hash_max_size;
71     ngx_uint_t                     headers_hash_bucket_size;
72 } ngx_http_proxy_loc_conf_t;
73
74
75 typedef struct {
76     ngx_uint_t                     status;
77     ngx_uint_t                     status_count;
78     u_char                        *status_start;
79     u_char                        *status_end;
80
81     ngx_http_proxy_vars_t          vars;
82
83     size_t                         internal_body_length;
84 } ngx_http_proxy_ctx_t;
85
86
87 #define NGX_HTTP_PROXY_PARSE_NO_HEADER  20
88
89
90 static ngx_int_t ngx_http_proxy_eval(ngx_http_request_t *r,
91     ngx_http_proxy_ctx_t *ctx, ngx_http_proxy_loc_conf_t *plcf);
92 static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r);
93 static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r);
94 static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r);
95 static ngx_int_t ngx_http_proxy_parse_status_line(ngx_http_request_t *r,
96     ngx_http_proxy_ctx_t *ctx);
97 static ngx_int_t ngx_http_proxy_process_header(ngx_http_request_t *r);
98 static void ngx_http_proxy_abort_request(ngx_http_request_t *r);
99 static void ngx_http_proxy_finalize_request(ngx_http_request_t *r,
100     ngx_int_t rc);
101
102 static ngx_int_t ngx_http_proxy_host_variable(ngx_http_request_t *r,
103     ngx_http_variable_value_t *v, uintptr_t data);
104 static ngx_int_t ngx_http_proxy_port_variable(ngx_http_request_t *r,
105     ngx_http_variable_value_t *v, uintptr_t data);
106 static ngx_int_t
107     ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
108     ngx_http_variable_value_t *v, uintptr_t data);
109 static ngx_int_t
110     ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
111     ngx_http_variable_value_t *v, uintptr_t data);
112 static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r,
113     ngx_table_elt_t *h, size_t prefix);
114
115 static ngx_int_t ngx_http_proxy_add_variables(ngx_conf_t *cf);
116 static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf);
117 static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf,
118     void *parent, void *child);
119
120 static char *ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd,
121     void *conf);
122 static char *ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd,
123     void *conf);
124 static char *ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd,
125     void *conf);
126
127 static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data);
128
129 static char *ngx_http_proxy_upstream_max_fails_unsupported(ngx_conf_t *cf,
130     ngx_command_t *cmd, void *conf);
131 static char *ngx_http_proxy_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
132     ngx_command_t *cmd, void *conf);
133
134 #if (NGX_HTTP_SSL)
135 static ngx_int_t ngx_http_proxy_set_ssl(ngx_conf_t *cf,
136     ngx_http_proxy_loc_conf_t *plcf);
137 #endif
138 static ngx_int_t ngx_http_proxy_set_vars(ngx_pool_t *pool, ngx_url_t *u,
139     ngx_http_proxy_vars_t *v);
140
141
142 static ngx_conf_post_t  ngx_http_proxy_lowat_post =
143     { ngx_http_proxy_lowat_check };
144
145
146 static ngx_conf_bitmask_t  ngx_http_proxy_next_upstream_masks[] = {
147     { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
148     { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
149     { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
150     { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
151     { ngx_string("http_502"), NGX_HTTP_UPSTREAM_FT_HTTP_502 },
152     { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
153     { ngx_string("http_504"), NGX_HTTP_UPSTREAM_FT_HTTP_504 },
154     { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
155     { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
156     { ngx_null_string, 0 }
157 };
158
159
160 static ngx_command_t  ngx_http_proxy_commands[] = {
161
162     { ngx_string("proxy_pass"),
163       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_HTTP_LMT_CONF|NGX_CONF_TAKE1,
164       ngx_http_proxy_pass,
165       NGX_HTTP_LOC_CONF_OFFSET,
166       0,
167       NULL },
168
169     { ngx_string("proxy_redirect"),
170       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
171       ngx_http_proxy_redirect,
172       NGX_HTTP_LOC_CONF_OFFSET,
173       0,
174       NULL },
175
176     { ngx_string("proxy_store"),
177       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
178       ngx_http_proxy_store,
179       NGX_HTTP_LOC_CONF_OFFSET,
180       0,
181       NULL },
182
183     { ngx_string("proxy_store_access"),
184       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
185       ngx_conf_set_access_slot,
186       NGX_HTTP_LOC_CONF_OFFSET,
187       offsetof(ngx_http_proxy_loc_conf_t, upstream.store_access),
188       NULL },
189
190     { ngx_string("proxy_buffering"),
191       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
192       ngx_conf_set_flag_slot,
193       NGX_HTTP_LOC_CONF_OFFSET,
194       offsetof(ngx_http_proxy_loc_conf_t, upstream.buffering),
195       NULL },
196
197     { ngx_string("proxy_ignore_client_abort"),
198       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
199       ngx_conf_set_flag_slot,
200       NGX_HTTP_LOC_CONF_OFFSET,
201       offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_client_abort),
202       NULL },
203
204     { ngx_string("proxy_connect_timeout"),
205       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
206       ngx_conf_set_msec_slot,
207       NGX_HTTP_LOC_CONF_OFFSET,
208       offsetof(ngx_http_proxy_loc_conf_t, upstream.connect_timeout),
209       NULL },
210
211     { ngx_string("proxy_send_timeout"),
212       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
213       ngx_conf_set_msec_slot,
214       NGX_HTTP_LOC_CONF_OFFSET,
215       offsetof(ngx_http_proxy_loc_conf_t, upstream.send_timeout),
216       NULL },
217
218     { ngx_string("proxy_send_lowat"),
219       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
220       ngx_conf_set_size_slot,
221       NGX_HTTP_LOC_CONF_OFFSET,
222       offsetof(ngx_http_proxy_loc_conf_t, upstream.send_lowat),
223       &ngx_http_proxy_lowat_post },
224
225     { ngx_string("proxy_intercept_errors"),
226       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
227       ngx_conf_set_flag_slot,
228       NGX_HTTP_LOC_CONF_OFFSET,
229       offsetof(ngx_http_proxy_loc_conf_t, upstream.intercept_errors),
230       NULL },
231
232     { ngx_string("proxy_set_header"),
233       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
234       ngx_conf_set_keyval_slot,
235       NGX_HTTP_LOC_CONF_OFFSET,
236       offsetof(ngx_http_proxy_loc_conf_t, headers_source),
237       NULL },
238
239     { ngx_string("proxy_headers_hash_max_size"),
240       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
241       ngx_conf_set_num_slot,
242       NGX_HTTP_LOC_CONF_OFFSET,
243       offsetof(ngx_http_proxy_loc_conf_t, headers_hash_max_size),
244       NULL },
245
246     { ngx_string("proxy_headers_hash_bucket_size"),
247       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
248       ngx_conf_set_num_slot,
249       NGX_HTTP_LOC_CONF_OFFSET,
250       offsetof(ngx_http_proxy_loc_conf_t, headers_hash_bucket_size),
251       NULL },
252
253     { ngx_string("proxy_set_body"),
254       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
255       ngx_conf_set_str_slot,
256       NGX_HTTP_LOC_CONF_OFFSET,
257       offsetof(ngx_http_proxy_loc_conf_t, body_source),
258       NULL },
259
260     { ngx_string("proxy_method"),
261       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
262       ngx_conf_set_str_slot,
263       NGX_HTTP_LOC_CONF_OFFSET,
264       offsetof(ngx_http_proxy_loc_conf_t, method),
265       NULL },
266
267     { ngx_string("proxy_pass_request_headers"),
268       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
269       ngx_conf_set_flag_slot,
270       NGX_HTTP_LOC_CONF_OFFSET,
271       offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_headers),
272       NULL },
273
274     { ngx_string("proxy_pass_request_body"),
275       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
276       ngx_conf_set_flag_slot,
277       NGX_HTTP_LOC_CONF_OFFSET,
278       offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_request_body),
279       NULL },
280
281     { ngx_string("proxy_buffer_size"),
282       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
283       ngx_conf_set_size_slot,
284       NGX_HTTP_LOC_CONF_OFFSET,
285       offsetof(ngx_http_proxy_loc_conf_t, upstream.buffer_size),
286       NULL },
287
288     { ngx_string("proxy_read_timeout"),
289       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
290       ngx_conf_set_msec_slot,
291       NGX_HTTP_LOC_CONF_OFFSET,
292       offsetof(ngx_http_proxy_loc_conf_t, upstream.read_timeout),
293       NULL },
294
295     { ngx_string("proxy_buffers"),
296       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
297       ngx_conf_set_bufs_slot,
298       NGX_HTTP_LOC_CONF_OFFSET,
299       offsetof(ngx_http_proxy_loc_conf_t, upstream.bufs),
300       NULL },
301
302     { ngx_string("proxy_busy_buffers_size"),
303       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
304       ngx_conf_set_size_slot,
305       NGX_HTTP_LOC_CONF_OFFSET,
306       offsetof(ngx_http_proxy_loc_conf_t, upstream.busy_buffers_size_conf),
307       NULL },
308
309     { ngx_string("proxy_temp_path"),
310       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
311       ngx_conf_set_path_slot,
312       NGX_HTTP_LOC_CONF_OFFSET,
313       offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_path),
314       (void *) ngx_garbage_collector_temp_handler },
315
316     { ngx_string("proxy_max_temp_file_size"),
317       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
318       ngx_conf_set_size_slot,
319       NGX_HTTP_LOC_CONF_OFFSET,
320       offsetof(ngx_http_proxy_loc_conf_t, upstream.max_temp_file_size_conf),
321       NULL },
322
323     { ngx_string("proxy_temp_file_write_size"),
324       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
325       ngx_conf_set_size_slot,
326       NGX_HTTP_LOC_CONF_OFFSET,
327       offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_file_write_size_conf),
328       NULL },
329
330     { ngx_string("proxy_next_upstream"),
331       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
332       ngx_conf_set_bitmask_slot,
333       NGX_HTTP_LOC_CONF_OFFSET,
334       offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream),
335       &ngx_http_proxy_next_upstream_masks },
336
337     { ngx_string("proxy_upstream_max_fails"),
338       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
339       ngx_http_proxy_upstream_max_fails_unsupported,
340       0,
341       0,
342       NULL },
343
344     { ngx_string("proxy_upstream_fail_timeout"),
345       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
346       ngx_http_proxy_upstream_fail_timeout_unsupported,
347       0,
348       0,
349       NULL },
350
351     { ngx_string("proxy_pass_header"),
352       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
353       ngx_conf_set_str_array_slot,
354       NGX_HTTP_LOC_CONF_OFFSET,
355       offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_headers),
356       NULL },
357
358     { ngx_string("proxy_hide_header"),
359       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
360       ngx_conf_set_str_array_slot,
361       NGX_HTTP_LOC_CONF_OFFSET,
362       offsetof(ngx_http_proxy_loc_conf_t, upstream.hide_headers),
363       NULL },
364
365 #if (NGX_HTTP_SSL)
366
367     { ngx_string("proxy_ssl_session_reuse"),
368       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
369       ngx_conf_set_flag_slot,
370       NGX_HTTP_LOC_CONF_OFFSET,
371       offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_session_reuse),
372       NULL },
373
374 #endif
375
376       ngx_null_command
377 };
378
379
380 static ngx_http_module_t  ngx_http_proxy_module_ctx = {
381     ngx_http_proxy_add_variables,          /* preconfiguration */
382     NULL,                                  /* postconfiguration */
383
384     NULL,                                  /* create main configuration */
385     NULL,                                  /* init main configuration */
386
387     NULL,                                  /* create server configuration */
388     NULL,                                  /* merge server configuration */
389
390     ngx_http_proxy_create_loc_conf,        /* create location configration */
391     ngx_http_proxy_merge_loc_conf          /* merge location configration */
392 };
393
394
395 ngx_module_t  ngx_http_proxy_module = {
396     NGX_MODULE_V1,
397     &ngx_http_proxy_module_ctx,            /* module context */
398     ngx_http_proxy_commands,               /* module directives */
399     NGX_HTTP_MODULE,                       /* module type */
400     NULL,                                  /* init master */
401     NULL,                                  /* init module */
402     NULL,                                  /* init process */
403     NULL,                                  /* init thread */
404     NULL,                                  /* exit thread */
405     NULL,                                  /* exit process */
406     NULL,                                  /* exit master */
407     NGX_MODULE_V1_PADDING
408 };
409
410
411 static char  ngx_http_proxy_version[] = " HTTP/1.0" CRLF;
412
413
414 static ngx_keyval_t  ngx_http_proxy_headers[] = {
415     { ngx_string("Host"), ngx_string("$proxy_host") },
416     { ngx_string("Connection"), ngx_string("close") },
417     { ngx_string("Keep-Alive"), ngx_string("") },
418     { ngx_string("Expect"), ngx_string("") },
419     { ngx_null_string, ngx_null_string }
420 };
421
422
423 static ngx_str_t  ngx_http_proxy_hide_headers[] = {
424     ngx_string("Date"),
425     ngx_string("Server"),
426     ngx_string("X-Pad"),
427     ngx_string("X-Accel-Expires"),
428     ngx_string("X-Accel-Redirect"),
429     ngx_string("X-Accel-Limit-Rate"),
430     ngx_string("X-Accel-Buffering"),
431     ngx_string("X-Accel-Charset"),
432     ngx_null_string
433 };
434
435
436 static ngx_http_variable_t  ngx_http_proxy_vars[] = {
437
438     { ngx_string("proxy_host"), NULL, ngx_http_proxy_host_variable, 0,
439       NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
440
441     { ngx_string("proxy_port"), NULL, ngx_http_proxy_port_variable, 0,
442       NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
443
444     { ngx_string("proxy_add_x_forwarded_for"), NULL,
445       ngx_http_proxy_add_x_forwarded_for_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
446
447 #if 0
448     { ngx_string("proxy_add_via"), NULL, NULL, 0, NGX_HTTP_VAR_NOHASH, 0 },
449 #endif
450
451     { ngx_string("proxy_internal_body_length"), NULL,
452       ngx_http_proxy_internal_body_length_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
453
454     { ngx_null_string, NULL, NULL, 0, 0, 0 }
455 };
456
457
458 static ngx_int_t
459 ngx_http_proxy_handler(ngx_http_request_t *r)
460 {
461     ngx_int_t                   rc;
462     ngx_http_upstream_t        *u;
463     ngx_http_proxy_ctx_t       *ctx;
464     ngx_http_proxy_loc_conf_t  *plcf;
465
466     u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t));
467     if (u == NULL) {
468         return NGX_HTTP_INTERNAL_SERVER_ERROR;
469     }
470
471     r->upstream = u;
472
473     ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t));
474     if (ctx == NULL) {
475         return NGX_ERROR;
476     }
477
478     ngx_http_set_ctx(r, ctx, ngx_http_proxy_module);
479
480     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
481
482     if (plcf->proxy_lengths == 0) {
483         ctx->vars = plcf->vars;
484         u->schema = plcf->vars.schema;
485 #if (NGX_HTTP_SSL)
486         u->ssl = (plcf->upstream.ssl != NULL);
487 #endif
488
489     } else {
490         if (ngx_http_proxy_eval(r, ctx, plcf) != NGX_OK) {
491             return NGX_HTTP_INTERNAL_SERVER_ERROR;
492         }
493     }
494
495     u->peer.log = r->connection->log;
496     u->peer.log_error = NGX_ERROR_ERR;
497 #if (NGX_THREADS)
498     u->peer.lock = &r->connection->lock;
499 #endif
500
501     u->output.tag = (ngx_buf_tag_t) &ngx_http_proxy_module;
502
503     u->conf = &plcf->upstream;
504
505     u->create_request = ngx_http_proxy_create_request;
506     u->reinit_request = ngx_http_proxy_reinit_request;
507     u->process_header = ngx_http_proxy_process_status_line;
508     u->abort_request = ngx_http_proxy_abort_request;
509     u->finalize_request = ngx_http_proxy_finalize_request;
510
511     if (plcf->redirects) {
512         u->rewrite_redirect = ngx_http_proxy_rewrite_redirect;
513     }
514
515     u->buffering = plcf->upstream.buffering;
516
517     u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
518     if (u->pipe == NULL) {
519         return NGX_HTTP_INTERNAL_SERVER_ERROR;
520     }
521
522     u->pipe->input_filter = ngx_event_pipe_copy_input_filter;
523
524     u->accel = 1;
525
526     rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
527
528     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
529         return rc;
530     }
531
532     return NGX_DONE;
533 }
534
535
536 static ngx_int_t
537 ngx_http_proxy_eval(ngx_http_request_t *r, ngx_http_proxy_ctx_t *ctx,
538     ngx_http_proxy_loc_conf_t *plcf)
539 {
540     u_char     *p;
541     size_t      add;
542     u_short     port;
543     ngx_str_t   proxy;
544     ngx_url_t   u;
545
546     if (ngx_http_script_run(r, &proxy, plcf->proxy_lengths->elts, 0,
547                             plcf->proxy_values->elts)
548         == NULL)
549     {
550         return NGX_ERROR;
551     }
552
553     if (ngx_strncasecmp(proxy.data, (u_char *) "http://", 7) == 0) {
554
555         add = 7;
556         port = 80;
557
558 #if (NGX_HTTP_SSL)
559
560     } else if (ngx_strncasecmp(proxy.data, (u_char *) "https://", 8) == 0) {
561
562         add = 8;
563         port = 443;
564         r->upstream->ssl = 1;
565
566 #endif
567
568     } else {
569         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
570                       "invalid URL prefix in \"%V\"", &proxy);
571         return NGX_ERROR;
572     }
573
574     r->upstream->schema.len = add;
575     r->upstream->schema.data = proxy.data;
576
577     ngx_memzero(&u, sizeof(ngx_url_t));
578
579     u.url.len = proxy.len - add;
580     u.url.data = proxy.data + add;
581     u.default_port = port;
582     u.uri_part = 1;
583     u.no_resolve = 1;
584
585     if (ngx_parse_url(r->pool, &u) != NGX_OK) {
586         if (u.err) {
587             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
588                           "%s in upstream \"%V\"", u.err, &u.url);
589         }
590
591         return NGX_ERROR;
592     }
593
594     if (u.uri.len && u.uri.data[0] == '?') {
595         p = ngx_pnalloc(r->pool, u.uri.len + 1);
596         if (p == NULL) {
597             return NGX_ERROR;
598         }
599
600         *p++ = '/';
601         ngx_memcpy(p, u.uri.data, u.uri.len);
602
603         u.uri.len++;
604         u.uri.data = p - 1;
605     }
606
607     if (ngx_http_proxy_set_vars(r->pool, &u, &ctx->vars) != NGX_OK) {
608         return NGX_ERROR;
609     }
610
611     r->upstream->resolved = ngx_pcalloc(r->pool,
612                                         sizeof(ngx_http_upstream_resolved_t));
613     if (r->upstream->resolved == NULL) {
614         return NGX_ERROR;
615     }
616
617     if (u.addrs && u.addrs[0].sockaddr) {
618         r->upstream->resolved->sockaddr = u.addrs[0].sockaddr;
619         r->upstream->resolved->socklen = u.addrs[0].socklen;
620         r->upstream->resolved->naddrs = 1;
621         r->upstream->resolved->host = u.addrs[0].name;
622
623     } else {
624         r->upstream->resolved->host = u.host;
625         r->upstream->resolved->port = (in_port_t) (u.no_port ? u.default_port:
626                                                                u.port);
627         r->upstream->resolved->no_port = u.no_port;
628     }
629
630     return NGX_OK;
631 }
632
633
634 static ngx_int_t
635 ngx_http_proxy_create_request(ngx_http_request_t *r)
636 {
637     size_t                        len, loc_len, body_len;
638     uintptr_t                     escape;
639     ngx_buf_t                    *b;
640     ngx_str_t                     method;
641     ngx_uint_t                    i, unparsed_uri;
642     ngx_chain_t                  *cl, *body;
643     ngx_list_part_t              *part;
644     ngx_table_elt_t              *header;
645     ngx_http_upstream_t          *u;
646     ngx_http_proxy_ctx_t         *ctx;
647     ngx_http_script_code_pt       code;
648     ngx_http_script_engine_t      e, le;
649     ngx_http_proxy_loc_conf_t    *plcf;
650     ngx_http_script_len_code_pt   lcode;
651
652     u = r->upstream;
653
654     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
655
656     if (u->method.len) {
657         /* HEAD was changed to GET to cache response */
658         method = u->method;
659         method.len++;
660
661     } else if (plcf->method.len) {
662         method = plcf->method;
663
664     } else {
665         method = r->method_name;
666         method.len++;
667     }
668
669     len = method.len + sizeof(ngx_http_proxy_version) - 1 + sizeof(CRLF) - 1;
670
671     escape = 0;
672     loc_len = 0;
673     unparsed_uri = 0;
674
675     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
676
677     if (plcf->proxy_lengths) {
678         len += ctx->vars.uri.len;
679
680     } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main)
681     {
682         unparsed_uri = 1;
683         len += r->unparsed_uri.len;
684
685     } else {
686         loc_len = (r->valid_location && ctx->vars.uri.len) ?
687                       plcf->location.len : 0;
688
689         if (r->quoted_uri || r->internal) {
690             escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
691                                         r->uri.len - loc_len, NGX_ESCAPE_URI);
692         }
693
694         len += ctx->vars.uri.len + r->uri.len - loc_len + escape
695                + sizeof("?") - 1 + r->args.len;
696     }
697
698     ngx_http_script_flush_no_cacheable_variables(r, plcf->flushes);
699
700     if (plcf->body_set_len) {
701         le.ip = plcf->body_set_len->elts;
702         le.request = r;
703         le.flushed = 1;
704         body_len = 0;
705
706         while (*(uintptr_t *) le.ip) {
707             lcode = *(ngx_http_script_len_code_pt *) le.ip;
708             body_len += lcode(&le);
709         }
710
711         ctx->internal_body_length = body_len;
712         len += body_len;
713     }
714
715     le.ip = plcf->headers_set_len->elts;
716     le.request = r;
717     le.flushed = 1;
718
719     while (*(uintptr_t *) le.ip) {
720         while (*(uintptr_t *) le.ip) {
721             lcode = *(ngx_http_script_len_code_pt *) le.ip;
722             len += lcode(&le);
723         }
724         le.ip += sizeof(uintptr_t);
725     }
726
727
728     if (plcf->upstream.pass_request_headers) {
729         part = &r->headers_in.headers.part;
730         header = part->elts;
731
732         for (i = 0; /* void */; i++) {
733
734             if (i >= part->nelts) {
735                 if (part->next == NULL) {
736                     break;
737                 }
738
739                 part = part->next;
740                 header = part->elts;
741                 i = 0;
742             }
743
744             if (ngx_hash_find(&plcf->headers_set_hash, header[i].hash,
745                               header[i].lowcase_key, header[i].key.len))
746             {
747                 continue;
748             }
749
750             len += header[i].key.len + sizeof(": ") - 1
751                 + header[i].value.len + sizeof(CRLF) - 1;
752         }
753     }
754
755
756     b = ngx_create_temp_buf(r->pool, len);
757     if (b == NULL) {
758         return NGX_ERROR;
759     }
760
761     cl = ngx_alloc_chain_link(r->pool);
762     if (cl == NULL) {
763         return NGX_ERROR;
764     }
765
766     cl->buf = b;
767
768
769     /* the request line */
770
771     b->last = ngx_copy(b->last, method.data, method.len);
772
773     u->uri.data = b->last;
774
775     if (plcf->proxy_lengths) {
776         b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
777
778     } else if (unparsed_uri) {
779         b->last = ngx_copy(b->last, r->unparsed_uri.data, r->unparsed_uri.len);
780
781     } else {
782         if (r->valid_location) {
783             b->last = ngx_copy(b->last, ctx->vars.uri.data, ctx->vars.uri.len);
784         }
785
786         if (escape) {
787             ngx_escape_uri(b->last, r->uri.data + loc_len,
788                            r->uri.len - loc_len, NGX_ESCAPE_URI);
789             b->last += r->uri.len - loc_len + escape;
790
791         } else {
792             b->last = ngx_copy(b->last, r->uri.data + loc_len,
793                                r->uri.len - loc_len);
794         }
795
796         if (r->args.len > 0) {
797             *b->last++ = '?';
798             b->last = ngx_copy(b->last, r->args.data, r->args.len);
799         }
800     }
801
802     u->uri.len = b->last - u->uri.data;
803
804     b->last = ngx_cpymem(b->last, ngx_http_proxy_version,
805                          sizeof(ngx_http_proxy_version) - 1);
806
807     ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
808
809     e.ip = plcf->headers_set->elts;
810     e.pos = b->last;
811     e.request = r;
812     e.flushed = 1;
813
814     le.ip = plcf->headers_set_len->elts;
815
816     while (*(uintptr_t *) le.ip) {
817         lcode = *(ngx_http_script_len_code_pt *) le.ip;
818
819         /* skip the header line name length */
820         (void) lcode(&le);
821
822         if (*(ngx_http_script_len_code_pt *) le.ip) {
823
824             for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) {
825                 lcode = *(ngx_http_script_len_code_pt *) le.ip;
826             }
827
828             e.skip = (len == sizeof(CRLF) - 1) ? 1 : 0;
829
830         } else {
831             e.skip = 0;
832         }
833
834         le.ip += sizeof(uintptr_t);
835
836         while (*(uintptr_t *) e.ip) {
837             code = *(ngx_http_script_code_pt *) e.ip;
838             code((ngx_http_script_engine_t *) &e);
839         }
840         e.ip += sizeof(uintptr_t);
841     }
842
843     b->last = e.pos;
844
845
846     if (plcf->upstream.pass_request_headers) {
847         part = &r->headers_in.headers.part;
848         header = part->elts;
849
850         for (i = 0; /* void */; i++) {
851
852             if (i >= part->nelts) {
853                 if (part->next == NULL) {
854                     break;
855                 }
856
857                 part = part->next;
858                 header = part->elts;
859                 i = 0;
860             }
861
862             if (ngx_hash_find(&plcf->headers_set_hash, header[i].hash,
863                               header[i].lowcase_key, header[i].key.len))
864             {
865                 continue;
866             }
867
868             b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len);
869
870             *b->last++ = ':'; *b->last++ = ' ';
871
872             b->last = ngx_copy(b->last, header[i].value.data,
873                                header[i].value.len);
874
875             *b->last++ = CR; *b->last++ = LF;
876
877             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
878                            "http proxy header: \"%V: %V\"",
879                            &header[i].key, &header[i].value);
880         }
881     }
882
883
884     /* add "\r\n" at the header end */
885     *b->last++ = CR; *b->last++ = LF;
886
887     if (plcf->body_set) {
888         e.ip = plcf->body_set->elts;
889         e.pos = b->last;
890
891         while (*(uintptr_t *) e.ip) {
892             code = *(ngx_http_script_code_pt *) e.ip;
893             code((ngx_http_script_engine_t *) &e);
894         }
895
896         b->last = e.pos;
897     }
898
899     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
900                    "http proxy header:\n\"%*s\"",
901                    (size_t) (b->last - b->pos), b->pos);
902
903     if (plcf->body_set == NULL && plcf->upstream.pass_request_body) {
904
905         body = u->request_bufs;
906         u->request_bufs = cl;
907
908         while (body) {
909             b = ngx_alloc_buf(r->pool);
910             if (b == NULL) {
911                 return NGX_ERROR;
912             }
913
914             ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
915
916             cl->next = ngx_alloc_chain_link(r->pool);
917             if (cl->next == NULL) {
918                 return NGX_ERROR;
919             }
920
921             cl = cl->next;
922             cl->buf = b;
923
924             body = body->next;
925         }
926
927         b->flush = 1;
928
929     } else {
930         u->request_bufs = cl;
931     }
932
933     cl->next = NULL;
934
935     return NGX_OK;
936 }
937
938
939 static ngx_int_t
940 ngx_http_proxy_reinit_request(ngx_http_request_t *r)
941 {
942     ngx_http_proxy_ctx_t  *ctx;
943
944     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
945
946     if (ctx == NULL) {
947         return NGX_OK;
948     }
949
950     ctx->status = 0;
951     ctx->status_count = 0;
952     ctx->status_start = NULL;
953     ctx->status_end = NULL;
954
955     r->upstream->process_header = ngx_http_proxy_process_status_line;
956
957     return NGX_OK;
958 }
959
960
961 static ngx_int_t
962 ngx_http_proxy_process_status_line(ngx_http_request_t *r)
963 {
964     ngx_int_t              rc;
965     ngx_http_upstream_t   *u;
966     ngx_http_proxy_ctx_t  *ctx;
967
968     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
969
970     if (ctx == NULL) {
971         return NGX_ERROR;
972     }
973
974     rc = ngx_http_proxy_parse_status_line(r, ctx);
975
976     if (rc == NGX_AGAIN) {
977         return rc;
978     }
979
980     u = r->upstream;
981
982     if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) {
983         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
984                       "upstream sent no valid HTTP/1.0 header");
985
986 #if 0
987         if (u->accel) {
988             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
989         }
990 #endif
991
992         r->http_version = NGX_HTTP_VERSION_9;
993         u->headers_in.status_n = NGX_HTTP_OK;
994         u->state->status = NGX_HTTP_OK;
995
996         return NGX_OK;
997     }
998
999     u->headers_in.status_n = ctx->status;
1000     u->state->status = ctx->status;
1001
1002     u->headers_in.status_line.len = ctx->status_end - ctx->status_start;
1003     u->headers_in.status_line.data = ngx_pnalloc(r->pool,
1004                                                  u->headers_in.status_line.len);
1005     if (u->headers_in.status_line.data == NULL) {
1006         return NGX_ERROR;
1007     }
1008
1009     ngx_memcpy(u->headers_in.status_line.data, ctx->status_start,
1010                u->headers_in.status_line.len);
1011
1012     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1013                    "http proxy status %ui \"%V\"",
1014                    u->headers_in.status_n, &u->headers_in.status_line);
1015
1016     u->process_header = ngx_http_proxy_process_header;
1017
1018     return ngx_http_proxy_process_header(r);
1019 }
1020
1021
1022 static ngx_int_t
1023 ngx_http_proxy_parse_status_line(ngx_http_request_t *r,
1024     ngx_http_proxy_ctx_t *ctx)
1025 {
1026     u_char                ch;
1027     u_char               *p;
1028     ngx_http_upstream_t  *u;
1029     enum  {
1030         sw_start = 0,
1031         sw_H,
1032         sw_HT,
1033         sw_HTT,
1034         sw_HTTP,
1035         sw_first_major_digit,
1036         sw_major_digit,
1037         sw_first_minor_digit,
1038         sw_minor_digit,
1039         sw_status,
1040         sw_space_after_status,
1041         sw_status_text,
1042         sw_almost_done
1043     } state;
1044
1045     u = r->upstream;
1046
1047     state = r->state;
1048
1049     for (p = u->buffer.pos; p < u->buffer.last; p++) {
1050         ch = *p;
1051
1052         switch (state) {
1053
1054         /* "HTTP/" */
1055         case sw_start:
1056             switch (ch) {
1057             case 'H':
1058                 state = sw_H;
1059                 break;
1060             default:
1061                 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1062             }
1063             break;
1064
1065         case sw_H:
1066             switch (ch) {
1067             case 'T':
1068                 state = sw_HT;
1069                 break;
1070             default:
1071                 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1072             }
1073             break;
1074
1075         case sw_HT:
1076             switch (ch) {
1077             case 'T':
1078                 state = sw_HTT;
1079                 break;
1080             default:
1081                 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1082             }
1083             break;
1084
1085         case sw_HTT:
1086             switch (ch) {
1087             case 'P':
1088                 state = sw_HTTP;
1089                 break;
1090             default:
1091                 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1092             }
1093             break;
1094
1095         case sw_HTTP:
1096             switch (ch) {
1097             case '/':
1098                 state = sw_first_major_digit;
1099                 break;
1100             default:
1101                 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1102             }
1103             break;
1104
1105         /* the first digit of major HTTP version */
1106         case sw_first_major_digit:
1107             if (ch < '1' || ch > '9') {
1108                 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1109             }
1110
1111             state = sw_major_digit;
1112             break;
1113
1114         /* the major HTTP version or dot */
1115         case sw_major_digit:
1116             if (ch == '.') {
1117                 state = sw_first_minor_digit;
1118                 break;
1119             }
1120
1121             if (ch < '0' || ch > '9') {
1122                 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1123             }
1124
1125             break;
1126
1127         /* the first digit of minor HTTP version */
1128         case sw_first_minor_digit:
1129             if (ch < '0' || ch > '9') {
1130                 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1131             }
1132
1133             state = sw_minor_digit;
1134             break;
1135
1136         /* the minor HTTP version or the end of the request line */
1137         case sw_minor_digit:
1138             if (ch == ' ') {
1139                 state = sw_status;
1140                 break;
1141             }
1142
1143             if (ch < '0' || ch > '9') {
1144                 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1145             }
1146
1147             break;
1148
1149         /* HTTP status code */
1150         case sw_status:
1151             if (ch == ' ') {
1152                 break;
1153             }
1154
1155             if (ch < '0' || ch > '9') {
1156                 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1157             }
1158
1159             ctx->status = ctx->status * 10 + ch - '0';
1160
1161             if (++ctx->status_count == 3) {
1162                 state = sw_space_after_status;
1163                 ctx->status_start = p - 2;
1164             }
1165
1166             break;
1167
1168          /* space or end of line */
1169          case sw_space_after_status:
1170             switch (ch) {
1171             case ' ':
1172                 state = sw_status_text;
1173                 break;
1174             case '.':                    /* IIS may send 403.1, 403.2, etc */
1175                 state = sw_status_text;
1176                 break;
1177             case CR:
1178                 state = sw_almost_done;
1179                 break;
1180             case LF:
1181                 goto done;
1182             default:
1183                 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1184             }
1185             break;
1186
1187         /* any text until end of line */
1188         case sw_status_text:
1189             switch (ch) {
1190             case CR:
1191                 state = sw_almost_done;
1192
1193                 break;
1194             case LF:
1195                 goto done;
1196             }
1197             break;
1198
1199         /* end of status line */
1200         case sw_almost_done:
1201             ctx->status_end = p - 1;
1202             switch (ch) {
1203             case LF:
1204                 goto done;
1205             default:
1206                 return NGX_HTTP_PROXY_PARSE_NO_HEADER;
1207             }
1208         }
1209     }
1210
1211     u->buffer.pos = p;
1212     r->state = state;
1213
1214     return NGX_AGAIN;
1215
1216 done:
1217
1218     u->buffer.pos = p + 1;
1219
1220     if (ctx->status_end == NULL) {
1221         ctx->status_end = p;
1222     }
1223
1224     r->state = sw_start;
1225
1226     return NGX_OK;
1227 }
1228
1229
1230 static ngx_int_t
1231 ngx_http_proxy_process_header(ngx_http_request_t *r)
1232 {
1233     ngx_int_t                       rc;
1234     ngx_table_elt_t                *h;
1235     ngx_http_upstream_header_t     *hh;
1236     ngx_http_upstream_main_conf_t  *umcf;
1237
1238     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
1239
1240     for ( ;; ) {
1241
1242         rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);
1243
1244         if (rc == NGX_OK) {
1245
1246             /* a header line has been parsed successfully */
1247
1248             h = ngx_list_push(&r->upstream->headers_in.headers);
1249             if (h == NULL) {
1250                 return NGX_ERROR;
1251             }
1252
1253             h->hash = r->header_hash;
1254
1255             h->key.len = r->header_name_end - r->header_name_start;
1256             h->value.len = r->header_end - r->header_start;
1257
1258             h->key.data = ngx_pnalloc(r->pool,
1259                                h->key.len + 1 + h->value.len + 1 + h->key.len);
1260             if (h->key.data == NULL) {
1261                 return NGX_ERROR;
1262             }
1263
1264             h->value.data = h->key.data + h->key.len + 1;
1265             h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;
1266
1267             ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1);
1268             ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1);
1269
1270             if (h->key.len == r->lowcase_index) {
1271                 ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
1272
1273             } else {
1274                 ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
1275             }
1276
1277             hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
1278                                h->lowcase_key, h->key.len);
1279
1280             if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1281                 return NGX_ERROR;
1282             }
1283
1284             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1285                            "http proxy header: \"%V: %V\"",
1286                            &h->key, &h->value);
1287
1288             continue;
1289         }
1290
1291         if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
1292
1293             /* a whole header has been parsed successfully */
1294
1295             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1296                            "http proxy header done");
1297
1298             /*
1299              * if no "Server" and "Date" in header line,
1300              * then add the special empty headers
1301              */
1302
1303             if (r->upstream->headers_in.server == NULL) {
1304                 h = ngx_list_push(&r->upstream->headers_in.headers);
1305                 if (h == NULL) {
1306                     return NGX_ERROR;
1307                 }
1308
1309                 h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(
1310                                     ngx_hash('s', 'e'), 'r'), 'v'), 'e'), 'r');
1311
1312                 h->key.len = sizeof("Server") - 1;
1313                 h->key.data = (u_char *) "Server";
1314                 h->value.len = 0;
1315                 h->value.data = NULL;
1316                 h->lowcase_key = (u_char *) "server";
1317             }
1318
1319             if (r->upstream->headers_in.date == NULL) {
1320                 h = ngx_list_push(&r->upstream->headers_in.headers);
1321                 if (h == NULL) {
1322                     return NGX_ERROR;
1323                 }
1324
1325                 h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e');
1326
1327                 h->key.len = sizeof("Date") - 1;
1328                 h->key.data = (u_char *) "Date";
1329                 h->value.len = 0;
1330                 h->value.data = NULL;
1331                 h->lowcase_key = (u_char *) "date";
1332             }
1333
1334             return NGX_OK;
1335         }
1336
1337         if (rc == NGX_AGAIN) {
1338             return NGX_AGAIN;
1339         }
1340
1341         /* there was error while a header line parsing */
1342
1343         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1344                       "upstream sent invalid header");
1345
1346         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1347     }
1348 }
1349
1350
1351 static void
1352 ngx_http_proxy_abort_request(ngx_http_request_t *r)
1353 {
1354     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1355                    "abort http proxy request");
1356
1357     return;
1358 }
1359
1360
1361 static void
1362 ngx_http_proxy_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
1363 {
1364     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1365                    "finalize http proxy request");
1366
1367     return;
1368 }
1369
1370
1371 static ngx_int_t
1372 ngx_http_proxy_host_variable(ngx_http_request_t *r,
1373     ngx_http_variable_value_t *v, uintptr_t data)
1374 {
1375     ngx_http_proxy_ctx_t  *ctx;
1376
1377     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1378
1379     if (ctx == NULL) {
1380         v->not_found = 1;
1381         return NGX_OK;
1382     }
1383
1384     v->len = ctx->vars.host_header.len;
1385     v->valid = 1;
1386     v->no_cacheable = 0;
1387     v->not_found = 0;
1388     v->data = ctx->vars.host_header.data;
1389
1390     return NGX_OK;
1391 }
1392
1393
1394 static ngx_int_t
1395 ngx_http_proxy_port_variable(ngx_http_request_t *r,
1396     ngx_http_variable_value_t *v, uintptr_t data)
1397 {
1398     ngx_http_proxy_ctx_t  *ctx;
1399
1400     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1401
1402     if (ctx == NULL) {
1403         v->not_found = 1;
1404         return NGX_OK;
1405     }
1406
1407     v->len = ctx->vars.port.len;
1408     v->valid = 1;
1409     v->no_cacheable = 0;
1410     v->not_found = 0;
1411     v->data = ctx->vars.port.data;
1412
1413     return NGX_OK;
1414 }
1415
1416
1417 static ngx_int_t
1418 ngx_http_proxy_add_x_forwarded_for_variable(ngx_http_request_t *r,
1419     ngx_http_variable_value_t *v, uintptr_t data)
1420 {
1421     u_char  *p;
1422
1423     v->valid = 1;
1424     v->no_cacheable = 0;
1425     v->not_found = 0;
1426
1427     if (r->headers_in.x_forwarded_for == NULL) {
1428         v->len = r->connection->addr_text.len;
1429         v->data = r->connection->addr_text.data;
1430         return NGX_OK;
1431     }
1432
1433     v->len = r->headers_in.x_forwarded_for->value.len
1434              + sizeof(", ") - 1 + r->connection->addr_text.len;
1435
1436     p = ngx_pnalloc(r->pool, v->len);
1437     if (p == NULL) {
1438         return NGX_ERROR;
1439     }
1440
1441     v->data = p;
1442
1443     p = ngx_copy(p, r->headers_in.x_forwarded_for->value.data,
1444                  r->headers_in.x_forwarded_for->value.len);
1445
1446     *p++ = ','; *p++ = ' ';
1447
1448     ngx_memcpy(p, r->connection->addr_text.data, r->connection->addr_text.len);
1449
1450     return NGX_OK;
1451 }
1452
1453
1454 static ngx_int_t
1455 ngx_http_proxy_internal_body_length_variable(ngx_http_request_t *r,
1456     ngx_http_variable_value_t *v, uintptr_t data)
1457 {
1458     ngx_http_proxy_ctx_t  *ctx;
1459
1460     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
1461
1462     if (ctx == NULL) {
1463         v->not_found = 1;
1464         return NGX_OK;
1465     }
1466
1467     v->valid = 1;
1468     v->no_cacheable = 0;
1469     v->not_found = 0;
1470
1471     v->data = ngx_pnalloc(r->connection->pool, NGX_SIZE_T_LEN);
1472
1473     if (v->data == NULL) {
1474         return NGX_ERROR;
1475     }
1476
1477     v->len = ngx_sprintf(v->data, "%uz", ctx->internal_body_length) - v->data;
1478
1479     return NGX_OK;
1480 }
1481
1482
1483 static ngx_int_t
1484 ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h,
1485     size_t prefix)
1486 {
1487     ngx_int_t                   rc;
1488     ngx_uint_t                  i;
1489     ngx_http_proxy_loc_conf_t  *plcf;
1490     ngx_http_proxy_redirect_t  *pr;
1491
1492     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
1493
1494     pr = plcf->redirects->elts;
1495
1496     if (pr == NULL) {
1497         return NGX_DECLINED;
1498     }
1499
1500     for (i = 0; i < plcf->redirects->nelts; i++) {
1501         rc = pr[i].handler(r, h, prefix, &pr[i]);
1502
1503         if (rc != NGX_DECLINED) {
1504             return rc;
1505         }
1506     }
1507
1508     return NGX_DECLINED;
1509 }
1510
1511
1512 static ngx_int_t
1513 ngx_http_proxy_rewrite_redirect_text(ngx_http_request_t *r, ngx_table_elt_t *h,
1514     size_t prefix, ngx_http_proxy_redirect_t *pr)
1515 {
1516     size_t   len;
1517     u_char  *data, *p;
1518
1519     if (pr->redirect.len > h->value.len - prefix
1520         || ngx_rstrncmp(h->value.data + prefix, pr->redirect.data,
1521                         pr->redirect.len) != 0)
1522     {
1523         return NGX_DECLINED;
1524     }
1525
1526     len = prefix + pr->replacement.text.len + h->value.len - pr->redirect.len;
1527
1528     data = ngx_pnalloc(r->pool, len);
1529     if (data == NULL) {
1530         return NGX_ERROR;
1531     }
1532
1533     p = data;
1534
1535     p = ngx_copy(p, h->value.data, prefix);
1536
1537     if (pr->replacement.text.len) {
1538         p = ngx_copy(p, pr->replacement.text.data, pr->replacement.text.len);
1539     }
1540
1541     ngx_memcpy(p, h->value.data + prefix + pr->redirect.len,
1542                h->value.len - pr->redirect.len - prefix);
1543
1544     h->value.len = len;
1545     h->value.data = data;
1546
1547     return NGX_OK;
1548 }
1549
1550
1551 static ngx_int_t
1552 ngx_http_proxy_rewrite_redirect_vars(ngx_http_request_t *r, ngx_table_elt_t *h,
1553     size_t prefix, ngx_http_proxy_redirect_t *pr)
1554 {
1555     size_t                        len;
1556     u_char                       *data, *p;
1557     ngx_http_script_code_pt       code;
1558     ngx_http_script_engine_t      e;
1559     ngx_http_script_len_code_pt   lcode;
1560
1561     if (pr->redirect.len > h->value.len - prefix
1562         || ngx_rstrncmp(h->value.data + prefix, pr->redirect.data,
1563                         pr->redirect.len) != 0)
1564     {
1565         return NGX_DECLINED;
1566     }
1567
1568     ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
1569
1570     e.ip = pr->replacement.vars.lengths;
1571     e.request = r;
1572
1573     len = prefix + h->value.len - pr->redirect.len;
1574
1575     while (*(uintptr_t *) e.ip) {
1576         lcode = *(ngx_http_script_len_code_pt *) e.ip;
1577         len += lcode(&e);
1578     }
1579
1580     data = ngx_pnalloc(r->pool, len);
1581     if (data == NULL) {
1582         return NGX_ERROR;
1583     }
1584
1585     p = data;
1586
1587     p = ngx_copy(p, h->value.data, prefix);
1588
1589     e.ip = pr->replacement.vars.values;
1590     e.pos = p;
1591
1592     while (*(uintptr_t *) e.ip) {
1593         code = *(ngx_http_script_code_pt *) e.ip;
1594         code(&e);
1595     }
1596
1597     ngx_memcpy(e.pos, h->value.data + prefix + pr->redirect.len,
1598                h->value.len - pr->redirect.len - prefix);
1599
1600     h->value.len = len;
1601     h->value.data = data;
1602
1603     return NGX_OK;
1604 }
1605
1606
1607 static ngx_int_t
1608 ngx_http_proxy_add_variables(ngx_conf_t *cf)
1609 {
1610     ngx_http_variable_t  *var, *v;
1611
1612     for (v = ngx_http_proxy_vars; v->name.len; v++) {
1613         var = ngx_http_add_variable(cf, &v->name, v->flags);
1614         if (var == NULL) {
1615             return NGX_ERROR;
1616         }
1617
1618         var->get_handler = v->get_handler;
1619         var->data = v->data;
1620     }
1621
1622     return NGX_OK;
1623 }
1624
1625
1626 static void *
1627 ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
1628 {
1629     ngx_http_proxy_loc_conf_t  *conf;
1630
1631     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t));
1632     if (conf == NULL) {
1633         return NGX_CONF_ERROR;
1634     }
1635
1636     /*
1637      * set by ngx_pcalloc():
1638      *
1639      *     conf->upstream.bufs.num = 0;
1640      *     conf->upstream.next_upstream = 0;
1641      *     conf->upstream.temp_path = NULL;
1642      *     conf->upstream.hide_headers_hash = { NULL, 0 };
1643      *     conf->upstream.uri = { 0, NULL };
1644      *     conf->upstream.location = NULL;
1645      *     conf->upstream.store_lengths = NULL;
1646      *     conf->upstream.store_values = NULL;
1647      *
1648      *     conf->method = NULL;
1649      *     conf->headers_source = NULL;
1650      *     conf->headers_set_len = NULL;
1651      *     conf->headers_set = NULL;
1652      *     conf->headers_set_hash = NULL;
1653      *     conf->body_set_len = NULL;
1654      *     conf->body_set = NULL;
1655      *     conf->body_source = { 0, NULL };
1656      *     conf->rewrite_locations = NULL;
1657      */
1658
1659     conf->upstream.store = NGX_CONF_UNSET;
1660     conf->upstream.store_access = NGX_CONF_UNSET_UINT;
1661     conf->upstream.buffering = NGX_CONF_UNSET;
1662     conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
1663
1664     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
1665     conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
1666     conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
1667
1668     conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
1669     conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
1670
1671     conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
1672     conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
1673     conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;
1674
1675     conf->upstream.pass_request_headers = NGX_CONF_UNSET;
1676     conf->upstream.pass_request_body = NGX_CONF_UNSET;
1677
1678     conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
1679     conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
1680
1681     conf->upstream.intercept_errors = NGX_CONF_UNSET;
1682 #if (NGX_HTTP_SSL)
1683     conf->upstream.ssl_session_reuse = NGX_CONF_UNSET;
1684 #endif
1685
1686     /* "proxy_cyclic_temp_file" is disabled */
1687     conf->upstream.cyclic_temp_file = 0;
1688
1689     conf->redirect = NGX_CONF_UNSET;
1690     conf->upstream.change_buffering = 1;
1691
1692     conf->headers_hash_max_size = NGX_CONF_UNSET_UINT;
1693     conf->headers_hash_bucket_size = NGX_CONF_UNSET_UINT;
1694
1695     return conf;
1696 }
1697
1698
1699 static char *
1700 ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
1701 {
1702     ngx_http_proxy_loc_conf_t *prev = parent;
1703     ngx_http_proxy_loc_conf_t *conf = child;
1704
1705     u_char                       *p;
1706     size_t                        size;
1707     uintptr_t                    *code;
1708     ngx_uint_t                    i;
1709     ngx_keyval_t                 *src, *s, *h;
1710     ngx_hash_key_t               *hk;
1711     ngx_hash_init_t               hash;
1712     ngx_http_proxy_redirect_t    *pr;
1713     ngx_http_script_compile_t     sc;
1714     ngx_http_script_copy_code_t  *copy;
1715
1716     if (conf->upstream.store != 0) {
1717         ngx_conf_merge_value(conf->upstream.store,
1718                                   prev->upstream.store, 0);
1719
1720         if (conf->upstream.store_lengths == NULL) {
1721             conf->upstream.store_lengths = prev->upstream.store_lengths;
1722             conf->upstream.store_values = prev->upstream.store_values;
1723         }
1724     }
1725
1726     ngx_conf_merge_uint_value(conf->upstream.store_access,
1727                               prev->upstream.store_access, 0600);
1728
1729     ngx_conf_merge_value(conf->upstream.buffering,
1730                               prev->upstream.buffering, 1);
1731
1732     ngx_conf_merge_value(conf->upstream.ignore_client_abort,
1733                               prev->upstream.ignore_client_abort, 0);
1734
1735     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
1736                               prev->upstream.connect_timeout, 60000);
1737
1738     ngx_conf_merge_msec_value(conf->upstream.send_timeout,
1739                               prev->upstream.send_timeout, 60000);
1740
1741     ngx_conf_merge_msec_value(conf->upstream.read_timeout,
1742                               prev->upstream.read_timeout, 60000);
1743
1744     ngx_conf_merge_size_value(conf->upstream.send_lowat,
1745                               prev->upstream.send_lowat, 0);
1746
1747     ngx_conf_merge_size_value(conf->upstream.buffer_size,
1748                               prev->upstream.buffer_size,
1749                               (size_t) ngx_pagesize);
1750
1751     ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
1752                               8, ngx_pagesize);
1753
1754     if (conf->upstream.bufs.num < 2) {
1755         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1756                            "there must be at least 2 \"proxy_buffers\"");
1757         return NGX_CONF_ERROR;
1758     }
1759
1760
1761     size = conf->upstream.buffer_size;
1762     if (size < conf->upstream.bufs.size) {
1763         size = conf->upstream.bufs.size;
1764     }
1765
1766
1767     ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
1768                               prev->upstream.busy_buffers_size_conf,
1769                               NGX_CONF_UNSET_SIZE);
1770
1771     if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
1772         conf->upstream.busy_buffers_size = 2 * size;
1773     } else {
1774         conf->upstream.busy_buffers_size =
1775                                          conf->upstream.busy_buffers_size_conf;
1776     }
1777
1778     if (conf->upstream.busy_buffers_size < size) {
1779         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1780              "\"proxy_busy_buffers_size\" must be equal or bigger than "
1781              "maximum of the value of \"proxy_buffer_size\" and "
1782              "one of the \"proxy_buffers\"");
1783
1784         return NGX_CONF_ERROR;
1785     }
1786
1787     if (conf->upstream.busy_buffers_size
1788         > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
1789     {
1790         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1791              "\"proxy_busy_buffers_size\" must be less than "
1792              "the size of all \"proxy_buffers\" minus one buffer");
1793
1794         return NGX_CONF_ERROR;
1795     }
1796
1797
1798     ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf,
1799                               prev->upstream.temp_file_write_size_conf,
1800                               NGX_CONF_UNSET_SIZE);
1801
1802     if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
1803         conf->upstream.temp_file_write_size = 2 * size;
1804     } else {
1805         conf->upstream.temp_file_write_size =
1806                                       conf->upstream.temp_file_write_size_conf;
1807     }
1808
1809     if (conf->upstream.temp_file_write_size < size) {
1810         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1811              "\"proxy_temp_file_write_size\" must be equal or bigger than "
1812              "maximum of the value of \"proxy_buffer_size\" and "
1813              "one of the \"proxy_buffers\"");
1814
1815         return NGX_CONF_ERROR;
1816     }
1817
1818     ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf,
1819                               prev->upstream.max_temp_file_size_conf,
1820                               NGX_CONF_UNSET_SIZE);
1821
1822     if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
1823         conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
1824     } else {
1825         conf->upstream.max_temp_file_size =
1826                                         conf->upstream.max_temp_file_size_conf;
1827     }
1828
1829     if (conf->upstream.max_temp_file_size != 0
1830         && conf->upstream.max_temp_file_size < size)
1831     {
1832         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1833              "\"proxy_max_temp_file_size\" must be equal to zero to disable "
1834              "the temporary files usage or must be equal or bigger than "
1835              "maximum of the value of \"proxy_buffer_size\" and "
1836              "one of the \"proxy_buffers\"");
1837
1838         return NGX_CONF_ERROR;
1839     }
1840
1841
1842     ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
1843                               prev->upstream.next_upstream,
1844                               (NGX_CONF_BITMASK_SET
1845                                |NGX_HTTP_UPSTREAM_FT_ERROR
1846                                |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
1847
1848     if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
1849         conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
1850                                        |NGX_HTTP_UPSTREAM_FT_OFF;
1851     }
1852
1853     ngx_conf_merge_path_value(conf->upstream.temp_path,
1854                               prev->upstream.temp_path,
1855                               NGX_HTTP_PROXY_TEMP_PATH, 1, 2, 0,
1856                               ngx_garbage_collector_temp_handler, cf);
1857
1858     if (conf->method.len == 0) {
1859         conf->method = prev->method;
1860
1861     } else {
1862         conf->method.data[conf->method.len] = ' ';
1863         conf->method.len++;
1864     }
1865
1866     ngx_conf_merge_value(conf->upstream.pass_request_headers,
1867                               prev->upstream.pass_request_headers, 1);
1868     ngx_conf_merge_value(conf->upstream.pass_request_body,
1869                               prev->upstream.pass_request_body, 1);
1870
1871     ngx_conf_merge_value(conf->upstream.intercept_errors,
1872                               prev->upstream.intercept_errors, 0);
1873
1874 #if (NGX_HTTP_SSL)
1875     ngx_conf_merge_value(conf->upstream.ssl_session_reuse,
1876                               prev->upstream.ssl_session_reuse, 1);
1877 #endif
1878
1879     ngx_conf_merge_value(conf->redirect, prev->redirect, 1);
1880
1881     if (conf->redirect) {
1882
1883         if (conf->redirects == NULL) {
1884             conf->redirects = prev->redirects;
1885         }
1886
1887         if (conf->redirects == NULL && conf->url.data) {
1888
1889             conf->redirects = ngx_array_create(cf->pool, 1,
1890                                             sizeof(ngx_http_proxy_redirect_t));
1891             if (conf->redirects == NULL) {
1892                 return NGX_CONF_ERROR;
1893             }
1894
1895             pr = ngx_array_push(conf->redirects);
1896             if (pr == NULL) {
1897                 return NGX_CONF_ERROR;
1898             }
1899
1900             pr->handler = ngx_http_proxy_rewrite_redirect_text;
1901             pr->redirect = conf->url;
1902
1903             if (conf->vars.uri.len) {
1904                 pr->replacement.text = conf->location;
1905
1906             } else {
1907                 pr->replacement.text.len = 0;
1908                 pr->replacement.text.data = NULL;
1909             }
1910         }
1911     }
1912
1913     /* STUB */
1914     if (prev->proxy_lengths) {
1915         conf->proxy_lengths = prev->proxy_lengths;
1916         conf->proxy_values = prev->proxy_values;
1917     }
1918
1919     ngx_conf_merge_uint_value(conf->headers_hash_max_size,
1920                               prev->headers_hash_max_size, 512);
1921
1922     ngx_conf_merge_uint_value(conf->headers_hash_bucket_size,
1923                               prev->headers_hash_bucket_size, 64);
1924
1925     conf->headers_hash_bucket_size = ngx_align(conf->headers_hash_bucket_size,
1926                                                ngx_cacheline_size);
1927
1928     hash.max_size = conf->headers_hash_max_size;
1929     hash.bucket_size = conf->headers_hash_bucket_size;
1930     hash.name = "proxy_headers_hash";
1931
1932     if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
1933                                             &prev->upstream,
1934                                             ngx_http_proxy_hide_headers, &hash)
1935         != NGX_OK)
1936     {
1937         return NGX_CONF_ERROR;
1938     }
1939
1940     if (conf->upstream.upstream == NULL) {
1941         conf->upstream.upstream = prev->upstream.upstream;
1942         conf->vars = prev->vars;
1943     }
1944
1945
1946     if (conf->body_source.data == NULL) {
1947         conf->body_source = prev->body_source;
1948         conf->body_set_len = prev->body_set_len;
1949         conf->body_set = prev->body_set;
1950     }
1951
1952     if (conf->body_source.data && conf->body_set_len == NULL) {
1953
1954         ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
1955
1956         sc.cf = cf;
1957         sc.source = &conf->body_source;
1958         sc.flushes = &conf->flushes;
1959         sc.lengths = &conf->body_set_len;
1960         sc.values = &conf->body_set;
1961         sc.complete_lengths = 1;
1962         sc.complete_values = 1;
1963
1964         if (ngx_http_script_compile(&sc) != NGX_OK) {
1965             return NGX_CONF_ERROR;
1966         }
1967
1968         if (conf->headers_source == NULL) {
1969             conf->headers_source = ngx_array_create(cf->pool, 4,
1970                                                     sizeof(ngx_keyval_t));
1971             if (conf->headers_source == NULL) {
1972                 return NGX_CONF_ERROR;
1973             }
1974         }
1975
1976         s = ngx_array_push(conf->headers_source);
1977         if (s == NULL) {
1978             return NGX_CONF_ERROR;
1979         }
1980
1981         s->key.len = sizeof("Content-Length") - 1;
1982         s->key.data = (u_char *) "Content-Length";
1983         s->value.len = sizeof("$proxy_internal_body_length") - 1;
1984         s->value.data = (u_char *) "$proxy_internal_body_length";
1985     }
1986
1987
1988     if (conf->headers_source == NULL) {
1989         conf->flushes = prev->flushes;
1990         conf->headers_set_len = prev->headers_set_len;
1991         conf->headers_set = prev->headers_set;
1992         conf->headers_set_hash = prev->headers_set_hash;
1993         conf->headers_source = prev->headers_source;
1994     }
1995
1996     if (conf->headers_set_hash.buckets) {
1997         return NGX_CONF_OK;
1998     }
1999
2000
2001     conf->headers_names = ngx_array_create(cf->pool, 4, sizeof(ngx_hash_key_t));
2002     if (conf->headers_names == NULL) {
2003         return NGX_CONF_ERROR;
2004     }
2005
2006     if (conf->headers_source == NULL) {
2007         conf->headers_source = ngx_array_create(cf->pool, 4,
2008                                                 sizeof(ngx_keyval_t));
2009         if (conf->headers_source == NULL) {
2010             return NGX_CONF_ERROR;
2011         }
2012     }
2013
2014     conf->headers_set_len = ngx_array_create(cf->pool, 64, 1);
2015     if (conf->headers_set_len == NULL) {
2016         return NGX_CONF_ERROR;
2017     }
2018
2019     conf->headers_set = ngx_array_create(cf->pool, 512, 1);
2020     if (conf->headers_set == NULL) {
2021         return NGX_CONF_ERROR;
2022     }
2023
2024
2025     src = conf->headers_source->elts;
2026
2027     for (h = ngx_http_proxy_headers; h->key.len; h++) {
2028
2029         for (i = 0; i < conf->headers_source->nelts; i++) {
2030             if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
2031                 goto next;
2032             }
2033         }
2034
2035         s = ngx_array_push(conf->headers_source);
2036         if (s == NULL) {
2037             return NGX_CONF_ERROR;
2038         }
2039
2040         *s = *h;
2041
2042         src = conf->headers_source->elts;
2043
2044     next:
2045
2046         continue;
2047     }
2048
2049
2050     src = conf->headers_source->elts;
2051     for (i = 0; i < conf->headers_source->nelts; i++) {
2052
2053         hk = ngx_array_push(conf->headers_names);
2054         if (hk == NULL) {
2055             return NGX_CONF_ERROR;
2056         }
2057
2058         hk->key = src[i].key;
2059         hk->key_hash = ngx_hash_key_lc(src[i].key.data, src[i].key.len);
2060         hk->value = (void *) 1;
2061
2062         if (src[i].value.len == 0) {
2063             continue;
2064         }
2065
2066         if (ngx_http_script_variables_count(&src[i].value) == 0) {
2067             copy = ngx_array_push_n(conf->headers_set_len,
2068                                     sizeof(ngx_http_script_copy_code_t));
2069             if (copy == NULL) {
2070                 return NGX_CONF_ERROR;
2071             }
2072
2073             copy->code = (ngx_http_script_code_pt)
2074                                                  ngx_http_script_copy_len_code;
2075             copy->len = src[i].key.len + sizeof(": ") - 1
2076                         + src[i].value.len + sizeof(CRLF) - 1;
2077
2078
2079             size = (sizeof(ngx_http_script_copy_code_t)
2080                        + src[i].key.len + sizeof(": ") - 1
2081                        + src[i].value.len + sizeof(CRLF) - 1
2082                        + sizeof(uintptr_t) - 1)
2083                     & ~(sizeof(uintptr_t) - 1);
2084
2085             copy = ngx_array_push_n(conf->headers_set, size);
2086             if (copy == NULL) {
2087                 return NGX_CONF_ERROR;
2088             }
2089
2090             copy->code = ngx_http_script_copy_code;
2091             copy->len = src[i].key.len + sizeof(": ") - 1
2092                         + src[i].value.len + sizeof(CRLF) - 1;
2093
2094             p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
2095
2096             p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
2097             *p++ = ':'; *p++ = ' ';
2098             p = ngx_cpymem(p, src[i].value.data, src[i].value.len);
2099             *p++ = CR; *p = LF;
2100
2101         } else {
2102             copy = ngx_array_push_n(conf->headers_set_len,
2103                                     sizeof(ngx_http_script_copy_code_t));
2104             if (copy == NULL) {
2105                 return NGX_CONF_ERROR;
2106             }
2107
2108             copy->code = (ngx_http_script_code_pt)
2109                                                  ngx_http_script_copy_len_code;
2110             copy->len = src[i].key.len + sizeof(": ") - 1;
2111
2112
2113             size = (sizeof(ngx_http_script_copy_code_t)
2114                     + src[i].key.len + sizeof(": ") - 1 + sizeof(uintptr_t) - 1)
2115                     & ~(sizeof(uintptr_t) - 1);
2116
2117             copy = ngx_array_push_n(conf->headers_set, size);
2118             if (copy == NULL) {
2119                 return NGX_CONF_ERROR;
2120             }
2121
2122             copy->code = ngx_http_script_copy_code;
2123             copy->len = src[i].key.len + sizeof(": ") - 1;
2124
2125             p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
2126             p = ngx_cpymem(p, src[i].key.data, src[i].key.len);
2127             *p++ = ':'; *p = ' ';
2128
2129
2130             ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
2131
2132             sc.cf = cf;
2133             sc.source = &src[i].value;
2134             sc.flushes = &conf->flushes;
2135             sc.lengths = &conf->headers_set_len;
2136             sc.values = &conf->headers_set;
2137
2138             if (ngx_http_script_compile(&sc) != NGX_OK) {
2139                 return NGX_CONF_ERROR;
2140             }
2141
2142
2143             copy = ngx_array_push_n(conf->headers_set_len,
2144                                     sizeof(ngx_http_script_copy_code_t));
2145             if (copy == NULL) {
2146                 return NGX_CONF_ERROR;
2147             }
2148
2149             copy->code = (ngx_http_script_code_pt)
2150                                                  ngx_http_script_copy_len_code;
2151             copy->len = sizeof(CRLF) - 1;
2152
2153
2154             size = (sizeof(ngx_http_script_copy_code_t)
2155                     + sizeof(CRLF) - 1 + sizeof(uintptr_t) - 1)
2156                     & ~(sizeof(uintptr_t) - 1);
2157
2158             copy = ngx_array_push_n(conf->headers_set, size);
2159             if (copy == NULL) {
2160                 return NGX_CONF_ERROR;
2161             }
2162
2163             copy->code = ngx_http_script_copy_code;
2164             copy->len = sizeof(CRLF) - 1;
2165
2166             p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
2167             *p++ = CR; *p = LF;
2168         }
2169
2170         code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t));
2171         if (code == NULL) {
2172             return NGX_CONF_ERROR;
2173         }
2174
2175         *code = (uintptr_t) NULL;
2176
2177         code = ngx_array_push_n(conf->headers_set, sizeof(uintptr_t));
2178         if (code == NULL) {
2179             return NGX_CONF_ERROR;
2180         }
2181
2182         *code = (uintptr_t) NULL;
2183     }
2184
2185     code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t));
2186     if (code == NULL) {
2187         return NGX_CONF_ERROR;
2188     }
2189
2190     *code = (uintptr_t) NULL;
2191
2192
2193     hash.hash = &conf->headers_set_hash;
2194     hash.key = ngx_hash_key_lc;
2195     hash.max_size = conf->headers_hash_max_size;
2196     hash.bucket_size = conf->headers_hash_bucket_size;
2197     hash.name = "proxy_headers_hash";
2198     hash.pool = cf->pool;
2199     hash.temp_pool = NULL;
2200
2201     if (ngx_hash_init(&hash, conf->headers_names->elts,
2202                       conf->headers_names->nelts)
2203         != NGX_OK)
2204     {
2205         return NGX_CONF_ERROR;
2206     }
2207
2208     return NGX_CONF_OK;
2209 }
2210
2211
2212 static char *
2213 ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
2214 {
2215     ngx_http_proxy_loc_conf_t *plcf = conf;
2216
2217     size_t                      add;
2218     u_short                     port;
2219     ngx_str_t                  *value, *url;
2220     ngx_url_t                   u;
2221     ngx_uint_t                  n;
2222     ngx_http_core_loc_conf_t   *clcf;
2223     ngx_http_script_compile_t   sc;
2224
2225     if (plcf->upstream.upstream || plcf->proxy_lengths) {
2226         return "is duplicate";
2227     }
2228
2229     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
2230
2231     value = cf->args->elts;
2232
2233     url = &value[1];
2234
2235     n = ngx_http_script_variables_count(url);
2236
2237     if (n) {
2238
2239         ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
2240
2241         sc.cf = cf;
2242         sc.source = url;
2243         sc.lengths = &plcf->proxy_lengths;
2244         sc.values = &plcf->proxy_values;
2245         sc.variables = n;
2246         sc.complete_lengths = 1;
2247         sc.complete_values = 1;
2248
2249         if (ngx_http_script_compile(&sc) != NGX_OK) {
2250             return NGX_CONF_ERROR;
2251         }
2252
2253 #if (NGX_HTTP_SSL)
2254         if (ngx_http_proxy_set_ssl(cf, plcf) != NGX_OK) {
2255             return NGX_CONF_ERROR;
2256         }
2257 #endif
2258
2259         clcf->handler = ngx_http_proxy_handler;
2260
2261         return NGX_CONF_OK;
2262     }
2263
2264     if (ngx_strncasecmp(url->data, (u_char *) "http://", 7) == 0) {
2265         add = 7;
2266         port = 80;
2267
2268     } else if (ngx_strncasecmp(url->data, (u_char *) "https://", 8) == 0) {
2269
2270 #if (NGX_HTTP_SSL)
2271         if (ngx_http_proxy_set_ssl(cf, plcf) != NGX_OK) {
2272             return NGX_CONF_ERROR;
2273         }
2274
2275         add = 8;
2276         port = 443;
2277 #else
2278         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2279                            "https protocol requires SSL support");
2280         return NGX_CONF_ERROR;
2281 #endif
2282
2283     } else {
2284         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid URL prefix");
2285         return NGX_CONF_ERROR;
2286     }
2287
2288     ngx_memzero(&u, sizeof(ngx_url_t));
2289
2290     u.url.len = url->len - add;
2291     u.url.data = url->data + add;
2292     u.default_port = port;
2293     u.uri_part = 1;
2294     u.no_resolve = 1;
2295
2296     plcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
2297     if (plcf->upstream.upstream == NULL) {
2298         return NGX_CONF_ERROR;
2299     }
2300
2301     if (ngx_http_proxy_set_vars(cf->pool, &u, &plcf->vars) != NGX_OK) {
2302         return NGX_CONF_ERROR;
2303     }
2304
2305     plcf->vars.schema.len = add;
2306     plcf->vars.schema.data = url->data;
2307     plcf->location = clcf->name;
2308
2309     clcf->handler = ngx_http_proxy_handler;
2310
2311     if (clcf->named
2312 #if (NGX_PCRE)
2313         || clcf->regex
2314 #endif
2315         || clcf->noname)
2316     {
2317         if (plcf->vars.uri.len) {
2318             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2319                                "\"proxy_pass\" may not have URI part in "
2320                                "location given by regular expression, "
2321                                "or inside named location, "
2322                                "or inside the \"if\" statement, "
2323                                "or inside the \"limit_except\" block");
2324             return NGX_CONF_ERROR;
2325         }
2326
2327         plcf->location.len = 0;
2328     }
2329
2330     plcf->url = *url;
2331
2332     if (clcf->name.data[clcf->name.len - 1] == '/') {
2333         clcf->auto_redirect = 1;
2334     }
2335
2336     return NGX_CONF_OK;
2337 }
2338
2339
2340 static char *
2341 ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
2342 {
2343     ngx_http_proxy_loc_conf_t *plcf = conf;
2344
2345     ngx_str_t                  *value;
2346     ngx_array_t                *vars_lengths, *vars_values;
2347     ngx_http_script_compile_t   sc;
2348     ngx_http_proxy_redirect_t  *pr;
2349
2350     if (plcf->redirect == 0) {
2351         return NGX_CONF_OK;
2352     }
2353
2354     value = cf->args->elts;
2355
2356     if (ngx_strcmp(value[1].data, "off") == 0) {
2357         plcf->redirect = 0;
2358         plcf->redirects = NULL;
2359         return NGX_CONF_OK;
2360     }
2361
2362     if (plcf->redirects == NULL) {
2363         plcf->redirects = ngx_array_create(cf->pool, 1,
2364                                            sizeof(ngx_http_proxy_redirect_t));
2365         if (plcf->redirects == NULL) {
2366             return NGX_CONF_ERROR;
2367         }
2368     }
2369
2370     pr = ngx_array_push(plcf->redirects);
2371     if (pr == NULL) {
2372         return NGX_CONF_ERROR;
2373     }
2374
2375     if (cf->args->nelts == 2 && ngx_strcmp(value[1].data, "default") == 0) {
2376         if (plcf->url.data == NULL) {
2377             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2378                                "\"proxy_rewrite_location default\" must go "
2379                                "after the \"proxy_pass\" directive");
2380             return NGX_CONF_ERROR;
2381         }
2382
2383         pr->handler = ngx_http_proxy_rewrite_redirect_text;
2384         pr->redirect = plcf->url;
2385
2386         if (plcf->vars.uri.len) {
2387             pr->replacement.text = plcf->location;
2388
2389         } else {
2390             pr->replacement.text.len = 0;
2391             pr->replacement.text.data = NULL;
2392         }
2393
2394         return NGX_CONF_OK;
2395     }
2396
2397     if (ngx_http_script_variables_count(&value[2]) == 0) {
2398         pr->handler = ngx_http_proxy_rewrite_redirect_text;
2399         pr->redirect = value[1];
2400         pr->replacement.text = value[2];
2401
2402         return NGX_CONF_OK;
2403     }
2404
2405     ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
2406
2407     vars_lengths = NULL;
2408     vars_values = NULL;
2409
2410     sc.cf = cf;
2411     sc.source = &value[2];
2412     sc.lengths = &vars_lengths;
2413     sc.values = &vars_values;
2414     sc.complete_lengths = 1;
2415     sc.complete_values = 1;
2416
2417     if (ngx_http_script_compile(&sc) != NGX_OK) {
2418         return NGX_CONF_ERROR;
2419     }
2420
2421     pr->handler = ngx_http_proxy_rewrite_redirect_vars;
2422     pr->redirect = value[1];
2423     pr->replacement.vars.lengths = vars_lengths->elts;
2424     pr->replacement.vars.values = vars_values->elts;
2425
2426     return NGX_CONF_OK;
2427 }
2428
2429
2430 static char *
2431 ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
2432 {
2433     ngx_http_proxy_loc_conf_t *plcf = conf;
2434
2435     ngx_str_t                  *value;
2436     ngx_http_script_compile_t   sc;
2437
2438     if (plcf->upstream.store != NGX_CONF_UNSET || plcf->upstream.store_lengths)
2439     {
2440         return "is duplicate";
2441     }
2442
2443     value = cf->args->elts;
2444
2445     if (ngx_strcmp(value[1].data, "on") == 0) {
2446         plcf->upstream.store = 1;
2447         return NGX_CONF_OK;
2448     }
2449
2450     if (ngx_strcmp(value[1].data, "off") == 0) {
2451         plcf->upstream.store = 0;
2452         return NGX_CONF_OK;
2453     }
2454
2455     /* include the terminating '\0' into script */
2456     value[1].len++;
2457
2458     ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
2459
2460     sc.cf = cf;
2461     sc.source = &value[1];
2462     sc.lengths = &plcf->upstream.store_lengths;
2463     sc.values = &plcf->upstream.store_values;
2464     sc.variables = ngx_http_script_variables_count(&value[1]);
2465     sc.complete_lengths = 1;
2466     sc.complete_values = 1;
2467
2468     if (ngx_http_script_compile(&sc) != NGX_OK) {
2469         return NGX_CONF_ERROR;
2470     }
2471
2472     return NGX_CONF_OK;
2473 }
2474
2475
2476 static char *
2477 ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data)
2478 {
2479 #if (NGX_FREEBSD)
2480     ssize_t *np = data;
2481
2482     if ((u_long) *np >= ngx_freebsd_net_inet_tcp_sendspace) {
2483         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2484                            "\"proxy_send_lowat\" must be less than %d "
2485                            "(sysctl net.inet.tcp.sendspace)",
2486                            ngx_freebsd_net_inet_tcp_sendspace);
2487
2488         return NGX_CONF_ERROR;
2489     }
2490
2491 #elif !(NGX_HAVE_SO_SNDLOWAT)
2492     ssize_t *np = data;
2493
2494     ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
2495                        "\"proxy_send_lowat\" is not supported, ignored");
2496
2497     *np = 0;
2498
2499 #endif
2500
2501     return NGX_CONF_OK;
2502 }
2503
2504
2505 static char *
2506 ngx_http_proxy_upstream_max_fails_unsupported(ngx_conf_t *cf,
2507     ngx_command_t *cmd, void *conf)
2508 {
2509     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2510          "\"proxy_upstream_max_fails\" is not supported, "
2511          "use the \"max_fails\" parameter of the \"server\" directive ",
2512          "inside the \"upstream\" block");
2513
2514     return NGX_CONF_ERROR;
2515 }
2516
2517
2518 static char *
2519 ngx_http_proxy_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
2520     ngx_command_t *cmd, void *conf)
2521 {
2522     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2523          "\"proxy_upstream_fail_timeout\" is not supported, "
2524          "use the \"fail_timeout\" parameter of the \"server\" directive ",
2525          "inside the \"upstream\" block");
2526
2527     return NGX_CONF_ERROR;
2528 }
2529
2530
2531 #if (NGX_HTTP_SSL)
2532
2533 static ngx_int_t
2534 ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf)
2535 {
2536     ngx_pool_cleanup_t  *cln;
2537
2538     plcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));
2539     if (plcf->upstream.ssl == NULL) {
2540         return NGX_ERROR;
2541     }
2542
2543     plcf->upstream.ssl->log = cf->log;
2544
2545     if (ngx_ssl_create(plcf->upstream.ssl,
2546                        NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1, NULL)
2547         != NGX_OK)
2548     {
2549         return NGX_ERROR;
2550     }
2551
2552     cln = ngx_pool_cleanup_add(cf->pool, 0);
2553     if (cln == NULL) {
2554         return NGX_ERROR;
2555     }
2556
2557     cln->handler = ngx_ssl_cleanup_ctx;
2558     cln->data = plcf->upstream.ssl;
2559
2560     return NGX_OK;
2561 }
2562
2563 #endif
2564
2565
2566 static ngx_int_t
2567 ngx_http_proxy_set_vars(ngx_pool_t *pool, ngx_url_t *u,
2568     ngx_http_proxy_vars_t *v)
2569 {
2570     if (u->family != AF_UNIX) {
2571         if (u->no_port || u->port == u->default_port) {
2572             v->host_header = u->host;
2573
2574             if (u->default_port == 80) {
2575                 v->port.len = sizeof("80") - 1;
2576                 v->port.data = (u_char *) "80";
2577
2578             } else {
2579                 v->port.len = sizeof("443") - 1;
2580                 v->port.data = (u_char *) "443";
2581             }
2582
2583         } else {
2584             v->host_header.len = u->host.len + 1 + u->port_text.len;
2585             v->host_header.data = u->host.data;
2586             v->port = u->port_text;
2587         }
2588
2589     } else {
2590         v->host_header.len = sizeof("localhost") - 1;
2591         v->host_header.data = (u_char *) "localhost";
2592         v->port.len = 0;
2593         v->port.data = (u_char *) "";
2594     }
2595
2596     v->uri = u->uri;
2597
2598     return NGX_OK;
2599 }