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

Last change on this file was 7077:2a288909abc6, checked in by Ruslan Ermilov <ru@…>, 3 weeks ago

Variables: macros for null variables.

No functional changes.

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