source: nginx/src/http/modules/ngx_http_fastcgi_module.c

tip
Last change on this file was 6052:8ad78808a612, checked in by Maxim Dounin <mdounin@…>, 2 months ago

FastCGI: fastcgi_request_buffering.

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