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

Last change on this file was 7152:3b635e8fd499, checked in by Maxim Dounin <mdounin@…>, 5 weeks ago

FastCGI: adjust buffer position when parsing incomplete records.

Previously, nginx failed to move buffer position when parsing an incomplete
record header, and due to this wasn't be able to continue parsing once
remaining bytes of the record header were received.

This can affect response header parsing, potentially generating spurious errors
like "upstream sent unexpected FastCGI request id high byte: 1 while reading
response header from upstream". While this is very unlikely, since usually
record headers are written in a single buffer, this still can happen in real
life, for example, if a record header will be split across two TCP packets
and the second packet will be delayed.

This does not affect non-buffered response body proxying, due to "buf->pos =
buf->last;" at the start of the ngx_http_fastcgi_non_buffered_filter()
function. Also this does not affect buffered response body proxying, as
each input buffer is only passed to the filter once.

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