0001
0002
0003
0004
0005
0006
0007
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_http.h>
0011
0012
0013 typedef struct {
0014 ngx_array_t caches;
0015 } ngx_http_fastcgi_main_conf_t;
0016
0017
0018 typedef struct {
0019 ngx_array_t *flushes;
0020 ngx_array_t *lengths;
0021 ngx_array_t *values;
0022 ngx_uint_t number;
0023 ngx_hash_t hash;
0024 } ngx_http_fastcgi_params_t;
0025
0026
0027 typedef struct {
0028 ngx_http_upstream_conf_t upstream;
0029
0030 ngx_str_t index;
0031
0032 ngx_http_fastcgi_params_t params;
0033 #if (NGX_HTTP_CACHE)
0034 ngx_http_fastcgi_params_t params_cache;
0035 #endif
0036
0037 ngx_array_t *params_source;
0038 ngx_array_t *catch_stderr;
0039
0040 ngx_array_t *fastcgi_lengths;
0041 ngx_array_t *fastcgi_values;
0042
0043 ngx_flag_t keep_conn;
0044
0045 #if (NGX_HTTP_CACHE)
0046 ngx_http_complex_value_t cache_key;
0047 #endif
0048
0049 #if (NGX_PCRE)
0050 ngx_regex_t *split_regex;
0051 ngx_str_t split_name;
0052 #endif
0053 } ngx_http_fastcgi_loc_conf_t;
0054
0055
0056 typedef enum {
0057 ngx_http_fastcgi_st_version = 0,
0058 ngx_http_fastcgi_st_type,
0059 ngx_http_fastcgi_st_request_id_hi,
0060 ngx_http_fastcgi_st_request_id_lo,
0061 ngx_http_fastcgi_st_content_length_hi,
0062 ngx_http_fastcgi_st_content_length_lo,
0063 ngx_http_fastcgi_st_padding_length,
0064 ngx_http_fastcgi_st_reserved,
0065 ngx_http_fastcgi_st_data,
0066 ngx_http_fastcgi_st_padding
0067 } ngx_http_fastcgi_state_e;
0068
0069
0070 typedef struct {
0071 u_char *start;
0072 u_char *end;
0073 } ngx_http_fastcgi_split_part_t;
0074
0075
0076 typedef struct {
0077 ngx_http_fastcgi_state_e state;
0078 u_char *pos;
0079 u_char *last;
0080 ngx_uint_t type;
0081 size_t length;
0082 size_t padding;
0083
0084 ngx_chain_t *free;
0085 ngx_chain_t *busy;
0086
0087 unsigned fastcgi_stdout:1;
0088 unsigned large_stderr:1;
0089 unsigned header_sent:1;
0090
0091 ngx_array_t *split_parts;
0092
0093 ngx_str_t script_name;
0094 ngx_str_t path_info;
0095 } ngx_http_fastcgi_ctx_t;
0096
0097
0098 #define NGX_HTTP_FASTCGI_RESPONDER 1
0099
0100 #define NGX_HTTP_FASTCGI_KEEP_CONN 1
0101
0102 #define NGX_HTTP_FASTCGI_BEGIN_REQUEST 1
0103 #define NGX_HTTP_FASTCGI_ABORT_REQUEST 2
0104 #define NGX_HTTP_FASTCGI_END_REQUEST 3
0105 #define NGX_HTTP_FASTCGI_PARAMS 4
0106 #define NGX_HTTP_FASTCGI_STDIN 5
0107 #define NGX_HTTP_FASTCGI_STDOUT 6
0108 #define NGX_HTTP_FASTCGI_STDERR 7
0109 #define NGX_HTTP_FASTCGI_DATA 8
0110
0111
0112 typedef struct {
0113 u_char version;
0114 u_char type;
0115 u_char request_id_hi;
0116 u_char request_id_lo;
0117 u_char content_length_hi;
0118 u_char content_length_lo;
0119 u_char padding_length;
0120 u_char reserved;
0121 } ngx_http_fastcgi_header_t;
0122
0123
0124 typedef struct {
0125 u_char role_hi;
0126 u_char role_lo;
0127 u_char flags;
0128 u_char reserved[5];
0129 } ngx_http_fastcgi_begin_request_t;
0130
0131
0132 typedef struct {
0133 u_char version;
0134 u_char type;
0135 u_char request_id_hi;
0136 u_char request_id_lo;
0137 } ngx_http_fastcgi_header_small_t;
0138
0139
0140 typedef struct {
0141 ngx_http_fastcgi_header_t h0;
0142 ngx_http_fastcgi_begin_request_t br;
0143 ngx_http_fastcgi_header_small_t h1;
0144 } ngx_http_fastcgi_request_start_t;
0145
0146
0147 static ngx_int_t ngx_http_fastcgi_eval(ngx_http_request_t *r,
0148 ngx_http_fastcgi_loc_conf_t *flcf);
0149 #if (NGX_HTTP_CACHE)
0150 static ngx_int_t ngx_http_fastcgi_create_key(ngx_http_request_t *r);
0151 #endif
0152 static ngx_int_t ngx_http_fastcgi_create_request(ngx_http_request_t *r);
0153 static ngx_int_t ngx_http_fastcgi_reinit_request(ngx_http_request_t *r);
0154 static ngx_int_t ngx_http_fastcgi_body_output_filter(void *data,
0155 ngx_chain_t *in);
0156 static ngx_int_t ngx_http_fastcgi_process_header(ngx_http_request_t *r);
0157 static ngx_int_t ngx_http_fastcgi_input_filter_init(void *data);
0158 static ngx_int_t ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p,
0159 ngx_buf_t *buf);
0160 static ngx_int_t ngx_http_fastcgi_non_buffered_filter(void *data,
0161 ssize_t bytes);
0162 static ngx_int_t ngx_http_fastcgi_process_record(ngx_http_request_t *r,
0163 ngx_http_fastcgi_ctx_t *f);
0164 static void ngx_http_fastcgi_abort_request(ngx_http_request_t *r);
0165 static void ngx_http_fastcgi_finalize_request(ngx_http_request_t *r,
0166 ngx_int_t rc);
0167
0168 static ngx_int_t ngx_http_fastcgi_add_variables(ngx_conf_t *cf);
0169 static void *ngx_http_fastcgi_create_main_conf(ngx_conf_t *cf);
0170 static void *ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf);
0171 static char *ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf,
0172 void *parent, void *child);
0173 static ngx_int_t ngx_http_fastcgi_init_params(ngx_conf_t *cf,
0174 ngx_http_fastcgi_loc_conf_t *conf, ngx_http_fastcgi_params_t *params,
0175 ngx_keyval_t *default_params);
0176
0177 static ngx_int_t ngx_http_fastcgi_script_name_variable(ngx_http_request_t *r,
0178 ngx_http_variable_value_t *v, uintptr_t data);
0179 static ngx_int_t ngx_http_fastcgi_path_info_variable(ngx_http_request_t *r,
0180 ngx_http_variable_value_t *v, uintptr_t data);
0181 static ngx_http_fastcgi_ctx_t *ngx_http_fastcgi_split(ngx_http_request_t *r,
0182 ngx_http_fastcgi_loc_conf_t *flcf);
0183
0184 static char *ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd,
0185 void *conf);
0186 static char *ngx_http_fastcgi_split_path_info(ngx_conf_t *cf,
0187 ngx_command_t *cmd, void *conf);
0188 static char *ngx_http_fastcgi_store(ngx_conf_t *cf, ngx_command_t *cmd,
0189 void *conf);
0190 #if (NGX_HTTP_CACHE)
0191 static char *ngx_http_fastcgi_cache(ngx_conf_t *cf, ngx_command_t *cmd,
0192 void *conf);
0193 static char *ngx_http_fastcgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd,
0194 void *conf);
0195 #endif
0196
0197 static char *ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post,
0198 void *data);
0199
0200
0201 static ngx_conf_post_t ngx_http_fastcgi_lowat_post =
0202 { ngx_http_fastcgi_lowat_check };
0203
0204
0205 static ngx_conf_bitmask_t ngx_http_fastcgi_next_upstream_masks[] = {
0206 { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
0207 { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
0208 { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
0209 { ngx_string("non_idempotent"), NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT },
0210 { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
0211 { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
0212 { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 },
0213 { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
0214 { ngx_string("http_429"), NGX_HTTP_UPSTREAM_FT_HTTP_429 },
0215 { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING },
0216 { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
0217 { ngx_null_string, 0 }
0218 };
0219
0220
0221 ngx_module_t ngx_http_fastcgi_module;
0222
0223
0224 static ngx_command_t ngx_http_fastcgi_commands[] = {
0225
0226 { ngx_string("fastcgi_pass"),
0227 NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
0228 ngx_http_fastcgi_pass,
0229 NGX_HTTP_LOC_CONF_OFFSET,
0230 0,
0231 NULL },
0232
0233 { ngx_string("fastcgi_index"),
0234 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0235 ngx_conf_set_str_slot,
0236 NGX_HTTP_LOC_CONF_OFFSET,
0237 offsetof(ngx_http_fastcgi_loc_conf_t, index),
0238 NULL },
0239
0240 { ngx_string("fastcgi_split_path_info"),
0241 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0242 ngx_http_fastcgi_split_path_info,
0243 NGX_HTTP_LOC_CONF_OFFSET,
0244 0,
0245 NULL },
0246
0247 { ngx_string("fastcgi_store"),
0248 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0249 ngx_http_fastcgi_store,
0250 NGX_HTTP_LOC_CONF_OFFSET,
0251 0,
0252 NULL },
0253
0254 { ngx_string("fastcgi_store_access"),
0255 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
0256 ngx_conf_set_access_slot,
0257 NGX_HTTP_LOC_CONF_OFFSET,
0258 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.store_access),
0259 NULL },
0260
0261 { ngx_string("fastcgi_buffering"),
0262 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0263 ngx_conf_set_flag_slot,
0264 NGX_HTTP_LOC_CONF_OFFSET,
0265 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.buffering),
0266 NULL },
0267
0268 { ngx_string("fastcgi_request_buffering"),
0269 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0270 ngx_conf_set_flag_slot,
0271 NGX_HTTP_LOC_CONF_OFFSET,
0272 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.request_buffering),
0273 NULL },
0274
0275 { ngx_string("fastcgi_ignore_client_abort"),
0276 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0277 ngx_conf_set_flag_slot,
0278 NGX_HTTP_LOC_CONF_OFFSET,
0279 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.ignore_client_abort),
0280 NULL },
0281
0282 { ngx_string("fastcgi_bind"),
0283 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
0284 ngx_http_upstream_bind_set_slot,
0285 NGX_HTTP_LOC_CONF_OFFSET,
0286 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.local),
0287 NULL },
0288
0289 { ngx_string("fastcgi_connect_timeout"),
0290 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0291 ngx_conf_set_msec_slot,
0292 NGX_HTTP_LOC_CONF_OFFSET,
0293 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.connect_timeout),
0294 NULL },
0295
0296 { ngx_string("fastcgi_send_timeout"),
0297 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0298 ngx_conf_set_msec_slot,
0299 NGX_HTTP_LOC_CONF_OFFSET,
0300 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.send_timeout),
0301 NULL },
0302
0303 { ngx_string("fastcgi_send_lowat"),
0304 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0305 ngx_conf_set_size_slot,
0306 NGX_HTTP_LOC_CONF_OFFSET,
0307 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.send_lowat),
0308 &ngx_http_fastcgi_lowat_post },
0309
0310 { ngx_string("fastcgi_buffer_size"),
0311 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0312 ngx_conf_set_size_slot,
0313 NGX_HTTP_LOC_CONF_OFFSET,
0314 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.buffer_size),
0315 NULL },
0316
0317 { ngx_string("fastcgi_pass_request_headers"),
0318 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0319 ngx_conf_set_flag_slot,
0320 NGX_HTTP_LOC_CONF_OFFSET,
0321 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.pass_request_headers),
0322 NULL },
0323
0324 { ngx_string("fastcgi_pass_request_body"),
0325 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0326 ngx_conf_set_flag_slot,
0327 NGX_HTTP_LOC_CONF_OFFSET,
0328 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.pass_request_body),
0329 NULL },
0330
0331 { ngx_string("fastcgi_intercept_errors"),
0332 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0333 ngx_conf_set_flag_slot,
0334 NGX_HTTP_LOC_CONF_OFFSET,
0335 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.intercept_errors),
0336 NULL },
0337
0338 { ngx_string("fastcgi_read_timeout"),
0339 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0340 ngx_conf_set_msec_slot,
0341 NGX_HTTP_LOC_CONF_OFFSET,
0342 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.read_timeout),
0343 NULL },
0344
0345 { ngx_string("fastcgi_buffers"),
0346 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
0347 ngx_conf_set_bufs_slot,
0348 NGX_HTTP_LOC_CONF_OFFSET,
0349 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.bufs),
0350 NULL },
0351
0352 { ngx_string("fastcgi_busy_buffers_size"),
0353 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0354 ngx_conf_set_size_slot,
0355 NGX_HTTP_LOC_CONF_OFFSET,
0356 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.busy_buffers_size_conf),
0357 NULL },
0358
0359 { ngx_string("fastcgi_force_ranges"),
0360 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0361 ngx_conf_set_flag_slot,
0362 NGX_HTTP_LOC_CONF_OFFSET,
0363 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.force_ranges),
0364 NULL },
0365
0366 { ngx_string("fastcgi_limit_rate"),
0367 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0368 ngx_conf_set_size_slot,
0369 NGX_HTTP_LOC_CONF_OFFSET,
0370 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.limit_rate),
0371 NULL },
0372
0373 #if (NGX_HTTP_CACHE)
0374
0375 { ngx_string("fastcgi_cache"),
0376 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0377 ngx_http_fastcgi_cache,
0378 NGX_HTTP_LOC_CONF_OFFSET,
0379 0,
0380 NULL },
0381
0382 { ngx_string("fastcgi_cache_key"),
0383 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0384 ngx_http_fastcgi_cache_key,
0385 NGX_HTTP_LOC_CONF_OFFSET,
0386 0,
0387 NULL },
0388
0389 { ngx_string("fastcgi_cache_path"),
0390 NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
0391 ngx_http_file_cache_set_slot,
0392 NGX_HTTP_MAIN_CONF_OFFSET,
0393 offsetof(ngx_http_fastcgi_main_conf_t, caches),
0394 &ngx_http_fastcgi_module },
0395
0396 { ngx_string("fastcgi_cache_bypass"),
0397 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
0398 ngx_http_set_predicate_slot,
0399 NGX_HTTP_LOC_CONF_OFFSET,
0400 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_bypass),
0401 NULL },
0402
0403 { ngx_string("fastcgi_no_cache"),
0404 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
0405 ngx_http_set_predicate_slot,
0406 NGX_HTTP_LOC_CONF_OFFSET,
0407 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.no_cache),
0408 NULL },
0409
0410 { ngx_string("fastcgi_cache_valid"),
0411 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
0412 ngx_http_file_cache_valid_set_slot,
0413 NGX_HTTP_LOC_CONF_OFFSET,
0414 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_valid),
0415 NULL },
0416
0417 { ngx_string("fastcgi_cache_min_uses"),
0418 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0419 ngx_conf_set_num_slot,
0420 NGX_HTTP_LOC_CONF_OFFSET,
0421 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_min_uses),
0422 NULL },
0423
0424 { ngx_string("fastcgi_cache_max_range_offset"),
0425 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0426 ngx_conf_set_off_slot,
0427 NGX_HTTP_LOC_CONF_OFFSET,
0428 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_max_range_offset),
0429 NULL },
0430
0431 { ngx_string("fastcgi_cache_use_stale"),
0432 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
0433 ngx_conf_set_bitmask_slot,
0434 NGX_HTTP_LOC_CONF_OFFSET,
0435 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_use_stale),
0436 &ngx_http_fastcgi_next_upstream_masks },
0437
0438 { ngx_string("fastcgi_cache_methods"),
0439 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
0440 ngx_conf_set_bitmask_slot,
0441 NGX_HTTP_LOC_CONF_OFFSET,
0442 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_methods),
0443 &ngx_http_upstream_cache_method_mask },
0444
0445 { ngx_string("fastcgi_cache_lock"),
0446 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0447 ngx_conf_set_flag_slot,
0448 NGX_HTTP_LOC_CONF_OFFSET,
0449 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_lock),
0450 NULL },
0451
0452 { ngx_string("fastcgi_cache_lock_timeout"),
0453 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0454 ngx_conf_set_msec_slot,
0455 NGX_HTTP_LOC_CONF_OFFSET,
0456 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_lock_timeout),
0457 NULL },
0458
0459 { ngx_string("fastcgi_cache_lock_age"),
0460 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0461 ngx_conf_set_msec_slot,
0462 NGX_HTTP_LOC_CONF_OFFSET,
0463 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_lock_age),
0464 NULL },
0465
0466 { ngx_string("fastcgi_cache_revalidate"),
0467 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0468 ngx_conf_set_flag_slot,
0469 NGX_HTTP_LOC_CONF_OFFSET,
0470 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_revalidate),
0471 NULL },
0472
0473 { ngx_string("fastcgi_cache_background_update"),
0474 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0475 ngx_conf_set_flag_slot,
0476 NGX_HTTP_LOC_CONF_OFFSET,
0477 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_background_update),
0478 NULL },
0479
0480 #endif
0481
0482 { ngx_string("fastcgi_temp_path"),
0483 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
0484 ngx_conf_set_path_slot,
0485 NGX_HTTP_LOC_CONF_OFFSET,
0486 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.temp_path),
0487 NULL },
0488
0489 { ngx_string("fastcgi_max_temp_file_size"),
0490 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0491 ngx_conf_set_size_slot,
0492 NGX_HTTP_LOC_CONF_OFFSET,
0493 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.max_temp_file_size_conf),
0494 NULL },
0495
0496 { ngx_string("fastcgi_temp_file_write_size"),
0497 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0498 ngx_conf_set_size_slot,
0499 NGX_HTTP_LOC_CONF_OFFSET,
0500 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.temp_file_write_size_conf),
0501 NULL },
0502
0503 { ngx_string("fastcgi_next_upstream"),
0504 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
0505 ngx_conf_set_bitmask_slot,
0506 NGX_HTTP_LOC_CONF_OFFSET,
0507 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.next_upstream),
0508 &ngx_http_fastcgi_next_upstream_masks },
0509
0510 { ngx_string("fastcgi_next_upstream_tries"),
0511 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0512 ngx_conf_set_num_slot,
0513 NGX_HTTP_LOC_CONF_OFFSET,
0514 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.next_upstream_tries),
0515 NULL },
0516
0517 { ngx_string("fastcgi_next_upstream_timeout"),
0518 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0519 ngx_conf_set_msec_slot,
0520 NGX_HTTP_LOC_CONF_OFFSET,
0521 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.next_upstream_timeout),
0522 NULL },
0523
0524 { ngx_string("fastcgi_param"),
0525 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE23,
0526 ngx_http_upstream_param_set_slot,
0527 NGX_HTTP_LOC_CONF_OFFSET,
0528 offsetof(ngx_http_fastcgi_loc_conf_t, params_source),
0529 NULL },
0530
0531 { ngx_string("fastcgi_pass_header"),
0532 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0533 ngx_conf_set_str_array_slot,
0534 NGX_HTTP_LOC_CONF_OFFSET,
0535 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.pass_headers),
0536 NULL },
0537
0538 { ngx_string("fastcgi_hide_header"),
0539 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0540 ngx_conf_set_str_array_slot,
0541 NGX_HTTP_LOC_CONF_OFFSET,
0542 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.hide_headers),
0543 NULL },
0544
0545 { ngx_string("fastcgi_ignore_headers"),
0546 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
0547 ngx_conf_set_bitmask_slot,
0548 NGX_HTTP_LOC_CONF_OFFSET,
0549 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.ignore_headers),
0550 &ngx_http_upstream_ignore_headers_masks },
0551
0552 { ngx_string("fastcgi_catch_stderr"),
0553 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0554 ngx_conf_set_str_array_slot,
0555 NGX_HTTP_LOC_CONF_OFFSET,
0556 offsetof(ngx_http_fastcgi_loc_conf_t, catch_stderr),
0557 NULL },
0558
0559 { ngx_string("fastcgi_keep_conn"),
0560 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0561 ngx_conf_set_flag_slot,
0562 NGX_HTTP_LOC_CONF_OFFSET,
0563 offsetof(ngx_http_fastcgi_loc_conf_t, keep_conn),
0564 NULL },
0565
0566 ngx_null_command
0567 };
0568
0569
0570 static ngx_http_module_t ngx_http_fastcgi_module_ctx = {
0571 ngx_http_fastcgi_add_variables,
0572 NULL,
0573
0574 ngx_http_fastcgi_create_main_conf,
0575 NULL,
0576
0577 NULL,
0578 NULL,
0579
0580 ngx_http_fastcgi_create_loc_conf,
0581 ngx_http_fastcgi_merge_loc_conf
0582 };
0583
0584
0585 ngx_module_t ngx_http_fastcgi_module = {
0586 NGX_MODULE_V1,
0587 &ngx_http_fastcgi_module_ctx,
0588 ngx_http_fastcgi_commands,
0589 NGX_HTTP_MODULE,
0590 NULL,
0591 NULL,
0592 NULL,
0593 NULL,
0594 NULL,
0595 NULL,
0596 NULL,
0597 NGX_MODULE_V1_PADDING
0598 };
0599
0600
0601 static ngx_http_fastcgi_request_start_t ngx_http_fastcgi_request_start = {
0602 { 1,
0603 NGX_HTTP_FASTCGI_BEGIN_REQUEST,
0604 0,
0605 1,
0606 0,
0607 sizeof(ngx_http_fastcgi_begin_request_t),
0608 0,
0609 0 },
0610
0611 { 0,
0612 NGX_HTTP_FASTCGI_RESPONDER,
0613 0,
0614 { 0, 0, 0, 0, 0 } },
0615
0616 { 1,
0617 NGX_HTTP_FASTCGI_PARAMS,
0618 0,
0619 1 },
0620
0621 };
0622
0623
0624 static ngx_http_variable_t ngx_http_fastcgi_vars[] = {
0625
0626 { ngx_string("fastcgi_script_name"), NULL,
0627 ngx_http_fastcgi_script_name_variable, 0,
0628 NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
0629
0630 { ngx_string("fastcgi_path_info"), NULL,
0631 ngx_http_fastcgi_path_info_variable, 0,
0632 NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 },
0633
0634 { ngx_null_string, NULL, NULL, 0, 0, 0 }
0635 };
0636
0637
0638 static ngx_str_t ngx_http_fastcgi_hide_headers[] = {
0639 ngx_string("Status"),
0640 ngx_string("X-Accel-Expires"),
0641 ngx_string("X-Accel-Redirect"),
0642 ngx_string("X-Accel-Limit-Rate"),
0643 ngx_string("X-Accel-Buffering"),
0644 ngx_string("X-Accel-Charset"),
0645 ngx_null_string
0646 };
0647
0648
0649 #if (NGX_HTTP_CACHE)
0650
0651 static ngx_keyval_t ngx_http_fastcgi_cache_headers[] = {
0652 { ngx_string("HTTP_IF_MODIFIED_SINCE"),
0653 ngx_string("$upstream_cache_last_modified") },
0654 { ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") },
0655 { ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("$upstream_cache_etag") },
0656 { ngx_string("HTTP_IF_MATCH"), ngx_string("") },
0657 { ngx_string("HTTP_RANGE"), ngx_string("") },
0658 { ngx_string("HTTP_IF_RANGE"), ngx_string("") },
0659 { ngx_null_string, ngx_null_string }
0660 };
0661
0662 #endif
0663
0664
0665 static ngx_path_init_t ngx_http_fastcgi_temp_path = {
0666 ngx_string(NGX_HTTP_FASTCGI_TEMP_PATH), { 1, 2, 0 }
0667 };
0668
0669
0670 static ngx_int_t
0671 ngx_http_fastcgi_handler(ngx_http_request_t *r)
0672 {
0673 ngx_int_t rc;
0674 ngx_http_upstream_t *u;
0675 ngx_http_fastcgi_ctx_t *f;
0676 ngx_http_fastcgi_loc_conf_t *flcf;
0677 #if (NGX_HTTP_CACHE)
0678 ngx_http_fastcgi_main_conf_t *fmcf;
0679 #endif
0680
0681 if (ngx_http_upstream_create(r) != NGX_OK) {
0682 return NGX_HTTP_INTERNAL_SERVER_ERROR;
0683 }
0684
0685 f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
0686 if (f == NULL) {
0687 return NGX_HTTP_INTERNAL_SERVER_ERROR;
0688 }
0689
0690 ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
0691
0692 flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
0693
0694 if (flcf->fastcgi_lengths) {
0695 if (ngx_http_fastcgi_eval(r, flcf) != NGX_OK) {
0696 return NGX_HTTP_INTERNAL_SERVER_ERROR;
0697 }
0698 }
0699
0700 u = r->upstream;
0701
0702 ngx_str_set(&u->schema, "fastcgi://");
0703 u->output.tag = (ngx_buf_tag_t) &ngx_http_fastcgi_module;
0704
0705 u->conf = &flcf->upstream;
0706
0707 #if (NGX_HTTP_CACHE)
0708 fmcf = ngx_http_get_module_main_conf(r, ngx_http_fastcgi_module);
0709
0710 u->caches = &fmcf->caches;
0711 u->create_key = ngx_http_fastcgi_create_key;
0712 #endif
0713
0714 u->create_request = ngx_http_fastcgi_create_request;
0715 u->reinit_request = ngx_http_fastcgi_reinit_request;
0716 u->process_header = ngx_http_fastcgi_process_header;
0717 u->abort_request = ngx_http_fastcgi_abort_request;
0718 u->finalize_request = ngx_http_fastcgi_finalize_request;
0719 r->state = 0;
0720
0721 u->buffering = flcf->upstream.buffering;
0722
0723 u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
0724 if (u->pipe == NULL) {
0725 return NGX_HTTP_INTERNAL_SERVER_ERROR;
0726 }
0727
0728 u->pipe->input_filter = ngx_http_fastcgi_input_filter;
0729 u->pipe->input_ctx = r;
0730
0731 u->input_filter_init = ngx_http_fastcgi_input_filter_init;
0732 u->input_filter = ngx_http_fastcgi_non_buffered_filter;
0733 u->input_filter_ctx = r;
0734
0735 if (!flcf->upstream.request_buffering
0736 && flcf->upstream.pass_request_body)
0737 {
0738 r->request_body_no_buffering = 1;
0739 }
0740
0741 rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
0742
0743 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
0744 return rc;
0745 }
0746
0747 return NGX_DONE;
0748 }
0749
0750
0751 static ngx_int_t
0752 ngx_http_fastcgi_eval(ngx_http_request_t *r, ngx_http_fastcgi_loc_conf_t *flcf)
0753 {
0754 ngx_url_t url;
0755 ngx_http_upstream_t *u;
0756
0757 ngx_memzero(&url, sizeof(ngx_url_t));
0758
0759 if (ngx_http_script_run(r, &url.url, flcf->fastcgi_lengths->elts, 0,
0760 flcf->fastcgi_values->elts)
0761 == NULL)
0762 {
0763 return NGX_ERROR;
0764 }
0765
0766 url.no_resolve = 1;
0767
0768 if (ngx_parse_url(r->pool, &url) != NGX_OK) {
0769 if (url.err) {
0770 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
0771 "%s in upstream \"%V\"", url.err, &url.url);
0772 }
0773
0774 return NGX_ERROR;
0775 }
0776
0777 u = r->upstream;
0778
0779 u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
0780 if (u->resolved == NULL) {
0781 return NGX_ERROR;
0782 }
0783
0784 if (url.addrs) {
0785 u->resolved->sockaddr = url.addrs[0].sockaddr;
0786 u->resolved->socklen = url.addrs[0].socklen;
0787 u->resolved->name = url.addrs[0].name;
0788 u->resolved->naddrs = 1;
0789 }
0790
0791 u->resolved->host = url.host;
0792 u->resolved->port = url.port;
0793 u->resolved->no_port = url.no_port;
0794
0795 return NGX_OK;
0796 }
0797
0798
0799 #if (NGX_HTTP_CACHE)
0800
0801 static ngx_int_t
0802 ngx_http_fastcgi_create_key(ngx_http_request_t *r)
0803 {
0804 ngx_str_t *key;
0805 ngx_http_fastcgi_loc_conf_t *flcf;
0806
0807 key = ngx_array_push(&r->cache->keys);
0808 if (key == NULL) {
0809 return NGX_ERROR;
0810 }
0811
0812 flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
0813
0814 if (ngx_http_complex_value(r, &flcf->cache_key, key) != NGX_OK) {
0815 return NGX_ERROR;
0816 }
0817
0818 return NGX_OK;
0819 }
0820
0821 #endif
0822
0823
0824 static ngx_int_t
0825 ngx_http_fastcgi_create_request(ngx_http_request_t *r)
0826 {
0827 off_t file_pos;
0828 u_char ch, *pos, *lowcase_key;
0829 size_t size, len, key_len, val_len, padding,
0830 allocated;
0831 ngx_uint_t i, n, next, hash, skip_empty, header_params;
0832 ngx_buf_t *b;
0833 ngx_chain_t *cl, *body;
0834 ngx_list_part_t *part;
0835 ngx_table_elt_t *header, **ignored;
0836 ngx_http_upstream_t *u;
0837 ngx_http_script_code_pt code;
0838 ngx_http_script_engine_t e, le;
0839 ngx_http_fastcgi_header_t *h;
0840 ngx_http_fastcgi_params_t *params;
0841 ngx_http_fastcgi_loc_conf_t *flcf;
0842 ngx_http_script_len_code_pt lcode;
0843
0844 len = 0;
0845 header_params = 0;
0846 ignored = NULL;
0847
0848 u = r->upstream;
0849
0850 flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
0851
0852 #if (NGX_HTTP_CACHE)
0853 params = u->cacheable ? &flcf->params_cache : &flcf->params;
0854 #else
0855 params = &flcf->params;
0856 #endif
0857
0858 if (params->lengths) {
0859 ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
0860
0861 ngx_http_script_flush_no_cacheable_variables(r, params->flushes);
0862 le.flushed = 1;
0863
0864 le.ip = params->lengths->elts;
0865 le.request = r;
0866
0867 while (*(uintptr_t *) le.ip) {
0868
0869 lcode = *(ngx_http_script_len_code_pt *) le.ip;
0870 key_len = lcode(&le);
0871
0872 lcode = *(ngx_http_script_len_code_pt *) le.ip;
0873 skip_empty = lcode(&le);
0874
0875 for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
0876 lcode = *(ngx_http_script_len_code_pt *) le.ip;
0877 }
0878 le.ip += sizeof(uintptr_t);
0879
0880 if (skip_empty && val_len == 0) {
0881 continue;
0882 }
0883
0884 len += 1 + key_len + ((val_len > 127) ? 4 : 1) + val_len;
0885 }
0886 }
0887
0888 if (flcf->upstream.pass_request_headers) {
0889
0890 allocated = 0;
0891 lowcase_key = NULL;
0892
0893 if (params->number) {
0894 n = 0;
0895 part = &r->headers_in.headers.part;
0896
0897 while (part) {
0898 n += part->nelts;
0899 part = part->next;
0900 }
0901
0902 ignored = ngx_palloc(r->pool, n * sizeof(void *));
0903 if (ignored == NULL) {
0904 return NGX_ERROR;
0905 }
0906 }
0907
0908 part = &r->headers_in.headers.part;
0909 header = part->elts;
0910
0911 for (i = 0; ; i++) {
0912
0913 if (i >= part->nelts) {
0914 if (part->next == NULL) {
0915 break;
0916 }
0917
0918 part = part->next;
0919 header = part->elts;
0920 i = 0;
0921 }
0922
0923 if (params->number) {
0924 if (allocated < header[i].key.len) {
0925 allocated = header[i].key.len + 16;
0926 lowcase_key = ngx_pnalloc(r->pool, allocated);
0927 if (lowcase_key == NULL) {
0928 return NGX_ERROR;
0929 }
0930 }
0931
0932 hash = 0;
0933
0934 for (n = 0; n < header[i].key.len; n++) {
0935 ch = header[i].key.data[n];
0936
0937 if (ch >= 'A' && ch <= 'Z') {
0938 ch |= 0x20;
0939
0940 } else if (ch == '-') {
0941 ch = '_';
0942 }
0943
0944 hash = ngx_hash(hash, ch);
0945 lowcase_key[n] = ch;
0946 }
0947
0948 if (ngx_hash_find(¶ms->hash, hash, lowcase_key, n)) {
0949 ignored[header_params++] = &header[i];
0950 continue;
0951 }
0952
0953 n += sizeof("HTTP_") - 1;
0954
0955 } else {
0956 n = sizeof("HTTP_") - 1 + header[i].key.len;
0957 }
0958
0959 len += ((n > 127) ? 4 : 1) + ((header[i].value.len > 127) ? 4 : 1)
0960 + n + header[i].value.len;
0961 }
0962 }
0963
0964
0965 if (len > 65535) {
0966 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
0967 "fastcgi request record is too big: %uz", len);
0968 return NGX_ERROR;
0969 }
0970
0971
0972 padding = 8 - len % 8;
0973 padding = (padding == 8) ? 0 : padding;
0974
0975
0976 size = sizeof(ngx_http_fastcgi_header_t)
0977 + sizeof(ngx_http_fastcgi_begin_request_t)
0978
0979 + sizeof(ngx_http_fastcgi_header_t)
0980 + len + padding
0981 + sizeof(ngx_http_fastcgi_header_t)
0982
0983 + sizeof(ngx_http_fastcgi_header_t);
0984
0985
0986 b = ngx_create_temp_buf(r->pool, size);
0987 if (b == NULL) {
0988 return NGX_ERROR;
0989 }
0990
0991 cl = ngx_alloc_chain_link(r->pool);
0992 if (cl == NULL) {
0993 return NGX_ERROR;
0994 }
0995
0996 cl->buf = b;
0997
0998 ngx_http_fastcgi_request_start.br.flags =
0999 flcf->keep_conn ? NGX_HTTP_FASTCGI_KEEP_CONN : 0;
1000
1001 ngx_memcpy(b->pos, &ngx_http_fastcgi_request_start,
1002 sizeof(ngx_http_fastcgi_request_start_t));
1003
1004 h = (ngx_http_fastcgi_header_t *)
1005 (b->pos + sizeof(ngx_http_fastcgi_header_t)
1006 + sizeof(ngx_http_fastcgi_begin_request_t));
1007
1008 h->content_length_hi = (u_char) ((len >> 8) & 0xff);
1009 h->content_length_lo = (u_char) (len & 0xff);
1010 h->padding_length = (u_char) padding;
1011 h->reserved = 0;
1012
1013 b->last = b->pos + sizeof(ngx_http_fastcgi_header_t)
1014 + sizeof(ngx_http_fastcgi_begin_request_t)
1015 + sizeof(ngx_http_fastcgi_header_t);
1016
1017
1018 if (params->lengths) {
1019 ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
1020
1021 e.ip = params->values->elts;
1022 e.pos = b->last;
1023 e.request = r;
1024 e.flushed = 1;
1025
1026 le.ip = params->lengths->elts;
1027
1028 while (*(uintptr_t *) le.ip) {
1029
1030 lcode = *(ngx_http_script_len_code_pt *) le.ip;
1031 key_len = (u_char) lcode(&le);
1032
1033 lcode = *(ngx_http_script_len_code_pt *) le.ip;
1034 skip_empty = lcode(&le);
1035
1036 for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
1037 lcode = *(ngx_http_script_len_code_pt *) le.ip;
1038 }
1039 le.ip += sizeof(uintptr_t);
1040
1041 if (skip_empty && val_len == 0) {
1042 e.skip = 1;
1043
1044 while (*(uintptr_t *) e.ip) {
1045 code = *(ngx_http_script_code_pt *) e.ip;
1046 code((ngx_http_script_engine_t *) &e);
1047 }
1048 e.ip += sizeof(uintptr_t);
1049
1050 e.skip = 0;
1051
1052 continue;
1053 }
1054
1055 *e.pos++ = (u_char) key_len;
1056
1057 if (val_len > 127) {
1058 *e.pos++ = (u_char) (((val_len >> 24) & 0x7f) | 0x80);
1059 *e.pos++ = (u_char) ((val_len >> 16) & 0xff);
1060 *e.pos++ = (u_char) ((val_len >> 8) & 0xff);
1061 *e.pos++ = (u_char) (val_len & 0xff);
1062
1063 } else {
1064 *e.pos++ = (u_char) val_len;
1065 }
1066
1067 while (*(uintptr_t *) e.ip) {
1068 code = *(ngx_http_script_code_pt *) e.ip;
1069 code((ngx_http_script_engine_t *) &e);
1070 }
1071 e.ip += sizeof(uintptr_t);
1072
1073 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1074 "fastcgi param: \"%*s: %*s\"",
1075 key_len, e.pos - (key_len + val_len),
1076 val_len, e.pos - val_len);
1077 }
1078
1079 b->last = e.pos;
1080 }
1081
1082
1083 if (flcf->upstream.pass_request_headers) {
1084
1085 part = &r->headers_in.headers.part;
1086 header = part->elts;
1087
1088 for (i = 0; ; i++) {
1089
1090 if (i >= part->nelts) {
1091 if (part->next == NULL) {
1092 break;
1093 }
1094
1095 part = part->next;
1096 header = part->elts;
1097 i = 0;
1098 }
1099
1100 for (n = 0; n < header_params; n++) {
1101 if (&header[i] == ignored[n]) {
1102 goto next;
1103 }
1104 }
1105
1106 key_len = sizeof("HTTP_") - 1 + header[i].key.len;
1107 if (key_len > 127) {
1108 *b->last++ = (u_char) (((key_len >> 24) & 0x7f) | 0x80);
1109 *b->last++ = (u_char) ((key_len >> 16) & 0xff);
1110 *b->last++ = (u_char) ((key_len >> 8) & 0xff);
1111 *b->last++ = (u_char) (key_len & 0xff);
1112
1113 } else {
1114 *b->last++ = (u_char) key_len;
1115 }
1116
1117 val_len = header[i].value.len;
1118 if (val_len > 127) {
1119 *b->last++ = (u_char) (((val_len >> 24) & 0x7f) | 0x80);
1120 *b->last++ = (u_char) ((val_len >> 16) & 0xff);
1121 *b->last++ = (u_char) ((val_len >> 8) & 0xff);
1122 *b->last++ = (u_char) (val_len & 0xff);
1123
1124 } else {
1125 *b->last++ = (u_char) val_len;
1126 }
1127
1128 b->last = ngx_cpymem(b->last, "HTTP_", sizeof("HTTP_") - 1);
1129
1130 for (n = 0; n < header[i].key.len; n++) {
1131 ch = header[i].key.data[n];
1132
1133 if (ch >= 'a' && ch <= 'z') {
1134 ch &= ~0x20;
1135
1136 } else if (ch == '-') {
1137 ch = '_';
1138 }
1139
1140 *b->last++ = ch;
1141 }
1142
1143 b->last = ngx_copy(b->last, header[i].value.data, val_len);
1144
1145 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1146 "fastcgi param: \"%*s: %*s\"",
1147 key_len, b->last - (key_len + val_len),
1148 val_len, b->last - val_len);
1149 next:
1150
1151 continue;
1152 }
1153 }
1154
1155
1156 if (padding) {
1157 ngx_memzero(b->last, padding);
1158 b->last += padding;
1159 }
1160
1161
1162 h = (ngx_http_fastcgi_header_t *) b->last;
1163 b->last += sizeof(ngx_http_fastcgi_header_t);
1164
1165 h->version = 1;
1166 h->type = NGX_HTTP_FASTCGI_PARAMS;
1167 h->request_id_hi = 0;
1168 h->request_id_lo = 1;
1169 h->content_length_hi = 0;
1170 h->content_length_lo = 0;
1171 h->padding_length = 0;
1172 h->reserved = 0;
1173
1174 if (r->request_body_no_buffering) {
1175
1176 u->request_bufs = cl;
1177
1178 u->output.output_filter = ngx_http_fastcgi_body_output_filter;
1179 u->output.filter_ctx = r;
1180
1181 } else if (flcf->upstream.pass_request_body) {
1182
1183 body = u->request_bufs;
1184 u->request_bufs = cl;
1185
1186 #if (NGX_SUPPRESS_WARN)
1187 file_pos = 0;
1188 pos = NULL;
1189 #endif
1190
1191 while (body) {
1192
1193 if (ngx_buf_special(body->buf)) {
1194 body = body->next;
1195 continue;
1196 }
1197
1198 if (body->buf->in_file) {
1199 file_pos = body->buf->file_pos;
1200
1201 } else {
1202 pos = body->buf->pos;
1203 }
1204
1205 next = 0;
1206
1207 do {
1208 b = ngx_alloc_buf(r->pool);
1209 if (b == NULL) {
1210 return NGX_ERROR;
1211 }
1212
1213 ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
1214
1215 if (body->buf->in_file) {
1216 b->file_pos = file_pos;
1217 file_pos += 32 * 1024;
1218
1219 if (file_pos >= body->buf->file_last) {
1220 file_pos = body->buf->file_last;
1221 next = 1;
1222 }
1223
1224 b->file_last = file_pos;
1225 len = (ngx_uint_t) (file_pos - b->file_pos);
1226
1227 } else {
1228 b->pos = pos;
1229 b->start = pos;
1230 pos += 32 * 1024;
1231
1232 if (pos >= body->buf->last) {
1233 pos = body->buf->last;
1234 next = 1;
1235 }
1236
1237 b->last = pos;
1238 len = (ngx_uint_t) (pos - b->pos);
1239 }
1240
1241 padding = 8 - len % 8;
1242 padding = (padding == 8) ? 0 : padding;
1243
1244 h = (ngx_http_fastcgi_header_t *) cl->buf->last;
1245 cl->buf->last += sizeof(ngx_http_fastcgi_header_t);
1246
1247 h->version = 1;
1248 h->type = NGX_HTTP_FASTCGI_STDIN;
1249 h->request_id_hi = 0;
1250 h->request_id_lo = 1;
1251 h->content_length_hi = (u_char) ((len >> 8) & 0xff);
1252 h->content_length_lo = (u_char) (len & 0xff);
1253 h->padding_length = (u_char) padding;
1254 h->reserved = 0;
1255
1256 cl->next = ngx_alloc_chain_link(r->pool);
1257 if (cl->next == NULL) {
1258 return NGX_ERROR;
1259 }
1260
1261 cl = cl->next;
1262 cl->buf = b;
1263
1264 b = ngx_create_temp_buf(r->pool,
1265 sizeof(ngx_http_fastcgi_header_t)
1266 + padding);
1267 if (b == NULL) {
1268 return NGX_ERROR;
1269 }
1270
1271 if (padding) {
1272 ngx_memzero(b->last, padding);
1273 b->last += padding;
1274 }
1275
1276 cl->next = ngx_alloc_chain_link(r->pool);
1277 if (cl->next == NULL) {
1278 return NGX_ERROR;
1279 }
1280
1281 cl = cl->next;
1282 cl->buf = b;
1283
1284 } while (!next);
1285
1286 body = body->next;
1287 }
1288
1289 } else {
1290 u->request_bufs = cl;
1291 }
1292
1293 if (!r->request_body_no_buffering) {
1294 h = (ngx_http_fastcgi_header_t *) cl->buf->last;
1295 cl->buf->last += sizeof(ngx_http_fastcgi_header_t);
1296
1297 h->version = 1;
1298 h->type = NGX_HTTP_FASTCGI_STDIN;
1299 h->request_id_hi = 0;
1300 h->request_id_lo = 1;
1301 h->content_length_hi = 0;
1302 h->content_length_lo = 0;
1303 h->padding_length = 0;
1304 h->reserved = 0;
1305 }
1306
1307 cl->next = NULL;
1308
1309 return NGX_OK;
1310 }
1311
1312
1313 static ngx_int_t
1314 ngx_http_fastcgi_reinit_request(ngx_http_request_t *r)
1315 {
1316 ngx_http_fastcgi_ctx_t *f;
1317
1318 f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
1319
1320 if (f == NULL) {
1321 return NGX_OK;
1322 }
1323
1324 f->state = ngx_http_fastcgi_st_version;
1325 f->fastcgi_stdout = 0;
1326 f->large_stderr = 0;
1327
1328 if (f->split_parts) {
1329 f->split_parts->nelts = 0;
1330 }
1331
1332 r->state = 0;
1333
1334 return NGX_OK;
1335 }
1336
1337
1338 static ngx_int_t
1339 ngx_http_fastcgi_body_output_filter(void *data, ngx_chain_t *in)
1340 {
1341 ngx_http_request_t *r = data;
1342
1343 off_t file_pos;
1344 u_char *pos, *start;
1345 size_t len, padding;
1346 ngx_buf_t *b;
1347 ngx_int_t rc;
1348 ngx_uint_t next, last;
1349 ngx_chain_t *cl, *tl, *out, **ll;
1350 ngx_http_fastcgi_ctx_t *f;
1351 ngx_http_fastcgi_header_t *h;
1352
1353 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1354 "fastcgi output filter");
1355
1356 f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
1357
1358 if (in == NULL) {
1359 out = in;
1360 goto out;
1361 }
1362
1363 out = NULL;
1364 ll = &out;
1365
1366 if (!f->header_sent) {
1367
1368
1369 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1370 "fastcgi output header");
1371
1372 f->header_sent = 1;
1373
1374 tl = ngx_alloc_chain_link(r->pool);
1375 if (tl == NULL) {
1376 return NGX_ERROR;
1377 }
1378
1379 tl->buf = in->buf;
1380 *ll = tl;
1381 ll = &tl->next;
1382
1383 in = in->next;
1384
1385 if (in == NULL) {
1386 tl->next = NULL;
1387 goto out;
1388 }
1389 }
1390
1391 cl = ngx_chain_get_free_buf(r->pool, &f->free);
1392 if (cl == NULL) {
1393 return NGX_ERROR;
1394 }
1395
1396 b = cl->buf;
1397
1398 b->tag = (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter;
1399 b->temporary = 1;
1400
1401 if (b->start == NULL) {
1402
1403
1404 b->start = ngx_palloc(r->pool,
1405 sizeof(ngx_http_fastcgi_header_t) + 7);
1406 if (b->start == NULL) {
1407 return NGX_ERROR;
1408 }
1409
1410 b->pos = b->start;
1411 b->last = b->start;
1412
1413 b->end = b->start + sizeof(ngx_http_fastcgi_header_t) + 7;
1414 }
1415
1416 *ll = cl;
1417
1418 last = 0;
1419 padding = 0;
1420
1421 #if (NGX_SUPPRESS_WARN)
1422 file_pos = 0;
1423 pos = NULL;
1424 #endif
1425
1426 while (in) {
1427
1428 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
1429 "fastcgi output in l:%d f:%d %p, pos %p, size: %z "
1430 "file: %O, size: %O",
1431 in->buf->last_buf,
1432 in->buf->in_file,
1433 in->buf->start, in->buf->pos,
1434 in->buf->last - in->buf->pos,
1435 in->buf->file_pos,
1436 in->buf->file_last - in->buf->file_pos);
1437
1438 if (in->buf->last_buf) {
1439 last = 1;
1440 }
1441
1442 if (ngx_buf_special(in->buf)) {
1443 in = in->next;
1444 continue;
1445 }
1446
1447 if (in->buf->in_file) {
1448 file_pos = in->buf->file_pos;
1449
1450 } else {
1451 pos = in->buf->pos;
1452 }
1453
1454 next = 0;
1455
1456 do {
1457 tl = ngx_chain_get_free_buf(r->pool, &f->free);
1458 if (tl == NULL) {
1459 return NGX_ERROR;
1460 }
1461
1462 b = tl->buf;
1463 start = b->start;
1464
1465 ngx_memcpy(b, in->buf, sizeof(ngx_buf_t));
1466
1467
1468
1469
1470
1471
1472 b->start = start;
1473
1474 if (in->buf->in_file) {
1475 b->file_pos = file_pos;
1476 file_pos += 32 * 1024;
1477
1478 if (file_pos >= in->buf->file_last) {
1479 file_pos = in->buf->file_last;
1480 next = 1;
1481 }
1482
1483 b->file_last = file_pos;
1484 len = (ngx_uint_t) (file_pos - b->file_pos);
1485
1486 } else {
1487 b->pos = pos;
1488 pos += 32 * 1024;
1489
1490 if (pos >= in->buf->last) {
1491 pos = in->buf->last;
1492 next = 1;
1493 }
1494
1495 b->last = pos;
1496 len = (ngx_uint_t) (pos - b->pos);
1497 }
1498
1499 b->tag = (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter;
1500 b->shadow = in->buf;
1501 b->last_shadow = next;
1502
1503 b->last_buf = 0;
1504 b->last_in_chain = 0;
1505
1506 padding = 8 - len % 8;
1507 padding = (padding == 8) ? 0 : padding;
1508
1509 h = (ngx_http_fastcgi_header_t *) cl->buf->last;
1510 cl->buf->last += sizeof(ngx_http_fastcgi_header_t);
1511
1512 h->version = 1;
1513 h->type = NGX_HTTP_FASTCGI_STDIN;
1514 h->request_id_hi = 0;
1515 h->request_id_lo = 1;
1516 h->content_length_hi = (u_char) ((len >> 8) & 0xff);
1517 h->content_length_lo = (u_char) (len & 0xff);
1518 h->padding_length = (u_char) padding;
1519 h->reserved = 0;
1520
1521 cl->next = tl;
1522 cl = tl;
1523
1524 tl = ngx_chain_get_free_buf(r->pool, &f->free);
1525 if (tl == NULL) {
1526 return NGX_ERROR;
1527 }
1528
1529 b = tl->buf;
1530
1531 b->tag = (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter;
1532 b->temporary = 1;
1533
1534 if (b->start == NULL) {
1535
1536
1537 b->start = ngx_palloc(r->pool,
1538 sizeof(ngx_http_fastcgi_header_t) + 7);
1539 if (b->start == NULL) {
1540 return NGX_ERROR;
1541 }
1542
1543 b->pos = b->start;
1544 b->last = b->start;
1545
1546 b->end = b->start + sizeof(ngx_http_fastcgi_header_t) + 7;
1547 }
1548
1549 if (padding) {
1550 ngx_memzero(b->last, padding);
1551 b->last += padding;
1552 }
1553
1554 cl->next = tl;
1555 cl = tl;
1556
1557 } while (!next);
1558
1559 in = in->next;
1560 }
1561
1562 if (last) {
1563 h = (ngx_http_fastcgi_header_t *) cl->buf->last;
1564 cl->buf->last += sizeof(ngx_http_fastcgi_header_t);
1565
1566 h->version = 1;
1567 h->type = NGX_HTTP_FASTCGI_STDIN;
1568 h->request_id_hi = 0;
1569 h->request_id_lo = 1;
1570 h->content_length_hi = 0;
1571 h->content_length_lo = 0;
1572 h->padding_length = 0;
1573 h->reserved = 0;
1574
1575 cl->buf->last_buf = 1;
1576
1577 } else if (padding == 0) {
1578
1579 cl->buf->temporary = 0;
1580 cl->buf->sync = 1;
1581 }
1582
1583 cl->next = NULL;
1584
1585 out:
1586
1587 #if (NGX_DEBUG)
1588
1589 for (cl = out; cl; cl = cl->next) {
1590 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
1591 "fastcgi output out l:%d f:%d %p, pos %p, size: %z "
1592 "file: %O, size: %O",
1593 cl->buf->last_buf,
1594 cl->buf->in_file,
1595 cl->buf->start, cl->buf->pos,
1596 cl->buf->last - cl->buf->pos,
1597 cl->buf->file_pos,
1598 cl->buf->file_last - cl->buf->file_pos);
1599 }
1600
1601 #endif
1602
1603 rc = ngx_chain_writer(&r->upstream->writer, out);
1604
1605 ngx_chain_update_chains(r->pool, &f->free, &f->busy, &out,
1606 (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter);
1607
1608 for (cl = f->free; cl; cl = cl->next) {
1609
1610
1611
1612 if (cl->buf->shadow) {
1613 if (cl->buf->last_shadow) {
1614 b = cl->buf->shadow;
1615 b->pos = b->last;
1616 }
1617
1618 cl->buf->shadow = NULL;
1619 }
1620 }
1621
1622 return rc;
1623 }
1624
1625
1626 static ngx_int_t
1627 ngx_http_fastcgi_process_header(ngx_http_request_t *r)
1628 {
1629 u_char *p, *msg, *start, *last,
1630 *part_start, *part_end;
1631 size_t size;
1632 ngx_str_t *status_line, *pattern;
1633 ngx_int_t rc, status;
1634 ngx_buf_t buf;
1635 ngx_uint_t i;
1636 ngx_table_elt_t *h;
1637 ngx_http_upstream_t *u;
1638 ngx_http_fastcgi_ctx_t *f;
1639 ngx_http_upstream_header_t *hh;
1640 ngx_http_fastcgi_loc_conf_t *flcf;
1641 ngx_http_fastcgi_split_part_t *part;
1642 ngx_http_upstream_main_conf_t *umcf;
1643
1644 f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
1645
1646 umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
1647
1648 u = r->upstream;
1649
1650 for ( ;; ) {
1651
1652 if (f->state < ngx_http_fastcgi_st_data) {
1653
1654 f->pos = u->buffer.pos;
1655 f->last = u->buffer.last;
1656
1657 rc = ngx_http_fastcgi_process_record(r, f);
1658
1659 u->buffer.pos = f->pos;
1660 u->buffer.last = f->last;
1661
1662 if (rc == NGX_AGAIN) {
1663 return NGX_AGAIN;
1664 }
1665
1666 if (rc == NGX_ERROR) {
1667 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1668 }
1669
1670 if (f->type != NGX_HTTP_FASTCGI_STDOUT
1671 && f->type != NGX_HTTP_FASTCGI_STDERR)
1672 {
1673 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1674 "upstream sent unexpected FastCGI record: %ui",
1675 f->type);
1676
1677 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1678 }
1679
1680 if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) {
1681 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1682 "upstream prematurely closed FastCGI stdout");
1683
1684 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1685 }
1686 }
1687
1688 if (f->state == ngx_http_fastcgi_st_padding) {
1689
1690 if (u->buffer.pos + f->padding < u->buffer.last) {
1691 f->state = ngx_http_fastcgi_st_version;
1692 u->buffer.pos += f->padding;
1693
1694 continue;
1695 }
1696
1697 if (u->buffer.pos + f->padding == u->buffer.last) {
1698 f->state = ngx_http_fastcgi_st_version;
1699 u->buffer.pos = u->buffer.last;
1700
1701 return NGX_AGAIN;
1702 }
1703
1704 f->padding -= u->buffer.last - u->buffer.pos;
1705 u->buffer.pos = u->buffer.last;
1706
1707 return NGX_AGAIN;
1708 }
1709
1710
1711
1712
1713 if (f->type == NGX_HTTP_FASTCGI_STDERR) {
1714
1715 if (f->length) {
1716 msg = u->buffer.pos;
1717
1718 if (u->buffer.pos + f->length <= u->buffer.last) {
1719 u->buffer.pos += f->length;
1720 f->length = 0;
1721 f->state = ngx_http_fastcgi_st_padding;
1722
1723 } else {
1724 f->length -= u->buffer.last - u->buffer.pos;
1725 u->buffer.pos = u->buffer.last;
1726 }
1727
1728 for (p = u->buffer.pos - 1; msg < p; p--) {
1729 if (*p != LF && *p != CR && *p != '.' && *p != ' ') {
1730 break;
1731 }
1732 }
1733
1734 p++;
1735
1736 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1737 "FastCGI sent in stderr: \"%*s\"", p - msg, msg);
1738
1739 flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
1740
1741 if (flcf->catch_stderr) {
1742 pattern = flcf->catch_stderr->elts;
1743
1744 for (i = 0; i < flcf->catch_stderr->nelts; i++) {
1745 if (ngx_strnstr(msg, (char *) pattern[i].data,
1746 p - msg)
1747 != NULL)
1748 {
1749 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1750 }
1751 }
1752 }
1753
1754 if (u->buffer.pos == u->buffer.last) {
1755
1756 if (!f->fastcgi_stdout) {
1757
1758
1759
1760
1761
1762
1763 #if (NGX_HTTP_CACHE)
1764 if (r->cache) {
1765 u->buffer.pos = u->buffer.start
1766 + r->cache->header_start;
1767 } else {
1768 u->buffer.pos = u->buffer.start;
1769 }
1770 #else
1771 u->buffer.pos = u->buffer.start;
1772 #endif
1773 u->buffer.last = u->buffer.pos;
1774 f->large_stderr = 1;
1775 }
1776
1777 return NGX_AGAIN;
1778 }
1779
1780 } else {
1781 f->state = ngx_http_fastcgi_st_padding;
1782 }
1783
1784 continue;
1785 }
1786
1787
1788
1789
1790 #if (NGX_HTTP_CACHE)
1791
1792 if (f->large_stderr && r->cache) {
1793 ssize_t len;
1794 ngx_http_fastcgi_header_t *fh;
1795
1796 start = u->buffer.start + r->cache->header_start;
1797
1798 len = u->buffer.pos - start - 2 * sizeof(ngx_http_fastcgi_header_t);
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808 if (len >= 0) {
1809 fh = (ngx_http_fastcgi_header_t *) start;
1810 fh->version = 1;
1811 fh->type = NGX_HTTP_FASTCGI_STDERR;
1812 fh->request_id_hi = 0;
1813 fh->request_id_lo = 1;
1814 fh->content_length_hi = (u_char) ((len >> 8) & 0xff);
1815 fh->content_length_lo = (u_char) (len & 0xff);
1816 fh->padding_length = 0;
1817 fh->reserved = 0;
1818
1819 } else {
1820 r->cache->header_start += u->buffer.pos - start
1821 - sizeof(ngx_http_fastcgi_header_t);
1822 }
1823
1824 f->large_stderr = 0;
1825 }
1826
1827 #endif
1828
1829 f->fastcgi_stdout = 1;
1830
1831 start = u->buffer.pos;
1832
1833 if (u->buffer.pos + f->length < u->buffer.last) {
1834
1835
1836
1837
1838
1839
1840 last = u->buffer.last;
1841 u->buffer.last = u->buffer.pos + f->length;
1842
1843 } else {
1844 last = NULL;
1845 }
1846
1847 for ( ;; ) {
1848
1849 part_start = u->buffer.pos;
1850 part_end = u->buffer.last;
1851
1852 rc = ngx_http_parse_header_line(r, &u->buffer, 1);
1853
1854 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1855 "http fastcgi parser: %i", rc);
1856
1857 if (rc == NGX_AGAIN) {
1858 break;
1859 }
1860
1861 if (rc == NGX_OK) {
1862
1863
1864
1865 h = ngx_list_push(&u->headers_in.headers);
1866 if (h == NULL) {
1867 return NGX_ERROR;
1868 }
1869
1870 if (f->split_parts && f->split_parts->nelts) {
1871
1872 part = f->split_parts->elts;
1873 size = u->buffer.pos - part_start;
1874
1875 for (i = 0; i < f->split_parts->nelts; i++) {
1876 size += part[i].end - part[i].start;
1877 }
1878
1879 p = ngx_pnalloc(r->pool, size);
1880 if (p == NULL) {
1881 return NGX_ERROR;
1882 }
1883
1884 buf.pos = p;
1885
1886 for (i = 0; i < f->split_parts->nelts; i++) {
1887 p = ngx_cpymem(p, part[i].start,
1888 part[i].end - part[i].start);
1889 }
1890
1891 p = ngx_cpymem(p, part_start, u->buffer.pos - part_start);
1892
1893 buf.last = p;
1894
1895 f->split_parts->nelts = 0;
1896
1897 rc = ngx_http_parse_header_line(r, &buf, 1);
1898
1899 if (rc != NGX_OK) {
1900 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
1901 "invalid header after joining "
1902 "FastCGI records");
1903 return NGX_ERROR;
1904 }
1905
1906 h->key.len = r->header_name_end - r->header_name_start;
1907 h->key.data = r->header_name_start;
1908 h->key.data[h->key.len] = '\0';
1909
1910 h->value.len = r->header_end - r->header_start;
1911 h->value.data = r->header_start;
1912 h->value.data[h->value.len] = '\0';
1913
1914 h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
1915 if (h->lowcase_key == NULL) {
1916 return NGX_ERROR;
1917 }
1918
1919 } else {
1920
1921 h->key.len = r->header_name_end - r->header_name_start;
1922 h->value.len = r->header_end - r->header_start;
1923
1924 h->key.data = ngx_pnalloc(r->pool,
1925 h->key.len + 1 + h->value.len + 1
1926 + h->key.len);
1927 if (h->key.data == NULL) {
1928 return NGX_ERROR;
1929 }
1930
1931 h->value.data = h->key.data + h->key.len + 1;
1932 h->lowcase_key = h->key.data + h->key.len + 1
1933 + h->value.len + 1;
1934
1935 ngx_memcpy(h->key.data, r->header_name_start, h->key.len);
1936 h->key.data[h->key.len] = '\0';
1937 ngx_memcpy(h->value.data, r->header_start, h->value.len);
1938 h->value.data[h->value.len] = '\0';
1939 }
1940
1941 h->hash = r->header_hash;
1942
1943 if (h->key.len == r->lowcase_index) {
1944 ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
1945
1946 } else {
1947 ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
1948 }
1949
1950 hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
1951 h->lowcase_key, h->key.len);
1952
1953 if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1954 return NGX_ERROR;
1955 }
1956
1957 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1958 "http fastcgi header: \"%V: %V\"",
1959 &h->key, &h->value);
1960
1961 if (u->buffer.pos < u->buffer.last) {
1962 continue;
1963 }
1964
1965
1966
1967 break;
1968 }
1969
1970 if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
1971
1972
1973
1974 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1975 "http fastcgi header done");
1976
1977 if (u->headers_in.status) {
1978 status_line = &u->headers_in.status->value;
1979
1980 status = ngx_atoi(status_line->data, 3);
1981
1982 if (status == NGX_ERROR) {
1983 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1984 "upstream sent invalid status \"%V\"",
1985 status_line);
1986 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1987 }
1988
1989 u->headers_in.status_n = status;
1990 u->headers_in.status_line = *status_line;
1991
1992 } else if (u->headers_in.location) {
1993 u->headers_in.status_n = 302;
1994 ngx_str_set(&u->headers_in.status_line,
1995 "302 Moved Temporarily");
1996
1997 } else {
1998 u->headers_in.status_n = 200;
1999 ngx_str_set(&u->headers_in.status_line, "200 OK");
2000 }
2001
2002 if (u->state && u->state->status == 0) {
2003 u->state->status = u->headers_in.status_n;
2004 }
2005
2006 break;
2007 }
2008
2009
2010
2011 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2012 "upstream sent invalid header");
2013
2014 return NGX_HTTP_UPSTREAM_INVALID_HEADER;
2015 }
2016
2017 if (last) {
2018 u->buffer.last = last;
2019 }
2020
2021 f->length -= u->buffer.pos - start;
2022
2023 if (f->length == 0) {
2024 f->state = ngx_http_fastcgi_st_padding;
2025 }
2026
2027 if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
2028 return NGX_OK;
2029 }
2030
2031 if (rc == NGX_OK) {
2032 continue;
2033 }
2034
2035
2036
2037 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2038 "upstream split a header line in FastCGI records");
2039
2040 if (f->split_parts == NULL) {
2041 f->split_parts = ngx_array_create(r->pool, 1,
2042 sizeof(ngx_http_fastcgi_split_part_t));
2043 if (f->split_parts == NULL) {
2044 return NGX_ERROR;
2045 }
2046 }
2047
2048 part = ngx_array_push(f->split_parts);
2049 if (part == NULL) {
2050 return NGX_ERROR;
2051 }
2052
2053 part->start = part_start;
2054 part->end = part_end;
2055
2056 if (u->buffer.pos < u->buffer.last) {
2057 continue;
2058 }
2059
2060 return NGX_AGAIN;
2061 }
2062 }
2063
2064
2065 static ngx_int_t
2066 ngx_http_fastcgi_input_filter_init(void *data)
2067 {
2068 ngx_http_request_t *r = data;
2069 ngx_http_fastcgi_loc_conf_t *flcf;
2070
2071 flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
2072
2073 r->upstream->pipe->length = flcf->keep_conn ?
2074 (off_t) sizeof(ngx_http_fastcgi_header_t) : -1;
2075
2076 return NGX_OK;
2077 }
2078
2079
2080 static ngx_int_t
2081 ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
2082 {
2083 u_char *m, *msg;
2084 ngx_int_t rc;
2085 ngx_buf_t *b, **prev;
2086 ngx_chain_t *cl;
2087 ngx_http_request_t *r;
2088 ngx_http_fastcgi_ctx_t *f;
2089 ngx_http_fastcgi_loc_conf_t *flcf;
2090
2091 if (buf->pos == buf->last) {
2092 return NGX_OK;
2093 }
2094
2095 r = p->input_ctx;
2096 f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
2097 flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
2098
2099 b = NULL;
2100 prev = &buf->shadow;
2101
2102 f->pos = buf->pos;
2103 f->last = buf->last;
2104
2105 for ( ;; ) {
2106 if (f->state < ngx_http_fastcgi_st_data) {
2107
2108 rc = ngx_http_fastcgi_process_record(r, f);
2109
2110 if (rc == NGX_AGAIN) {
2111 break;
2112 }
2113
2114 if (rc == NGX_ERROR) {
2115 return NGX_ERROR;
2116 }
2117
2118 if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) {
2119 f->state = ngx_http_fastcgi_st_padding;
2120
2121 if (!flcf->keep_conn) {
2122 p->upstream_done = 1;
2123 }
2124
2125 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
2126 "http fastcgi closed stdout");
2127
2128 continue;
2129 }
2130
2131 if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
2132
2133 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
2134 "http fastcgi sent end request");
2135
2136 if (!flcf->keep_conn) {
2137 p->upstream_done = 1;
2138 break;
2139 }
2140
2141 continue;
2142 }
2143 }
2144
2145
2146 if (f->state == ngx_http_fastcgi_st_padding) {
2147
2148 if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
2149
2150 if (f->pos + f->padding < f->last) {
2151 p->upstream_done = 1;
2152 break;
2153 }
2154
2155 if (f->pos + f->padding == f->last) {
2156 p->upstream_done = 1;
2157 r->upstream->keepalive = 1;
2158 break;
2159 }
2160
2161 f->padding -= f->last - f->pos;
2162
2163 break;
2164 }
2165
2166 if (f->pos + f->padding < f->last) {
2167 f->state = ngx_http_fastcgi_st_version;
2168 f->pos += f->padding;
2169
2170 continue;
2171 }
2172
2173 if (f->pos + f->padding == f->last) {
2174 f->state = ngx_http_fastcgi_st_version;
2175
2176 break;
2177 }
2178
2179 f->padding -= f->last - f->pos;
2180
2181 break;
2182 }
2183
2184
2185
2186
2187 if (f->type == NGX_HTTP_FASTCGI_STDERR) {
2188
2189 if (f->length) {
2190
2191 if (f->pos == f->last) {
2192 break;
2193 }
2194
2195 msg = f->pos;
2196
2197 if (f->pos + f->length <= f->last) {
2198 f->pos += f->length;
2199 f->length = 0;
2200 f->state = ngx_http_fastcgi_st_padding;
2201
2202 } else {
2203 f->length -= f->last - f->pos;
2204 f->pos = f->last;
2205 }
2206
2207 for (m = f->pos - 1; msg < m; m--) {
2208 if (*m != LF && *m != CR && *m != '.' && *m != ' ') {
2209 break;
2210 }
2211 }
2212
2213 ngx_log_error(NGX_LOG_ERR, p->log, 0,
2214 "FastCGI sent in stderr: \"%*s\"",
2215 m + 1 - msg, msg);
2216
2217 } else {
2218 f->state = ngx_http_fastcgi_st_padding;
2219 }
2220
2221 continue;
2222 }
2223
2224 if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
2225
2226 if (f->pos + f->length <= f->last) {
2227 f->state = ngx_http_fastcgi_st_padding;
2228 f->pos += f->length;
2229
2230 continue;
2231 }
2232
2233 f->length -= f->last - f->pos;
2234
2235 break;
2236 }
2237
2238
2239
2240
2241 if (f->pos == f->last) {
2242 break;
2243 }
2244
2245 cl = ngx_chain_get_free_buf(p->pool, &p->free);
2246 if (cl == NULL) {
2247 return NGX_ERROR;
2248 }
2249
2250 b = cl->buf;
2251
2252 ngx_memzero(b, sizeof(ngx_buf_t));
2253
2254 b->pos = f->pos;
2255 b->start = buf->start;
2256 b->end = buf->end;
2257 b->tag = p->tag;
2258 b->temporary = 1;
2259 b->recycled = 1;
2260
2261 *prev = b;
2262 prev = &b->shadow;
2263
2264 if (p->in) {
2265 *p->last_in = cl;
2266 } else {
2267 p->in = cl;
2268 }
2269 p->last_in = &cl->next;
2270
2271
2272 b->num = buf->num;
2273
2274 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
2275 "input buf #%d %p", b->num, b->pos);
2276
2277 if (f->pos + f->length <= f->last) {
2278 f->state = ngx_http_fastcgi_st_padding;
2279 f->pos += f->length;
2280 b->last = f->pos;
2281
2282 continue;
2283 }
2284
2285 f->length -= f->last - f->pos;
2286
2287 b->last = f->last;
2288
2289 break;
2290
2291 }
2292
2293 if (flcf->keep_conn) {
2294
2295
2296
2297 if (f->state < ngx_http_fastcgi_st_data) {
2298 p->length = 1;
2299
2300 } else if (f->state == ngx_http_fastcgi_st_padding) {
2301 p->length = f->padding;
2302
2303 } else {
2304
2305
2306 p->length = f->length;
2307 }
2308 }
2309
2310 if (b) {
2311 b->shadow = buf;
2312 b->last_shadow = 1;
2313
2314 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
2315 "input buf %p %z", b->pos, b->last - b->pos);
2316
2317 return NGX_OK;
2318 }
2319
2320
2321
2322 if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) {
2323 return NGX_ERROR;
2324 }
2325
2326 return NGX_OK;
2327 }
2328
2329
2330 static ngx_int_t
2331 ngx_http_fastcgi_non_buffered_filter(void *data, ssize_t bytes)
2332 {
2333 u_char *m, *msg;
2334 ngx_int_t rc;
2335 ngx_buf_t *b, *buf;
2336 ngx_chain_t *cl, **ll;
2337 ngx_http_request_t *r;
2338 ngx_http_upstream_t *u;
2339 ngx_http_fastcgi_ctx_t *f;
2340
2341 r = data;
2342 f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
2343
2344 u = r->upstream;
2345 buf = &u->buffer;
2346
2347 buf->pos = buf->last;
2348 buf->last += bytes;
2349
2350 for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
2351 ll = &cl->next;
2352 }
2353
2354 f->pos = buf->pos;
2355 f->last = buf->last;
2356
2357 for ( ;; ) {
2358 if (f->state < ngx_http_fastcgi_st_data) {
2359
2360 rc = ngx_http_fastcgi_process_record(r, f);
2361
2362 if (rc == NGX_AGAIN) {
2363 break;
2364 }
2365
2366 if (rc == NGX_ERROR) {
2367 return NGX_ERROR;
2368 }
2369
2370 if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) {
2371 f->state = ngx_http_fastcgi_st_padding;
2372
2373 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2374 "http fastcgi closed stdout");
2375
2376 continue;
2377 }
2378 }
2379
2380 if (f->state == ngx_http_fastcgi_st_padding) {
2381
2382 if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
2383
2384 if (f->pos + f->padding < f->last) {
2385 u->length = 0;
2386 break;
2387 }
2388
2389 if (f->pos + f->padding == f->last) {
2390 u->length = 0;
2391 u->keepalive = 1;
2392 break;
2393 }
2394
2395 f->padding -= f->last - f->pos;
2396
2397 break;
2398 }
2399
2400 if (f->pos + f->padding < f->last) {
2401 f->state = ngx_http_fastcgi_st_version;
2402 f->pos += f->padding;
2403
2404 continue;
2405 }
2406
2407 if (f->pos + f->padding == f->last) {
2408 f->state = ngx_http_fastcgi_st_version;
2409
2410 break;
2411 }
2412
2413 f->padding -= f->last - f->pos;
2414
2415 break;
2416 }
2417
2418
2419
2420
2421 if (f->type == NGX_HTTP_FASTCGI_STDERR) {
2422
2423 if (f->length) {
2424
2425 if (f->pos == f->last) {
2426 break;
2427 }
2428
2429 msg = f->pos;
2430
2431 if (f->pos + f->length <= f->last) {
2432 f->pos += f->length;
2433 f->length = 0;
2434 f->state = ngx_http_fastcgi_st_padding;
2435
2436 } else {
2437 f->length -= f->last - f->pos;
2438 f->pos = f->last;
2439 }
2440
2441 for (m = f->pos - 1; msg < m; m--) {
2442 if (*m != LF && *m != CR && *m != '.' && *m != ' ') {
2443 break;
2444 }
2445 }
2446
2447 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2448 "FastCGI sent in stderr: \"%*s\"",
2449 m + 1 - msg, msg);
2450
2451 } else {
2452 f->state = ngx_http_fastcgi_st_padding;
2453 }
2454
2455 continue;
2456 }
2457
2458 if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
2459
2460 if (f->pos + f->length <= f->last) {
2461 f->state = ngx_http_fastcgi_st_padding;
2462 f->pos += f->length;
2463
2464 continue;
2465 }
2466
2467 f->length -= f->last - f->pos;
2468
2469 break;
2470 }
2471
2472
2473
2474
2475 if (f->pos == f->last) {
2476 break;
2477 }
2478
2479 cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
2480 if (cl == NULL) {
2481 return NGX_ERROR;
2482 }
2483
2484 *ll = cl;
2485 ll = &cl->next;
2486
2487 b = cl->buf;
2488
2489 b->flush = 1;
2490 b->memory = 1;
2491
2492 b->pos = f->pos;
2493 b->tag = u->output.tag;
2494
2495 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2496 "http fastcgi output buf %p", b->pos);
2497
2498 if (f->pos + f->length <= f->last) {
2499 f->state = ngx_http_fastcgi_st_padding;
2500 f->pos += f->length;
2501 b->last = f->pos;
2502
2503 continue;
2504 }
2505
2506 f->length -= f->last - f->pos;
2507 b->last = f->last;
2508
2509 break;
2510 }
2511
2512
2513
2514 if (r->subrequest_in_memory) {
2515
2516 cl = u->out_bufs;
2517
2518 if (cl) {
2519 buf->pos = cl->buf->pos;
2520 }
2521
2522 buf->last = buf->pos;
2523
2524 for (cl = u->out_bufs; cl; cl = cl->next) {
2525 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2526 "http fastcgi in memory %p-%p %O",
2527 cl->buf->pos, cl->buf->last, ngx_buf_size(cl->buf));
2528
2529 if (buf->last == cl->buf->pos) {
2530 buf->last = cl->buf->last;
2531 continue;
2532 }
2533
2534 buf->last = ngx_movemem(buf->last, cl->buf->pos,
2535 cl->buf->last - cl->buf->pos);
2536
2537 cl->buf->pos = buf->last - (cl->buf->last - cl->buf->pos);
2538 cl->buf->last = buf->last;
2539 }
2540 }
2541
2542 return NGX_OK;
2543 }
2544
2545
2546 static ngx_int_t
2547 ngx_http_fastcgi_process_record(ngx_http_request_t *r,
2548 ngx_http_fastcgi_ctx_t *f)
2549 {
2550 u_char ch, *p;
2551 ngx_http_fastcgi_state_e state;
2552
2553 state = f->state;
2554
2555 for (p = f->pos; p < f->last; p++) {
2556
2557 ch = *p;
2558
2559 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2560 "http fastcgi record byte: %02Xd", ch);
2561
2562 switch (state) {
2563
2564 case ngx_http_fastcgi_st_version:
2565 if (ch != 1) {
2566 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2567 "upstream sent unsupported FastCGI "
2568 "protocol version: %d", ch);
2569 return NGX_ERROR;
2570 }
2571 state = ngx_http_fastcgi_st_type;
2572 break;
2573
2574 case ngx_http_fastcgi_st_type:
2575 switch (ch) {
2576 case NGX_HTTP_FASTCGI_STDOUT:
2577 case NGX_HTTP_FASTCGI_STDERR:
2578 case NGX_HTTP_FASTCGI_END_REQUEST:
2579 f->type = (ngx_uint_t) ch;
2580 break;
2581 default:
2582 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2583 "upstream sent invalid FastCGI "
2584 "record type: %d", ch);
2585 return NGX_ERROR;
2586
2587 }
2588 state = ngx_http_fastcgi_st_request_id_hi;
2589 break;
2590
2591
2592
2593 case ngx_http_fastcgi_st_request_id_hi:
2594 if (ch != 0) {
2595 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2596 "upstream sent unexpected FastCGI "
2597 "request id high byte: %d", ch);
2598 return NGX_ERROR;
2599 }
2600 state = ngx_http_fastcgi_st_request_id_lo;
2601 break;
2602
2603 case ngx_http_fastcgi_st_request_id_lo:
2604 if (ch != 1) {
2605 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2606 "upstream sent unexpected FastCGI "
2607 "request id low byte: %d", ch);
2608 return NGX_ERROR;
2609 }
2610 state = ngx_http_fastcgi_st_content_length_hi;
2611 break;
2612
2613 case ngx_http_fastcgi_st_content_length_hi:
2614 f->length = ch << 8;
2615 state = ngx_http_fastcgi_st_content_length_lo;
2616 break;
2617
2618 case ngx_http_fastcgi_st_content_length_lo:
2619 f->length |= (size_t) ch;
2620 state = ngx_http_fastcgi_st_padding_length;
2621 break;
2622
2623 case ngx_http_fastcgi_st_padding_length:
2624 f->padding = (size_t) ch;
2625 state = ngx_http_fastcgi_st_reserved;
2626 break;
2627
2628 case ngx_http_fastcgi_st_reserved:
2629 state = ngx_http_fastcgi_st_data;
2630
2631 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2632 "http fastcgi record length: %z", f->length);
2633
2634 f->pos = p + 1;
2635 f->state = state;
2636
2637 return NGX_OK;
2638
2639
2640 case ngx_http_fastcgi_st_data:
2641 case ngx_http_fastcgi_st_padding:
2642 break;
2643 }
2644 }
2645
2646 f->state = state;
2647
2648 return NGX_AGAIN;
2649 }
2650
2651
2652 static void
2653 ngx_http_fastcgi_abort_request(ngx_http_request_t *r)
2654 {
2655 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2656 "abort http fastcgi request");
2657
2658 return;
2659 }
2660
2661
2662 static void
2663 ngx_http_fastcgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
2664 {
2665 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2666 "finalize http fastcgi request");
2667
2668 return;
2669 }
2670
2671
2672 static ngx_int_t
2673 ngx_http_fastcgi_add_variables(ngx_conf_t *cf)
2674 {
2675 ngx_http_variable_t *var, *v;
2676
2677 for (v = ngx_http_fastcgi_vars; v->name.len; v++) {
2678 var = ngx_http_add_variable(cf, &v->name, v->flags);
2679 if (var == NULL) {
2680 return NGX_ERROR;
2681 }
2682
2683 var->get_handler = v->get_handler;
2684 var->data = v->data;
2685 }
2686
2687 return NGX_OK;
2688 }
2689
2690
2691 static void *
2692 ngx_http_fastcgi_create_main_conf(ngx_conf_t *cf)
2693 {
2694 ngx_http_fastcgi_main_conf_t *conf;
2695
2696 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_main_conf_t));
2697 if (conf == NULL) {
2698 return NULL;
2699 }
2700
2701 #if (NGX_HTTP_CACHE)
2702 if (ngx_array_init(&conf->caches, cf->pool, 4,
2703 sizeof(ngx_http_file_cache_t *))
2704 != NGX_OK)
2705 {
2706 return NULL;
2707 }
2708 #endif
2709
2710 return conf;
2711 }
2712
2713
2714 static void *
2715 ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
2716 {
2717 ngx_http_fastcgi_loc_conf_t *conf;
2718
2719 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_loc_conf_t));
2720 if (conf == NULL) {
2721 return NULL;
2722 }
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743 conf->upstream.store = NGX_CONF_UNSET;
2744 conf->upstream.store_access = NGX_CONF_UNSET_UINT;
2745 conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
2746 conf->upstream.buffering = NGX_CONF_UNSET;
2747 conf->upstream.request_buffering = NGX_CONF_UNSET;
2748 conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
2749 conf->upstream.force_ranges = NGX_CONF_UNSET;
2750
2751 conf->upstream.local = NGX_CONF_UNSET_PTR;
2752
2753 conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
2754 conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
2755 conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
2756 conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC;
2757
2758 conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
2759 conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
2760 conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE;
2761
2762 conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
2763 conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
2764 conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;
2765
2766 conf->upstream.pass_request_headers = NGX_CONF_UNSET;
2767 conf->upstream.pass_request_body = NGX_CONF_UNSET;
2768
2769 #if (NGX_HTTP_CACHE)
2770 conf->upstream.cache = NGX_CONF_UNSET;
2771 conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
2772 conf->upstream.cache_max_range_offset = NGX_CONF_UNSET;
2773 conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
2774 conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
2775 conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
2776 conf->upstream.cache_lock = NGX_CONF_UNSET;
2777 conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
2778 conf->upstream.cache_lock_age = NGX_CONF_UNSET_MSEC;
2779 conf->upstream.cache_revalidate = NGX_CONF_UNSET;
2780 conf->upstream.cache_background_update = NGX_CONF_UNSET;
2781 #endif
2782
2783 conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
2784 conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
2785
2786 conf->upstream.intercept_errors = NGX_CONF_UNSET;
2787
2788
2789 conf->upstream.cyclic_temp_file = 0;
2790
2791 conf->upstream.change_buffering = 1;
2792
2793 conf->catch_stderr = NGX_CONF_UNSET_PTR;
2794
2795 conf->keep_conn = NGX_CONF_UNSET;
2796
2797 ngx_str_set(&conf->upstream.module, "fastcgi");
2798
2799 return conf;
2800 }
2801
2802
2803 static char *
2804 ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
2805 {
2806 ngx_http_fastcgi_loc_conf_t *prev = parent;
2807 ngx_http_fastcgi_loc_conf_t *conf = child;
2808
2809 size_t size;
2810 ngx_int_t rc;
2811 ngx_hash_init_t hash;
2812 ngx_http_core_loc_conf_t *clcf;
2813
2814 #if (NGX_HTTP_CACHE)
2815
2816 if (conf->upstream.store > 0) {
2817 conf->upstream.cache = 0;
2818 }
2819
2820 if (conf->upstream.cache > 0) {
2821 conf->upstream.store = 0;
2822 }
2823
2824 #endif
2825
2826 if (conf->upstream.store == NGX_CONF_UNSET) {
2827 ngx_conf_merge_value(conf->upstream.store,
2828 prev->upstream.store, 0);
2829
2830 conf->upstream.store_lengths = prev->upstream.store_lengths;
2831 conf->upstream.store_values = prev->upstream.store_values;
2832 }
2833
2834 ngx_conf_merge_uint_value(conf->upstream.store_access,
2835 prev->upstream.store_access, 0600);
2836
2837 ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
2838 prev->upstream.next_upstream_tries, 0);
2839
2840 ngx_conf_merge_value(conf->upstream.buffering,
2841 prev->upstream.buffering, 1);
2842
2843 ngx_conf_merge_value(conf->upstream.request_buffering,
2844 prev->upstream.request_buffering, 1);
2845
2846 ngx_conf_merge_value(conf->upstream.ignore_client_abort,
2847 prev->upstream.ignore_client_abort, 0);
2848
2849 ngx_conf_merge_value(conf->upstream.force_ranges,
2850 prev->upstream.force_ranges, 0);
2851
2852 ngx_conf_merge_ptr_value(conf->upstream.local,
2853 prev->upstream.local, NULL);
2854
2855 ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
2856 prev->upstream.connect_timeout, 60000);
2857
2858 ngx_conf_merge_msec_value(conf->upstream.send_timeout,
2859 prev->upstream.send_timeout, 60000);
2860
2861 ngx_conf_merge_msec_value(conf->upstream.read_timeout,
2862 prev->upstream.read_timeout, 60000);
2863
2864 ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
2865 prev->upstream.next_upstream_timeout, 0);
2866
2867 ngx_conf_merge_size_value(conf->upstream.send_lowat,
2868 prev->upstream.send_lowat, 0);
2869
2870 ngx_conf_merge_size_value(conf->upstream.buffer_size,
2871 prev->upstream.buffer_size,
2872 (size_t) ngx_pagesize);
2873
2874 ngx_conf_merge_size_value(conf->upstream.limit_rate,
2875 prev->upstream.limit_rate, 0);
2876
2877
2878 ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
2879 8, ngx_pagesize);
2880
2881 if (conf->upstream.bufs.num < 2) {
2882 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2883 "there must be at least 2 \"fastcgi_buffers\"");
2884 return NGX_CONF_ERROR;
2885 }
2886
2887
2888 size = conf->upstream.buffer_size;
2889 if (size < conf->upstream.bufs.size) {
2890 size = conf->upstream.bufs.size;
2891 }
2892
2893
2894 ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
2895 prev->upstream.busy_buffers_size_conf,
2896 NGX_CONF_UNSET_SIZE);
2897
2898 if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
2899 conf->upstream.busy_buffers_size = 2 * size;
2900 } else {
2901 conf->upstream.busy_buffers_size =
2902 conf->upstream.busy_buffers_size_conf;
2903 }
2904
2905 if (conf->upstream.busy_buffers_size < size) {
2906 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2907 "\"fastcgi_busy_buffers_size\" must be equal to or greater than "
2908 "the maximum of the value of \"fastcgi_buffer_size\" and "
2909 "one of the \"fastcgi_buffers\"");
2910
2911 return NGX_CONF_ERROR;
2912 }
2913
2914 if (conf->upstream.busy_buffers_size
2915 > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
2916 {
2917 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2918 "\"fastcgi_busy_buffers_size\" must be less than "
2919 "the size of all \"fastcgi_buffers\" minus one buffer");
2920
2921 return NGX_CONF_ERROR;
2922 }
2923
2924
2925 ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf,
2926 prev->upstream.temp_file_write_size_conf,
2927 NGX_CONF_UNSET_SIZE);
2928
2929 if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
2930 conf->upstream.temp_file_write_size = 2 * size;
2931 } else {
2932 conf->upstream.temp_file_write_size =
2933 conf->upstream.temp_file_write_size_conf;
2934 }
2935
2936 if (conf->upstream.temp_file_write_size < size) {
2937 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2938 "\"fastcgi_temp_file_write_size\" must be equal to or greater "
2939 "than the maximum of the value of \"fastcgi_buffer_size\" and "
2940 "one of the \"fastcgi_buffers\"");
2941
2942 return NGX_CONF_ERROR;
2943 }
2944
2945
2946 ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf,
2947 prev->upstream.max_temp_file_size_conf,
2948 NGX_CONF_UNSET_SIZE);
2949
2950 if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
2951 conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
2952 } else {
2953 conf->upstream.max_temp_file_size =
2954 conf->upstream.max_temp_file_size_conf;
2955 }
2956
2957 if (conf->upstream.max_temp_file_size != 0
2958 && conf->upstream.max_temp_file_size < size)
2959 {
2960 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2961 "\"fastcgi_max_temp_file_size\" must be equal to zero to disable "
2962 "temporary files usage or must be equal to or greater than "
2963 "the maximum of the value of \"fastcgi_buffer_size\" and "
2964 "one of the \"fastcgi_buffers\"");
2965
2966 return NGX_CONF_ERROR;
2967 }
2968
2969
2970 ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
2971 prev->upstream.ignore_headers,
2972 NGX_CONF_BITMASK_SET);
2973
2974
2975 ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
2976 prev->upstream.next_upstream,
2977 (NGX_CONF_BITMASK_SET
2978 |NGX_HTTP_UPSTREAM_FT_ERROR
2979 |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
2980
2981 if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
2982 conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
2983 |NGX_HTTP_UPSTREAM_FT_OFF;
2984 }
2985
2986 if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
2987 prev->upstream.temp_path,
2988 &ngx_http_fastcgi_temp_path)
2989 != NGX_OK)
2990 {
2991 return NGX_CONF_ERROR;
2992 }
2993
2994 #if (NGX_HTTP_CACHE)
2995
2996 if (conf->upstream.cache == NGX_CONF_UNSET) {
2997 ngx_conf_merge_value(conf->upstream.cache,
2998 prev->upstream.cache, 0);
2999
3000 conf->upstream.cache_zone = prev->upstream.cache_zone;
3001 conf->upstream.cache_value = prev->upstream.cache_value;
3002 }
3003
3004 if (conf->upstream.cache_zone && conf->upstream.cache_zone->data == NULL) {
3005 ngx_shm_zone_t *shm_zone;
3006
3007 shm_zone = conf->upstream.cache_zone;
3008
3009 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3010 "\"fastcgi_cache\" zone \"%V\" is unknown",
3011 &shm_zone->shm.name);
3012
3013 return NGX_CONF_ERROR;
3014 }
3015
3016 ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
3017 prev->upstream.cache_min_uses, 1);
3018
3019 ngx_conf_merge_off_value(conf->upstream.cache_max_range_offset,
3020 prev->upstream.cache_max_range_offset,
3021 NGX_MAX_OFF_T_VALUE);
3022
3023 ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
3024 prev->upstream.cache_use_stale,
3025 (NGX_CONF_BITMASK_SET
3026 |NGX_HTTP_UPSTREAM_FT_OFF));
3027
3028 if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
3029 conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
3030 |NGX_HTTP_UPSTREAM_FT_OFF;
3031 }
3032
3033 if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
3034 conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
3035 }
3036
3037 if (conf->upstream.cache_methods == 0) {
3038 conf->upstream.cache_methods = prev->upstream.cache_methods;
3039 }
3040
3041 conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD;
3042
3043 ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
3044 prev->upstream.cache_bypass, NULL);
3045
3046 ngx_conf_merge_ptr_value(conf->upstream.no_cache,
3047 prev->upstream.no_cache, NULL);
3048
3049 ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
3050 prev->upstream.cache_valid, NULL);
3051
3052 if (conf->cache_key.value.data == NULL) {
3053 conf->cache_key = prev->cache_key;
3054 }
3055
3056 if (conf->upstream.cache && conf->cache_key.value.data == NULL) {
3057 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
3058 "no \"fastcgi_cache_key\" for \"fastcgi_cache\"");
3059 }
3060
3061 ngx_conf_merge_value(conf->upstream.cache_lock,
3062 prev->upstream.cache_lock, 0);
3063
3064 ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
3065 prev->upstream.cache_lock_timeout, 5000);
3066
3067 ngx_conf_merge_msec_value(conf->upstream.cache_lock_age,
3068 prev->upstream.cache_lock_age, 5000);
3069
3070 ngx_conf_merge_value(conf->upstream.cache_revalidate,
3071 prev->upstream.cache_revalidate, 0);
3072
3073 ngx_conf_merge_value(conf->upstream.cache_background_update,
3074 prev->upstream.cache_background_update, 0);
3075
3076 #endif
3077
3078 ngx_conf_merge_value(conf->upstream.pass_request_headers,
3079 prev->upstream.pass_request_headers, 1);
3080 ngx_conf_merge_value(conf->upstream.pass_request_body,
3081 prev->upstream.pass_request_body, 1);
3082
3083 ngx_conf_merge_value(conf->upstream.intercept_errors,
3084 prev->upstream.intercept_errors, 0);
3085
3086 ngx_conf_merge_ptr_value(conf->catch_stderr, prev->catch_stderr, NULL);
3087
3088 ngx_conf_merge_value(conf->keep_conn, prev->keep_conn, 0);
3089
3090
3091 ngx_conf_merge_str_value(conf->index, prev->index, "");
3092
3093 hash.max_size = 512;
3094 hash.bucket_size = ngx_align(64, ngx_cacheline_size);
3095 hash.name = "fastcgi_hide_headers_hash";
3096
3097 if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
3098 &prev->upstream, ngx_http_fastcgi_hide_headers, &hash)
3099 != NGX_OK)
3100 {
3101 return NGX_CONF_ERROR;
3102 }
3103
3104 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
3105
3106 if (clcf->noname
3107 && conf->upstream.upstream == NULL && conf->fastcgi_lengths == NULL)
3108 {
3109 conf->upstream.upstream = prev->upstream.upstream;
3110 conf->fastcgi_lengths = prev->fastcgi_lengths;
3111 conf->fastcgi_values = prev->fastcgi_values;
3112 }
3113
3114 if (clcf->lmt_excpt && clcf->handler == NULL
3115 && (conf->upstream.upstream || conf->fastcgi_lengths))
3116 {
3117 clcf->handler = ngx_http_fastcgi_handler;
3118 }
3119
3120 #if (NGX_PCRE)
3121 if (conf->split_regex == NULL) {
3122 conf->split_regex = prev->split_regex;
3123 conf->split_name = prev->split_name;
3124 }
3125 #endif
3126
3127 if (conf->params_source == NULL) {
3128 conf->params = prev->params;
3129 #if (NGX_HTTP_CACHE)
3130 conf->params_cache = prev->params_cache;
3131 #endif
3132 conf->params_source = prev->params_source;
3133 }
3134
3135 rc = ngx_http_fastcgi_init_params(cf, conf, &conf->params, NULL);
3136 if (rc != NGX_OK) {
3137 return NGX_CONF_ERROR;
3138 }
3139
3140 #if (NGX_HTTP_CACHE)
3141
3142 if (conf->upstream.cache) {
3143 rc = ngx_http_fastcgi_init_params(cf, conf, &conf->params_cache,
3144 ngx_http_fastcgi_cache_headers);
3145 if (rc != NGX_OK) {
3146 return NGX_CONF_ERROR;
3147 }
3148 }
3149
3150 #endif
3151
3152
3153
3154
3155
3156
3157 if (prev->params.hash.buckets == NULL
3158 && conf->params_source == prev->params_source)
3159 {
3160 prev->params = conf->params;
3161 #if (NGX_HTTP_CACHE)
3162 prev->params_cache = conf->params_cache;
3163 #endif
3164 }
3165
3166 return NGX_CONF_OK;
3167 }
3168
3169
3170 static ngx_int_t
3171 ngx_http_fastcgi_init_params(ngx_conf_t *cf, ngx_http_fastcgi_loc_conf_t *conf,
3172 ngx_http_fastcgi_params_t *params, ngx_keyval_t *default_params)
3173 {
3174 u_char *p;
3175 size_t size;
3176 uintptr_t *code;
3177 ngx_uint_t i, nsrc;
3178 ngx_array_t headers_names, params_merged;
3179 ngx_keyval_t *h;
3180 ngx_hash_key_t *hk;
3181 ngx_hash_init_t hash;
3182 ngx_http_upstream_param_t *src, *s;
3183 ngx_http_script_compile_t sc;
3184 ngx_http_script_copy_code_t *copy;
3185
3186 if (params->hash.buckets) {
3187 return NGX_OK;
3188 }
3189
3190 if (conf->params_source == NULL && default_params == NULL) {
3191 params->hash.buckets = (void *) 1;
3192 return NGX_OK;
3193 }
3194
3195 params->lengths = ngx_array_create(cf->pool, 64, 1);
3196 if (params->lengths == NULL) {
3197 return NGX_ERROR;
3198 }
3199
3200 params->values = ngx_array_create(cf->pool, 512, 1);
3201 if (params->values == NULL) {
3202 return NGX_ERROR;
3203 }
3204
3205 if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
3206 != NGX_OK)
3207 {
3208 return NGX_ERROR;
3209 }
3210
3211 if (conf->params_source) {
3212 src = conf->params_source->elts;
3213 nsrc = conf->params_source->nelts;
3214
3215 } else {
3216 src = NULL;
3217 nsrc = 0;
3218 }
3219
3220 if (default_params) {
3221 if (ngx_array_init(¶ms_merged, cf->temp_pool, 4,
3222 sizeof(ngx_http_upstream_param_t))
3223 != NGX_OK)
3224 {
3225 return NGX_ERROR;
3226 }
3227
3228 for (i = 0; i < nsrc; i++) {
3229
3230 s = ngx_array_push(¶ms_merged);
3231 if (s == NULL) {
3232 return NGX_ERROR;
3233 }
3234
3235 *s = src[i];
3236 }
3237
3238 h = default_params;
3239
3240 while (h->key.len) {
3241
3242 src = params_merged.elts;
3243 nsrc = params_merged.nelts;
3244
3245 for (i = 0; i < nsrc; i++) {
3246 if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
3247 goto next;
3248 }
3249 }
3250
3251 s = ngx_array_push(¶ms_merged);
3252 if (s == NULL) {
3253 return NGX_ERROR;
3254 }
3255
3256 s->key = h->key;
3257 s->value = h->value;
3258 s->skip_empty = 1;
3259
3260 next:
3261
3262 h++;
3263 }
3264
3265 src = params_merged.elts;
3266 nsrc = params_merged.nelts;
3267 }
3268
3269 for (i = 0; i < nsrc; i++) {
3270
3271 if (src[i].key.len > sizeof("HTTP_") - 1
3272 && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0)
3273 {
3274 hk = ngx_array_push(&headers_names);
3275 if (hk == NULL) {
3276 return NGX_ERROR;
3277 }
3278
3279 hk->key.len = src[i].key.len - 5;
3280 hk->key.data = src[i].key.data + 5;
3281 hk->key_hash = ngx_hash_key_lc(hk->key.data, hk->key.len);
3282 hk->value = (void *) 1;
3283
3284 if (src[i].value.len == 0) {
3285 continue;
3286 }
3287 }
3288
3289 copy = ngx_array_push_n(params->lengths,
3290 sizeof(ngx_http_script_copy_code_t));
3291 if (copy == NULL) {
3292 return NGX_ERROR;
3293 }
3294
3295 copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
3296 copy->len = src[i].key.len;
3297
3298 copy = ngx_array_push_n(params->lengths,
3299 sizeof(ngx_http_script_copy_code_t));
3300 if (copy == NULL) {
3301 return NGX_ERROR;
3302 }
3303
3304 copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
3305 copy->len = src[i].skip_empty;
3306
3307
3308 size = (sizeof(ngx_http_script_copy_code_t)
3309 + src[i].key.len + sizeof(uintptr_t) - 1)
3310 & ~(sizeof(uintptr_t) - 1);
3311
3312 copy = ngx_array_push_n(params->values, size);
3313 if (copy == NULL) {
3314 return NGX_ERROR;
3315 }
3316
3317 copy->code = ngx_http_script_copy_code;
3318 copy->len = src[i].key.len;
3319
3320 p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
3321 ngx_memcpy(p, src[i].key.data, src[i].key.len);
3322
3323
3324 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3325
3326 sc.cf = cf;
3327 sc.source = &src[i].value;
3328 sc.flushes = ¶ms->flushes;
3329 sc.lengths = ¶ms->lengths;
3330 sc.values = ¶ms->values;
3331
3332 if (ngx_http_script_compile(&sc) != NGX_OK) {
3333 return NGX_ERROR;
3334 }
3335
3336 code = ngx_array_push_n(params->lengths, sizeof(uintptr_t));
3337 if (code == NULL) {
3338 return NGX_ERROR;
3339 }
3340
3341 *code = (uintptr_t) NULL;
3342
3343
3344 code = ngx_array_push_n(params->values, sizeof(uintptr_t));
3345 if (code == NULL) {
3346 return NGX_ERROR;
3347 }
3348
3349 *code = (uintptr_t) NULL;
3350 }
3351
3352 code = ngx_array_push_n(params->lengths, sizeof(uintptr_t));
3353 if (code == NULL) {
3354 return NGX_ERROR;
3355 }
3356
3357 *code = (uintptr_t) NULL;
3358
3359 params->number = headers_names.nelts;
3360
3361 hash.hash = ¶ms->hash;
3362 hash.key = ngx_hash_key_lc;
3363 hash.max_size = 512;
3364 hash.bucket_size = 64;
3365 hash.name = "fastcgi_params_hash";
3366 hash.pool = cf->pool;
3367 hash.temp_pool = NULL;
3368
3369 return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
3370 }
3371
3372
3373 static ngx_int_t
3374 ngx_http_fastcgi_script_name_variable(ngx_http_request_t *r,
3375 ngx_http_variable_value_t *v, uintptr_t data)
3376 {
3377 u_char *p;
3378 ngx_http_fastcgi_ctx_t *f;
3379 ngx_http_fastcgi_loc_conf_t *flcf;
3380
3381 flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
3382
3383 f = ngx_http_fastcgi_split(r, flcf);
3384
3385 if (f == NULL) {
3386 return NGX_ERROR;
3387 }
3388
3389 if (f->script_name.len == 0
3390 || f->script_name.data[f->script_name.len - 1] != '/')
3391 {
3392 v->len = f->script_name.len;
3393 v->valid = 1;
3394 v->no_cacheable = 0;
3395 v->not_found = 0;
3396 v->data = f->script_name.data;
3397
3398 return NGX_OK;
3399 }
3400
3401 v->len = f->script_name.len + flcf->index.len;
3402
3403 v->data = ngx_pnalloc(r->pool, v->len);
3404 if (v->data == NULL) {
3405 return NGX_ERROR;
3406 }
3407
3408 p = ngx_copy(v->data, f->script_name.data, f->script_name.len);
3409 ngx_memcpy(p, flcf->index.data, flcf->index.len);
3410
3411 return NGX_OK;
3412 }
3413
3414
3415 static ngx_int_t
3416 ngx_http_fastcgi_path_info_variable(ngx_http_request_t *r,
3417 ngx_http_variable_value_t *v, uintptr_t data)
3418 {
3419 ngx_http_fastcgi_ctx_t *f;
3420 ngx_http_fastcgi_loc_conf_t *flcf;
3421
3422 flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
3423
3424 f = ngx_http_fastcgi_split(r, flcf);
3425
3426 if (f == NULL) {
3427 return NGX_ERROR;
3428 }
3429
3430 v->len = f->path_info.len;
3431 v->valid = 1;
3432 v->no_cacheable = 0;
3433 v->not_found = 0;
3434 v->data = f->path_info.data;
3435
3436 return NGX_OK;
3437 }
3438
3439
3440 static ngx_http_fastcgi_ctx_t *
3441 ngx_http_fastcgi_split(ngx_http_request_t *r, ngx_http_fastcgi_loc_conf_t *flcf)
3442 {
3443 ngx_http_fastcgi_ctx_t *f;
3444 #if (NGX_PCRE)
3445 ngx_int_t n;
3446 int captures[(1 + 2) * 3];
3447
3448 f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
3449
3450 if (f == NULL) {
3451 f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
3452 if (f == NULL) {
3453 return NULL;
3454 }
3455
3456 ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
3457 }
3458
3459 if (f->script_name.len) {
3460 return f;
3461 }
3462
3463 if (flcf->split_regex == NULL) {
3464 f->script_name = r->uri;
3465 return f;
3466 }
3467
3468 n = ngx_regex_exec(flcf->split_regex, &r->uri, captures, (1 + 2) * 3);
3469
3470 if (n >= 0) {
3471 f->script_name.len = captures[3] - captures[2];
3472 f->script_name.data = r->uri.data + captures[2];
3473
3474 f->path_info.len = captures[5] - captures[4];
3475 f->path_info.data = r->uri.data + captures[4];
3476
3477 return f;
3478 }
3479
3480 if (n == NGX_REGEX_NO_MATCHED) {
3481 f->script_name = r->uri;
3482 return f;
3483 }
3484
3485 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
3486 ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"",
3487 n, &r->uri, &flcf->split_name);
3488 return NULL;
3489
3490 #else
3491
3492 f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
3493
3494 if (f == NULL) {
3495 f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
3496 if (f == NULL) {
3497 return NULL;
3498 }
3499
3500 ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
3501 }
3502
3503 f->script_name = r->uri;
3504
3505 return f;
3506
3507 #endif
3508 }
3509
3510
3511 static char *
3512 ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3513 {
3514 ngx_http_fastcgi_loc_conf_t *flcf = conf;
3515
3516 ngx_url_t u;
3517 ngx_str_t *value, *url;
3518 ngx_uint_t n;
3519 ngx_http_core_loc_conf_t *clcf;
3520 ngx_http_script_compile_t sc;
3521
3522 if (flcf->upstream.upstream || flcf->fastcgi_lengths) {
3523 return "is duplicate";
3524 }
3525
3526 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
3527
3528 clcf->handler = ngx_http_fastcgi_handler;
3529
3530 if (clcf->name.data[clcf->name.len - 1] == '/') {
3531 clcf->auto_redirect = 1;
3532 }
3533
3534 value = cf->args->elts;
3535
3536 url = &value[1];
3537
3538 n = ngx_http_script_variables_count(url);
3539
3540 if (n) {
3541
3542 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3543
3544 sc.cf = cf;
3545 sc.source = url;
3546 sc.lengths = &flcf->fastcgi_lengths;
3547 sc.values = &flcf->fastcgi_values;
3548 sc.variables = n;
3549 sc.complete_lengths = 1;
3550 sc.complete_values = 1;
3551
3552 if (ngx_http_script_compile(&sc) != NGX_OK) {
3553 return NGX_CONF_ERROR;
3554 }
3555
3556 return NGX_CONF_OK;
3557 }
3558
3559 ngx_memzero(&u, sizeof(ngx_url_t));
3560
3561 u.url = value[1];
3562 u.no_resolve = 1;
3563
3564 flcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
3565 if (flcf->upstream.upstream == NULL) {
3566 return NGX_CONF_ERROR;
3567 }
3568
3569 return NGX_CONF_OK;
3570 }
3571
3572
3573 static char *
3574 ngx_http_fastcgi_split_path_info(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3575 {
3576 #if (NGX_PCRE)
3577 ngx_http_fastcgi_loc_conf_t *flcf = conf;
3578
3579 ngx_str_t *value;
3580 ngx_regex_compile_t rc;
3581 u_char errstr[NGX_MAX_CONF_ERRSTR];
3582
3583 value = cf->args->elts;
3584
3585 flcf->split_name = value[1];
3586
3587 ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
3588
3589 rc.pattern = value[1];
3590 rc.pool = cf->pool;
3591 rc.err.len = NGX_MAX_CONF_ERRSTR;
3592 rc.err.data = errstr;
3593
3594 if (ngx_regex_compile(&rc) != NGX_OK) {
3595 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err);
3596 return NGX_CONF_ERROR;
3597 }
3598
3599 if (rc.captures != 2) {
3600 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3601 "pattern \"%V\" must have 2 captures", &value[1]);
3602 return NGX_CONF_ERROR;
3603 }
3604
3605 flcf->split_regex = rc.regex;
3606
3607 return NGX_CONF_OK;
3608
3609 #else
3610
3611 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3612 "\"%V\" requires PCRE library", &cmd->name);
3613 return NGX_CONF_ERROR;
3614
3615 #endif
3616 }
3617
3618
3619 static char *
3620 ngx_http_fastcgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3621 {
3622 ngx_http_fastcgi_loc_conf_t *flcf = conf;
3623
3624 ngx_str_t *value;
3625 ngx_http_script_compile_t sc;
3626
3627 if (flcf->upstream.store != NGX_CONF_UNSET) {
3628 return "is duplicate";
3629 }
3630
3631 value = cf->args->elts;
3632
3633 if (ngx_strcmp(value[1].data, "off") == 0) {
3634 flcf->upstream.store = 0;
3635 return NGX_CONF_OK;
3636 }
3637
3638 #if (NGX_HTTP_CACHE)
3639 if (flcf->upstream.cache > 0) {
3640 return "is incompatible with \"fastcgi_cache\"";
3641 }
3642 #endif
3643
3644 flcf->upstream.store = 1;
3645
3646 if (ngx_strcmp(value[1].data, "on") == 0) {
3647 return NGX_CONF_OK;
3648 }
3649
3650
3651 value[1].len++;
3652
3653 ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3654
3655 sc.cf = cf;
3656 sc.source = &value[1];
3657 sc.lengths = &flcf->upstream.store_lengths;
3658 sc.values = &flcf->upstream.store_values;
3659 sc.variables = ngx_http_script_variables_count(&value[1]);
3660 sc.complete_lengths = 1;
3661 sc.complete_values = 1;
3662
3663 if (ngx_http_script_compile(&sc) != NGX_OK) {
3664 return NGX_CONF_ERROR;
3665 }
3666
3667 return NGX_CONF_OK;
3668 }
3669
3670
3671 #if (NGX_HTTP_CACHE)
3672
3673 static char *
3674 ngx_http_fastcgi_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3675 {
3676 ngx_http_fastcgi_loc_conf_t *flcf = conf;
3677
3678 ngx_str_t *value;
3679 ngx_http_complex_value_t cv;
3680 ngx_http_compile_complex_value_t ccv;
3681
3682 value = cf->args->elts;
3683
3684 if (flcf->upstream.cache != NGX_CONF_UNSET) {
3685 return "is duplicate";
3686 }
3687
3688 if (ngx_strcmp(value[1].data, "off") == 0) {
3689 flcf->upstream.cache = 0;
3690 return NGX_CONF_OK;
3691 }
3692
3693 if (flcf->upstream.store > 0) {
3694 return "is incompatible with \"fastcgi_store\"";
3695 }
3696
3697 flcf->upstream.cache = 1;
3698
3699 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3700
3701 ccv.cf = cf;
3702 ccv.value = &value[1];
3703 ccv.complex_value = &cv;
3704
3705 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3706 return NGX_CONF_ERROR;
3707 }
3708
3709 if (cv.lengths != NULL) {
3710
3711 flcf->upstream.cache_value = ngx_palloc(cf->pool,
3712 sizeof(ngx_http_complex_value_t));
3713 if (flcf->upstream.cache_value == NULL) {
3714 return NGX_CONF_ERROR;
3715 }
3716
3717 *flcf->upstream.cache_value = cv;
3718
3719 return NGX_CONF_OK;
3720 }
3721
3722 flcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0,
3723 &ngx_http_fastcgi_module);
3724 if (flcf->upstream.cache_zone == NULL) {
3725 return NGX_CONF_ERROR;
3726 }
3727
3728 return NGX_CONF_OK;
3729 }
3730
3731
3732 static char *
3733 ngx_http_fastcgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3734 {
3735 ngx_http_fastcgi_loc_conf_t *flcf = conf;
3736
3737 ngx_str_t *value;
3738 ngx_http_compile_complex_value_t ccv;
3739
3740 value = cf->args->elts;
3741
3742 if (flcf->cache_key.value.data) {
3743 return "is duplicate";
3744 }
3745
3746 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3747
3748 ccv.cf = cf;
3749 ccv.value = &value[1];
3750 ccv.complex_value = &flcf->cache_key;
3751
3752 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3753 return NGX_CONF_ERROR;
3754 }
3755
3756 return NGX_CONF_OK;
3757 }
3758
3759 #endif
3760
3761
3762 static char *
3763 ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post, void *data)
3764 {
3765 #if (NGX_FREEBSD)
3766 ssize_t *np = data;
3767
3768 if ((u_long) *np >= ngx_freebsd_net_inet_tcp_sendspace) {
3769 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3770 "\"fastcgi_send_lowat\" must be less than %d "
3771 "(sysctl net.inet.tcp.sendspace)",
3772 ngx_freebsd_net_inet_tcp_sendspace);
3773
3774 return NGX_CONF_ERROR;
3775 }
3776
3777 #elif !(NGX_HAVE_SO_SNDLOWAT)
3778 ssize_t *np = data;
3779
3780 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
3781 "\"fastcgi_send_lowat\" is not supported, ignored");
3782
3783 *np = 0;
3784
3785 #endif
3786
3787 return NGX_CONF_OK;
3788 }