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

tip
Last change on this file was 5951:610832763648, checked in by Valentin Bartenev <vbart@…>, 12 hours ago

Upstream: added variables support to proxy_cache and friends.

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