~ubuntu-branches/ubuntu/quantal/nginx/quantal-security

« back to all changes in this revision

Viewing changes to .pc/cve-2013-2070.patch/src/http/modules/ngx_http_proxy_module.c

  • Committer: Package Import Robot
  • Author(s): Thomas Ward
  • Date: 2013-05-24 12:37:12 UTC
  • Revision ID: package-import@ubuntu.com-20130524123712-5rykl481p5f4hj0e
Tags: 1.2.1-2.2ubuntu0.1
* Security update (closes LP: #1182586):
  * Patch to fix a buffer overflow vulnerability (CVE-2013-2070)

Show diffs side-by-side

added added

removed removed

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