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

Last change on this file was 6530:1d0e03db9f8e, checked in by Roman Arutyunyan <arut@…>, 4 months ago

Upstream: the "transparent" parameter of proxy_bind and friends.

This parameter lets binding the proxy connection to a non-local address.
Upstream will see the connection as coming from that address.
When used with $remote_addr, upstream will accept the connection from real
client address.

Example:

proxy_bind $remote_addr transparent;

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