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

tip
Last change on this file was 6230:2a621245f4cf, checked in by Maxim Dounin <mdounin@…>, 2 weeks ago

Win32: MSVC 2015 compatibility.

Resolved warnings about declarations that hide previous local declarations.
Warnings about WSASocketA() being deprecated resolved by explicit use of
WSASocketW() instead of WSASocket(). When compiling without IPv6 support,
WinSock? deprecated warnings are disabled to allow use of gethostbyname().

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            ssize_t                     len;
1774            ngx_http_fastcgi_header_t  *fh;
1775
1776            start = u->buffer.start + r->cache->header_start;
1777
1778            len = u->buffer.pos - start - 2 * sizeof(ngx_http_fastcgi_header_t);
1779
1780            /*
1781             * A tail of large stderr output before HTTP header is placed
1782             * in a cache file without a FastCGI record header.
1783             * To workaround it we put a dummy FastCGI record header at the
1784             * start of the stderr output or update r->cache_header_start,
1785             * if there is no enough place for the record header.
1786             */
1787
1788            if (len >= 0) {
1789                fh = (ngx_http_fastcgi_header_t *) start;
1790                fh->version = 1;
1791                fh->type = NGX_HTTP_FASTCGI_STDERR;
1792                fh->request_id_hi = 0;
1793                fh->request_id_lo = 1;
1794                fh->content_length_hi = (u_char) ((len >> 8) & 0xff);
1795                fh->content_length_lo = (u_char) (len & 0xff);
1796                fh->padding_length = 0;
1797                fh->reserved = 0;
1798
1799            } else {
1800                r->cache->header_start += u->buffer.pos - start
1801                                           - sizeof(ngx_http_fastcgi_header_t);
1802            }
1803
1804            f->large_stderr = 0;
1805        }
1806
1807#endif
1808
1809        f->fastcgi_stdout = 1;
1810
1811        start = u->buffer.pos;
1812
1813        if (u->buffer.pos + f->length < u->buffer.last) {
1814
1815            /*
1816             * set u->buffer.last to the end of the FastCGI record data
1817             * for ngx_http_parse_header_line()
1818             */
1819
1820            last = u->buffer.last;
1821            u->buffer.last = u->buffer.pos + f->length;
1822
1823        } else {
1824            last = NULL;
1825        }
1826
1827        for ( ;; ) {
1828
1829            part_start = u->buffer.pos;
1830            part_end = u->buffer.last;
1831
1832            rc = ngx_http_parse_header_line(r, &u->buffer, 1);
1833
1834            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1835                           "http fastcgi parser: %d", rc);
1836
1837            if (rc == NGX_AGAIN) {
1838                break;
1839            }
1840
1841            if (rc == NGX_OK) {
1842
1843                /* a header line has been parsed successfully */
1844
1845                h = ngx_list_push(&u->headers_in.headers);
1846                if (h == NULL) {
1847                    return NGX_ERROR;
1848                }
1849
1850                if (f->split_parts && f->split_parts->nelts) {
1851
1852                    part = f->split_parts->elts;
1853                    size = u->buffer.pos - part_start;
1854
1855                    for (i = 0; i < f->split_parts->nelts; i++) {
1856                        size += part[i].end - part[i].start;
1857                    }
1858
1859                    p = ngx_pnalloc(r->pool, size);
1860                    if (p == NULL) {
1861                        return NGX_ERROR;
1862                    }
1863
1864                    buf.pos = p;
1865
1866                    for (i = 0; i < f->split_parts->nelts; i++) {
1867                        p = ngx_cpymem(p, part[i].start,
1868                                       part[i].end - part[i].start);
1869                    }
1870
1871                    p = ngx_cpymem(p, part_start, u->buffer.pos - part_start);
1872
1873                    buf.last = p;
1874
1875                    f->split_parts->nelts = 0;
1876
1877                    rc = ngx_http_parse_header_line(r, &buf, 1);
1878
1879                    if (rc != NGX_OK) {
1880                        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
1881                                      "invalid header after joining "
1882                                      "FastCGI records");
1883                        return NGX_ERROR;
1884                    }
1885
1886                    h->key.len = r->header_name_end - r->header_name_start;
1887                    h->key.data = r->header_name_start;
1888                    h->key.data[h->key.len] = '\0';
1889
1890                    h->value.len = r->header_end - r->header_start;
1891                    h->value.data = r->header_start;
1892                    h->value.data[h->value.len] = '\0';
1893
1894                    h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
1895                    if (h->lowcase_key == NULL) {
1896                        return NGX_ERROR;
1897                    }
1898
1899                } else {
1900
1901                    h->key.len = r->header_name_end - r->header_name_start;
1902                    h->value.len = r->header_end - r->header_start;
1903
1904                    h->key.data = ngx_pnalloc(r->pool,
1905                                              h->key.len + 1 + h->value.len + 1
1906                                              + h->key.len);
1907                    if (h->key.data == NULL) {
1908                        return NGX_ERROR;
1909                    }
1910
1911                    h->value.data = h->key.data + h->key.len + 1;
1912                    h->lowcase_key = h->key.data + h->key.len + 1
1913                                     + h->value.len + 1;
1914
1915                    ngx_memcpy(h->key.data, r->header_name_start, h->key.len);
1916                    h->key.data[h->key.len] = '\0';
1917                    ngx_memcpy(h->value.data, r->header_start, h->value.len);
1918                    h->value.data[h->value.len] = '\0';
1919                }
1920
1921                h->hash = r->header_hash;
1922
1923                if (h->key.len == r->lowcase_index) {
1924                    ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
1925
1926                } else {
1927                    ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
1928                }
1929
1930                hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
1931                                   h->lowcase_key, h->key.len);
1932
1933                if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1934                    return NGX_ERROR;
1935                }
1936
1937                ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1938                               "http fastcgi header: \"%V: %V\"",
1939                               &h->key, &h->value);
1940
1941                if (u->buffer.pos < u->buffer.last) {
1942                    continue;
1943                }
1944
1945                /* the end of the FastCGI record */
1946
1947                break;
1948            }
1949
1950            if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
1951
1952                /* a whole header has been parsed successfully */
1953
1954                ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1955                               "http fastcgi header done");
1956
1957                if (u->headers_in.status) {
1958                    status_line = &u->headers_in.status->value;
1959
1960                    status = ngx_atoi(status_line->data, 3);
1961
1962                    if (status == NGX_ERROR) {
1963                        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1964                                      "upstream sent invalid status \"%V\"",
1965                                      status_line);
1966                        return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1967                    }
1968
1969                    u->headers_in.status_n = status;
1970                    u->headers_in.status_line = *status_line;
1971
1972                } else if (u->headers_in.location) {
1973                    u->headers_in.status_n = 302;
1974                    ngx_str_set(&u->headers_in.status_line,
1975                                "302 Moved Temporarily");
1976
1977                } else {
1978                    u->headers_in.status_n = 200;
1979                    ngx_str_set(&u->headers_in.status_line, "200 OK");
1980                }
1981
1982                if (u->state && u->state->status == 0) {
1983                    u->state->status = u->headers_in.status_n;
1984                }
1985
1986                break;
1987            }
1988
1989            /* there was error while a header line parsing */
1990
1991            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1992                          "upstream sent invalid header");
1993
1994            return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1995        }
1996
1997        if (last) {
1998            u->buffer.last = last;
1999        }
2000
2001        f->length -= u->buffer.pos - start;
2002
2003        if (f->length == 0) {
2004            f->state = ngx_http_fastcgi_st_padding;
2005        }
2006
2007        if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
2008            return NGX_OK;
2009        }
2010
2011        if (rc == NGX_OK) {
2012            continue;
2013        }
2014
2015        /* rc == NGX_AGAIN */
2016
2017        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2018                       "upstream split a header line in FastCGI records");
2019
2020        if (f->split_parts == NULL) {
2021            f->split_parts = ngx_array_create(r->pool, 1,
2022                                        sizeof(ngx_http_fastcgi_split_part_t));
2023            if (f->split_parts == NULL) {
2024                return NGX_ERROR;
2025            }
2026        }
2027
2028        part = ngx_array_push(f->split_parts);
2029        if (part == NULL) {
2030            return NGX_ERROR;
2031        }
2032
2033        part->start = part_start;
2034        part->end = part_end;
2035
2036        if (u->buffer.pos < u->buffer.last) {
2037            continue;
2038        }
2039
2040        return NGX_AGAIN;
2041    }
2042}
2043
2044
2045static ngx_int_t
2046ngx_http_fastcgi_input_filter_init(void *data)
2047{
2048    ngx_http_request_t           *r = data;
2049    ngx_http_fastcgi_loc_conf_t  *flcf;
2050
2051    flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
2052
2053    r->upstream->pipe->length = flcf->keep_conn ?
2054                                (off_t) sizeof(ngx_http_fastcgi_header_t) : -1;
2055
2056    return NGX_OK;
2057}
2058
2059
2060static ngx_int_t
2061ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
2062{
2063    u_char                       *m, *msg;
2064    ngx_int_t                     rc;
2065    ngx_buf_t                    *b, **prev;
2066    ngx_chain_t                  *cl;
2067    ngx_http_request_t           *r;
2068    ngx_http_fastcgi_ctx_t       *f;
2069    ngx_http_fastcgi_loc_conf_t  *flcf;
2070
2071    if (buf->pos == buf->last) {
2072        return NGX_OK;
2073    }
2074
2075    r = p->input_ctx;
2076    f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
2077    flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
2078
2079    b = NULL;
2080    prev = &buf->shadow;
2081
2082    f->pos = buf->pos;
2083    f->last = buf->last;
2084
2085    for ( ;; ) {
2086        if (f->state < ngx_http_fastcgi_st_data) {
2087
2088            rc = ngx_http_fastcgi_process_record(r, f);
2089
2090            if (rc == NGX_AGAIN) {
2091                break;
2092            }
2093
2094            if (rc == NGX_ERROR) {
2095                return NGX_ERROR;
2096            }
2097
2098            if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) {
2099                f->state = ngx_http_fastcgi_st_padding;
2100
2101                if (!flcf->keep_conn) {
2102                    p->upstream_done = 1;
2103                }
2104
2105                ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
2106                               "http fastcgi closed stdout");
2107
2108                continue;
2109            }
2110
2111            if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
2112
2113                ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
2114                               "http fastcgi sent end request");
2115
2116                if (!flcf->keep_conn) {
2117                    p->upstream_done = 1;
2118                    break;
2119                }
2120
2121                continue;
2122            }
2123        }
2124
2125
2126        if (f->state == ngx_http_fastcgi_st_padding) {
2127
2128            if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
2129
2130                if (f->pos + f->padding < f->last) {
2131                    p->upstream_done = 1;
2132                    break;
2133                }
2134
2135                if (f->pos + f->padding == f->last) {
2136                    p->upstream_done = 1;
2137                    r->upstream->keepalive = 1;
2138                    break;
2139                }
2140
2141                f->padding -= f->last - f->pos;
2142
2143                break;
2144            }
2145
2146            if (f->pos + f->padding < f->last) {
2147                f->state = ngx_http_fastcgi_st_version;
2148                f->pos += f->padding;
2149
2150                continue;
2151            }
2152
2153            if (f->pos + f->padding == f->last) {
2154                f->state = ngx_http_fastcgi_st_version;
2155
2156                break;
2157            }
2158
2159            f->padding -= f->last - f->pos;
2160
2161            break;
2162        }
2163
2164
2165        /* f->state == ngx_http_fastcgi_st_data */
2166
2167        if (f->type == NGX_HTTP_FASTCGI_STDERR) {
2168
2169            if (f->length) {
2170
2171                if (f->pos == f->last) {
2172                    break;
2173                }
2174
2175                msg = f->pos;
2176
2177                if (f->pos + f->length <= f->last) {
2178                    f->pos += f->length;
2179                    f->length = 0;
2180                    f->state = ngx_http_fastcgi_st_padding;
2181
2182                } else {
2183                    f->length -= f->last - f->pos;
2184                    f->pos = f->last;
2185                }
2186
2187                for (m = f->pos - 1; msg < m; m--) {
2188                    if (*m != LF && *m != CR && *m != '.' && *m != ' ') {
2189                        break;
2190                    }
2191                }
2192
2193                ngx_log_error(NGX_LOG_ERR, p->log, 0,
2194                              "FastCGI sent in stderr: \"%*s\"",
2195                              m + 1 - msg, msg);
2196
2197            } else {
2198                f->state = ngx_http_fastcgi_st_padding;
2199            }
2200
2201            continue;
2202        }
2203
2204        if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
2205
2206            if (f->pos + f->length <= f->last) {
2207                f->state = ngx_http_fastcgi_st_padding;
2208                f->pos += f->length;
2209
2210                continue;
2211            }
2212
2213            f->length -= f->last - f->pos;
2214
2215            break;
2216        }
2217
2218
2219        /* f->type == NGX_HTTP_FASTCGI_STDOUT */
2220
2221        if (f->pos == f->last) {
2222            break;
2223        }
2224
2225        cl = ngx_chain_get_free_buf(p->pool, &p->free);
2226        if (cl == NULL) {
2227            return NGX_ERROR;
2228        }
2229
2230        b = cl->buf;
2231
2232        ngx_memzero(b, sizeof(ngx_buf_t));
2233
2234        b->pos = f->pos;
2235        b->start = buf->start;
2236        b->end = buf->end;
2237        b->tag = p->tag;
2238        b->temporary = 1;
2239        b->recycled = 1;
2240
2241        *prev = b;
2242        prev = &b->shadow;
2243
2244        if (p->in) {
2245            *p->last_in = cl;
2246        } else {
2247            p->in = cl;
2248        }
2249        p->last_in = &cl->next;
2250
2251
2252        /* STUB */ b->num = buf->num;
2253
2254        ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
2255                       "input buf #%d %p", b->num, b->pos);
2256
2257        if (f->pos + f->length <= f->last) {
2258            f->state = ngx_http_fastcgi_st_padding;
2259            f->pos += f->length;
2260            b->last = f->pos;
2261
2262            continue;
2263        }
2264
2265        f->length -= f->last - f->pos;
2266
2267        b->last = f->last;
2268
2269        break;
2270
2271    }
2272
2273    if (flcf->keep_conn) {
2274
2275        /* set p->length, minimal amount of data we want to see */
2276
2277        if (f->state < ngx_http_fastcgi_st_data) {
2278            p->length = 1;
2279
2280        } else if (f->state == ngx_http_fastcgi_st_padding) {
2281            p->length = f->padding;
2282
2283        } else {
2284            /* ngx_http_fastcgi_st_data */
2285
2286            p->length = f->length;
2287        }
2288    }
2289
2290    if (b) {
2291        b->shadow = buf;
2292        b->last_shadow = 1;
2293
2294        ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
2295                       "input buf %p %z", b->pos, b->last - b->pos);
2296
2297        return NGX_OK;
2298    }
2299
2300    /* there is no data record in the buf, add it to free chain */
2301
2302    if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) {
2303        return NGX_ERROR;
2304    }
2305
2306    return NGX_OK;
2307}
2308
2309
2310static ngx_int_t
2311ngx_http_fastcgi_non_buffered_filter(void *data, ssize_t bytes)
2312{
2313    u_char                  *m, *msg;
2314    ngx_int_t                rc;
2315    ngx_buf_t               *b, *buf;
2316    ngx_chain_t             *cl, **ll;
2317    ngx_http_request_t      *r;
2318    ngx_http_upstream_t     *u;
2319    ngx_http_fastcgi_ctx_t  *f;
2320
2321    r = data;
2322    f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
2323
2324    u = r->upstream;
2325    buf = &u->buffer;
2326
2327    buf->pos = buf->last;
2328    buf->last += bytes;
2329
2330    for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
2331        ll = &cl->next;
2332    }
2333
2334    f->pos = buf->pos;
2335    f->last = buf->last;
2336
2337    for ( ;; ) {
2338        if (f->state < ngx_http_fastcgi_st_data) {
2339
2340            rc = ngx_http_fastcgi_process_record(r, f);
2341
2342            if (rc == NGX_AGAIN) {
2343                break;
2344            }
2345
2346            if (rc == NGX_ERROR) {
2347                return NGX_ERROR;
2348            }
2349
2350            if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) {
2351                f->state = ngx_http_fastcgi_st_padding;
2352
2353                ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2354                               "http fastcgi closed stdout");
2355
2356                continue;
2357            }
2358        }
2359
2360        if (f->state == ngx_http_fastcgi_st_padding) {
2361
2362            if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
2363
2364                if (f->pos + f->padding < f->last) {
2365                    u->length = 0;
2366                    break;
2367                }
2368
2369                if (f->pos + f->padding == f->last) {
2370                    u->length = 0;
2371                    u->keepalive = 1;
2372                    break;
2373                }
2374
2375                f->padding -= f->last - f->pos;
2376
2377                break;
2378            }
2379
2380            if (f->pos + f->padding < f->last) {
2381                f->state = ngx_http_fastcgi_st_version;
2382                f->pos += f->padding;
2383
2384                continue;
2385            }
2386
2387            if (f->pos + f->padding == f->last) {
2388                f->state = ngx_http_fastcgi_st_version;
2389
2390                break;
2391            }
2392
2393            f->padding -= f->last - f->pos;
2394
2395            break;
2396        }
2397
2398
2399        /* f->state == ngx_http_fastcgi_st_data */
2400
2401        if (f->type == NGX_HTTP_FASTCGI_STDERR) {
2402
2403            if (f->length) {
2404
2405                if (f->pos == f->last) {
2406                    break;
2407                }
2408
2409                msg = f->pos;
2410
2411                if (f->pos + f->length <= f->last) {
2412                    f->pos += f->length;
2413                    f->length = 0;
2414                    f->state = ngx_http_fastcgi_st_padding;
2415
2416                } else {
2417                    f->length -= f->last - f->pos;
2418                    f->pos = f->last;
2419                }
2420
2421                for (m = f->pos - 1; msg < m; m--) {
2422                    if (*m != LF && *m != CR && *m != '.' && *m != ' ') {
2423                        break;
2424                    }
2425                }
2426
2427                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2428                              "FastCGI sent in stderr: \"%*s\"",
2429                              m + 1 - msg, msg);
2430
2431            } else {
2432                f->state = ngx_http_fastcgi_st_padding;
2433            }
2434
2435            continue;
2436        }
2437
2438        if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
2439
2440            if (f->pos + f->length <= f->last) {
2441                f->state = ngx_http_fastcgi_st_padding;
2442                f->pos += f->length;
2443
2444                continue;
2445            }
2446
2447            f->length -= f->last - f->pos;
2448
2449            break;
2450        }
2451
2452
2453        /* f->type == NGX_HTTP_FASTCGI_STDOUT */
2454
2455        if (f->pos == f->last) {
2456            break;
2457        }
2458
2459        cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
2460        if (cl == NULL) {
2461            return NGX_ERROR;
2462        }
2463
2464        *ll = cl;
2465        ll = &cl->next;
2466
2467        b = cl->buf;
2468
2469        b->flush = 1;
2470        b->memory = 1;
2471
2472        b->pos = f->pos;
2473        b->tag = u->output.tag;
2474
2475        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2476                       "http fastcgi output buf %p", b->pos);
2477
2478        if (f->pos + f->length <= f->last) {
2479            f->state = ngx_http_fastcgi_st_padding;
2480            f->pos += f->length;
2481            b->last = f->pos;
2482
2483            continue;
2484        }
2485
2486        f->length -= f->last - f->pos;
2487        b->last = f->last;
2488
2489        break;
2490    }
2491
2492    /* provide continuous buffer for subrequests in memory */
2493
2494    if (r->subrequest_in_memory) {
2495
2496        cl = u->out_bufs;
2497
2498        if (cl) {
2499            buf->pos = cl->buf->pos;
2500        }
2501
2502        buf->last = buf->pos;
2503
2504        for (cl = u->out_bufs; cl; cl = cl->next) {
2505            ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2506                           "http fastcgi in memory %p-%p %uz",
2507                           cl->buf->pos, cl->buf->last, ngx_buf_size(cl->buf));
2508
2509            if (buf->last == cl->buf->pos) {
2510                buf->last = cl->buf->last;
2511                continue;
2512            }
2513
2514            buf->last = ngx_movemem(buf->last, cl->buf->pos,
2515                                    cl->buf->last - cl->buf->pos);
2516
2517            cl->buf->pos = buf->last - (cl->buf->last - cl->buf->pos);
2518            cl->buf->last = buf->last;
2519        }
2520    }
2521
2522    return NGX_OK;
2523}
2524
2525
2526static ngx_int_t
2527ngx_http_fastcgi_process_record(ngx_http_request_t *r,
2528    ngx_http_fastcgi_ctx_t *f)
2529{
2530    u_char                     ch, *p;
2531    ngx_http_fastcgi_state_e   state;
2532
2533    state = f->state;
2534
2535    for (p = f->pos; p < f->last; p++) {
2536
2537        ch = *p;
2538
2539        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2540                       "http fastcgi record byte: %02Xd", ch);
2541
2542        switch (state) {
2543
2544        case ngx_http_fastcgi_st_version:
2545            if (ch != 1) {
2546                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2547                              "upstream sent unsupported FastCGI "
2548                              "protocol version: %d", ch);
2549                return NGX_ERROR;
2550            }
2551            state = ngx_http_fastcgi_st_type;
2552            break;
2553
2554        case ngx_http_fastcgi_st_type:
2555            switch (ch) {
2556            case NGX_HTTP_FASTCGI_STDOUT:
2557            case NGX_HTTP_FASTCGI_STDERR:
2558            case NGX_HTTP_FASTCGI_END_REQUEST:
2559                 f->type = (ngx_uint_t) ch;
2560                 break;
2561            default:
2562                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2563                              "upstream sent invalid FastCGI "
2564                              "record type: %d", ch);
2565                return NGX_ERROR;
2566
2567            }
2568            state = ngx_http_fastcgi_st_request_id_hi;
2569            break;
2570
2571        /* we support the single request per connection */
2572
2573        case ngx_http_fastcgi_st_request_id_hi:
2574            if (ch != 0) {
2575                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2576                              "upstream sent unexpected FastCGI "
2577                              "request id high byte: %d", ch);
2578                return NGX_ERROR;
2579            }
2580            state = ngx_http_fastcgi_st_request_id_lo;
2581            break;
2582
2583        case ngx_http_fastcgi_st_request_id_lo:
2584            if (ch != 1) {
2585                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2586                              "upstream sent unexpected FastCGI "
2587                              "request id low byte: %d", ch);
2588                return NGX_ERROR;
2589            }
2590            state = ngx_http_fastcgi_st_content_length_hi;
2591            break;
2592
2593        case ngx_http_fastcgi_st_content_length_hi:
2594            f->length = ch << 8;
2595            state = ngx_http_fastcgi_st_content_length_lo;
2596            break;
2597
2598        case ngx_http_fastcgi_st_content_length_lo:
2599            f->length |= (size_t) ch;
2600            state = ngx_http_fastcgi_st_padding_length;
2601            break;
2602
2603        case ngx_http_fastcgi_st_padding_length:
2604            f->padding = (size_t) ch;
2605            state = ngx_http_fastcgi_st_reserved;
2606            break;
2607
2608        case ngx_http_fastcgi_st_reserved:
2609            state = ngx_http_fastcgi_st_data;
2610
2611            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2612                           "http fastcgi record length: %z", f->length);
2613
2614            f->pos = p + 1;
2615            f->state = state;
2616
2617            return NGX_OK;
2618
2619        /* suppress warning */
2620        case ngx_http_fastcgi_st_data:
2621        case ngx_http_fastcgi_st_padding:
2622            break;
2623        }
2624    }
2625
2626    f->state = state;
2627
2628    return NGX_AGAIN;
2629}
2630
2631
2632static void
2633ngx_http_fastcgi_abort_request(ngx_http_request_t *r)
2634{
2635    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2636                   "abort http fastcgi request");
2637
2638    return;
2639}
2640
2641
2642static void
2643ngx_http_fastcgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
2644{
2645    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2646                   "finalize http fastcgi request");
2647
2648    return;
2649}
2650
2651
2652static ngx_int_t
2653ngx_http_fastcgi_add_variables(ngx_conf_t *cf)
2654{
2655   ngx_http_variable_t  *var, *v;
2656
2657    for (v = ngx_http_fastcgi_vars; v->name.len; v++) {
2658        var = ngx_http_add_variable(cf, &v->name, v->flags);
2659        if (var == NULL) {
2660            return NGX_ERROR;
2661        }
2662
2663        var->get_handler = v->get_handler;
2664        var->data = v->data;
2665    }
2666
2667    return NGX_OK;
2668}
2669
2670
2671static void *
2672ngx_http_fastcgi_create_main_conf(ngx_conf_t *cf)
2673{
2674    ngx_http_fastcgi_main_conf_t  *conf;
2675
2676    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_main_conf_t));
2677    if (conf == NULL) {
2678        return NULL;
2679    }
2680
2681#if (NGX_HTTP_CACHE)
2682    if (ngx_array_init(&conf->caches, cf->pool, 4,
2683                       sizeof(ngx_http_file_cache_t *))
2684        != NGX_OK)
2685    {
2686        return NULL;
2687    }
2688#endif
2689
2690    return conf;
2691}
2692
2693
2694static void *
2695ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
2696{
2697    ngx_http_fastcgi_loc_conf_t  *conf;
2698
2699    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_loc_conf_t));
2700    if (conf == NULL) {
2701        return NULL;
2702    }
2703
2704    /*
2705     * set by ngx_pcalloc():
2706     *
2707     *     conf->upstream.bufs.num = 0;
2708     *     conf->upstream.ignore_headers = 0;
2709     *     conf->upstream.next_upstream = 0;
2710     *     conf->upstream.cache_zone = NULL;
2711     *     conf->upstream.cache_use_stale = 0;
2712     *     conf->upstream.cache_methods = 0;
2713     *     conf->upstream.temp_path = NULL;
2714     *     conf->upstream.hide_headers_hash = { NULL, 0 };
2715     *     conf->upstream.uri = { 0, NULL };
2716     *     conf->upstream.location = NULL;
2717     *     conf->upstream.store_lengths = NULL;
2718     *     conf->upstream.store_values = NULL;
2719     *
2720     *     conf->index.len = { 0, NULL };
2721     */
2722
2723    conf->upstream.store = NGX_CONF_UNSET;
2724    conf->upstream.store_access = NGX_CONF_UNSET_UINT;
2725    conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
2726    conf->upstream.buffering = NGX_CONF_UNSET;
2727    conf->upstream.request_buffering = NGX_CONF_UNSET;
2728    conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
2729    conf->upstream.force_ranges = NGX_CONF_UNSET;
2730
2731    conf->upstream.local = NGX_CONF_UNSET_PTR;
2732
2733    conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
2734    conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
2735    conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
2736    conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC;
2737
2738    conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
2739    conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
2740    conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE;
2741
2742    conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
2743    conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
2744    conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;
2745
2746    conf->upstream.pass_request_headers = NGX_CONF_UNSET;
2747    conf->upstream.pass_request_body = NGX_CONF_UNSET;
2748
2749#if (NGX_HTTP_CACHE)
2750    conf->upstream.cache = NGX_CONF_UNSET;
2751    conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
2752    conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
2753    conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
2754    conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
2755    conf->upstream.cache_lock = NGX_CONF_UNSET;
2756    conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
2757    conf->upstream.cache_lock_age = NGX_CONF_UNSET_MSEC;
2758    conf->upstream.cache_revalidate = NGX_CONF_UNSET;
2759#endif
2760
2761    conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
2762    conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
2763
2764    conf->upstream.intercept_errors = NGX_CONF_UNSET;
2765
2766    /* "fastcgi_cyclic_temp_file" is disabled */
2767    conf->upstream.cyclic_temp_file = 0;
2768
2769    conf->upstream.change_buffering = 1;
2770
2771    conf->catch_stderr = NGX_CONF_UNSET_PTR;
2772
2773    conf->keep_conn = NGX_CONF_UNSET;
2774
2775    ngx_str_set(&conf->upstream.module, "fastcgi");
2776
2777    return conf;
2778}
2779
2780
2781static char *
2782ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
2783{
2784    ngx_http_fastcgi_loc_conf_t *prev = parent;
2785    ngx_http_fastcgi_loc_conf_t *conf = child;
2786
2787    size_t                        size;
2788    ngx_int_t                     rc;
2789    ngx_hash_init_t               hash;
2790    ngx_http_core_loc_conf_t     *clcf;
2791
2792#if (NGX_HTTP_CACHE)
2793
2794    if (conf->upstream.store > 0) {
2795        conf->upstream.cache = 0;
2796    }
2797
2798    if (conf->upstream.cache > 0) {
2799        conf->upstream.store = 0;
2800    }
2801
2802#endif
2803
2804    if (conf->upstream.store == NGX_CONF_UNSET) {
2805        ngx_conf_merge_value(conf->upstream.store,
2806                              prev->upstream.store, 0);
2807
2808        conf->upstream.store_lengths = prev->upstream.store_lengths;
2809        conf->upstream.store_values = prev->upstream.store_values;
2810    }
2811
2812    ngx_conf_merge_uint_value(conf->upstream.store_access,
2813                              prev->upstream.store_access, 0600);
2814
2815    ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
2816                              prev->upstream.next_upstream_tries, 0);
2817
2818    ngx_conf_merge_value(conf->upstream.buffering,
2819                              prev->upstream.buffering, 1);
2820
2821    ngx_conf_merge_value(conf->upstream.request_buffering,
2822                              prev->upstream.request_buffering, 1);
2823
2824    ngx_conf_merge_value(conf->upstream.ignore_client_abort,
2825                              prev->upstream.ignore_client_abort, 0);
2826
2827    ngx_conf_merge_value(conf->upstream.force_ranges,
2828                              prev->upstream.force_ranges, 0);
2829
2830    ngx_conf_merge_ptr_value(conf->upstream.local,
2831                              prev->upstream.local, NULL);
2832
2833    ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
2834                              prev->upstream.connect_timeout, 60000);
2835
2836    ngx_conf_merge_msec_value(conf->upstream.send_timeout,
2837                              prev->upstream.send_timeout, 60000);
2838
2839    ngx_conf_merge_msec_value(conf->upstream.read_timeout,
2840                              prev->upstream.read_timeout, 60000);
2841
2842    ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
2843                              prev->upstream.next_upstream_timeout, 0);
2844
2845    ngx_conf_merge_size_value(conf->upstream.send_lowat,
2846                              prev->upstream.send_lowat, 0);
2847
2848    ngx_conf_merge_size_value(conf->upstream.buffer_size,
2849                              prev->upstream.buffer_size,
2850                              (size_t) ngx_pagesize);
2851
2852    ngx_conf_merge_size_value(conf->upstream.limit_rate,
2853                              prev->upstream.limit_rate, 0);
2854
2855
2856    ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
2857                              8, ngx_pagesize);
2858
2859    if (conf->upstream.bufs.num < 2) {
2860        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2861                           "there must be at least 2 \"fastcgi_buffers\"");
2862        return NGX_CONF_ERROR;
2863    }
2864
2865
2866    size = conf->upstream.buffer_size;
2867    if (size < conf->upstream.bufs.size) {
2868        size = conf->upstream.bufs.size;
2869    }
2870
2871
2872    ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
2873                              prev->upstream.busy_buffers_size_conf,
2874                              NGX_CONF_UNSET_SIZE);
2875
2876    if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
2877        conf->upstream.busy_buffers_size = 2 * size;
2878    } else {
2879        conf->upstream.busy_buffers_size =
2880                                         conf->upstream.busy_buffers_size_conf;
2881    }
2882
2883    if (conf->upstream.busy_buffers_size < size) {
2884        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2885             "\"fastcgi_busy_buffers_size\" must be equal to or greater than "
2886             "the maximum of the value of \"fastcgi_buffer_size\" and "
2887             "one of the \"fastcgi_buffers\"");
2888
2889        return NGX_CONF_ERROR;
2890    }
2891
2892    if (conf->upstream.busy_buffers_size
2893        > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
2894    {
2895        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2896             "\"fastcgi_busy_buffers_size\" must be less than "
2897             "the size of all \"fastcgi_buffers\" minus one buffer");
2898
2899        return NGX_CONF_ERROR;
2900    }
2901
2902
2903    ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf,
2904                              prev->upstream.temp_file_write_size_conf,
2905                              NGX_CONF_UNSET_SIZE);
2906
2907    if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
2908        conf->upstream.temp_file_write_size = 2 * size;
2909    } else {
2910        conf->upstream.temp_file_write_size =
2911                                      conf->upstream.temp_file_write_size_conf;
2912    }
2913
2914    if (conf->upstream.temp_file_write_size < size) {
2915        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2916             "\"fastcgi_temp_file_write_size\" must be equal to or greater "
2917             "than the maximum of the value of \"fastcgi_buffer_size\" and "
2918             "one of the \"fastcgi_buffers\"");
2919
2920        return NGX_CONF_ERROR;
2921    }
2922
2923
2924    ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf,
2925                              prev->upstream.max_temp_file_size_conf,
2926                              NGX_CONF_UNSET_SIZE);
2927
2928    if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
2929        conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
2930    } else {
2931        conf->upstream.max_temp_file_size =
2932                                        conf->upstream.max_temp_file_size_conf;
2933    }
2934
2935    if (conf->upstream.max_temp_file_size != 0
2936        && conf->upstream.max_temp_file_size < size)
2937    {
2938        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2939             "\"fastcgi_max_temp_file_size\" must be equal to zero to disable "
2940             "temporary files usage or must be equal to or greater than "
2941             "the maximum of the value of \"fastcgi_buffer_size\" and "
2942             "one of the \"fastcgi_buffers\"");
2943
2944        return NGX_CONF_ERROR;
2945    }
2946
2947
2948    ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
2949                              prev->upstream.ignore_headers,
2950                              NGX_CONF_BITMASK_SET);
2951
2952
2953    ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
2954                              prev->upstream.next_upstream,
2955                              (NGX_CONF_BITMASK_SET
2956                               |NGX_HTTP_UPSTREAM_FT_ERROR
2957                               |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
2958
2959    if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
2960        conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
2961                                       |NGX_HTTP_UPSTREAM_FT_OFF;
2962    }
2963
2964    if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
2965                              prev->upstream.temp_path,
2966                              &ngx_http_fastcgi_temp_path)
2967        != NGX_OK)
2968    {
2969        return NGX_CONF_ERROR;
2970    }
2971
2972#if (NGX_HTTP_CACHE)
2973
2974    if (conf->upstream.cache == NGX_CONF_UNSET) {
2975        ngx_conf_merge_value(conf->upstream.cache,
2976                              prev->upstream.cache, 0);
2977
2978        conf->upstream.cache_zone = prev->upstream.cache_zone;
2979        conf->upstream.cache_value = prev->upstream.cache_value;
2980    }
2981
2982    if (conf->upstream.cache_zone && conf->upstream.cache_zone->data == NULL) {
2983        ngx_shm_zone_t  *shm_zone;
2984
2985        shm_zone = conf->upstream.cache_zone;
2986
2987        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2988                           "\"fastcgi_cache\" zone \"%V\" is unknown",
2989                           &shm_zone->shm.name);
2990
2991        return NGX_CONF_ERROR;
2992    }
2993
2994    ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
2995                              prev->upstream.cache_min_uses, 1);
2996
2997    ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
2998                              prev->upstream.cache_use_stale,
2999                              (NGX_CONF_BITMASK_SET
3000                               |NGX_HTTP_UPSTREAM_FT_OFF));
3001
3002    if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
3003        conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
3004                                         |NGX_HTTP_UPSTREAM_FT_OFF;
3005    }
3006
3007    if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
3008        conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
3009    }
3010
3011    if (conf->upstream.cache_methods == 0) {
3012        conf->upstream.cache_methods = prev->upstream.cache_methods;
3013    }
3014
3015    conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD;
3016
3017    ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
3018                             prev->upstream.cache_bypass, NULL);
3019
3020    ngx_conf_merge_ptr_value(conf->upstream.no_cache,
3021                             prev->upstream.no_cache, NULL);
3022
3023    ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
3024                             prev->upstream.cache_valid, NULL);
3025
3026    if (conf->cache_key.value.data == NULL) {
3027        conf->cache_key = prev->cache_key;
3028    }
3029
3030    if (conf->upstream.cache && conf->cache_key.value.data == NULL) {
3031        ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
3032                           "no \"fastcgi_cache_key\" for \"fastcgi_cache\"");
3033    }
3034
3035    ngx_conf_merge_value(conf->upstream.cache_lock,
3036                              prev->upstream.cache_lock, 0);
3037
3038    ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
3039                              prev->upstream.cache_lock_timeout, 5000);
3040
3041    ngx_conf_merge_msec_value(conf->upstream.cache_lock_age,
3042                              prev->upstream.cache_lock_age, 5000);
3043
3044    ngx_conf_merge_value(conf->upstream.cache_revalidate,
3045                              prev->upstream.cache_revalidate, 0);
3046
3047#endif
3048
3049    ngx_conf_merge_value(conf->upstream.pass_request_headers,
3050                              prev->upstream.pass_request_headers, 1);
3051    ngx_conf_merge_value(conf->upstream.pass_request_body,
3052                              prev->upstream.pass_request_body, 1);
3053
3054    ngx_conf_merge_value(conf->upstream.intercept_errors,
3055                              prev->upstream.intercept_errors, 0);
3056
3057    ngx_conf_merge_ptr_value(conf->catch_stderr, prev->catch_stderr, NULL);
3058
3059    ngx_conf_merge_value(conf->keep_conn, prev->keep_conn, 0);
3060
3061
3062    ngx_conf_merge_str_value(conf->index, prev->index, "");
3063
3064    hash.max_size = 512;
3065    hash.bucket_size = ngx_align(64, ngx_cacheline_size);
3066    hash.name = "fastcgi_hide_headers_hash";
3067
3068    if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
3069             &prev->upstream, ngx_http_fastcgi_hide_headers, &hash)
3070        != NGX_OK)
3071    {
3072        return NGX_CONF_ERROR;
3073    }
3074
3075    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
3076
3077    if (clcf->noname
3078        && conf->upstream.upstream == NULL && conf->fastcgi_lengths == NULL)
3079    {
3080        conf->upstream.upstream = prev->upstream.upstream;
3081        conf->fastcgi_lengths = prev->fastcgi_lengths;
3082        conf->fastcgi_values = prev->fastcgi_values;
3083    }
3084
3085    if (clcf->lmt_excpt && clcf->handler == NULL
3086        && (conf->upstream.upstream || conf->fastcgi_lengths))
3087    {
3088        clcf->handler = ngx_http_fastcgi_handler;
3089    }
3090
3091#if (NGX_PCRE)
3092    if (conf->split_regex == NULL) {
3093        conf->split_regex = prev->split_regex;
3094        conf->split_name = prev->split_name;
3095    }
3096#endif
3097
3098    if (conf->params_source == NULL) {
3099        conf->params = prev->params;
3100#if (NGX_HTTP_CACHE)
3101        conf->params_cache = prev->params_cache;
3102#endif
3103        conf->params_source = prev->params_source;
3104    }
3105
3106    rc = ngx_http_fastcgi_init_params(cf, conf, &conf->params, NULL);
3107    if (rc != NGX_OK) {
3108        return NGX_CONF_ERROR;
3109    }
3110
3111#if (NGX_HTTP_CACHE)
3112
3113    if (conf->upstream.cache) {
3114        rc = ngx_http_fastcgi_init_params(cf, conf, &conf->params_cache,
3115                                          ngx_http_fastcgi_cache_headers);
3116        if (rc != NGX_OK) {
3117            return NGX_CONF_ERROR;
3118        }
3119    }
3120
3121#endif
3122
3123    return NGX_CONF_OK;
3124}
3125
3126
3127static ngx_int_t
3128ngx_http_fastcgi_init_params(ngx_conf_t *cf, ngx_http_fastcgi_loc_conf_t *conf,
3129    ngx_http_fastcgi_params_t *params, ngx_keyval_t *default_params)
3130{
3131    u_char                       *p;
3132    size_t                        size;
3133    uintptr_t                    *code;
3134    ngx_uint_t                    i, nsrc;
3135    ngx_array_t                   headers_names, params_merged;
3136    ngx_keyval_t                 *h;
3137    ngx_hash_key_t               *hk;
3138    ngx_hash_init_t               hash;
3139    ngx_http_upstream_param_t    *src, *s;
3140    ngx_http_script_compile_t     sc;
3141    ngx_http_script_copy_code_t  *copy;
3142
3143    if (params->hash.buckets) {
3144        return NGX_OK;
3145    }
3146
3147    if (conf->params_source == NULL && default_params == NULL) {
3148        params->hash.buckets = (void *) 1;
3149        return NGX_OK;
3150    }
3151
3152    params->lengths = ngx_array_create(cf->pool, 64, 1);
3153    if (params->lengths == NULL) {
3154        return NGX_ERROR;
3155    }
3156
3157    params->values = ngx_array_create(cf->pool, 512, 1);
3158    if (params->values == NULL) {
3159        return NGX_ERROR;
3160    }
3161
3162    if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
3163        != NGX_OK)
3164    {
3165        return NGX_ERROR;
3166    }
3167
3168    if (conf->params_source) {
3169        src = conf->params_source->elts;
3170        nsrc = conf->params_source->nelts;
3171
3172    } else {
3173        src = NULL;
3174        nsrc = 0;
3175    }
3176
3177    if (default_params) {
3178        if (ngx_array_init(&params_merged, cf->temp_pool, 4,
3179                           sizeof(ngx_http_upstream_param_t))
3180            != NGX_OK)
3181        {
3182            return NGX_ERROR;
3183        }
3184
3185        for (i = 0; i < nsrc; i++) {
3186
3187            s = ngx_array_push(&params_merged);
3188            if (s == NULL) {
3189                return NGX_ERROR;
3190            }
3191
3192            *s = src[i];
3193        }
3194
3195        h = default_params;
3196
3197        while (h->key.len) {
3198
3199            src = params_merged.elts;
3200            nsrc = params_merged.nelts;
3201
3202            for (i = 0; i < nsrc; i++) {
3203                if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
3204                    goto next;
3205                }
3206            }
3207
3208            s = ngx_array_push(&params_merged);
3209            if (s == NULL) {
3210                return NGX_ERROR;
3211            }
3212
3213            s->key = h->key;
3214            s->value = h->value;
3215            s->skip_empty = 1;
3216
3217        next:
3218
3219            h++;
3220        }
3221
3222        src = params_merged.elts;
3223        nsrc = params_merged.nelts;
3224    }
3225
3226    for (i = 0; i < nsrc; i++) {
3227
3228        if (src[i].key.len > sizeof("HTTP_") - 1
3229            && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0)
3230        {
3231            hk = ngx_array_push(&headers_names);
3232            if (hk == NULL) {
3233                return NGX_ERROR;
3234            }
3235
3236            hk->key.len = src[i].key.len - 5;
3237            hk->key.data = src[i].key.data + 5;
3238            hk->key_hash = ngx_hash_key_lc(hk->key.data, hk->key.len);
3239            hk->value = (void *) 1;
3240
3241            if (src[i].value.len == 0) {
3242                continue;
3243            }
3244        }
3245
3246        copy = ngx_array_push_n(params->lengths,
3247                                sizeof(ngx_http_script_copy_code_t));
3248        if (copy == NULL) {
3249            return NGX_ERROR;
3250        }
3251
3252        copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
3253        copy->len = src[i].key.len;
3254
3255        copy = ngx_array_push_n(params->lengths,
3256                                sizeof(ngx_http_script_copy_code_t));
3257        if (copy == NULL) {
3258            return NGX_ERROR;
3259        }
3260
3261        copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
3262        copy->len = src[i].skip_empty;
3263
3264
3265        size = (sizeof(ngx_http_script_copy_code_t)
3266                + src[i].key.len + sizeof(uintptr_t) - 1)
3267               & ~(sizeof(uintptr_t) - 1);
3268
3269        copy = ngx_array_push_n(params->values, size);
3270        if (copy == NULL) {
3271            return NGX_ERROR;
3272        }
3273
3274        copy->code = ngx_http_script_copy_code;
3275        copy->len = src[i].key.len;
3276
3277        p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
3278        ngx_memcpy(p, src[i].key.data, src[i].key.len);
3279
3280
3281        ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3282
3283        sc.cf = cf;
3284        sc.source = &src[i].value;
3285        sc.flushes = &params->flushes;
3286        sc.lengths = &params->lengths;
3287        sc.values = &params->values;
3288
3289        if (ngx_http_script_compile(&sc) != NGX_OK) {
3290            return NGX_ERROR;
3291        }
3292
3293        code = ngx_array_push_n(params->lengths, sizeof(uintptr_t));
3294        if (code == NULL) {
3295            return NGX_ERROR;
3296        }
3297
3298        *code = (uintptr_t) NULL;
3299
3300
3301        code = ngx_array_push_n(params->values, sizeof(uintptr_t));
3302        if (code == NULL) {
3303            return NGX_ERROR;
3304        }
3305
3306        *code = (uintptr_t) NULL;
3307    }
3308
3309    code = ngx_array_push_n(params->lengths, sizeof(uintptr_t));
3310    if (code == NULL) {
3311        return NGX_ERROR;
3312    }
3313
3314    *code = (uintptr_t) NULL;
3315
3316    params->number = headers_names.nelts;
3317
3318    hash.hash = &params->hash;
3319    hash.key = ngx_hash_key_lc;
3320    hash.max_size = 512;
3321    hash.bucket_size = 64;
3322    hash.name = "fastcgi_params_hash";
3323    hash.pool = cf->pool;
3324    hash.temp_pool = NULL;
3325
3326    return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
3327}
3328
3329
3330static ngx_int_t
3331ngx_http_fastcgi_script_name_variable(ngx_http_request_t *r,
3332    ngx_http_variable_value_t *v, uintptr_t data)
3333{
3334    u_char                       *p;
3335    ngx_http_fastcgi_ctx_t       *f;
3336    ngx_http_fastcgi_loc_conf_t  *flcf;
3337
3338    flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
3339
3340    f = ngx_http_fastcgi_split(r, flcf);
3341
3342    if (f == NULL) {
3343        return NGX_ERROR;
3344    }
3345
3346    if (f->script_name.len == 0
3347        || f->script_name.data[f->script_name.len - 1] != '/')
3348    {
3349        v->len = f->script_name.len;
3350        v->valid = 1;
3351        v->no_cacheable = 0;
3352        v->not_found = 0;
3353        v->data = f->script_name.data;
3354
3355        return NGX_OK;
3356    }
3357
3358    v->len = f->script_name.len + flcf->index.len;
3359
3360    v->data = ngx_pnalloc(r->pool, v->len);
3361    if (v->data == NULL) {
3362        return NGX_ERROR;
3363    }
3364
3365    p = ngx_copy(v->data, f->script_name.data, f->script_name.len);
3366    ngx_memcpy(p, flcf->index.data, flcf->index.len);
3367
3368    return NGX_OK;
3369}
3370
3371
3372static ngx_int_t
3373ngx_http_fastcgi_path_info_variable(ngx_http_request_t *r,
3374    ngx_http_variable_value_t *v, uintptr_t data)
3375{
3376    ngx_http_fastcgi_ctx_t       *f;
3377    ngx_http_fastcgi_loc_conf_t  *flcf;
3378
3379    flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
3380
3381    f = ngx_http_fastcgi_split(r, flcf);
3382
3383    if (f == NULL) {
3384        return NGX_ERROR;
3385    }
3386
3387    v->len = f->path_info.len;
3388    v->valid = 1;
3389    v->no_cacheable = 0;
3390    v->not_found = 0;
3391    v->data = f->path_info.data;
3392
3393    return NGX_OK;
3394}
3395
3396
3397static ngx_http_fastcgi_ctx_t *
3398ngx_http_fastcgi_split(ngx_http_request_t *r, ngx_http_fastcgi_loc_conf_t *flcf)
3399{
3400    ngx_http_fastcgi_ctx_t       *f;
3401#if (NGX_PCRE)
3402    ngx_int_t                     n;
3403    int                           captures[(1 + 2) * 3];
3404
3405    f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
3406
3407    if (f == NULL) {
3408        f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
3409        if (f == NULL) {
3410            return NULL;
3411        }
3412
3413        ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
3414    }
3415
3416    if (f->script_name.len) {
3417        return f;
3418    }
3419
3420    if (flcf->split_regex == NULL) {
3421        f->script_name = r->uri;
3422        return f;
3423    }
3424
3425    n = ngx_regex_exec(flcf->split_regex, &r->uri, captures, (1 + 2) * 3);
3426
3427    if (n >= 0) { /* match */
3428        f->script_name.len = captures[3] - captures[2];
3429        f->script_name.data = r->uri.data + captures[2];
3430
3431        f->path_info.len = captures[5] - captures[4];
3432        f->path_info.data = r->uri.data + captures[4];
3433
3434        return f;
3435    }
3436
3437    if (n == NGX_REGEX_NO_MATCHED) {
3438        f->script_name = r->uri;
3439        return f;
3440    }
3441
3442    ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
3443                  ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"",
3444                  n, &r->uri, &flcf->split_name);
3445    return NULL;
3446
3447#else
3448
3449    f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
3450
3451    if (f == NULL) {
3452        f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
3453        if (f == NULL) {
3454            return NULL;
3455        }
3456
3457        ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
3458    }
3459
3460    f->script_name = r->uri;
3461
3462    return f;
3463
3464#endif
3465}
3466
3467
3468static char *
3469ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3470{
3471    ngx_http_fastcgi_loc_conf_t *flcf = conf;
3472
3473    ngx_url_t                   u;
3474    ngx_str_t                  *value, *url;
3475    ngx_uint_t                  n;
3476    ngx_http_core_loc_conf_t   *clcf;
3477    ngx_http_script_compile_t   sc;
3478
3479    if (flcf->upstream.upstream || flcf->fastcgi_lengths) {
3480        return "is duplicate";
3481    }
3482
3483    clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
3484
3485    clcf->handler = ngx_http_fastcgi_handler;
3486
3487    if (clcf->name.data[clcf->name.len - 1] == '/') {
3488        clcf->auto_redirect = 1;
3489    }
3490
3491    value = cf->args->elts;
3492
3493    url = &value[1];
3494
3495    n = ngx_http_script_variables_count(url);
3496
3497    if (n) {
3498
3499        ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3500
3501        sc.cf = cf;
3502        sc.source = url;
3503        sc.lengths = &flcf->fastcgi_lengths;
3504        sc.values = &flcf->fastcgi_values;
3505        sc.variables = n;
3506        sc.complete_lengths = 1;
3507        sc.complete_values = 1;
3508
3509        if (ngx_http_script_compile(&sc) != NGX_OK) {
3510            return NGX_CONF_ERROR;
3511        }
3512
3513        return NGX_CONF_OK;
3514    }
3515
3516    ngx_memzero(&u, sizeof(ngx_url_t));
3517
3518    u.url = value[1];
3519    u.no_resolve = 1;
3520
3521    flcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
3522    if (flcf->upstream.upstream == NULL) {
3523        return NGX_CONF_ERROR;
3524    }
3525
3526    return NGX_CONF_OK;
3527}
3528
3529
3530static char *
3531ngx_http_fastcgi_split_path_info(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3532{
3533#if (NGX_PCRE)
3534    ngx_http_fastcgi_loc_conf_t *flcf = conf;
3535
3536    ngx_str_t            *value;
3537    ngx_regex_compile_t   rc;
3538    u_char                errstr[NGX_MAX_CONF_ERRSTR];
3539
3540    value = cf->args->elts;
3541
3542    flcf->split_name = value[1];
3543
3544    ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
3545
3546    rc.pattern = value[1];
3547    rc.pool = cf->pool;
3548    rc.err.len = NGX_MAX_CONF_ERRSTR;
3549    rc.err.data = errstr;
3550
3551    if (ngx_regex_compile(&rc) != NGX_OK) {
3552        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err);
3553        return NGX_CONF_ERROR;
3554    }
3555
3556    if (rc.captures != 2) {
3557        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3558                           "pattern \"%V\" must have 2 captures", &value[1]);
3559        return NGX_CONF_ERROR;
3560    }
3561
3562    flcf->split_regex = rc.regex;
3563
3564    return NGX_CONF_OK;
3565
3566#else
3567
3568    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3569                       "\"%V\" requires PCRE library", &cmd->name);
3570    return NGX_CONF_ERROR;
3571
3572#endif
3573}
3574
3575
3576static char *
3577ngx_http_fastcgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3578{
3579    ngx_http_fastcgi_loc_conf_t *flcf = conf;
3580
3581    ngx_str_t                  *value;
3582    ngx_http_script_compile_t   sc;
3583
3584    if (flcf->upstream.store != NGX_CONF_UNSET) {
3585        return "is duplicate";
3586    }
3587
3588    value = cf->args->elts;
3589
3590    if (ngx_strcmp(value[1].data, "off") == 0) {
3591        flcf->upstream.store = 0;
3592        return NGX_CONF_OK;
3593    }
3594
3595#if (NGX_HTTP_CACHE)
3596    if (flcf->upstream.cache > 0) {
3597        return "is incompatible with \"fastcgi_cache\"";
3598    }
3599#endif
3600
3601    flcf->upstream.store = 1;
3602
3603    if (ngx_strcmp(value[1].data, "on") == 0) {
3604        return NGX_CONF_OK;
3605    }
3606
3607    /* include the terminating '\0' into script */
3608    value[1].len++;
3609
3610    ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3611
3612    sc.cf = cf;
3613    sc.source = &value[1];
3614    sc.lengths = &flcf->upstream.store_lengths;
3615    sc.values = &flcf->upstream.store_values;
3616    sc.variables = ngx_http_script_variables_count(&value[1]);
3617    sc.complete_lengths = 1;
3618    sc.complete_values = 1;
3619
3620    if (ngx_http_script_compile(&sc) != NGX_OK) {
3621        return NGX_CONF_ERROR;
3622    }
3623
3624    return NGX_CONF_OK;
3625}
3626
3627
3628#if (NGX_HTTP_CACHE)
3629
3630static char *
3631ngx_http_fastcgi_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3632{
3633    ngx_http_fastcgi_loc_conf_t *flcf = conf;
3634
3635    ngx_str_t                         *value;
3636    ngx_http_complex_value_t           cv;
3637    ngx_http_compile_complex_value_t   ccv;
3638
3639    value = cf->args->elts;
3640
3641    if (flcf->upstream.cache != NGX_CONF_UNSET) {
3642        return "is duplicate";
3643    }
3644
3645    if (ngx_strcmp(value[1].data, "off") == 0) {
3646        flcf->upstream.cache = 0;
3647        return NGX_CONF_OK;
3648    }
3649
3650    if (flcf->upstream.store > 0) {
3651        return "is incompatible with \"fastcgi_store\"";
3652    }
3653
3654    flcf->upstream.cache = 1;
3655
3656    ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3657
3658    ccv.cf = cf;
3659    ccv.value = &value[1];
3660    ccv.complex_value = &cv;
3661
3662    if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3663        return NGX_CONF_ERROR;
3664    }
3665
3666    if (cv.lengths != NULL) {
3667
3668        flcf->upstream.cache_value = ngx_palloc(cf->pool,
3669                                             sizeof(ngx_http_complex_value_t));
3670        if (flcf->upstream.cache_value == NULL) {
3671            return NGX_CONF_ERROR;
3672        }
3673
3674        *flcf->upstream.cache_value = cv;
3675
3676        return NGX_CONF_OK;
3677    }
3678
3679    flcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0,
3680                                                      &ngx_http_fastcgi_module);
3681    if (flcf->upstream.cache_zone == NULL) {
3682        return NGX_CONF_ERROR;
3683    }
3684
3685    return NGX_CONF_OK;
3686}
3687
3688
3689static char *
3690ngx_http_fastcgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3691{
3692    ngx_http_fastcgi_loc_conf_t *flcf = conf;
3693
3694    ngx_str_t                         *value;
3695    ngx_http_compile_complex_value_t   ccv;
3696
3697    value = cf->args->elts;
3698
3699    if (flcf->cache_key.value.data) {
3700        return "is duplicate";
3701    }
3702
3703    ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3704
3705    ccv.cf = cf;
3706    ccv.value = &value[1];
3707    ccv.complex_value = &flcf->cache_key;
3708
3709    if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3710        return NGX_CONF_ERROR;
3711    }
3712
3713    return NGX_CONF_OK;
3714}
3715
3716#endif
3717
3718
3719static char *
3720ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post, void *data)
3721{
3722#if (NGX_FREEBSD)
3723    ssize_t *np = data;
3724
3725    if ((u_long) *np >= ngx_freebsd_net_inet_tcp_sendspace) {
3726        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3727                           "\"fastcgi_send_lowat\" must be less than %d "
3728                           "(sysctl net.inet.tcp.sendspace)",
3729                           ngx_freebsd_net_inet_tcp_sendspace);
3730
3731        return NGX_CONF_ERROR;
3732    }
3733
3734#elif !(NGX_HAVE_SO_SNDLOWAT)
3735    ssize_t *np = data;
3736
3737    ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
3738                       "\"fastcgi_send_lowat\" is not supported, ignored");
3739
3740    *np = 0;
3741
3742#endif
3743
3744    return NGX_CONF_OK;
3745}
Note: See TracBrowser for help on using the repository browser.