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

Last change on this file was 6793:0fba3ed4e7eb, checked in by Dmitry Volyntsev <xeioex@…>, 5 weeks ago

Cache: proxy_cache_max_range_offset and friends.

It configures a threshold in bytes, above which client range
requests are not cached. In such a case the client's Range
header is passed directly to a proxied server.

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