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

tip
Last change on this file was 5909:8d0cf26ce071, checked in by Roman Arutyunyan <arut@…>, 6 days ago

Upstream: different header lists for cached and uncached requests.

The upstream modules remove and alter a number of client headers
before sending the request to upstream. This set of headers is
smaller or even empty when cache is disabled.

It's still possible that a request in a cache-enabled location is
uncached, for example, if cache entry counter is below min_uses.
In this case it's better to alter a smaller set of headers and
pass more client headers to backend unchanged. One of the benefits
is enabling server-side byte ranges in such requests.

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