Update and clean Tomato RAF files
[tomato.git] / release / src / router / nginx / src / http / modules / ngx_http_fastcgi_module.c
blobf386926da6466947e8b726aa0e6a067dc2a857ad
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_http.h>
13 typedef struct {
14 ngx_http_upstream_conf_t upstream;
16 ngx_str_t index;
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;
24 ngx_array_t *fastcgi_lengths;
25 ngx_array_t *fastcgi_values;
27 ngx_hash_t headers_hash;
28 ngx_uint_t header_params;
30 ngx_flag_t keep_conn;
32 #if (NGX_HTTP_CACHE)
33 ngx_http_complex_value_t cache_key;
34 #endif
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;
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;
57 typedef struct {
58 u_char *start;
59 u_char *end;
60 } ngx_http_fastcgi_split_part_t;
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;
71 unsigned fastcgi_stdout:1;
72 unsigned large_stderr:1;
74 ngx_array_t *split_parts;
76 ngx_str_t script_name;
77 ngx_str_t path_info;
78 } ngx_http_fastcgi_ctx_t;
81 #define NGX_HTTP_FASTCGI_RESPONDER 1
83 #define NGX_HTTP_FASTCGI_KEEP_CONN 1
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
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;
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;
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;
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;
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);
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);
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);
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
174 static char *ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post,
175 void *data);
178 static ngx_conf_post_t ngx_http_fastcgi_lowat_post =
179 { ngx_http_fastcgi_lowat_check };
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 }
195 ngx_module_t ngx_http_fastcgi_module;
198 static ngx_command_t ngx_http_fastcgi_commands[] = {
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,
205 NULL },
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 },
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,
219 NULL },
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,
226 NULL },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
319 #if (NGX_HTTP_CACHE)
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,
326 NULL },
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,
333 NULL },
335 { ngx_string("fastcgi_cache_path"),
336 NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
337 ngx_http_file_cache_set_slot,
340 &ngx_http_fastcgi_module },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
398 #endif
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
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 },
470 ngx_null_command
474 static ngx_http_module_t ngx_http_fastcgi_module_ctx = {
475 ngx_http_fastcgi_add_variables, /* preconfiguration */
476 NULL, /* postconfiguration */
478 NULL, /* create main configuration */
479 NULL, /* init main configuration */
481 NULL, /* create server configuration */
482 NULL, /* merge server configuration */
484 ngx_http_fastcgi_create_loc_conf, /* create location configuration */
485 ngx_http_fastcgi_merge_loc_conf /* merge location configuration */
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
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 */
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] */
520 { 1, /* version */
521 NGX_HTTP_FASTCGI_PARAMS, /* type */
522 0, /* request_id_hi */
523 1 }, /* request_id_lo */
528 static ngx_http_variable_t ngx_http_fastcgi_vars[] = {
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 },
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 },
538 { ngx_null_string, NULL, NULL, 0, 0, 0 }
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
553 #if (NGX_HTTP_CACHE)
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 }
565 #endif
568 static ngx_path_init_t ngx_http_fastcgi_temp_path = {
569 ngx_string(NGX_HTTP_FASTCGI_TEMP_PATH), { 1, 2, 0 }
573 static ngx_int_t
574 ngx_http_fastcgi_handler(ngx_http_request_t *r)
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;
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;
588 if (ngx_http_upstream_create(r) != NGX_OK) {
589 return NGX_HTTP_INTERNAL_SERVER_ERROR;
592 f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
593 if (f == NULL) {
594 return NGX_HTTP_INTERNAL_SERVER_ERROR;
597 ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
599 flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
601 if (flcf->fastcgi_lengths) {
602 if (ngx_http_fastcgi_eval(r, flcf) != NGX_OK) {
603 return NGX_HTTP_INTERNAL_SERVER_ERROR;
607 u = r->upstream;
609 ngx_str_set(&u->schema, "fastcgi://");
610 u->output.tag = (ngx_buf_tag_t) &ngx_http_fastcgi_module;
612 u->conf = &flcf->upstream;
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;
624 u->buffering = 1;
626 u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
627 if (u->pipe == NULL) {
628 return NGX_HTTP_INTERNAL_SERVER_ERROR;
631 u->pipe->input_filter = ngx_http_fastcgi_input_filter;
632 u->pipe->input_ctx = r;
634 u->input_filter_init = ngx_http_fastcgi_input_filter_init;
636 rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
638 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
639 return rc;
642 return NGX_DONE;
646 static ngx_int_t
647 ngx_http_fastcgi_eval(ngx_http_request_t *r, ngx_http_fastcgi_loc_conf_t *flcf)
649 ngx_url_t url;
650 ngx_http_upstream_t *u;
652 ngx_memzero(&url, sizeof(ngx_url_t));
654 if (ngx_http_script_run(r, &url.url, flcf->fastcgi_lengths->elts, 0,
655 flcf->fastcgi_values->elts)
656 == NULL)
658 return NGX_ERROR;
661 url.no_resolve = 1;
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);
669 return NGX_ERROR;
672 u = r->upstream;
674 u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
675 if (u->resolved == NULL) {
676 return NGX_ERROR;
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;
685 } else {
686 u->resolved->host = url.host;
687 u->resolved->port = url.port;
688 u->resolved->no_port = url.no_port;
691 return NGX_OK;
695 #if (NGX_HTTP_CACHE)
697 static ngx_int_t
698 ngx_http_fastcgi_create_key(ngx_http_request_t *r)
700 ngx_str_t *key;
701 ngx_http_fastcgi_loc_conf_t *flcf;
703 key = ngx_array_push(&r->cache->keys);
704 if (key == NULL) {
705 return NGX_ERROR;
708 flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
710 if (ngx_http_complex_value(r, &flcf->cache_key, key) != NGX_OK) {
711 return NGX_ERROR;
714 return NGX_OK;
717 #endif
720 static ngx_int_t
721 ngx_http_fastcgi_create_request(ngx_http_request_t *r)
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;
738 len = 0;
739 header_params = 0;
740 ignored = NULL;
742 flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
744 if (flcf->params_len) {
745 ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
747 ngx_http_script_flush_no_cacheable_variables(r, flcf->flushes);
748 le.flushed = 1;
750 le.ip = flcf->params_len->elts;
751 le.request = r;
753 while (*(uintptr_t *) le.ip) {
755 lcode = *(ngx_http_script_len_code_pt *) le.ip;
756 key_len = lcode(&le);
758 lcode = *(ngx_http_script_len_code_pt *) le.ip;
759 skip_empty = lcode(&le);
761 for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
762 lcode = *(ngx_http_script_len_code_pt *) le.ip;
764 le.ip += sizeof(uintptr_t);
766 if (skip_empty && val_len == 0) {
767 continue;
770 len += 1 + key_len + ((val_len > 127) ? 4 : 1) + val_len;
774 if (flcf->upstream.pass_request_headers) {
776 allocated = 0;
777 lowcase_key = NULL;
779 if (flcf->header_params) {
780 n = 0;
781 part = &r->headers_in.headers.part;
783 while (part) {
784 n += part->nelts;
785 part = part->next;
788 ignored = ngx_palloc(r->pool, n * sizeof(void *));
789 if (ignored == NULL) {
790 return NGX_ERROR;
794 part = &r->headers_in.headers.part;
795 header = part->elts;
797 for (i = 0; /* void */; i++) {
799 if (i >= part->nelts) {
800 if (part->next == NULL) {
801 break;
804 part = part->next;
805 header = part->elts;
806 i = 0;
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;
818 hash = 0;
820 for (n = 0; n < header[i].key.len; n++) {
821 ch = header[i].key.data[n];
823 if (ch >= 'A' && ch <= 'Z') {
824 ch |= 0x20;
826 } else if (ch == '-') {
827 ch = '_';
830 hash = ngx_hash(hash, ch);
831 lowcase_key[n] = ch;
834 if (ngx_hash_find(&flcf->headers_hash, hash, lowcase_key, n)) {
835 ignored[header_params++] = &header[i];
836 continue;
839 n += sizeof("HTTP_") - 1;
841 } else {
842 n = sizeof("HTTP_") - 1 + header[i].key.len;
845 len += ((n > 127) ? 4 : 1) + ((header[i].value.len > 127) ? 4 : 1)
846 + n + header[i].value.len;
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;
858 padding = 8 - len % 8;
859 padding = (padding == 8) ? 0 : padding;
862 size = sizeof(ngx_http_fastcgi_header_t)
863 + sizeof(ngx_http_fastcgi_begin_request_t)
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 */
869 + sizeof(ngx_http_fastcgi_header_t); /* NGX_HTTP_FASTCGI_STDIN */
872 b = ngx_create_temp_buf(r->pool, size);
873 if (b == NULL) {
874 return NGX_ERROR;
877 cl = ngx_alloc_chain_link(r->pool);
878 if (cl == NULL) {
879 return NGX_ERROR;
882 cl->buf = b;
884 ngx_http_fastcgi_request_start.br.flags =
885 flcf->keep_conn ? NGX_HTTP_FASTCGI_KEEP_CONN : 0;
887 ngx_memcpy(b->pos, &ngx_http_fastcgi_request_start,
888 sizeof(ngx_http_fastcgi_request_start_t));
890 h = (ngx_http_fastcgi_header_t *)
891 (b->pos + sizeof(ngx_http_fastcgi_header_t)
892 + sizeof(ngx_http_fastcgi_begin_request_t));
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;
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);
904 if (flcf->params_len) {
905 ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
907 e.ip = flcf->params->elts;
908 e.pos = b->last;
909 e.request = r;
910 e.flushed = 1;
912 le.ip = flcf->params_len->elts;
914 while (*(uintptr_t *) le.ip) {
916 lcode = *(ngx_http_script_len_code_pt *) le.ip;
917 key_len = (u_char) lcode(&le);
919 lcode = *(ngx_http_script_len_code_pt *) le.ip;
920 skip_empty = lcode(&le);
922 for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
923 lcode = *(ngx_http_script_len_code_pt *) le.ip;
925 le.ip += sizeof(uintptr_t);
927 if (skip_empty && val_len == 0) {
928 e.skip = 1;
930 while (*(uintptr_t *) e.ip) {
931 code = *(ngx_http_script_code_pt *) e.ip;
932 code((ngx_http_script_engine_t *) &e);
934 e.ip += sizeof(uintptr_t);
936 e.skip = 0;
938 continue;
941 *e.pos++ = (u_char) key_len;
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);
949 } else {
950 *e.pos++ = (u_char) val_len;
953 while (*(uintptr_t *) e.ip) {
954 code = *(ngx_http_script_code_pt *) e.ip;
955 code((ngx_http_script_engine_t *) &e);
957 e.ip += sizeof(uintptr_t);
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);
965 b->last = e.pos;
969 if (flcf->upstream.pass_request_headers) {
971 part = &r->headers_in.headers.part;
972 header = part->elts;
974 for (i = 0; /* void */; i++) {
976 if (i >= part->nelts) {
977 if (part->next == NULL) {
978 break;
981 part = part->next;
982 header = part->elts;
983 i = 0;
986 for (n = 0; n < header_params; n++) {
987 if (&header[i] == ignored[n]) {
988 goto next;
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);
999 } else {
1000 *b->last++ = (u_char) key_len;
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);
1010 } else {
1011 *b->last++ = (u_char) val_len;
1014 b->last = ngx_cpymem(b->last, "HTTP_", sizeof("HTTP_") - 1);
1016 for (n = 0; n < header[i].key.len; n++) {
1017 ch = header[i].key.data[n];
1019 if (ch >= 'a' && ch <= 'z') {
1020 ch &= ~0x20;
1022 } else if (ch == '-') {
1023 ch = '_';
1026 *b->last++ = ch;
1029 b->last = ngx_copy(b->last, header[i].value.data, val_len);
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:
1037 continue;
1042 if (padding) {
1043 ngx_memzero(b->last, padding);
1044 b->last += padding;
1048 h = (ngx_http_fastcgi_header_t *) b->last;
1049 b->last += sizeof(ngx_http_fastcgi_header_t);
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;
1060 h = (ngx_http_fastcgi_header_t *) b->last;
1061 b->last += sizeof(ngx_http_fastcgi_header_t);
1063 if (flcf->upstream.pass_request_body) {
1064 body = r->upstream->request_bufs;
1065 r->upstream->request_bufs = cl;
1067 #if (NGX_SUPPRESS_WARN)
1068 file_pos = 0;
1069 pos = NULL;
1070 #endif
1072 while (body) {
1074 if (body->buf->in_file) {
1075 file_pos = body->buf->file_pos;
1077 } else {
1078 pos = body->buf->pos;
1081 next = 0;
1083 do {
1084 b = ngx_alloc_buf(r->pool);
1085 if (b == NULL) {
1086 return NGX_ERROR;
1089 ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
1091 if (body->buf->in_file) {
1092 b->file_pos = file_pos;
1093 file_pos += 32 * 1024;
1095 if (file_pos >= body->buf->file_last) {
1096 file_pos = body->buf->file_last;
1097 next = 1;
1100 b->file_last = file_pos;
1101 len = (ngx_uint_t) (file_pos - b->file_pos);
1103 } else {
1104 b->pos = pos;
1105 pos += 32 * 1024;
1107 if (pos >= body->buf->last) {
1108 pos = body->buf->last;
1109 next = 1;
1112 b->last = pos;
1113 len = (ngx_uint_t) (pos - b->pos);
1116 padding = 8 - len % 8;
1117 padding = (padding == 8) ? 0 : padding;
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;
1128 cl->next = ngx_alloc_chain_link(r->pool);
1129 if (cl->next == NULL) {
1130 return NGX_ERROR;
1133 cl = cl->next;
1134 cl->buf = b;
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;
1143 if (padding) {
1144 ngx_memzero(b->last, padding);
1145 b->last += padding;
1148 h = (ngx_http_fastcgi_header_t *) b->last;
1149 b->last += sizeof(ngx_http_fastcgi_header_t);
1151 cl->next = ngx_alloc_chain_link(r->pool);
1152 if (cl->next == NULL) {
1153 return NGX_ERROR;
1156 cl = cl->next;
1157 cl->buf = b;
1159 } while (!next);
1161 body = body->next;
1164 } else {
1165 r->upstream->request_bufs = cl;
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;
1177 cl->next = NULL;
1179 return NGX_OK;
1183 static ngx_int_t
1184 ngx_http_fastcgi_reinit_request(ngx_http_request_t *r)
1186 ngx_http_fastcgi_ctx_t *f;
1188 f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
1190 if (f == NULL) {
1191 return NGX_OK;
1194 f->state = ngx_http_fastcgi_st_version;
1195 f->fastcgi_stdout = 0;
1196 f->large_stderr = 0;
1198 r->state = 0;
1200 return NGX_OK;
1204 static ngx_int_t
1205 ngx_http_fastcgi_process_header(ngx_http_request_t *r)
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;
1222 f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
1224 umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
1226 u = r->upstream;
1228 for ( ;; ) {
1230 if (f->state < ngx_http_fastcgi_st_data) {
1232 f->pos = u->buffer.pos;
1233 f->last = u->buffer.last;
1235 rc = ngx_http_fastcgi_process_record(r, f);
1237 u->buffer.pos = f->pos;
1238 u->buffer.last = f->last;
1240 if (rc == NGX_AGAIN) {
1241 return NGX_AGAIN;
1244 if (rc == NGX_ERROR) {
1245 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1248 if (f->type != NGX_HTTP_FASTCGI_STDOUT
1249 && f->type != NGX_HTTP_FASTCGI_STDERR)
1251 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1252 "upstream sent unexpected FastCGI record: %d",
1253 f->type);
1255 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
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");
1262 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1266 if (f->state == ngx_http_fastcgi_st_padding) {
1268 if (u->buffer.pos + f->padding < u->buffer.last) {
1269 f->state = ngx_http_fastcgi_st_version;
1270 u->buffer.pos += f->padding;
1272 continue;
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;
1279 return NGX_AGAIN;
1282 f->padding -= u->buffer.last - u->buffer.pos;
1283 u->buffer.pos = u->buffer.last;
1285 return NGX_AGAIN;
1289 /* f->state == ngx_http_fastcgi_st_data */
1291 if (f->type == NGX_HTTP_FASTCGI_STDERR) {
1293 if (f->length) {
1294 msg = u->buffer.pos;
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;
1301 } else {
1302 f->length -= u->buffer.last - u->buffer.pos;
1303 u->buffer.pos = u->buffer.last;
1306 for (p = u->buffer.pos - 1; msg < p; p--) {
1307 if (*p != LF && *p != CR && *p != '.' && *p != ' ') {
1308 break;
1312 p++;
1314 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1315 "FastCGI sent in stderr: \"%*s\"", p - msg, msg);
1317 flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
1319 if (flcf->catch_stderr) {
1320 pattern = flcf->catch_stderr->elts;
1322 for (i = 0; i < flcf->catch_stderr->nelts; i++) {
1323 if (ngx_strnstr(msg, (char *) pattern[i].data,
1324 p - msg)
1325 != NULL)
1327 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1332 if (u->buffer.pos == u->buffer.last) {
1334 if (!f->fastcgi_stdout) {
1337 * the special handling the large number
1338 * of the PHP warnings to not allocate memory
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;
1348 #else
1349 u->buffer.pos = u->buffer.start;
1350 #endif
1351 u->buffer.last = u->buffer.pos;
1352 f->large_stderr = 1;
1355 return NGX_AGAIN;
1358 } else {
1359 f->state = ngx_http_fastcgi_st_padding;
1362 continue;
1366 /* f->type == NGX_HTTP_FASTCGI_STDOUT */
1368 #if (NGX_HTTP_CACHE)
1370 if (f->large_stderr && r->cache) {
1371 u_char *start;
1372 ssize_t len;
1373 ngx_http_fastcgi_header_t *fh;
1375 start = u->buffer.start + r->cache->header_start;
1377 len = u->buffer.pos - start - 2 * sizeof(ngx_http_fastcgi_header_t);
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.
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;
1398 } else {
1399 r->cache->header_start += u->buffer.pos - start
1400 - sizeof(ngx_http_fastcgi_header_t);
1403 f->large_stderr = 0;
1406 #endif
1408 f->fastcgi_stdout = 1;
1410 start = u->buffer.pos;
1412 if (u->buffer.pos + f->length < u->buffer.last) {
1415 * set u->buffer.last to the end of the FastCGI record data
1416 * for ngx_http_parse_header_line()
1419 last = u->buffer.last;
1420 u->buffer.last = u->buffer.pos + f->length;
1422 } else {
1423 last = NULL;
1426 for ( ;; ) {
1428 part_start = u->buffer.pos;
1429 part_end = u->buffer.last;
1431 rc = ngx_http_parse_header_line(r, &u->buffer, 1);
1433 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1434 "http fastcgi parser: %d", rc);
1436 if (rc == NGX_AGAIN) {
1437 break;
1440 if (rc == NGX_OK) {
1442 /* a header line has been parsed successfully */
1444 h = ngx_list_push(&u->headers_in.headers);
1445 if (h == NULL) {
1446 return NGX_ERROR;
1449 if (f->split_parts && f->split_parts->nelts) {
1451 part = f->split_parts->elts;
1452 size = u->buffer.pos - part_start;
1454 for (i = 0; i < f->split_parts->nelts; i++) {
1455 size += part[i].end - part[i].start;
1458 p = ngx_pnalloc(r->pool, size);
1459 if (p == NULL) {
1460 return NGX_ERROR;
1463 buf.pos = p;
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);
1470 p = ngx_cpymem(p, part_start, u->buffer.pos - part_start);
1472 buf.last = p;
1474 f->split_parts->nelts = 0;
1476 rc = ngx_http_parse_header_line(r, &buf, 1);
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';
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';
1486 h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
1487 if (h->lowcase_key == NULL) {
1488 return NGX_ERROR;
1491 } else {
1493 h->key.len = r->header_name_end - r->header_name_start;
1494 h->value.len = r->header_end - r->header_start;
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;
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;
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';
1513 h->hash = r->header_hash;
1515 if (h->key.len == r->lowcase_index) {
1516 ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
1518 } else {
1519 ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
1522 hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
1523 h->lowcase_key, h->key.len);
1525 if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1526 return NGX_ERROR;
1529 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1530 "http fastcgi header: \"%V: %V\"",
1531 &h->key, &h->value);
1533 if (u->buffer.pos < u->buffer.last) {
1534 continue;
1537 /* the end of the FastCGI record */
1539 break;
1542 if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
1544 /* a whole header has been parsed successfully */
1546 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1547 "http fastcgi header done");
1549 if (u->headers_in.status) {
1550 status_line = &u->headers_in.status->value;
1552 status = ngx_atoi(status_line->data, 3);
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;
1561 u->headers_in.status_n = status;
1562 u->headers_in.status_line = *status_line;
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");
1569 } else {
1570 u->headers_in.status_n = 200;
1571 ngx_str_set(&u->headers_in.status_line, "200 OK");
1574 if (u->state) {
1575 u->state->status = u->headers_in.status_n;
1578 break;
1581 /* there was error while a header line parsing */
1583 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1584 "upstream sent invalid header");
1586 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1589 if (last) {
1590 u->buffer.last = last;
1593 f->length -= u->buffer.pos - start;
1595 if (f->length == 0) {
1596 f->state = ngx_http_fastcgi_st_padding;
1599 if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
1600 return NGX_OK;
1603 if (rc == NGX_OK) {
1604 continue;
1607 /* rc == NGX_AGAIN */
1609 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1610 "upstream split a header line in FastCGI records");
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;
1620 part = ngx_array_push(f->split_parts);
1621 if (part == NULL) {
1622 return NGX_ERROR;
1625 part->start = part_start;
1626 part->end = part_end;
1628 if (u->buffer.pos < u->buffer.last) {
1629 continue;
1632 return NGX_AGAIN;
1637 static ngx_int_t
1638 ngx_http_fastcgi_input_filter_init(void *data)
1640 ngx_http_request_t *r = data;
1641 ngx_http_fastcgi_loc_conf_t *flcf;
1643 flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
1645 r->upstream->pipe->length = flcf->keep_conn ?
1646 (off_t) sizeof(ngx_http_fastcgi_header_t) : -1;
1648 return NGX_OK;
1652 static ngx_int_t
1653 ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
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;
1663 if (buf->pos == buf->last) {
1664 return NGX_OK;
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);
1671 b = NULL;
1672 prev = &buf->shadow;
1674 f->pos = buf->pos;
1675 f->last = buf->last;
1677 for ( ;; ) {
1678 if (f->state < ngx_http_fastcgi_st_data) {
1680 rc = ngx_http_fastcgi_process_record(r, f);
1682 if (rc == NGX_AGAIN) {
1683 break;
1686 if (rc == NGX_ERROR) {
1687 return NGX_ERROR;
1690 if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) {
1691 f->state = ngx_http_fastcgi_st_padding;
1693 if (!flcf->keep_conn) {
1694 p->upstream_done = 1;
1697 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
1698 "http fastcgi closed stdout");
1700 continue;
1703 if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
1705 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
1706 "http fastcgi sent end request");
1708 if (!flcf->keep_conn) {
1709 p->upstream_done = 1;
1710 break;
1713 continue;
1718 if (f->state == ngx_http_fastcgi_st_padding) {
1720 if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
1722 if (f->pos + f->padding < f->last) {
1723 p->upstream_done = 1;
1724 break;
1727 if (f->pos + f->padding == f->last) {
1728 p->upstream_done = 1;
1729 r->upstream->keepalive = 1;
1730 break;
1733 f->padding -= f->last - f->pos;
1735 break;
1738 if (f->pos + f->padding < f->last) {
1739 f->state = ngx_http_fastcgi_st_version;
1740 f->pos += f->padding;
1742 continue;
1745 if (f->pos + f->padding == f->last) {
1746 f->state = ngx_http_fastcgi_st_version;
1748 break;
1751 f->padding -= f->last - f->pos;
1753 break;
1757 /* f->state == ngx_http_fastcgi_st_data */
1759 if (f->type == NGX_HTTP_FASTCGI_STDERR) {
1761 if (f->length) {
1763 if (f->pos == f->last) {
1764 break;
1767 msg = f->pos;
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;
1774 } else {
1775 f->length -= f->last - f->pos;
1776 f->pos = f->last;
1779 for (m = f->pos - 1; msg < m; m--) {
1780 if (*m != LF && *m != CR && *m != '.' && *m != ' ') {
1781 break;
1785 ngx_log_error(NGX_LOG_ERR, p->log, 0,
1786 "FastCGI sent in stderr: \"%*s\"",
1787 m + 1 - msg, msg);
1789 } else {
1790 f->state = ngx_http_fastcgi_st_padding;
1793 continue;
1796 if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
1798 if (f->pos + f->length <= f->last) {
1799 f->state = ngx_http_fastcgi_st_padding;
1800 f->pos += f->length;
1802 continue;
1805 f->length -= f->last - f->pos;
1807 break;
1811 /* f->type == NGX_HTTP_FASTCGI_STDOUT */
1813 if (f->pos == f->last) {
1814 break;
1817 if (p->free) {
1818 cl = p->free;
1819 b = cl->buf;
1820 p->free = cl->next;
1821 ngx_free_chain(p->pool, cl);
1823 } else {
1824 b = ngx_alloc_buf(p->pool);
1825 if (b == NULL) {
1826 return NGX_ERROR;
1830 ngx_memzero(b, sizeof(ngx_buf_t));
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;
1839 *prev = b;
1840 prev = &b->shadow;
1842 cl = ngx_alloc_chain_link(p->pool);
1843 if (cl == NULL) {
1844 return NGX_ERROR;
1847 cl->buf = b;
1848 cl->next = NULL;
1850 if (p->in) {
1851 *p->last_in = cl;
1852 } else {
1853 p->in = cl;
1855 p->last_in = &cl->next;
1858 /* STUB */ b->num = buf->num;
1860 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
1861 "input buf #%d %p", b->num, b->pos);
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;
1868 continue;
1871 f->length -= f->last - f->pos;
1873 b->last = f->last;
1875 break;
1879 if (flcf->keep_conn) {
1881 /* set p->length, minimal amount of data we want to see */
1883 if (f->state < ngx_http_fastcgi_st_data) {
1884 p->length = 1;
1886 } else if (f->state == ngx_http_fastcgi_st_padding) {
1887 p->length = f->padding;
1889 } else {
1890 /* ngx_http_fastcgi_st_data */
1892 p->length = f->length;
1896 if (b) {
1897 b->shadow = buf;
1898 b->last_shadow = 1;
1900 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
1901 "input buf %p %z", b->pos, b->last - b->pos);
1903 return NGX_OK;
1906 /* there is no data record in the buf, add it to free chain */
1908 if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) {
1909 return NGX_ERROR;
1912 return NGX_OK;
1916 static ngx_int_t
1917 ngx_http_fastcgi_process_record(ngx_http_request_t *r,
1918 ngx_http_fastcgi_ctx_t *f)
1920 u_char ch, *p;
1921 ngx_http_fastcgi_state_e state;
1923 state = f->state;
1925 for (p = f->pos; p < f->last; p++) {
1927 ch = *p;
1929 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1930 "http fastcgi record byte: %02Xd", ch);
1932 switch (state) {
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;
1941 state = ngx_http_fastcgi_st_type;
1942 break;
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;
1958 state = ngx_http_fastcgi_st_request_id_hi;
1959 break;
1961 /* we support the single request per connection */
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;
1970 state = ngx_http_fastcgi_st_request_id_lo;
1971 break;
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;
1980 state = ngx_http_fastcgi_st_content_length_hi;
1981 break;
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;
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;
1993 case ngx_http_fastcgi_st_padding_length:
1994 f->padding = (size_t) ch;
1995 state = ngx_http_fastcgi_st_reserved;
1996 break;
1998 case ngx_http_fastcgi_st_reserved:
1999 state = ngx_http_fastcgi_st_data;
2001 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2002 "http fastcgi record length: %z", f->length);
2004 f->pos = p + 1;
2005 f->state = state;
2007 return NGX_OK;
2009 /* suppress warning */
2010 case ngx_http_fastcgi_st_data:
2011 case ngx_http_fastcgi_st_padding:
2012 break;
2016 f->state = state;
2018 return NGX_AGAIN;
2022 static void
2023 ngx_http_fastcgi_abort_request(ngx_http_request_t *r)
2025 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2026 "abort http fastcgi request");
2028 return;
2032 static void
2033 ngx_http_fastcgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
2035 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2036 "finalize http fastcgi request");
2038 return;
2042 static ngx_int_t
2043 ngx_http_fastcgi_add_variables(ngx_conf_t *cf)
2045 ngx_http_variable_t *var, *v;
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;
2053 var->get_handler = v->get_handler;
2054 var->data = v->data;
2057 return NGX_OK;
2061 static void *
2062 ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
2064 ngx_http_fastcgi_loc_conf_t *conf;
2066 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_loc_conf_t));
2067 if (conf == NULL) {
2068 return NULL;
2072 * set by ngx_pcalloc():
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;
2086 * conf->index.len = { 0, NULL };
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;
2094 conf->upstream.local = NGX_CONF_UNSET_PTR;
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;
2100 conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
2101 conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
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;
2107 conf->upstream.pass_request_headers = NGX_CONF_UNSET;
2108 conf->upstream.pass_request_body = NGX_CONF_UNSET;
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
2120 conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
2121 conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
2123 conf->upstream.intercept_errors = NGX_CONF_UNSET;
2125 /* "fastcgi_cyclic_temp_file" is disabled */
2126 conf->upstream.cyclic_temp_file = 0;
2128 conf->catch_stderr = NGX_CONF_UNSET_PTR;
2130 conf->keep_conn = NGX_CONF_UNSET;
2132 ngx_str_set(&conf->upstream.module, "fastcgi");
2134 return conf;
2138 static char *
2139 ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
2141 ngx_http_fastcgi_loc_conf_t *prev = parent;
2142 ngx_http_fastcgi_loc_conf_t *conf = child;
2144 size_t size;
2145 ngx_hash_init_t hash;
2146 ngx_http_core_loc_conf_t *clcf;
2148 if (conf->upstream.store != 0) {
2149 ngx_conf_merge_value(conf->upstream.store,
2150 prev->upstream.store, 0);
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;
2158 ngx_conf_merge_uint_value(conf->upstream.store_access,
2159 prev->upstream.store_access, 0600);
2161 ngx_conf_merge_value(conf->upstream.buffering,
2162 prev->upstream.buffering, 1);
2164 ngx_conf_merge_value(conf->upstream.ignore_client_abort,
2165 prev->upstream.ignore_client_abort, 0);
2167 ngx_conf_merge_ptr_value(conf->upstream.local,
2168 prev->upstream.local, NULL);
2170 ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
2171 prev->upstream.connect_timeout, 60000);
2173 ngx_conf_merge_msec_value(conf->upstream.send_timeout,
2174 prev->upstream.send_timeout, 60000);
2176 ngx_conf_merge_msec_value(conf->upstream.read_timeout,
2177 prev->upstream.read_timeout, 60000);
2179 ngx_conf_merge_size_value(conf->upstream.send_lowat,
2180 prev->upstream.send_lowat, 0);
2182 ngx_conf_merge_size_value(conf->upstream.buffer_size,
2183 prev->upstream.buffer_size,
2184 (size_t) ngx_pagesize);
2187 ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
2188 8, ngx_pagesize);
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;
2197 size = conf->upstream.buffer_size;
2198 if (size < conf->upstream.bufs.size) {
2199 size = conf->upstream.bufs.size;
2203 ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
2204 prev->upstream.busy_buffers_size_conf,
2205 NGX_CONF_UNSET_SIZE);
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;
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\"");
2220 return NGX_CONF_ERROR;
2223 if (conf->upstream.busy_buffers_size
2224 > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
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");
2230 return NGX_CONF_ERROR;
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);
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;
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\"");
2251 return NGX_CONF_ERROR;
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);
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;
2266 if (conf->upstream.max_temp_file_size != 0
2267 && conf->upstream.max_temp_file_size < size)
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\"");
2275 return NGX_CONF_ERROR;
2279 ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
2280 prev->upstream.ignore_headers,
2281 NGX_CONF_BITMASK_SET);
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));
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;
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)
2300 return NGX_CONF_ERROR;
2303 #if (NGX_HTTP_CACHE)
2305 ngx_conf_merge_ptr_value(conf->upstream.cache,
2306 prev->upstream.cache, NULL);
2308 if (conf->upstream.cache && conf->upstream.cache->data == NULL) {
2309 ngx_shm_zone_t *shm_zone;
2311 shm_zone = conf->upstream.cache;
2313 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2314 "\"fastcgi_cache\" zone \"%V\" is unknown",
2315 &shm_zone->shm.name);
2317 return NGX_CONF_ERROR;
2320 ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
2321 prev->upstream.cache_min_uses, 1);
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));
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;
2333 if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
2334 conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
2337 if (conf->upstream.cache_methods == 0) {
2338 conf->upstream.cache_methods = prev->upstream.cache_methods;
2341 conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD;
2343 ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
2344 prev->upstream.cache_bypass, NULL);
2346 ngx_conf_merge_ptr_value(conf->upstream.no_cache,
2347 prev->upstream.no_cache, NULL);
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\"");
2355 ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
2356 prev->upstream.cache_valid, NULL);
2358 if (conf->cache_key.value.data == NULL) {
2359 conf->cache_key = prev->cache_key;
2362 ngx_conf_merge_value(conf->upstream.cache_lock,
2363 prev->upstream.cache_lock, 0);
2365 ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
2366 prev->upstream.cache_lock_timeout, 5000);
2368 #endif
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);
2375 ngx_conf_merge_value(conf->upstream.intercept_errors,
2376 prev->upstream.intercept_errors, 0);
2378 ngx_conf_merge_ptr_value(conf->catch_stderr, prev->catch_stderr, NULL);
2380 ngx_conf_merge_value(conf->keep_conn, prev->keep_conn, 0);
2383 ngx_conf_merge_str_value(conf->index, prev->index, "");
2385 hash.max_size = 512;
2386 hash.bucket_size = ngx_align(64, ngx_cacheline_size);
2387 hash.name = "fastcgi_hide_headers_hash";
2389 if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
2390 &prev->upstream, ngx_http_fastcgi_hide_headers, &hash)
2391 != NGX_OK)
2393 return NGX_CONF_ERROR;
2396 if (conf->upstream.upstream == NULL) {
2397 conf->upstream.upstream = prev->upstream.upstream;
2400 if (conf->fastcgi_lengths == NULL) {
2401 conf->fastcgi_lengths = prev->fastcgi_lengths;
2402 conf->fastcgi_values = prev->fastcgi_values;
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;
2412 #if (NGX_PCRE)
2413 if (conf->split_regex == NULL) {
2414 conf->split_regex = prev->split_regex;
2415 conf->split_name = prev->split_name;
2417 #endif
2419 if (ngx_http_fastcgi_merge_params(cf, conf, prev) != NGX_OK) {
2420 return NGX_CONF_ERROR;
2423 return NGX_CONF_OK;
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)
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;
2445 if (conf->params_source == NULL) {
2446 conf->params_source = prev->params_source;
2448 if (prev->headers_hash.buckets
2449 #if (NGX_HTTP_CACHE)
2450 && ((conf->upstream.cache == NULL)
2451 == (prev->upstream.cache == NULL))
2452 #endif
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;
2461 return NGX_OK;
2465 if (conf->params_source == NULL
2466 #if (NGX_HTTP_CACHE)
2467 && (conf->upstream.cache == NULL)
2468 #endif
2471 conf->headers_hash.buckets = (void *) 1;
2472 return NGX_OK;
2475 conf->params_len = ngx_array_create(cf->pool, 64, 1);
2476 if (conf->params_len == NULL) {
2477 return NGX_ERROR;
2480 conf->params = ngx_array_create(cf->pool, 512, 1);
2481 if (conf->params == NULL) {
2482 return NGX_ERROR;
2485 if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
2486 != NGX_OK)
2488 return NGX_ERROR;
2491 if (conf->params_source) {
2492 src = conf->params_source->elts;
2493 nsrc = conf->params_source->nelts;
2495 } else {
2496 src = NULL;
2497 nsrc = 0;
2500 #if (NGX_HTTP_CACHE)
2502 if (conf->upstream.cache) {
2503 ngx_keyval_t *h;
2504 ngx_http_upstream_param_t *s;
2506 if (ngx_array_init(&params_merged, cf->temp_pool, 4,
2507 sizeof(ngx_http_upstream_param_t))
2508 != NGX_OK)
2510 return NGX_ERROR;
2513 for (i = 0; i < nsrc; i++) {
2515 s = ngx_array_push(&params_merged);
2516 if (s == NULL) {
2517 return NGX_ERROR;
2520 *s = src[i];
2523 h = ngx_http_fastcgi_cache_headers;
2525 while (h->key.len) {
2527 src = params_merged.elts;
2528 nsrc = params_merged.nelts;
2530 for (i = 0; i < nsrc; i++) {
2531 if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
2532 goto next;
2536 s = ngx_array_push(&params_merged);
2537 if (s == NULL) {
2538 return NGX_ERROR;
2541 s->key = h->key;
2542 s->value = h->value;
2543 s->skip_empty = 0;
2545 next:
2547 h++;
2550 src = params_merged.elts;
2551 nsrc = params_merged.nelts;
2554 #endif
2556 for (i = 0; i < nsrc; i++) {
2558 if (src[i].key.len > sizeof("HTTP_") - 1
2559 && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0)
2561 hk = ngx_array_push(&headers_names);
2562 if (hk == NULL) {
2563 return NGX_ERROR;
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;
2571 if (src[i].value.len == 0) {
2572 continue;
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;
2582 copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
2583 copy->len = src[i].key.len;
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;
2591 copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
2592 copy->len = src[i].skip_empty;
2595 size = (sizeof(ngx_http_script_copy_code_t)
2596 + src[i].key.len + sizeof(uintptr_t) - 1)
2597 & ~(sizeof(uintptr_t) - 1);
2599 copy = ngx_array_push_n(conf->params, size);
2600 if (copy == NULL) {
2601 return NGX_ERROR;
2604 copy->code = ngx_http_script_copy_code;
2605 copy->len = src[i].key.len;
2607 p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
2608 ngx_memcpy(p, src[i].key.data, src[i].key.len);
2611 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
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;
2619 if (ngx_http_script_compile(&sc) != NGX_OK) {
2620 return NGX_ERROR;
2623 code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t));
2624 if (code == NULL) {
2625 return NGX_ERROR;
2628 *code = (uintptr_t) NULL;
2631 code = ngx_array_push_n(conf->params, sizeof(uintptr_t));
2632 if (code == NULL) {
2633 return NGX_ERROR;
2636 *code = (uintptr_t) NULL;
2639 code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t));
2640 if (code == NULL) {
2641 return NGX_ERROR;
2644 *code = (uintptr_t) NULL;
2646 conf->header_params = headers_names.nelts;
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;
2656 return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
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)
2664 u_char *p;
2665 ngx_http_fastcgi_ctx_t *f;
2666 ngx_http_fastcgi_loc_conf_t *flcf;
2668 flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
2670 f = ngx_http_fastcgi_split(r, flcf);
2672 if (f == NULL) {
2673 return NGX_ERROR;
2676 if (f->script_name.len == 0
2677 || f->script_name.data[f->script_name.len - 1] != '/')
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;
2685 return NGX_OK;
2688 v->len = f->script_name.len + flcf->index.len;
2690 v->data = ngx_pnalloc(r->pool, v->len);
2691 if (v->data == NULL) {
2692 return NGX_ERROR;
2695 p = ngx_copy(v->data, f->script_name.data, f->script_name.len);
2696 ngx_memcpy(p, flcf->index.data, flcf->index.len);
2698 return NGX_OK;
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)
2706 ngx_http_fastcgi_ctx_t *f;
2707 ngx_http_fastcgi_loc_conf_t *flcf;
2709 flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
2711 f = ngx_http_fastcgi_split(r, flcf);
2713 if (f == NULL) {
2714 return NGX_ERROR;
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;
2723 return NGX_OK;
2727 static ngx_http_fastcgi_ctx_t *
2728 ngx_http_fastcgi_split(ngx_http_request_t *r, ngx_http_fastcgi_loc_conf_t *flcf)
2730 ngx_http_fastcgi_ctx_t *f;
2731 #if (NGX_PCRE)
2732 ngx_int_t n;
2733 int captures[(1 + 2) * 3];
2735 f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
2737 if (f == NULL) {
2738 f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
2739 if (f == NULL) {
2740 return NULL;
2743 ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
2746 if (f->script_name.len) {
2747 return f;
2750 if (flcf->split_regex == NULL) {
2751 f->script_name = r->uri;
2752 return f;
2755 n = ngx_regex_exec(flcf->split_regex, &r->uri, captures, (1 + 2) * 3);
2757 if (n >= 0) { /* match */
2758 f->script_name.len = captures[3] - captures[2];
2759 f->script_name.data = r->uri.data + captures[2];
2761 f->path_info.len = captures[5] - captures[4];
2762 f->path_info.data = r->uri.data + captures[4];
2764 return f;
2767 if (n == NGX_REGEX_NO_MATCHED) {
2768 f->script_name = r->uri;
2769 return f;
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;
2777 #else
2779 f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
2781 if (f == NULL) {
2782 f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
2783 if (f == NULL) {
2784 return NULL;
2787 ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
2790 f->script_name = r->uri;
2792 return f;
2794 #endif
2798 static char *
2799 ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
2801 ngx_http_fastcgi_loc_conf_t *flcf = conf;
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;
2809 if (flcf->upstream.upstream || flcf->fastcgi_lengths) {
2810 return "is duplicate";
2813 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
2815 clcf->handler = ngx_http_fastcgi_handler;
2817 if (clcf->name.data[clcf->name.len - 1] == '/') {
2818 clcf->auto_redirect = 1;
2821 value = cf->args->elts;
2823 url = &value[1];
2825 n = ngx_http_script_variables_count(url);
2827 if (n) {
2829 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
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;
2839 if (ngx_http_script_compile(&sc) != NGX_OK) {
2840 return NGX_CONF_ERROR;
2843 return NGX_CONF_OK;
2846 ngx_memzero(&u, sizeof(ngx_url_t));
2848 u.url = value[1];
2849 u.no_resolve = 1;
2851 flcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
2852 if (flcf->upstream.upstream == NULL) {
2853 return NGX_CONF_ERROR;
2856 return NGX_CONF_OK;
2860 static char *
2861 ngx_http_fastcgi_split_path_info(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
2863 #if (NGX_PCRE)
2864 ngx_http_fastcgi_loc_conf_t *flcf = conf;
2866 ngx_str_t *value;
2867 ngx_regex_compile_t rc;
2868 u_char errstr[NGX_MAX_CONF_ERRSTR];
2870 value = cf->args->elts;
2872 flcf->split_name = value[1];
2874 ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
2876 rc.pattern = value[1];
2877 rc.pool = cf->pool;
2878 rc.err.len = NGX_MAX_CONF_ERRSTR;
2879 rc.err.data = errstr;
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;
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;
2892 flcf->split_regex = rc.regex;
2894 return NGX_CONF_OK;
2896 #else
2898 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2899 "\"%V\" requires PCRE library", &cmd->name);
2900 return NGX_CONF_ERROR;
2902 #endif
2906 static char *
2907 ngx_http_fastcgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
2909 ngx_http_fastcgi_loc_conf_t *flcf = conf;
2911 ngx_str_t *value;
2912 ngx_http_script_compile_t sc;
2914 if (flcf->upstream.store != NGX_CONF_UNSET
2915 || flcf->upstream.store_lengths)
2917 return "is duplicate";
2920 value = cf->args->elts;
2922 if (ngx_strcmp(value[1].data, "off") == 0) {
2923 flcf->upstream.store = 0;
2924 return NGX_CONF_OK;
2927 #if (NGX_HTTP_CACHE)
2929 if (flcf->upstream.cache != NGX_CONF_UNSET_PTR
2930 && flcf->upstream.cache != NULL)
2932 return "is incompatible with \"fastcgi_cache\"";
2935 #endif
2937 if (ngx_strcmp(value[1].data, "on") == 0) {
2938 flcf->upstream.store = 1;
2939 return NGX_CONF_OK;
2942 /* include the terminating '\0' into script */
2943 value[1].len++;
2945 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
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;
2955 if (ngx_http_script_compile(&sc) != NGX_OK) {
2956 return NGX_CONF_ERROR;
2959 return NGX_CONF_OK;
2963 #if (NGX_HTTP_CACHE)
2965 static char *
2966 ngx_http_fastcgi_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
2968 ngx_http_fastcgi_loc_conf_t *flcf = conf;
2970 ngx_str_t *value;
2972 value = cf->args->elts;
2974 if (flcf->upstream.cache != NGX_CONF_UNSET_PTR) {
2975 return "is duplicate";
2978 if (ngx_strcmp(value[1].data, "off") == 0) {
2979 flcf->upstream.cache = NULL;
2980 return NGX_CONF_OK;
2983 if (flcf->upstream.store > 0 || flcf->upstream.store_lengths) {
2984 return "is incompatible with \"fastcgi_store\"";
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;
2993 return NGX_CONF_OK;
2997 static char *
2998 ngx_http_fastcgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3000 ngx_http_fastcgi_loc_conf_t *flcf = conf;
3002 ngx_str_t *value;
3003 ngx_http_compile_complex_value_t ccv;
3005 value = cf->args->elts;
3007 if (flcf->cache_key.value.data) {
3008 return "is duplicate";
3011 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3013 ccv.cf = cf;
3014 ccv.value = &value[1];
3015 ccv.complex_value = &flcf->cache_key;
3017 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3018 return NGX_CONF_ERROR;
3021 return NGX_CONF_OK;
3024 #endif
3027 static char *
3028 ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post, void *data)
3030 #if (NGX_FREEBSD)
3031 ssize_t *np = data;
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);
3039 return NGX_CONF_ERROR;
3042 #elif !(NGX_HAVE_SO_SNDLOWAT)
3043 ssize_t *np = data;
3045 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
3046 "\"fastcgi_send_lowat\" is not supported, ignored");
3048 *np = 0;
3050 #endif
3052 return NGX_CONF_OK;