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

tip
Last change on this file was 5883:973ee2276300, checked in by Roman Arutyunyan <arut@…>, 4 days ago

Upstream: proxy_limit_rate and friends.

The directives limit the upstream read rate. For example,
"proxy_limit_rate 42" limits proxy upstream read rate to
42 bytes per second.

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