~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Nginx/http/modules/ngx_http_fastcgi_module.c

Version: ~ [ nginx-1.4.1 ] ~ [ nginx-1.5.0 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.