ngx_http_uwsgi_module.c revision e18a033b
1
2/*
3 * Copyright (C) Unbit S.a.s. 2009-2010
4 * Copyright (C) 2008 Manlio Perillo (manlio.perillo@gmail.com)
5 * Copyright (C) Igor Sysoev
6 * Copyright (C) Nginx, Inc.
7 */
8
9
10#include <ngx_config.h>
11#include <ngx_core.h>
12#include <ngx_http.h>
13
14
15typedef struct {
16    ngx_array_t                caches;  /* ngx_http_file_cache_t * */
17} ngx_http_uwsgi_main_conf_t;
18
19
20typedef struct {
21    ngx_array_t               *flushes;
22    ngx_array_t               *lengths;
23    ngx_array_t               *values;
24    ngx_uint_t                 number;
25    ngx_hash_t                 hash;
26} ngx_http_uwsgi_params_t;
27
28
29typedef struct {
30    ngx_http_upstream_conf_t   upstream;
31
32    ngx_http_uwsgi_params_t    params;
33#if (NGX_HTTP_CACHE)
34    ngx_http_uwsgi_params_t    params_cache;
35#endif
36    ngx_array_t               *params_source;
37
38    ngx_array_t               *uwsgi_lengths;
39    ngx_array_t               *uwsgi_values;
40
41#if (NGX_HTTP_CACHE)
42    ngx_http_complex_value_t   cache_key;
43#endif
44
45    ngx_str_t                  uwsgi_string;
46
47    ngx_uint_t                 modifier1;
48    ngx_uint_t                 modifier2;
49
50#if (NGX_HTTP_SSL)
51    ngx_uint_t                 ssl;
52    ngx_uint_t                 ssl_protocols;
53    ngx_str_t                  ssl_ciphers;
54    ngx_uint_t                 ssl_verify_depth;
55    ngx_str_t                  ssl_trusted_certificate;
56    ngx_str_t                  ssl_crl;
57    ngx_str_t                  ssl_certificate;
58    ngx_str_t                  ssl_certificate_key;
59    ngx_array_t               *ssl_passwords;
60#endif
61} ngx_http_uwsgi_loc_conf_t;
62
63
64static ngx_int_t ngx_http_uwsgi_eval(ngx_http_request_t *r,
65    ngx_http_uwsgi_loc_conf_t *uwcf);
66static ngx_int_t ngx_http_uwsgi_create_request(ngx_http_request_t *r);
67static ngx_int_t ngx_http_uwsgi_reinit_request(ngx_http_request_t *r);
68static ngx_int_t ngx_http_uwsgi_process_status_line(ngx_http_request_t *r);
69static ngx_int_t ngx_http_uwsgi_process_header(ngx_http_request_t *r);
70static void ngx_http_uwsgi_abort_request(ngx_http_request_t *r);
71static void ngx_http_uwsgi_finalize_request(ngx_http_request_t *r,
72    ngx_int_t rc);
73
74static void *ngx_http_uwsgi_create_main_conf(ngx_conf_t *cf);
75static void *ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf);
76static char *ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent,
77    void *child);
78static ngx_int_t ngx_http_uwsgi_init_params(ngx_conf_t *cf,
79    ngx_http_uwsgi_loc_conf_t *conf, ngx_http_uwsgi_params_t *params,
80    ngx_keyval_t *default_params);
81
82static char *ngx_http_uwsgi_pass(ngx_conf_t *cf, ngx_command_t *cmd,
83    void *conf);
84static char *ngx_http_uwsgi_store(ngx_conf_t *cf, ngx_command_t *cmd,
85    void *conf);
86
87#if (NGX_HTTP_CACHE)
88static ngx_int_t ngx_http_uwsgi_create_key(ngx_http_request_t *r);
89static char *ngx_http_uwsgi_cache(ngx_conf_t *cf, ngx_command_t *cmd,
90    void *conf);
91static char *ngx_http_uwsgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd,
92    void *conf);
93#endif
94
95#if (NGX_HTTP_SSL)
96static char *ngx_http_uwsgi_ssl_password_file(ngx_conf_t *cf,
97    ngx_command_t *cmd, void *conf);
98static ngx_int_t ngx_http_uwsgi_set_ssl(ngx_conf_t *cf,
99    ngx_http_uwsgi_loc_conf_t *uwcf);
100#endif
101
102
103static ngx_conf_num_bounds_t  ngx_http_uwsgi_modifier_bounds = {
104    ngx_conf_check_num_bounds, 0, 255
105};
106
107
108static ngx_conf_bitmask_t ngx_http_uwsgi_next_upstream_masks[] = {
109    { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
110    { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
111    { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
112    { ngx_string("non_idempotent"), NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT },
113    { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
114    { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
115    { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 },
116    { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
117    { ngx_string("http_429"), NGX_HTTP_UPSTREAM_FT_HTTP_429 },
118    { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING },
119    { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
120    { ngx_null_string, 0 }
121};
122
123
124#if (NGX_HTTP_SSL)
125
126static ngx_conf_bitmask_t  ngx_http_uwsgi_ssl_protocols[] = {
127    { ngx_string("SSLv2"), NGX_SSL_SSLv2 },
128    { ngx_string("SSLv3"), NGX_SSL_SSLv3 },
129    { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
130    { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 },
131    { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 },
132    { ngx_null_string, 0 }
133};
134
135#endif
136
137
138ngx_module_t  ngx_http_uwsgi_module;
139
140
141static ngx_command_t ngx_http_uwsgi_commands[] = {
142
143    { ngx_string("uwsgi_pass"),
144      NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
145      ngx_http_uwsgi_pass,
146      NGX_HTTP_LOC_CONF_OFFSET,
147      0,
148      NULL },
149
150    { ngx_string("uwsgi_modifier1"),
151      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
152      ngx_conf_set_num_slot,
153      NGX_HTTP_LOC_CONF_OFFSET,
154      offsetof(ngx_http_uwsgi_loc_conf_t, modifier1),
155      &ngx_http_uwsgi_modifier_bounds },
156
157    { ngx_string("uwsgi_modifier2"),
158      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
159      ngx_conf_set_num_slot,
160      NGX_HTTP_LOC_CONF_OFFSET,
161      offsetof(ngx_http_uwsgi_loc_conf_t, modifier2),
162      &ngx_http_uwsgi_modifier_bounds },
163
164    { ngx_string("uwsgi_store"),
165      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
166      ngx_http_uwsgi_store,
167      NGX_HTTP_LOC_CONF_OFFSET,
168      0,
169      NULL },
170
171    { ngx_string("uwsgi_store_access"),
172      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
173      ngx_conf_set_access_slot,
174      NGX_HTTP_LOC_CONF_OFFSET,
175      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.store_access),
176      NULL },
177
178    { ngx_string("uwsgi_buffering"),
179      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
180      ngx_conf_set_flag_slot,
181      NGX_HTTP_LOC_CONF_OFFSET,
182      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.buffering),
183      NULL },
184
185    { ngx_string("uwsgi_request_buffering"),
186      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
187      ngx_conf_set_flag_slot,
188      NGX_HTTP_LOC_CONF_OFFSET,
189      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.request_buffering),
190      NULL },
191
192    { ngx_string("uwsgi_ignore_client_abort"),
193      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
194      ngx_conf_set_flag_slot,
195      NGX_HTTP_LOC_CONF_OFFSET,
196      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.ignore_client_abort),
197      NULL },
198
199    { ngx_string("uwsgi_bind"),
200      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
201      ngx_http_upstream_bind_set_slot,
202      NGX_HTTP_LOC_CONF_OFFSET,
203      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.local),
204      NULL },
205
206    { ngx_string("uwsgi_connect_timeout"),
207      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
208      ngx_conf_set_msec_slot,
209      NGX_HTTP_LOC_CONF_OFFSET,
210      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.connect_timeout),
211      NULL },
212
213    { ngx_string("uwsgi_send_timeout"),
214      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
215      ngx_conf_set_msec_slot,
216      NGX_HTTP_LOC_CONF_OFFSET,
217      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.send_timeout),
218      NULL },
219
220    { ngx_string("uwsgi_buffer_size"),
221      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
222      ngx_conf_set_size_slot,
223      NGX_HTTP_LOC_CONF_OFFSET,
224      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.buffer_size),
225      NULL },
226
227    { ngx_string("uwsgi_pass_request_headers"),
228      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
229      ngx_conf_set_flag_slot,
230      NGX_HTTP_LOC_CONF_OFFSET,
231      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.pass_request_headers),
232      NULL },
233
234    { ngx_string("uwsgi_pass_request_body"),
235      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
236      ngx_conf_set_flag_slot,
237      NGX_HTTP_LOC_CONF_OFFSET,
238      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.pass_request_body),
239      NULL },
240
241    { ngx_string("uwsgi_intercept_errors"),
242      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
243      ngx_conf_set_flag_slot,
244      NGX_HTTP_LOC_CONF_OFFSET,
245      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.intercept_errors),
246      NULL },
247
248    { ngx_string("uwsgi_read_timeout"),
249      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
250      ngx_conf_set_msec_slot,
251      NGX_HTTP_LOC_CONF_OFFSET,
252      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.read_timeout),
253      NULL },
254
255    { ngx_string("uwsgi_buffers"),
256      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
257      ngx_conf_set_bufs_slot,
258      NGX_HTTP_LOC_CONF_OFFSET,
259      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.bufs),
260      NULL },
261
262    { ngx_string("uwsgi_busy_buffers_size"),
263      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
264      ngx_conf_set_size_slot,
265      NGX_HTTP_LOC_CONF_OFFSET,
266      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.busy_buffers_size_conf),
267      NULL },
268
269    { ngx_string("uwsgi_force_ranges"),
270      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
271      ngx_conf_set_flag_slot,
272      NGX_HTTP_LOC_CONF_OFFSET,
273      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.force_ranges),
274      NULL },
275
276    { ngx_string("uwsgi_limit_rate"),
277      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
278      ngx_conf_set_size_slot,
279      NGX_HTTP_LOC_CONF_OFFSET,
280      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.limit_rate),
281      NULL },
282
283#if (NGX_HTTP_CACHE)
284
285    { ngx_string("uwsgi_cache"),
286      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
287      ngx_http_uwsgi_cache,
288      NGX_HTTP_LOC_CONF_OFFSET,
289      0,
290      NULL },
291
292    { ngx_string("uwsgi_cache_key"),
293      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
294      ngx_http_uwsgi_cache_key,
295      NGX_HTTP_LOC_CONF_OFFSET,
296      0,
297      NULL },
298
299    { ngx_string("uwsgi_cache_path"),
300      NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
301      ngx_http_file_cache_set_slot,
302      NGX_HTTP_MAIN_CONF_OFFSET,
303      offsetof(ngx_http_uwsgi_main_conf_t, caches),
304      &ngx_http_uwsgi_module },
305
306    { ngx_string("uwsgi_cache_bypass"),
307      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
308      ngx_http_set_predicate_slot,
309      NGX_HTTP_LOC_CONF_OFFSET,
310      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_bypass),
311      NULL },
312
313    { ngx_string("uwsgi_no_cache"),
314      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
315      ngx_http_set_predicate_slot,
316      NGX_HTTP_LOC_CONF_OFFSET,
317      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.no_cache),
318      NULL },
319
320    { ngx_string("uwsgi_cache_valid"),
321      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
322      ngx_http_file_cache_valid_set_slot,
323      NGX_HTTP_LOC_CONF_OFFSET,
324      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_valid),
325      NULL },
326
327    { ngx_string("uwsgi_cache_min_uses"),
328      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
329      ngx_conf_set_num_slot,
330      NGX_HTTP_LOC_CONF_OFFSET,
331      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_min_uses),
332      NULL },
333
334    { ngx_string("uwsgi_cache_max_range_offset"),
335      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
336      ngx_conf_set_off_slot,
337      NGX_HTTP_LOC_CONF_OFFSET,
338      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_max_range_offset),
339      NULL },
340
341    { ngx_string("uwsgi_cache_use_stale"),
342      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
343      ngx_conf_set_bitmask_slot,
344      NGX_HTTP_LOC_CONF_OFFSET,
345      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_use_stale),
346      &ngx_http_uwsgi_next_upstream_masks },
347
348    { ngx_string("uwsgi_cache_methods"),
349      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
350      ngx_conf_set_bitmask_slot,
351      NGX_HTTP_LOC_CONF_OFFSET,
352      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_methods),
353      &ngx_http_upstream_cache_method_mask },
354
355    { ngx_string("uwsgi_cache_lock"),
356      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
357      ngx_conf_set_flag_slot,
358      NGX_HTTP_LOC_CONF_OFFSET,
359      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_lock),
360      NULL },
361
362    { ngx_string("uwsgi_cache_lock_timeout"),
363      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
364      ngx_conf_set_msec_slot,
365      NGX_HTTP_LOC_CONF_OFFSET,
366      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_lock_timeout),
367      NULL },
368
369    { ngx_string("uwsgi_cache_lock_age"),
370      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
371      ngx_conf_set_msec_slot,
372      NGX_HTTP_LOC_CONF_OFFSET,
373      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_lock_age),
374      NULL },
375
376    { ngx_string("uwsgi_cache_revalidate"),
377      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
378      ngx_conf_set_flag_slot,
379      NGX_HTTP_LOC_CONF_OFFSET,
380      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_revalidate),
381      NULL },
382
383    { ngx_string("uwsgi_cache_background_update"),
384      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
385      ngx_conf_set_flag_slot,
386      NGX_HTTP_LOC_CONF_OFFSET,
387      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_background_update),
388      NULL },
389
390#endif
391
392    { ngx_string("uwsgi_temp_path"),
393      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
394      ngx_conf_set_path_slot,
395      NGX_HTTP_LOC_CONF_OFFSET,
396      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.temp_path),
397      NULL },
398
399    { ngx_string("uwsgi_max_temp_file_size"),
400      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
401      ngx_conf_set_size_slot,
402      NGX_HTTP_LOC_CONF_OFFSET,
403      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.max_temp_file_size_conf),
404      NULL },
405
406    { ngx_string("uwsgi_temp_file_write_size"),
407      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
408      ngx_conf_set_size_slot,
409      NGX_HTTP_LOC_CONF_OFFSET,
410      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.temp_file_write_size_conf),
411      NULL },
412
413    { ngx_string("uwsgi_next_upstream"),
414      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
415      ngx_conf_set_bitmask_slot,
416      NGX_HTTP_LOC_CONF_OFFSET,
417      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.next_upstream),
418      &ngx_http_uwsgi_next_upstream_masks },
419
420    { ngx_string("uwsgi_next_upstream_tries"),
421      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
422      ngx_conf_set_num_slot,
423      NGX_HTTP_LOC_CONF_OFFSET,
424      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.next_upstream_tries),
425      NULL },
426
427    { ngx_string("uwsgi_next_upstream_timeout"),
428      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
429      ngx_conf_set_msec_slot,
430      NGX_HTTP_LOC_CONF_OFFSET,
431      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.next_upstream_timeout),
432      NULL },
433
434    { ngx_string("uwsgi_param"),
435      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE23,
436      ngx_http_upstream_param_set_slot,
437      NGX_HTTP_LOC_CONF_OFFSET,
438      offsetof(ngx_http_uwsgi_loc_conf_t, params_source),
439      NULL },
440
441    { ngx_string("uwsgi_string"),
442      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
443      ngx_conf_set_str_slot,
444      NGX_HTTP_LOC_CONF_OFFSET,
445      offsetof(ngx_http_uwsgi_loc_conf_t, uwsgi_string),
446      NULL },
447
448    { ngx_string("uwsgi_pass_header"),
449      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
450      ngx_conf_set_str_array_slot,
451      NGX_HTTP_LOC_CONF_OFFSET,
452      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.pass_headers),
453      NULL },
454
455    { ngx_string("uwsgi_hide_header"),
456      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
457      ngx_conf_set_str_array_slot,
458      NGX_HTTP_LOC_CONF_OFFSET,
459      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.hide_headers),
460      NULL },
461
462    { ngx_string("uwsgi_ignore_headers"),
463      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
464      ngx_conf_set_bitmask_slot,
465      NGX_HTTP_LOC_CONF_OFFSET,
466      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.ignore_headers),
467      &ngx_http_upstream_ignore_headers_masks },
468
469#if (NGX_HTTP_SSL)
470
471    { ngx_string("uwsgi_ssl_session_reuse"),
472      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
473      ngx_conf_set_flag_slot,
474      NGX_HTTP_LOC_CONF_OFFSET,
475      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.ssl_session_reuse),
476      NULL },
477
478    { ngx_string("uwsgi_ssl_protocols"),
479      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
480      ngx_conf_set_bitmask_slot,
481      NGX_HTTP_LOC_CONF_OFFSET,
482      offsetof(ngx_http_uwsgi_loc_conf_t, ssl_protocols),
483      &ngx_http_uwsgi_ssl_protocols },
484
485    { ngx_string("uwsgi_ssl_ciphers"),
486      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
487      ngx_conf_set_str_slot,
488      NGX_HTTP_LOC_CONF_OFFSET,
489      offsetof(ngx_http_uwsgi_loc_conf_t, ssl_ciphers),
490      NULL },
491
492    { ngx_string("uwsgi_ssl_name"),
493      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
494      ngx_http_set_complex_value_slot,
495      NGX_HTTP_LOC_CONF_OFFSET,
496      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.ssl_name),
497      NULL },
498
499    { ngx_string("uwsgi_ssl_server_name"),
500      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
501      ngx_conf_set_flag_slot,
502      NGX_HTTP_LOC_CONF_OFFSET,
503      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.ssl_server_name),
504      NULL },
505
506    { ngx_string("uwsgi_ssl_verify"),
507      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
508      ngx_conf_set_flag_slot,
509      NGX_HTTP_LOC_CONF_OFFSET,
510      offsetof(ngx_http_uwsgi_loc_conf_t, upstream.ssl_verify),
511      NULL },
512
513    { ngx_string("uwsgi_ssl_verify_depth"),
514      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
515      ngx_conf_set_num_slot,
516      NGX_HTTP_LOC_CONF_OFFSET,
517      offsetof(ngx_http_uwsgi_loc_conf_t, ssl_verify_depth),
518      NULL },
519
520    { ngx_string("uwsgi_ssl_trusted_certificate"),
521      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
522      ngx_conf_set_str_slot,
523      NGX_HTTP_LOC_CONF_OFFSET,
524      offsetof(ngx_http_uwsgi_loc_conf_t, ssl_trusted_certificate),
525      NULL },
526
527    { ngx_string("uwsgi_ssl_crl"),
528      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
529      ngx_conf_set_str_slot,
530      NGX_HTTP_LOC_CONF_OFFSET,
531      offsetof(ngx_http_uwsgi_loc_conf_t, ssl_crl),
532      NULL },
533
534    { ngx_string("uwsgi_ssl_certificate"),
535      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
536      ngx_conf_set_str_slot,
537      NGX_HTTP_LOC_CONF_OFFSET,
538      offsetof(ngx_http_uwsgi_loc_conf_t, ssl_certificate),
539      NULL },
540
541    { ngx_string("uwsgi_ssl_certificate_key"),
542      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
543      ngx_conf_set_str_slot,
544      NGX_HTTP_LOC_CONF_OFFSET,
545      offsetof(ngx_http_uwsgi_loc_conf_t, ssl_certificate_key),
546      NULL },
547
548    { ngx_string("uwsgi_ssl_password_file"),
549      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
550      ngx_http_uwsgi_ssl_password_file,
551      NGX_HTTP_LOC_CONF_OFFSET,
552      0,
553      NULL },
554
555#endif
556
557      ngx_null_command
558};
559
560
561static ngx_http_module_t ngx_http_uwsgi_module_ctx = {
562    NULL,                                  /* preconfiguration */
563    NULL,                                  /* postconfiguration */
564
565    ngx_http_uwsgi_create_main_conf,       /* create main configuration */
566    NULL,                                  /* init main configuration */
567
568    NULL,                                  /* create server configuration */
569    NULL,                                  /* merge server configuration */
570
571    ngx_http_uwsgi_create_loc_conf,        /* create location configuration */
572    ngx_http_uwsgi_merge_loc_conf          /* merge location configuration */
573};
574
575
576ngx_module_t ngx_http_uwsgi_module = {
577    NGX_MODULE_V1,
578    &ngx_http_uwsgi_module_ctx,            /* module context */
579    ngx_http_uwsgi_commands,               /* module directives */
580    NGX_HTTP_MODULE,                       /* module type */
581    NULL,                                  /* init master */
582    NULL,                                  /* init module */
583    NULL,                                  /* init process */
584    NULL,                                  /* init thread */
585    NULL,                                  /* exit thread */
586    NULL,                                  /* exit process */
587    NULL,                                  /* exit master */
588    NGX_MODULE_V1_PADDING
589};
590
591
592static ngx_str_t ngx_http_uwsgi_hide_headers[] = {
593    ngx_string("X-Accel-Expires"),
594    ngx_string("X-Accel-Redirect"),
595    ngx_string("X-Accel-Limit-Rate"),
596    ngx_string("X-Accel-Buffering"),
597    ngx_string("X-Accel-Charset"),
598    ngx_null_string
599};
600
601
602#if (NGX_HTTP_CACHE)
603
604static ngx_keyval_t  ngx_http_uwsgi_cache_headers[] = {
605    { ngx_string("HTTP_IF_MODIFIED_SINCE"),
606      ngx_string("$upstream_cache_last_modified") },
607    { ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") },
608    { ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("$upstream_cache_etag") },
609    { ngx_string("HTTP_IF_MATCH"), ngx_string("") },
610    { ngx_string("HTTP_RANGE"), ngx_string("") },
611    { ngx_string("HTTP_IF_RANGE"), ngx_string("") },
612    { ngx_null_string, ngx_null_string }
613};
614
615#endif
616
617
618static ngx_path_init_t ngx_http_uwsgi_temp_path = {
619    ngx_string(NGX_HTTP_UWSGI_TEMP_PATH), { 1, 2, 0 }
620};
621
622
623static ngx_int_t
624ngx_http_uwsgi_handler(ngx_http_request_t *r)
625{
626    ngx_int_t                    rc;
627    ngx_http_status_t           *status;
628    ngx_http_upstream_t         *u;
629    ngx_http_uwsgi_loc_conf_t   *uwcf;
630#if (NGX_HTTP_CACHE)
631    ngx_http_uwsgi_main_conf_t  *uwmcf;
632#endif
633
634    if (ngx_http_upstream_create(r) != NGX_OK) {
635        return NGX_HTTP_INTERNAL_SERVER_ERROR;
636    }
637
638    status = ngx_pcalloc(r->pool, sizeof(ngx_http_status_t));
639    if (status == NULL) {
640        return NGX_HTTP_INTERNAL_SERVER_ERROR;
641    }
642
643    ngx_http_set_ctx(r, status, ngx_http_uwsgi_module);
644
645    uwcf = ngx_http_get_module_loc_conf(r, ngx_http_uwsgi_module);
646
647    u = r->upstream;
648
649    if (uwcf->uwsgi_lengths == NULL) {
650
651#if (NGX_HTTP_SSL)
652        u->ssl = (uwcf->upstream.ssl != NULL);
653
654        if (u->ssl) {
655            ngx_str_set(&u->schema, "suwsgi://");
656
657        } else {
658            ngx_str_set(&u->schema, "uwsgi://");
659        }
660#else
661        ngx_str_set(&u->schema, "uwsgi://");
662#endif
663
664    } else {
665        if (ngx_http_uwsgi_eval(r, uwcf) != NGX_OK) {
666            return NGX_HTTP_INTERNAL_SERVER_ERROR;
667        }
668    }
669
670    u->output.tag = (ngx_buf_tag_t) &ngx_http_uwsgi_module;
671
672    u->conf = &uwcf->upstream;
673
674#if (NGX_HTTP_CACHE)
675    uwmcf = ngx_http_get_module_main_conf(r, ngx_http_uwsgi_module);
676
677    u->caches = &uwmcf->caches;
678    u->create_key = ngx_http_uwsgi_create_key;
679#endif
680
681    u->create_request = ngx_http_uwsgi_create_request;
682    u->reinit_request = ngx_http_uwsgi_reinit_request;
683    u->process_header = ngx_http_uwsgi_process_status_line;
684    u->abort_request = ngx_http_uwsgi_abort_request;
685    u->finalize_request = ngx_http_uwsgi_finalize_request;
686    r->state = 0;
687
688    u->buffering = uwcf->upstream.buffering;
689
690    u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
691    if (u->pipe == NULL) {
692        return NGX_HTTP_INTERNAL_SERVER_ERROR;
693    }
694
695    u->pipe->input_filter = ngx_event_pipe_copy_input_filter;
696    u->pipe->input_ctx = r;
697
698    if (!uwcf->upstream.request_buffering
699        && uwcf->upstream.pass_request_body
700        && !r->headers_in.chunked)
701    {
702        r->request_body_no_buffering = 1;
703    }
704
705    rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
706
707    if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
708        return rc;
709    }
710
711    return NGX_DONE;
712}
713
714
715static ngx_int_t
716ngx_http_uwsgi_eval(ngx_http_request_t *r, ngx_http_uwsgi_loc_conf_t * uwcf)
717{
718    size_t                add;
719    ngx_url_t             url;
720    ngx_http_upstream_t  *u;
721
722    ngx_memzero(&url, sizeof(ngx_url_t));
723
724    if (ngx_http_script_run(r, &url.url, uwcf->uwsgi_lengths->elts, 0,
725                            uwcf->uwsgi_values->elts)
726        == NULL)
727    {
728        return NGX_ERROR;
729    }
730
731    if (url.url.len > 8
732        && ngx_strncasecmp(url.url.data, (u_char *) "uwsgi://", 8) == 0)
733    {
734        add = 8;
735
736    } else if (url.url.len > 9
737               && ngx_strncasecmp(url.url.data, (u_char *) "suwsgi://", 9) == 0)
738    {
739
740#if (NGX_HTTP_SSL)
741        add = 9;
742        r->upstream->ssl = 1;
743#else
744        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
745                      "suwsgi protocol requires SSL support");
746        return NGX_ERROR;
747#endif
748
749    } else {
750        add = 0;
751    }
752
753    u = r->upstream;
754
755    if (add) {
756        u->schema.len = add;
757        u->schema.data = url.url.data;
758
759        url.url.data += add;
760        url.url.len -= add;
761
762    } else {
763        ngx_str_set(&u->schema, "uwsgi://");
764    }
765
766    url.no_resolve = 1;
767
768    if (ngx_parse_url(r->pool, &url) != NGX_OK) {
769        if (url.err) {
770            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
771                          "%s in upstream \"%V\"", url.err, &url.url);
772        }
773
774        return NGX_ERROR;
775    }
776
777    u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
778    if (u->resolved == NULL) {
779        return NGX_ERROR;
780    }
781
782    if (url.addrs) {
783        u->resolved->sockaddr = url.addrs[0].sockaddr;
784        u->resolved->socklen = url.addrs[0].socklen;
785        u->resolved->name = url.addrs[0].name;
786        u->resolved->naddrs = 1;
787    }
788
789    u->resolved->host = url.host;
790    u->resolved->port = url.port;
791    u->resolved->no_port = url.no_port;
792
793    return NGX_OK;
794}
795
796
797#if (NGX_HTTP_CACHE)
798
799static ngx_int_t
800ngx_http_uwsgi_create_key(ngx_http_request_t *r)
801{
802    ngx_str_t                  *key;
803    ngx_http_uwsgi_loc_conf_t  *uwcf;
804
805    key = ngx_array_push(&r->cache->keys);
806    if (key == NULL) {
807        return NGX_ERROR;
808    }
809
810    uwcf = ngx_http_get_module_loc_conf(r, ngx_http_uwsgi_module);
811
812    if (ngx_http_complex_value(r, &uwcf->cache_key, key) != NGX_OK) {
813        return NGX_ERROR;
814    }
815
816    return NGX_OK;
817}
818
819#endif
820
821
822static ngx_int_t
823ngx_http_uwsgi_create_request(ngx_http_request_t *r)
824{
825    u_char                        ch, *lowcase_key;
826    size_t                        key_len, val_len, len, allocated;
827    ngx_uint_t                    i, n, hash, skip_empty, header_params;
828    ngx_buf_t                    *b;
829    ngx_chain_t                  *cl, *body;
830    ngx_list_part_t              *part;
831    ngx_table_elt_t              *header, **ignored;
832    ngx_http_uwsgi_params_t      *params;
833    ngx_http_script_code_pt       code;
834    ngx_http_script_engine_t      e, le;
835    ngx_http_uwsgi_loc_conf_t    *uwcf;
836    ngx_http_script_len_code_pt   lcode;
837
838    len = 0;
839    header_params = 0;
840    ignored = NULL;
841
842    uwcf = ngx_http_get_module_loc_conf(r, ngx_http_uwsgi_module);
843
844#if (NGX_HTTP_CACHE)
845    params = r->upstream->cacheable ? &uwcf->params_cache : &uwcf->params;
846#else
847    params = &uwcf->params;
848#endif
849
850    if (params->lengths) {
851        ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
852
853        ngx_http_script_flush_no_cacheable_variables(r, params->flushes);
854        le.flushed = 1;
855
856        le.ip = params->lengths->elts;
857        le.request = r;
858
859        while (*(uintptr_t *) le.ip) {
860
861            lcode = *(ngx_http_script_len_code_pt *) le.ip;
862            key_len = lcode(&le);
863
864            lcode = *(ngx_http_script_len_code_pt *) le.ip;
865            skip_empty = lcode(&le);
866
867            for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode (&le)) {
868                lcode = *(ngx_http_script_len_code_pt *) le.ip;
869            }
870            le.ip += sizeof(uintptr_t);
871
872            if (skip_empty && val_len == 0) {
873                continue;
874            }
875
876            len += 2 + key_len + 2 + val_len;
877        }
878    }
879
880    if (uwcf->upstream.pass_request_headers) {
881
882        allocated = 0;
883        lowcase_key = NULL;
884
885        if (params->number) {
886            n = 0;
887            part = &r->headers_in.headers.part;
888
889            while (part) {
890                n += part->nelts;
891                part = part->next;
892            }
893
894            ignored = ngx_palloc(r->pool, n * sizeof(void *));
895            if (ignored == NULL) {
896                return NGX_ERROR;
897            }
898        }
899
900        part = &r->headers_in.headers.part;
901        header = part->elts;
902
903        for (i = 0; /* void */ ; i++) {
904
905            if (i >= part->nelts) {
906                if (part->next == NULL) {
907                    break;
908                }
909
910                part = part->next;
911                header = part->elts;
912                i = 0;
913            }
914
915            if (params->number) {
916                if (allocated < header[i].key.len) {
917                    allocated = header[i].key.len + 16;
918                    lowcase_key = ngx_pnalloc(r->pool, allocated);
919                    if (lowcase_key == NULL) {
920                        return NGX_ERROR;
921                    }
922                }
923
924                hash = 0;
925
926                for (n = 0; n < header[i].key.len; n++) {
927                    ch = header[i].key.data[n];
928
929                    if (ch >= 'A' && ch <= 'Z') {
930                        ch |= 0x20;
931
932                    } else if (ch == '-') {
933                        ch = '_';
934                    }
935
936                    hash = ngx_hash(hash, ch);
937                    lowcase_key[n] = ch;
938                }
939
940                if (ngx_hash_find(&params->hash, hash, lowcase_key, n)) {
941                    ignored[header_params++] = &header[i];
942                    continue;
943                }
944            }
945
946            len += 2 + sizeof("HTTP_") - 1 + header[i].key.len
947                 + 2 + header[i].value.len;
948        }
949    }
950
951    len += uwcf->uwsgi_string.len;
952
953#if 0
954    /* allow custom uwsgi packet */
955    if (len > 0 && len < 2) {
956        ngx_log_error (NGX_LOG_ALERT, r->connection->log, 0,
957                       "uwsgi request is too little: %uz", len);
958        return NGX_ERROR;
959    }
960#endif
961
962    b = ngx_create_temp_buf(r->pool, len + 4);
963    if (b == NULL) {
964        return NGX_ERROR;
965    }
966
967    cl = ngx_alloc_chain_link(r->pool);
968    if (cl == NULL) {
969        return NGX_ERROR;
970    }
971
972    cl->buf = b;
973
974    *b->last++ = (u_char) uwcf->modifier1;
975    *b->last++ = (u_char) (len & 0xff);
976    *b->last++ = (u_char) ((len >> 8) & 0xff);
977    *b->last++ = (u_char) uwcf->modifier2;
978
979    if (params->lengths) {
980        ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
981
982        e.ip = params->values->elts;
983        e.pos = b->last;
984        e.request = r;
985        e.flushed = 1;
986
987        le.ip = params->lengths->elts;
988
989        while (*(uintptr_t *) le.ip) {
990
991            lcode = *(ngx_http_script_len_code_pt *) le.ip;
992            key_len = (u_char) lcode (&le);
993
994            lcode = *(ngx_http_script_len_code_pt *) le.ip;
995            skip_empty = lcode(&le);
996
997            for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
998                lcode = *(ngx_http_script_len_code_pt *) le.ip;
999            }
1000            le.ip += sizeof(uintptr_t);
1001
1002            if (skip_empty && val_len == 0) {
1003                e.skip = 1;
1004
1005                while (*(uintptr_t *) e.ip) {
1006                    code = *(ngx_http_script_code_pt *) e.ip;
1007                    code((ngx_http_script_engine_t *) &e);
1008                }
1009                e.ip += sizeof(uintptr_t);
1010
1011                e.skip = 0;
1012
1013                continue;
1014            }
1015
1016            *e.pos++ = (u_char) (key_len & 0xff);
1017            *e.pos++ = (u_char) ((key_len >> 8) & 0xff);
1018
1019            code = *(ngx_http_script_code_pt *) e.ip;
1020            code((ngx_http_script_engine_t *) & e);
1021
1022            *e.pos++ = (u_char) (val_len & 0xff);
1023            *e.pos++ = (u_char) ((val_len >> 8) & 0xff);
1024
1025            while (*(uintptr_t *) e.ip) {
1026                code = *(ngx_http_script_code_pt *) e.ip;
1027                code((ngx_http_script_engine_t *) & e);
1028            }
1029
1030            e.ip += sizeof(uintptr_t);
1031
1032            ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1033                           "uwsgi param: \"%*s: %*s\"",
1034                           key_len, e.pos - (key_len + 2 + val_len),
1035                           val_len, e.pos - val_len);
1036        }
1037
1038        b->last = e.pos;
1039    }
1040
1041    if (uwcf->upstream.pass_request_headers) {
1042
1043        part = &r->headers_in.headers.part;
1044        header = part->elts;
1045
1046        for (i = 0; /* void */ ; i++) {
1047
1048            if (i >= part->nelts) {
1049                if (part->next == NULL) {
1050                    break;
1051                }
1052
1053                part = part->next;
1054                header = part->elts;
1055                i = 0;
1056            }
1057
1058            for (n = 0; n < header_params; n++) {
1059                if (&header[i] == ignored[n]) {
1060                    goto next;
1061                }
1062            }
1063
1064            key_len = sizeof("HTTP_") - 1 + header[i].key.len;
1065            *b->last++ = (u_char) (key_len & 0xff);
1066            *b->last++ = (u_char) ((key_len >> 8) & 0xff);
1067
1068            b->last = ngx_cpymem(b->last, "HTTP_", sizeof("HTTP_") - 1);
1069            for (n = 0; n < header[i].key.len; n++) {
1070                ch = header[i].key.data[n];
1071
1072                if (ch >= 'a' && ch <= 'z') {
1073                    ch &= ~0x20;
1074
1075                } else if (ch == '-') {
1076                    ch = '_';
1077                }
1078
1079                *b->last++ = ch;
1080            }
1081
1082            val_len = header[i].value.len;
1083            *b->last++ = (u_char) (val_len & 0xff);
1084            *b->last++ = (u_char) ((val_len >> 8) & 0xff);
1085            b->last = ngx_copy(b->last, header[i].value.data, val_len);
1086
1087            ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1088                           "uwsgi param: \"%*s: %*s\"",
1089                           key_len, b->last - (key_len + 2 + val_len),
1090                           val_len, b->last - val_len);
1091        next:
1092
1093            continue;
1094        }
1095    }
1096
1097    b->last = ngx_copy(b->last, uwcf->uwsgi_string.data,
1098                       uwcf->uwsgi_string.len);
1099
1100    if (r->request_body_no_buffering) {
1101        r->upstream->request_bufs = cl;
1102
1103    } else if (uwcf->upstream.pass_request_body) {
1104        body = r->upstream->request_bufs;
1105        r->upstream->request_bufs = cl;
1106
1107        while (body) {
1108            b = ngx_alloc_buf(r->pool);
1109            if (b == NULL) {
1110                return NGX_ERROR;
1111            }
1112
1113            ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
1114
1115            cl->next = ngx_alloc_chain_link(r->pool);
1116            if (cl->next == NULL) {
1117                return NGX_ERROR;
1118            }
1119
1120            cl = cl->next;
1121            cl->buf = b;
1122
1123            body = body->next;
1124        }
1125
1126    } else {
1127        r->upstream->request_bufs = cl;
1128    }
1129
1130    cl->next = NULL;
1131
1132    return NGX_OK;
1133}
1134
1135
1136static ngx_int_t
1137ngx_http_uwsgi_reinit_request(ngx_http_request_t *r)
1138{
1139    ngx_http_status_t  *status;
1140
1141    status = ngx_http_get_module_ctx(r, ngx_http_uwsgi_module);
1142
1143    if (status == NULL) {
1144        return NGX_OK;
1145    }
1146
1147    status->code = 0;
1148    status->count = 0;
1149    status->start = NULL;
1150    status->end = NULL;
1151
1152    r->upstream->process_header = ngx_http_uwsgi_process_status_line;
1153    r->state = 0;
1154
1155    return NGX_OK;
1156}
1157
1158
1159static ngx_int_t
1160ngx_http_uwsgi_process_status_line(ngx_http_request_t *r)
1161{
1162    size_t                 len;
1163    ngx_int_t              rc;
1164    ngx_http_status_t     *status;
1165    ngx_http_upstream_t   *u;
1166
1167    status = ngx_http_get_module_ctx(r, ngx_http_uwsgi_module);
1168
1169    if (status == NULL) {
1170        return NGX_ERROR;
1171    }
1172
1173    u = r->upstream;
1174
1175    rc = ngx_http_parse_status_line(r, &u->buffer, status);
1176
1177    if (rc == NGX_AGAIN) {
1178        return rc;
1179    }
1180
1181    if (rc == NGX_ERROR) {
1182        u->process_header = ngx_http_uwsgi_process_header;
1183        return ngx_http_uwsgi_process_header(r);
1184    }
1185
1186    if (u->state && u->state->status == 0) {
1187        u->state->status = status->code;
1188    }
1189
1190    u->headers_in.status_n = status->code;
1191
1192    len = status->end - status->start;
1193    u->headers_in.status_line.len = len;
1194
1195    u->headers_in.status_line.data = ngx_pnalloc(r->pool, len);
1196    if (u->headers_in.status_line.data == NULL) {
1197        return NGX_ERROR;
1198    }
1199
1200    ngx_memcpy(u->headers_in.status_line.data, status->start, len);
1201
1202    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1203                   "http uwsgi status %ui \"%V\"",
1204                   u->headers_in.status_n, &u->headers_in.status_line);
1205
1206    u->process_header = ngx_http_uwsgi_process_header;
1207
1208    return ngx_http_uwsgi_process_header(r);
1209}
1210
1211
1212static ngx_int_t
1213ngx_http_uwsgi_process_header(ngx_http_request_t *r)
1214{
1215    ngx_str_t                      *status_line;
1216    ngx_int_t                       rc, status;
1217    ngx_table_elt_t                *h;
1218    ngx_http_upstream_t            *u;
1219    ngx_http_upstream_header_t     *hh;
1220    ngx_http_upstream_main_conf_t  *umcf;
1221
1222    umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
1223
1224    for ( ;; ) {
1225
1226        rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);
1227
1228        if (rc == NGX_OK) {
1229
1230            /* a header line has been parsed successfully */
1231
1232            h = ngx_list_push(&r->upstream->headers_in.headers);
1233            if (h == NULL) {
1234                return NGX_ERROR;
1235            }
1236
1237            h->hash = r->header_hash;
1238
1239            h->key.len = r->header_name_end - r->header_name_start;
1240            h->value.len = r->header_end - r->header_start;
1241
1242            h->key.data = ngx_pnalloc(r->pool,
1243                                      h->key.len + 1 + h->value.len + 1
1244                                      + h->key.len);
1245            if (h->key.data == NULL) {
1246                return NGX_ERROR;
1247            }
1248
1249            h->value.data = h->key.data + h->key.len + 1;
1250            h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;
1251
1252            ngx_memcpy(h->key.data, r->header_name_start, h->key.len);
1253            h->key.data[h->key.len] = '\0';
1254            ngx_memcpy(h->value.data, r->header_start, h->value.len);
1255            h->value.data[h->value.len] = '\0';
1256
1257            if (h->key.len == r->lowcase_index) {
1258                ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
1259
1260            } else {
1261                ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
1262            }
1263
1264            hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
1265                               h->lowcase_key, h->key.len);
1266
1267            if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1268                return NGX_ERROR;
1269            }
1270
1271            ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1272                           "http uwsgi header: \"%V: %V\"", &h->key, &h->value);
1273
1274            continue;
1275        }
1276
1277        if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
1278
1279            /* a whole header has been parsed successfully */
1280
1281            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1282                           "http uwsgi header done");
1283
1284            u = r->upstream;
1285
1286            if (u->headers_in.status_n) {
1287                goto done;
1288            }
1289
1290            if (u->headers_in.status) {
1291                status_line = &u->headers_in.status->value;
1292
1293                status = ngx_atoi(status_line->data, 3);
1294                if (status == NGX_ERROR) {
1295                    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1296                                  "upstream sent invalid status \"%V\"",
1297                                  status_line);
1298                    return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1299                }
1300
1301                u->headers_in.status_n = status;
1302                u->headers_in.status_line = *status_line;
1303
1304            } else if (u->headers_in.location) {
1305                u->headers_in.status_n = 302;
1306                ngx_str_set(&u->headers_in.status_line,
1307                            "302 Moved Temporarily");
1308
1309            } else {
1310                u->headers_in.status_n = 200;
1311                ngx_str_set(&u->headers_in.status_line, "200 OK");
1312            }
1313
1314            if (u->state && u->state->status == 0) {
1315                u->state->status = u->headers_in.status_n;
1316            }
1317
1318        done:
1319
1320            if (u->headers_in.status_n == NGX_HTTP_SWITCHING_PROTOCOLS
1321                && r->headers_in.upgrade)
1322            {
1323                u->upgrade = 1;
1324            }
1325
1326            return NGX_OK;
1327        }
1328
1329        if (rc == NGX_AGAIN) {
1330            return NGX_AGAIN;
1331        }
1332
1333        /* there was error while a header line parsing */
1334
1335        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1336                      "upstream sent invalid header");
1337
1338        return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1339    }
1340}
1341
1342
1343static void
1344ngx_http_uwsgi_abort_request(ngx_http_request_t *r)
1345{
1346    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1347                   "abort http uwsgi request");
1348
1349    return;
1350}
1351
1352
1353static void
1354ngx_http_uwsgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
1355{
1356    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1357                   "finalize http uwsgi request");
1358
1359    return;
1360}
1361
1362
1363static void *
1364ngx_http_uwsgi_create_main_conf(ngx_conf_t *cf)
1365{
1366    ngx_http_uwsgi_main_conf_t  *conf;
1367
1368    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_uwsgi_main_conf_t));
1369    if (conf == NULL) {
1370        return NULL;
1371    }
1372
1373#if (NGX_HTTP_CACHE)
1374    if (ngx_array_init(&conf->caches, cf->pool, 4,
1375                       sizeof(ngx_http_file_cache_t *))
1376        != NGX_OK)
1377    {
1378        return NULL;
1379    }
1380#endif
1381
1382    return conf;
1383}
1384
1385
1386static void *
1387ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf)
1388{
1389    ngx_http_uwsgi_loc_conf_t  *conf;
1390
1391    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_uwsgi_loc_conf_t));
1392    if (conf == NULL) {
1393        return NULL;
1394    }
1395
1396    conf->modifier1 = NGX_CONF_UNSET_UINT;
1397    conf->modifier2 = NGX_CONF_UNSET_UINT;
1398
1399    conf->upstream.store = NGX_CONF_UNSET;
1400    conf->upstream.store_access = NGX_CONF_UNSET_UINT;
1401    conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
1402    conf->upstream.buffering = NGX_CONF_UNSET;
1403    conf->upstream.request_buffering = NGX_CONF_UNSET;
1404    conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
1405    conf->upstream.force_ranges = NGX_CONF_UNSET;
1406
1407    conf->upstream.local = NGX_CONF_UNSET_PTR;
1408
1409    conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
1410    conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
1411    conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
1412    conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC;
1413
1414    conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
1415    conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
1416    conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE;
1417
1418    conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
1419    conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
1420    conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;
1421
1422    conf->upstream.pass_request_headers = NGX_CONF_UNSET;
1423    conf->upstream.pass_request_body = NGX_CONF_UNSET;
1424
1425#if (NGX_HTTP_CACHE)
1426    conf->upstream.cache = NGX_CONF_UNSET;
1427    conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
1428    conf->upstream.cache_max_range_offset = NGX_CONF_UNSET;
1429    conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
1430    conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
1431    conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
1432    conf->upstream.cache_lock = NGX_CONF_UNSET;
1433    conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
1434    conf->upstream.cache_lock_age = NGX_CONF_UNSET_MSEC;
1435    conf->upstream.cache_revalidate = NGX_CONF_UNSET;
1436    conf->upstream.cache_background_update = NGX_CONF_UNSET;
1437#endif
1438
1439    conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
1440    conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
1441
1442    conf->upstream.intercept_errors = NGX_CONF_UNSET;
1443
1444#if (NGX_HTTP_SSL)
1445    conf->upstream.ssl_session_reuse = NGX_CONF_UNSET;
1446    conf->upstream.ssl_server_name = NGX_CONF_UNSET;
1447    conf->upstream.ssl_verify = NGX_CONF_UNSET;
1448    conf->ssl_verify_depth = NGX_CONF_UNSET_UINT;
1449    conf->ssl_passwords = NGX_CONF_UNSET_PTR;
1450#endif
1451
1452    /* "uwsgi_cyclic_temp_file" is disabled */
1453    conf->upstream.cyclic_temp_file = 0;
1454
1455    conf->upstream.change_buffering = 1;
1456
1457    ngx_str_set(&conf->upstream.module, "uwsgi");
1458
1459    return conf;
1460}
1461
1462
1463static char *
1464ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
1465{
1466    ngx_http_uwsgi_loc_conf_t *prev = parent;
1467    ngx_http_uwsgi_loc_conf_t *conf = child;
1468
1469    size_t                        size;
1470    ngx_int_t                     rc;
1471    ngx_hash_init_t               hash;
1472    ngx_http_core_loc_conf_t     *clcf;
1473
1474#if (NGX_HTTP_CACHE)
1475
1476    if (conf->upstream.store > 0) {
1477        conf->upstream.cache = 0;
1478    }
1479
1480    if (conf->upstream.cache > 0) {
1481        conf->upstream.store = 0;
1482    }
1483
1484#endif
1485
1486    if (conf->upstream.store == NGX_CONF_UNSET) {
1487        ngx_conf_merge_value(conf->upstream.store, prev->upstream.store, 0);
1488
1489        conf->upstream.store_lengths = prev->upstream.store_lengths;
1490        conf->upstream.store_values = prev->upstream.store_values;
1491    }
1492
1493    ngx_conf_merge_uint_value(conf->upstream.store_access,
1494                              prev->upstream.store_access, 0600);
1495
1496    ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
1497                              prev->upstream.next_upstream_tries, 0);
1498
1499    ngx_conf_merge_value(conf->upstream.buffering,
1500                              prev->upstream.buffering, 1);
1501
1502    ngx_conf_merge_value(conf->upstream.request_buffering,
1503                              prev->upstream.request_buffering, 1);
1504
1505    ngx_conf_merge_value(conf->upstream.ignore_client_abort,
1506                              prev->upstream.ignore_client_abort, 0);
1507
1508    ngx_conf_merge_value(conf->upstream.force_ranges,
1509                              prev->upstream.force_ranges, 0);
1510
1511    ngx_conf_merge_ptr_value(conf->upstream.local,
1512                              prev->upstream.local, NULL);
1513
1514    ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
1515                              prev->upstream.connect_timeout, 60000);
1516
1517    ngx_conf_merge_msec_value(conf->upstream.send_timeout,
1518                              prev->upstream.send_timeout, 60000);
1519
1520    ngx_conf_merge_msec_value(conf->upstream.read_timeout,
1521                              prev->upstream.read_timeout, 60000);
1522
1523    ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
1524                              prev->upstream.next_upstream_timeout, 0);
1525
1526    ngx_conf_merge_size_value(conf->upstream.send_lowat,
1527                              prev->upstream.send_lowat, 0);
1528
1529    ngx_conf_merge_size_value(conf->upstream.buffer_size,
1530                              prev->upstream.buffer_size,
1531                              (size_t) ngx_pagesize);
1532
1533    ngx_conf_merge_size_value(conf->upstream.limit_rate,
1534                              prev->upstream.limit_rate, 0);
1535
1536
1537    ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
1538                              8, ngx_pagesize);
1539
1540    if (conf->upstream.bufs.num < 2) {
1541        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1542                           "there must be at least 2 \"uwsgi_buffers\"");
1543        return NGX_CONF_ERROR;
1544    }
1545
1546
1547    size = conf->upstream.buffer_size;
1548    if (size < conf->upstream.bufs.size) {
1549        size = conf->upstream.bufs.size;
1550    }
1551
1552
1553    ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
1554                              prev->upstream.busy_buffers_size_conf,
1555                              NGX_CONF_UNSET_SIZE);
1556
1557    if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
1558        conf->upstream.busy_buffers_size = 2 * size;
1559    } else {
1560        conf->upstream.busy_buffers_size =
1561            conf->upstream.busy_buffers_size_conf;
1562    }
1563
1564    if (conf->upstream.busy_buffers_size < size) {
1565        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1566            "\"uwsgi_busy_buffers_size\" must be equal to or greater "
1567            "than the maximum of the value of \"uwsgi_buffer_size\" and "
1568            "one of the \"uwsgi_buffers\"");
1569
1570        return NGX_CONF_ERROR;
1571    }
1572
1573    if (conf->upstream.busy_buffers_size
1574        > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
1575    {
1576        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1577            "\"uwsgi_busy_buffers_size\" must be less than "
1578            "the size of all \"uwsgi_buffers\" minus one buffer");
1579
1580        return NGX_CONF_ERROR;
1581    }
1582
1583
1584    ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf,
1585                              prev->upstream.temp_file_write_size_conf,
1586                              NGX_CONF_UNSET_SIZE);
1587
1588    if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
1589        conf->upstream.temp_file_write_size = 2 * size;
1590    } else {
1591        conf->upstream.temp_file_write_size =
1592            conf->upstream.temp_file_write_size_conf;
1593    }
1594
1595    if (conf->upstream.temp_file_write_size < size) {
1596        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1597            "\"uwsgi_temp_file_write_size\" must be equal to or greater than "
1598            "the maximum of the value of \"uwsgi_buffer_size\" and "
1599            "one of the \"uwsgi_buffers\"");
1600
1601        return NGX_CONF_ERROR;
1602    }
1603
1604
1605    ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf,
1606                              prev->upstream.max_temp_file_size_conf,
1607                              NGX_CONF_UNSET_SIZE);
1608
1609    if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
1610        conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
1611    } else {
1612        conf->upstream.max_temp_file_size =
1613            conf->upstream.max_temp_file_size_conf;
1614    }
1615
1616    if (conf->upstream.max_temp_file_size != 0
1617        && conf->upstream.max_temp_file_size < size)
1618    {
1619        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1620            "\"uwsgi_max_temp_file_size\" must be equal to zero to disable "
1621            "temporary files usage or must be equal to or greater than "
1622            "the maximum of the value of \"uwsgi_buffer_size\" and "
1623            "one of the \"uwsgi_buffers\"");
1624
1625        return NGX_CONF_ERROR;
1626    }
1627
1628
1629    ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
1630                                 prev->upstream.ignore_headers,
1631                                 NGX_CONF_BITMASK_SET);
1632
1633
1634    ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
1635                                 prev->upstream.next_upstream,
1636                                 (NGX_CONF_BITMASK_SET
1637                                  |NGX_HTTP_UPSTREAM_FT_ERROR
1638                                  |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
1639
1640    if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
1641        conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
1642                                       |NGX_HTTP_UPSTREAM_FT_OFF;
1643    }
1644
1645    if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
1646                                  prev->upstream.temp_path,
1647                                  &ngx_http_uwsgi_temp_path)
1648        != NGX_OK)
1649    {
1650        return NGX_CONF_ERROR;
1651    }
1652
1653#if (NGX_HTTP_CACHE)
1654
1655    if (conf->upstream.cache == NGX_CONF_UNSET) {
1656        ngx_conf_merge_value(conf->upstream.cache,
1657                              prev->upstream.cache, 0);
1658
1659        conf->upstream.cache_zone = prev->upstream.cache_zone;
1660        conf->upstream.cache_value = prev->upstream.cache_value;
1661    }
1662
1663    if (conf->upstream.cache_zone && conf->upstream.cache_zone->data == NULL) {
1664        ngx_shm_zone_t  *shm_zone;
1665
1666        shm_zone = conf->upstream.cache_zone;
1667
1668        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1669                           "\"uwsgi_cache\" zone \"%V\" is unknown",
1670                           &shm_zone->shm.name);
1671
1672        return NGX_CONF_ERROR;
1673    }
1674
1675    ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
1676                              prev->upstream.cache_min_uses, 1);
1677
1678    ngx_conf_merge_off_value(conf->upstream.cache_max_range_offset,
1679                              prev->upstream.cache_max_range_offset,
1680                              NGX_MAX_OFF_T_VALUE);
1681
1682    ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
1683                              prev->upstream.cache_use_stale,
1684                              (NGX_CONF_BITMASK_SET
1685                               |NGX_HTTP_UPSTREAM_FT_OFF));
1686
1687    if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
1688        conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
1689                                         |NGX_HTTP_UPSTREAM_FT_OFF;
1690    }
1691
1692    if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
1693        conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
1694    }
1695
1696    if (conf->upstream.cache_methods == 0) {
1697        conf->upstream.cache_methods = prev->upstream.cache_methods;
1698    }
1699
1700    conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD;
1701
1702    ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
1703                             prev->upstream.cache_bypass, NULL);
1704
1705    ngx_conf_merge_ptr_value(conf->upstream.no_cache,
1706                             prev->upstream.no_cache, NULL);
1707
1708    ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
1709                             prev->upstream.cache_valid, NULL);
1710
1711    if (conf->cache_key.value.data == NULL) {
1712        conf->cache_key = prev->cache_key;
1713    }
1714
1715    if (conf->upstream.cache && conf->cache_key.value.data == NULL) {
1716        ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
1717                           "no \"uwsgi_cache_key\" for \"uwsgi_cache\"");
1718    }
1719
1720    ngx_conf_merge_value(conf->upstream.cache_lock,
1721                              prev->upstream.cache_lock, 0);
1722
1723    ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
1724                              prev->upstream.cache_lock_timeout, 5000);
1725
1726    ngx_conf_merge_msec_value(conf->upstream.cache_lock_age,
1727                              prev->upstream.cache_lock_age, 5000);
1728
1729    ngx_conf_merge_value(conf->upstream.cache_revalidate,
1730                              prev->upstream.cache_revalidate, 0);
1731
1732    ngx_conf_merge_value(conf->upstream.cache_background_update,
1733                              prev->upstream.cache_background_update, 0);
1734
1735#endif
1736
1737    ngx_conf_merge_value(conf->upstream.pass_request_headers,
1738                         prev->upstream.pass_request_headers, 1);
1739    ngx_conf_merge_value(conf->upstream.pass_request_body,
1740                         prev->upstream.pass_request_body, 1);
1741
1742    ngx_conf_merge_value(conf->upstream.intercept_errors,
1743                         prev->upstream.intercept_errors, 0);
1744
1745#if (NGX_HTTP_SSL)
1746
1747    ngx_conf_merge_value(conf->upstream.ssl_session_reuse,
1748                              prev->upstream.ssl_session_reuse, 1);
1749
1750    ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols,
1751                                 (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1
1752                                  |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2));
1753
1754    ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers,
1755                             "DEFAULT");
1756
1757    if (conf->upstream.ssl_name == NULL) {
1758        conf->upstream.ssl_name = prev->upstream.ssl_name;
1759    }
1760
1761    ngx_conf_merge_value(conf->upstream.ssl_server_name,
1762                              prev->upstream.ssl_server_name, 0);
1763    ngx_conf_merge_value(conf->upstream.ssl_verify,
1764                              prev->upstream.ssl_verify, 0);
1765    ngx_conf_merge_uint_value(conf->ssl_verify_depth,
1766                              prev->ssl_verify_depth, 1);
1767    ngx_conf_merge_str_value(conf->ssl_trusted_certificate,
1768                              prev->ssl_trusted_certificate, "");
1769    ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, "");
1770
1771    ngx_conf_merge_str_value(conf->ssl_certificate,
1772                              prev->ssl_certificate, "");
1773    ngx_conf_merge_str_value(conf->ssl_certificate_key,
1774                              prev->ssl_certificate_key, "");
1775    ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL);
1776
1777    if (conf->ssl && ngx_http_uwsgi_set_ssl(cf, conf) != NGX_OK) {
1778        return NGX_CONF_ERROR;
1779    }
1780
1781#endif
1782
1783    ngx_conf_merge_str_value(conf->uwsgi_string, prev->uwsgi_string, "");
1784
1785    hash.max_size = 512;
1786    hash.bucket_size = ngx_align(64, ngx_cacheline_size);
1787    hash.name = "uwsgi_hide_headers_hash";
1788
1789    if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
1790            &prev->upstream, ngx_http_uwsgi_hide_headers, &hash)
1791        != NGX_OK)
1792    {
1793        return NGX_CONF_ERROR;
1794    }
1795
1796    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
1797
1798    if (clcf->noname
1799        && conf->upstream.upstream == NULL && conf->uwsgi_lengths == NULL)
1800    {
1801        conf->upstream.upstream = prev->upstream.upstream;
1802
1803        conf->uwsgi_lengths = prev->uwsgi_lengths;
1804        conf->uwsgi_values = prev->uwsgi_values;
1805
1806#if (NGX_HTTP_SSL)
1807        conf->upstream.ssl = prev->upstream.ssl;
1808#endif
1809    }
1810
1811    if (clcf->lmt_excpt && clcf->handler == NULL
1812        && (conf->upstream.upstream || conf->uwsgi_lengths))
1813    {
1814        clcf->handler = ngx_http_uwsgi_handler;
1815    }
1816
1817    ngx_conf_merge_uint_value(conf->modifier1, prev->modifier1, 0);
1818    ngx_conf_merge_uint_value(conf->modifier2, prev->modifier2, 0);
1819
1820    if (conf->params_source == NULL) {
1821        conf->params = prev->params;
1822#if (NGX_HTTP_CACHE)
1823        conf->params_cache = prev->params_cache;
1824#endif
1825        conf->params_source = prev->params_source;
1826    }
1827
1828    rc = ngx_http_uwsgi_init_params(cf, conf, &conf->params, NULL);
1829    if (rc != NGX_OK) {
1830        return NGX_CONF_ERROR;
1831    }
1832
1833#if (NGX_HTTP_CACHE)
1834
1835    if (conf->upstream.cache) {
1836        rc = ngx_http_uwsgi_init_params(cf, conf, &conf->params_cache,
1837                                        ngx_http_uwsgi_cache_headers);
1838        if (rc != NGX_OK) {
1839            return NGX_CONF_ERROR;
1840        }
1841    }
1842
1843#endif
1844
1845    /*
1846     * special handling to preserve conf->params in the "http" section
1847     * to inherit it to all servers
1848     */
1849
1850    if (prev->params.hash.buckets == NULL
1851        && conf->params_source == prev->params_source)
1852    {
1853        prev->params = conf->params;
1854#if (NGX_HTTP_CACHE)
1855        prev->params_cache = conf->params_cache;
1856#endif
1857    }
1858
1859    return NGX_CONF_OK;
1860}
1861
1862
1863static ngx_int_t
1864ngx_http_uwsgi_init_params(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *conf,
1865    ngx_http_uwsgi_params_t *params, ngx_keyval_t *default_params)
1866{
1867    u_char                       *p;
1868    size_t                        size;
1869    uintptr_t                    *code;
1870    ngx_uint_t                    i, nsrc;
1871    ngx_array_t                   headers_names, params_merged;
1872    ngx_keyval_t                 *h;
1873    ngx_hash_key_t               *hk;
1874    ngx_hash_init_t               hash;
1875    ngx_http_upstream_param_t    *src, *s;
1876    ngx_http_script_compile_t     sc;
1877    ngx_http_script_copy_code_t  *copy;
1878
1879    if (params->hash.buckets) {
1880        return NGX_OK;
1881    }
1882
1883    if (conf->params_source == NULL && default_params == NULL) {
1884        params->hash.buckets = (void *) 1;
1885        return NGX_OK;
1886    }
1887
1888    params->lengths = ngx_array_create(cf->pool, 64, 1);
1889    if (params->lengths == NULL) {
1890        return NGX_ERROR;
1891    }
1892
1893    params->values = ngx_array_create(cf->pool, 512, 1);
1894    if (params->values == NULL) {
1895        return NGX_ERROR;
1896    }
1897
1898    if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
1899        != NGX_OK)
1900    {
1901        return NGX_ERROR;
1902    }
1903
1904    if (conf->params_source) {
1905        src = conf->params_source->elts;
1906        nsrc = conf->params_source->nelts;
1907
1908    } else {
1909        src = NULL;
1910        nsrc = 0;
1911    }
1912
1913    if (default_params) {
1914        if (ngx_array_init(&params_merged, cf->temp_pool, 4,
1915                           sizeof(ngx_http_upstream_param_t))
1916            != NGX_OK)
1917        {
1918            return NGX_ERROR;
1919        }
1920
1921        for (i = 0; i < nsrc; i++) {
1922
1923            s = ngx_array_push(&params_merged);
1924            if (s == NULL) {
1925                return NGX_ERROR;
1926            }
1927
1928            *s = src[i];
1929        }
1930
1931        h = default_params;
1932
1933        while (h->key.len) {
1934
1935            src = params_merged.elts;
1936            nsrc = params_merged.nelts;
1937
1938            for (i = 0; i < nsrc; i++) {
1939                if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
1940                    goto next;
1941                }
1942            }
1943
1944            s = ngx_array_push(&params_merged);
1945            if (s == NULL) {
1946                return NGX_ERROR;
1947            }
1948
1949            s->key = h->key;
1950            s->value = h->value;
1951            s->skip_empty = 1;
1952
1953        next:
1954
1955            h++;
1956        }
1957
1958        src = params_merged.elts;
1959        nsrc = params_merged.nelts;
1960    }
1961
1962    for (i = 0; i < nsrc; i++) {
1963
1964        if (src[i].key.len > sizeof("HTTP_") - 1
1965            && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0)
1966        {
1967            hk = ngx_array_push(&headers_names);
1968            if (hk == NULL) {
1969                return NGX_ERROR;
1970            }
1971
1972            hk->key.len = src[i].key.len - 5;
1973            hk->key.data = src[i].key.data + 5;
1974            hk->key_hash = ngx_hash_key_lc(hk->key.data, hk->key.len);
1975            hk->value = (void *) 1;
1976
1977            if (src[i].value.len == 0) {
1978                continue;
1979            }
1980        }
1981
1982        copy = ngx_array_push_n(params->lengths,
1983                                sizeof(ngx_http_script_copy_code_t));
1984        if (copy == NULL) {
1985            return NGX_ERROR;
1986        }
1987
1988        copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
1989        copy->len = src[i].key.len;
1990
1991        copy = ngx_array_push_n(params->lengths,
1992                                sizeof(ngx_http_script_copy_code_t));
1993        if (copy == NULL) {
1994            return NGX_ERROR;
1995        }
1996
1997        copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
1998        copy->len = src[i].skip_empty;
1999
2000
2001        size = (sizeof(ngx_http_script_copy_code_t)
2002                + src[i].key.len + sizeof(uintptr_t) - 1)
2003               & ~(sizeof(uintptr_t) - 1);
2004
2005        copy = ngx_array_push_n(params->values, size);
2006        if (copy == NULL) {
2007            return NGX_ERROR;
2008        }
2009
2010        copy->code = ngx_http_script_copy_code;
2011        copy->len = src[i].key.len;
2012
2013        p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
2014        ngx_memcpy(p, src[i].key.data, src[i].key.len);
2015
2016
2017        ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
2018
2019        sc.cf = cf;
2020        sc.source = &src[i].value;
2021        sc.flushes = &params->flushes;
2022        sc.lengths = &params->lengths;
2023        sc.values = &params->values;
2024
2025        if (ngx_http_script_compile(&sc) != NGX_OK) {
2026            return NGX_ERROR;
2027        }
2028
2029        code = ngx_array_push_n(params->lengths, sizeof(uintptr_t));
2030        if (code == NULL) {
2031            return NGX_ERROR;
2032        }
2033
2034        *code = (uintptr_t) NULL;
2035
2036
2037        code = ngx_array_push_n(params->values, sizeof(uintptr_t));
2038        if (code == NULL) {
2039            return NGX_ERROR;
2040        }
2041
2042        *code = (uintptr_t) NULL;
2043    }
2044
2045    code = ngx_array_push_n(params->lengths, sizeof(uintptr_t));
2046    if (code == NULL) {
2047        return NGX_ERROR;
2048    }
2049
2050    *code = (uintptr_t) NULL;
2051
2052    params->number = headers_names.nelts;
2053
2054    hash.hash = &params->hash;
2055    hash.key = ngx_hash_key_lc;
2056    hash.max_size = 512;
2057    hash.bucket_size = 64;
2058    hash.name = "uwsgi_params_hash";
2059    hash.pool = cf->pool;
2060    hash.temp_pool = NULL;
2061
2062    return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
2063}
2064
2065
2066static char *
2067ngx_http_uwsgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
2068{
2069    ngx_http_uwsgi_loc_conf_t *uwcf = conf;
2070
2071    size_t                      add;
2072    ngx_url_t                   u;
2073    ngx_str_t                  *value, *url;
2074    ngx_uint_t                  n;
2075    ngx_http_core_loc_conf_t   *clcf;
2076    ngx_http_script_compile_t   sc;
2077
2078    if (uwcf->upstream.upstream || uwcf->uwsgi_lengths) {
2079        return "is duplicate";
2080    }
2081
2082    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
2083    clcf->handler = ngx_http_uwsgi_handler;
2084
2085    value = cf->args->elts;
2086
2087    url = &value[1];
2088
2089    n = ngx_http_script_variables_count(url);
2090
2091    if (n) {
2092
2093        ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
2094
2095        sc.cf = cf;
2096        sc.source = url;
2097        sc.lengths = &uwcf->uwsgi_lengths;
2098        sc.values = &uwcf->uwsgi_values;
2099        sc.variables = n;
2100        sc.complete_lengths = 1;
2101        sc.complete_values = 1;
2102
2103        if (ngx_http_script_compile(&sc) != NGX_OK) {
2104            return NGX_CONF_ERROR;
2105        }
2106
2107#if (NGX_HTTP_SSL)
2108        uwcf->ssl = 1;
2109#endif
2110
2111        return NGX_CONF_OK;
2112    }
2113
2114    if (ngx_strncasecmp(url->data, (u_char *) "uwsgi://", 8) == 0) {
2115        add = 8;
2116
2117    } else if (ngx_strncasecmp(url->data, (u_char *) "suwsgi://", 9) == 0) {
2118
2119#if (NGX_HTTP_SSL)
2120        add = 9;
2121        uwcf->ssl = 1;
2122#else
2123        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2124                           "suwsgi protocol requires SSL support");
2125        return NGX_CONF_ERROR;
2126#endif
2127
2128    } else {
2129        add = 0;
2130    }
2131
2132    ngx_memzero(&u, sizeof(ngx_url_t));
2133
2134    u.url.len = url->len - add;
2135    u.url.data = url->data + add;
2136    u.no_resolve = 1;
2137
2138    uwcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
2139    if (uwcf->upstream.upstream == NULL) {
2140        return NGX_CONF_ERROR;
2141    }
2142
2143    if (clcf->name.data[clcf->name.len - 1] == '/') {
2144        clcf->auto_redirect = 1;
2145    }
2146
2147    return NGX_CONF_OK;
2148}
2149
2150
2151static char *
2152ngx_http_uwsgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
2153{
2154    ngx_http_uwsgi_loc_conf_t *uwcf = conf;
2155
2156    ngx_str_t                  *value;
2157    ngx_http_script_compile_t   sc;
2158
2159    if (uwcf->upstream.store != NGX_CONF_UNSET) {
2160        return "is duplicate";
2161    }
2162
2163    value = cf->args->elts;
2164
2165    if (ngx_strcmp(value[1].data, "off") == 0) {
2166        uwcf->upstream.store = 0;
2167        return NGX_CONF_OK;
2168    }
2169
2170#if (NGX_HTTP_CACHE)
2171
2172    if (uwcf->upstream.cache > 0) {
2173        return "is incompatible with \"uwsgi_cache\"";
2174    }
2175
2176#endif
2177
2178    uwcf->upstream.store = 1;
2179
2180    if (ngx_strcmp(value[1].data, "on") == 0) {
2181        return NGX_CONF_OK;
2182    }
2183
2184    /* include the terminating '\0' into script */
2185    value[1].len++;
2186
2187    ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
2188
2189    sc.cf = cf;
2190    sc.source = &value[1];
2191    sc.lengths = &uwcf->upstream.store_lengths;
2192    sc.values = &uwcf->upstream.store_values;
2193    sc.variables = ngx_http_script_variables_count(&value[1]);
2194    sc.complete_lengths = 1;
2195    sc.complete_values = 1;
2196
2197    if (ngx_http_script_compile(&sc) != NGX_OK) {
2198        return NGX_CONF_ERROR;
2199    }
2200
2201    return NGX_CONF_OK;
2202}
2203
2204
2205#if (NGX_HTTP_CACHE)
2206
2207static char *
2208ngx_http_uwsgi_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
2209{
2210    ngx_http_uwsgi_loc_conf_t *uwcf = conf;
2211
2212    ngx_str_t                         *value;
2213    ngx_http_complex_value_t           cv;
2214    ngx_http_compile_complex_value_t   ccv;
2215
2216    value = cf->args->elts;
2217
2218    if (uwcf->upstream.cache != NGX_CONF_UNSET) {
2219        return "is duplicate";
2220    }
2221
2222    if (ngx_strcmp(value[1].data, "off") == 0) {
2223        uwcf->upstream.cache = 0;
2224        return NGX_CONF_OK;
2225    }
2226
2227    if (uwcf->upstream.store > 0) {
2228        return "is incompatible with \"uwsgi_store\"";
2229    }
2230
2231    uwcf->upstream.cache = 1;
2232
2233    ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
2234
2235    ccv.cf = cf;
2236    ccv.value = &value[1];
2237    ccv.complex_value = &cv;
2238
2239    if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
2240        return NGX_CONF_ERROR;
2241    }
2242
2243    if (cv.lengths != NULL) {
2244
2245        uwcf->upstream.cache_value = ngx_palloc(cf->pool,
2246                                             sizeof(ngx_http_complex_value_t));
2247        if (uwcf->upstream.cache_value == NULL) {
2248            return NGX_CONF_ERROR;
2249        }
2250
2251        *uwcf->upstream.cache_value = cv;
2252
2253        return NGX_CONF_OK;
2254    }
2255
2256    uwcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0,
2257                                                      &ngx_http_uwsgi_module);
2258    if (uwcf->upstream.cache_zone == NULL) {
2259        return NGX_CONF_ERROR;
2260    }
2261
2262    return NGX_CONF_OK;
2263}
2264
2265
2266static char *
2267ngx_http_uwsgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
2268{
2269    ngx_http_uwsgi_loc_conf_t *uwcf = conf;
2270
2271    ngx_str_t                         *value;
2272    ngx_http_compile_complex_value_t   ccv;
2273
2274    value = cf->args->elts;
2275
2276    if (uwcf->cache_key.value.data) {
2277        return "is duplicate";
2278    }
2279
2280    ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
2281
2282    ccv.cf = cf;
2283    ccv.value = &value[1];
2284    ccv.complex_value = &uwcf->cache_key;
2285
2286    if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
2287        return NGX_CONF_ERROR;
2288    }
2289
2290    return NGX_CONF_OK;
2291}
2292
2293#endif
2294
2295
2296#if (NGX_HTTP_SSL)
2297
2298static char *
2299ngx_http_uwsgi_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
2300{
2301    ngx_http_uwsgi_loc_conf_t *uwcf = conf;
2302
2303    ngx_str_t  *value;
2304
2305    if (uwcf->ssl_passwords != NGX_CONF_UNSET_PTR) {
2306        return "is duplicate";
2307    }
2308
2309    value = cf->args->elts;
2310
2311    uwcf->ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]);
2312
2313    if (uwcf->ssl_passwords == NULL) {
2314        return NGX_CONF_ERROR;
2315    }
2316
2317    return NGX_CONF_OK;
2318}
2319
2320
2321static ngx_int_t
2322ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *uwcf)
2323{
2324    ngx_pool_cleanup_t  *cln;
2325
2326    uwcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));
2327    if (uwcf->upstream.ssl == NULL) {
2328        return NGX_ERROR;
2329    }
2330
2331    uwcf->upstream.ssl->log = cf->log;
2332
2333    if (ngx_ssl_create(uwcf->upstream.ssl, uwcf->ssl_protocols, NULL)
2334        != NGX_OK)
2335    {
2336        return NGX_ERROR;
2337    }
2338
2339    cln = ngx_pool_cleanup_add(cf->pool, 0);
2340    if (cln == NULL) {
2341        return NGX_ERROR;
2342    }
2343
2344    cln->handler = ngx_ssl_cleanup_ctx;
2345    cln->data = uwcf->upstream.ssl;
2346
2347    if (uwcf->ssl_certificate.len) {
2348
2349        if (uwcf->ssl_certificate_key.len == 0) {
2350            ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
2351                          "no \"uwsgi_ssl_certificate_key\" is defined "
2352                          "for certificate \"%V\"", &uwcf->ssl_certificate);
2353            return NGX_ERROR;
2354        }
2355
2356        if (ngx_ssl_certificate(cf, uwcf->upstream.ssl, &uwcf->ssl_certificate,
2357                                &uwcf->ssl_certificate_key, uwcf->ssl_passwords)
2358            != NGX_OK)
2359        {
2360            return NGX_ERROR;
2361        }
2362    }
2363
2364    if (ngx_ssl_ciphers(cf, uwcf->upstream.ssl, &uwcf->ssl_ciphers, 0)
2365        != NGX_OK)
2366    {
2367        return NGX_ERROR;
2368    }
2369
2370    if (uwcf->upstream.ssl_verify) {
2371        if (uwcf->ssl_trusted_certificate.len == 0) {
2372            ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
2373                      "no uwsgi_ssl_trusted_certificate for uwsgi_ssl_verify");
2374            return NGX_ERROR;
2375        }
2376
2377        if (ngx_ssl_trusted_certificate(cf, uwcf->upstream.ssl,
2378                                        &uwcf->ssl_trusted_certificate,
2379                                        uwcf->ssl_verify_depth)
2380            != NGX_OK)
2381        {
2382            return NGX_ERROR;
2383        }
2384
2385        if (ngx_ssl_crl(cf, uwcf->upstream.ssl, &uwcf->ssl_crl) != NGX_OK) {
2386            return NGX_ERROR;
2387        }
2388    }
2389
2390    return NGX_OK;
2391}
2392
2393#endif
2394