Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.2 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
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;  /* ngx_http_file_cache_t * */
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,        /* preconfiguration */
0572     NULL,                                  /* postconfiguration */
0573 
0574     ngx_http_fastcgi_create_main_conf,     /* create main configuration */
0575     NULL,                                  /* init main configuration */
0576 
0577     NULL,                                  /* create server configuration */
0578     NULL,                                  /* merge server configuration */
0579 
0580     ngx_http_fastcgi_create_loc_conf,      /* create location configuration */
0581     ngx_http_fastcgi_merge_loc_conf        /* merge location configuration */
0582 };
0583 
0584 
0585 ngx_module_t  ngx_http_fastcgi_module = {
0586     NGX_MODULE_V1,
0587     &ngx_http_fastcgi_module_ctx,          /* module context */
0588     ngx_http_fastcgi_commands,             /* module directives */
0589     NGX_HTTP_MODULE,                       /* module type */
0590     NULL,                                  /* init master */
0591     NULL,                                  /* init module */
0592     NULL,                                  /* init process */
0593     NULL,                                  /* init thread */
0594     NULL,                                  /* exit thread */
0595     NULL,                                  /* exit process */
0596     NULL,                                  /* exit master */
0597     NGX_MODULE_V1_PADDING
0598 };
0599 
0600 
0601 static ngx_http_fastcgi_request_start_t  ngx_http_fastcgi_request_start = {
0602     { 1,                                               /* version */
0603       NGX_HTTP_FASTCGI_BEGIN_REQUEST,                  /* type */
0604       0,                                               /* request_id_hi */
0605       1,                                               /* request_id_lo */
0606       0,                                               /* content_length_hi */
0607       sizeof(ngx_http_fastcgi_begin_request_t),        /* content_length_lo */
0608       0,                                               /* padding_length */
0609       0 },                                             /* reserved */
0610 
0611     { 0,                                               /* role_hi */
0612       NGX_HTTP_FASTCGI_RESPONDER,                      /* role_lo */
0613       0, /* NGX_HTTP_FASTCGI_KEEP_CONN */              /* flags */
0614       { 0, 0, 0, 0, 0 } },                             /* reserved[5] */
0615 
0616     { 1,                                               /* version */
0617       NGX_HTTP_FASTCGI_PARAMS,                         /* type */
0618       0,                                               /* request_id_hi */
0619       1 },                                             /* request_id_lo */
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_http_null_variable
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; /* void */; 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(&params->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)  /* NGX_HTTP_FASTCGI_PARAMS */
0980            + len + padding
0981            + sizeof(ngx_http_fastcgi_header_t)  /* NGX_HTTP_FASTCGI_PARAMS */
0982 
0983            + sizeof(ngx_http_fastcgi_header_t); /* NGX_HTTP_FASTCGI_STDIN */
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; /* void */; i++) {
1089 
1090             if (i >= part->nelts) {
1091                 if (part->next == NULL) {
1092                     break;
1093                 }
1094 
1095                 part = part->next;
1096                 header = part->elts;
1097                 i = 0;
1098             }
1099 
1100             for (n = 0; n < header_params; n++) {
1101                 if (&header[i] == ignored[n]) {
1102                     goto next;
1103                 }
1104             }
1105 
1106             key_len = sizeof("HTTP_") - 1 + header[i].key.len;
1107             if (key_len > 127) {
1108                 *b->last++ = (u_char) (((key_len >> 24) & 0x7f) | 0x80);
1109                 *b->last++ = (u_char) ((key_len >> 16) & 0xff);
1110                 *b->last++ = (u_char) ((key_len >> 8) & 0xff);
1111                 *b->last++ = (u_char) (key_len & 0xff);
1112 
1113             } else {
1114                 *b->last++ = (u_char) key_len;
1115             }
1116 
1117             val_len = header[i].value.len;
1118             if (val_len > 127) {
1119                 *b->last++ = (u_char) (((val_len >> 24) & 0x7f) | 0x80);
1120                 *b->last++ = (u_char) ((val_len >> 16) & 0xff);
1121                 *b->last++ = (u_char) ((val_len >> 8) & 0xff);
1122                 *b->last++ = (u_char) (val_len & 0xff);
1123 
1124             } else {
1125                 *b->last++ = (u_char) val_len;
1126             }
1127 
1128             b->last = ngx_cpymem(b->last, "HTTP_", sizeof("HTTP_") - 1);
1129 
1130             for (n = 0; n < header[i].key.len; n++) {
1131                 ch = header[i].key.data[n];
1132 
1133                 if (ch >= 'a' && ch <= 'z') {
1134                     ch &= ~0x20;
1135 
1136                 } else if (ch == '-') {
1137                     ch = '_';
1138                 }
1139 
1140                 *b->last++ = ch;
1141             }
1142 
1143             b->last = ngx_copy(b->last, header[i].value.data, val_len);
1144 
1145             ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1146                            "fastcgi param: \"%*s: %*s\"",
1147                            key_len, b->last - (key_len + val_len),
1148                            val_len, b->last - val_len);
1149         next:
1150 
1151             continue;
1152         }
1153     }
1154 
1155 
1156     if (padding) {
1157         ngx_memzero(b->last, padding);
1158         b->last += padding;
1159     }
1160 
1161 
1162     h = (ngx_http_fastcgi_header_t *) b->last;
1163     b->last += sizeof(ngx_http_fastcgi_header_t);
1164 
1165     h->version = 1;
1166     h->type = NGX_HTTP_FASTCGI_PARAMS;
1167     h->request_id_hi = 0;
1168     h->request_id_lo = 1;
1169     h->content_length_hi = 0;
1170     h->content_length_lo = 0;
1171     h->padding_length = 0;
1172     h->reserved = 0;
1173 
1174     if (r->request_body_no_buffering) {
1175 
1176         u->request_bufs = cl;
1177 
1178         u->output.output_filter = ngx_http_fastcgi_body_output_filter;
1179         u->output.filter_ctx = r;
1180 
1181     } else if (flcf->upstream.pass_request_body) {
1182 
1183         body = u->request_bufs;
1184         u->request_bufs = cl;
1185 
1186 #if (NGX_SUPPRESS_WARN)
1187         file_pos = 0;
1188         pos = NULL;
1189 #endif
1190 
1191         while (body) {
1192 
1193             if (ngx_buf_special(body->buf)) {
1194                 body = body->next;
1195                 continue;
1196             }
1197 
1198             if (body->buf->in_file) {
1199                 file_pos = body->buf->file_pos;
1200 
1201             } else {
1202                 pos = body->buf->pos;
1203             }
1204 
1205             next = 0;
1206 
1207             do {
1208                 b = ngx_alloc_buf(r->pool);
1209                 if (b == NULL) {
1210                     return NGX_ERROR;
1211                 }
1212 
1213                 ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
1214 
1215                 if (body->buf->in_file) {
1216                     b->file_pos = file_pos;
1217                     file_pos += 32 * 1024;
1218 
1219                     if (file_pos >= body->buf->file_last) {
1220                         file_pos = body->buf->file_last;
1221                         next = 1;
1222                     }
1223 
1224                     b->file_last = file_pos;
1225                     len = (ngx_uint_t) (file_pos - b->file_pos);
1226 
1227                 } else {
1228                     b->pos = pos;
1229                     b->start = pos;
1230                     pos += 32 * 1024;
1231 
1232                     if (pos >= body->buf->last) {
1233                         pos = body->buf->last;
1234                         next = 1;
1235                     }
1236 
1237                     b->last = pos;
1238                     len = (ngx_uint_t) (pos - b->pos);
1239                 }
1240 
1241                 padding = 8 - len % 8;
1242                 padding = (padding == 8) ? 0 : padding;
1243 
1244                 h = (ngx_http_fastcgi_header_t *) cl->buf->last;
1245                 cl->buf->last += sizeof(ngx_http_fastcgi_header_t);
1246 
1247                 h->version = 1;
1248                 h->type = NGX_HTTP_FASTCGI_STDIN;
1249                 h->request_id_hi = 0;
1250                 h->request_id_lo = 1;
1251                 h->content_length_hi = (u_char) ((len >> 8) & 0xff);
1252                 h->content_length_lo = (u_char) (len & 0xff);
1253                 h->padding_length = (u_char) padding;
1254                 h->reserved = 0;
1255 
1256                 cl->next = ngx_alloc_chain_link(r->pool);
1257                 if (cl->next == NULL) {
1258                     return NGX_ERROR;
1259                 }
1260 
1261                 cl = cl->next;
1262                 cl->buf = b;
1263 
1264                 b = ngx_create_temp_buf(r->pool,
1265                                         sizeof(ngx_http_fastcgi_header_t)
1266                                         + padding);
1267                 if (b == NULL) {
1268                     return NGX_ERROR;
1269                 }
1270 
1271                 if (padding) {
1272                     ngx_memzero(b->last, padding);
1273                     b->last += padding;
1274                 }
1275 
1276                 cl->next = ngx_alloc_chain_link(r->pool);
1277                 if (cl->next == NULL) {
1278                     return NGX_ERROR;
1279                 }
1280 
1281                 cl = cl->next;
1282                 cl->buf = b;
1283 
1284             } while (!next);
1285 
1286             body = body->next;
1287         }
1288 
1289     } else {
1290         u->request_bufs = cl;
1291     }
1292 
1293     if (!r->request_body_no_buffering) {
1294         h = (ngx_http_fastcgi_header_t *) cl->buf->last;
1295         cl->buf->last += sizeof(ngx_http_fastcgi_header_t);
1296 
1297         h->version = 1;
1298         h->type = NGX_HTTP_FASTCGI_STDIN;
1299         h->request_id_hi = 0;
1300         h->request_id_lo = 1;
1301         h->content_length_hi = 0;
1302         h->content_length_lo = 0;
1303         h->padding_length = 0;
1304         h->reserved = 0;
1305     }
1306 
1307     cl->next = NULL;
1308 
1309     return NGX_OK;
1310 }
1311 
1312 
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         /* first buffer contains headers, pass it unmodified */
1368 
1369         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1370                        "fastcgi output header");
1371 
1372         f->header_sent = 1;
1373 
1374         tl = ngx_alloc_chain_link(r->pool);
1375         if (tl == NULL) {
1376             return NGX_ERROR;
1377         }
1378 
1379         tl->buf = in->buf;
1380         *ll = tl;
1381         ll = &tl->next;
1382 
1383         in = in->next;
1384 
1385         if (in == NULL) {
1386             tl->next = NULL;
1387             goto out;
1388         }
1389     }
1390 
1391     cl = ngx_chain_get_free_buf(r->pool, &f->free);
1392     if (cl == NULL) {
1393         return NGX_ERROR;
1394     }
1395 
1396     b = cl->buf;
1397 
1398     b->tag = (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter;
1399     b->temporary = 1;
1400 
1401     if (b->start == NULL) {
1402         /* reserve space for maximum possible padding, 7 bytes */
1403 
1404         b->start = ngx_palloc(r->pool,
1405                               sizeof(ngx_http_fastcgi_header_t) + 7);
1406         if (b->start == NULL) {
1407             return NGX_ERROR;
1408         }
1409 
1410         b->pos = b->start;
1411         b->last = b->start;
1412 
1413         b->end = b->start + sizeof(ngx_http_fastcgi_header_t) + 7;
1414     }
1415 
1416     *ll = cl;
1417 
1418     last = 0;
1419     padding = 0;
1420 
1421 #if (NGX_SUPPRESS_WARN)
1422     file_pos = 0;
1423     pos = NULL;
1424 #endif
1425 
1426     while (in) {
1427 
1428         ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
1429                        "fastcgi output in  l:%d f:%d %p, pos %p, size: %z "
1430                        "file: %O, size: %O",
1431                        in->buf->last_buf,
1432                        in->buf->in_file,
1433                        in->buf->start, in->buf->pos,
1434                        in->buf->last - in->buf->pos,
1435                        in->buf->file_pos,
1436                        in->buf->file_last - in->buf->file_pos);
1437 
1438         if (in->buf->last_buf) {
1439             last = 1;
1440         }
1441 
1442         if (ngx_buf_special(in->buf)) {
1443             in = in->next;
1444             continue;
1445         }
1446 
1447         if (in->buf->in_file) {
1448             file_pos = in->buf->file_pos;
1449 
1450         } else {
1451             pos = in->buf->pos;
1452         }
1453 
1454         next = 0;
1455 
1456         do {
1457             tl = ngx_chain_get_free_buf(r->pool, &f->free);
1458             if (tl == NULL) {
1459                 return NGX_ERROR;
1460             }
1461 
1462             b = tl->buf;
1463             start = b->start;
1464 
1465             ngx_memcpy(b, in->buf, sizeof(ngx_buf_t));
1466 
1467             /*
1468              * restore b->start to preserve memory allocated in the buffer,
1469              * to reuse it later for headers and padding
1470              */
1471 
1472             b->start = start;
1473 
1474             if (in->buf->in_file) {
1475                 b->file_pos = file_pos;
1476                 file_pos += 32 * 1024;
1477 
1478                 if (file_pos >= in->buf->file_last) {
1479                     file_pos = in->buf->file_last;
1480                     next = 1;
1481                 }
1482 
1483                 b->file_last = file_pos;
1484                 len = (ngx_uint_t) (file_pos - b->file_pos);
1485 
1486             } else {
1487                 b->pos = pos;
1488                 pos += 32 * 1024;
1489 
1490                 if (pos >= in->buf->last) {
1491                     pos = in->buf->last;
1492                     next = 1;
1493                 }
1494 
1495                 b->last = pos;
1496                 len = (ngx_uint_t) (pos - b->pos);
1497             }
1498 
1499             b->tag = (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter;
1500             b->shadow = in->buf;
1501             b->last_shadow = next;
1502 
1503             b->last_buf = 0;
1504             b->last_in_chain = 0;
1505 
1506             padding = 8 - len % 8;
1507             padding = (padding == 8) ? 0 : padding;
1508 
1509             h = (ngx_http_fastcgi_header_t *) cl->buf->last;
1510             cl->buf->last += sizeof(ngx_http_fastcgi_header_t);
1511 
1512             h->version = 1;
1513             h->type = NGX_HTTP_FASTCGI_STDIN;
1514             h->request_id_hi = 0;
1515             h->request_id_lo = 1;
1516             h->content_length_hi = (u_char) ((len >> 8) & 0xff);
1517             h->content_length_lo = (u_char) (len & 0xff);
1518             h->padding_length = (u_char) padding;
1519             h->reserved = 0;
1520 
1521             cl->next = tl;
1522             cl = tl;
1523 
1524             tl = ngx_chain_get_free_buf(r->pool, &f->free);
1525             if (tl == NULL) {
1526                 return NGX_ERROR;
1527             }
1528 
1529             b = tl->buf;
1530 
1531             b->tag = (ngx_buf_tag_t) &ngx_http_fastcgi_body_output_filter;
1532             b->temporary = 1;
1533 
1534             if (b->start == NULL) {
1535                 /* reserve space for maximum possible padding, 7 bytes */
1536 
1537                 b->start = ngx_palloc(r->pool,
1538                                       sizeof(ngx_http_fastcgi_header_t) + 7);
1539                 if (b->start == NULL) {
1540                     return NGX_ERROR;
1541                 }
1542 
1543                 b->pos = b->start;
1544                 b->last = b->start;
1545 
1546                 b->end = b->start + sizeof(ngx_http_fastcgi_header_t) + 7;
1547             }
1548 
1549             if (padding) {
1550                 ngx_memzero(b->last, padding);
1551                 b->last += padding;
1552             }
1553 
1554             cl->next = tl;
1555             cl = tl;
1556 
1557         } while (!next);
1558 
1559         in = in->next;
1560     }
1561 
1562     if (last) {
1563         h = (ngx_http_fastcgi_header_t *) cl->buf->last;
1564         cl->buf->last += sizeof(ngx_http_fastcgi_header_t);
1565 
1566         h->version = 1;
1567         h->type = NGX_HTTP_FASTCGI_STDIN;
1568         h->request_id_hi = 0;
1569         h->request_id_lo = 1;
1570         h->content_length_hi = 0;
1571         h->content_length_lo = 0;
1572         h->padding_length = 0;
1573         h->reserved = 0;
1574 
1575         cl->buf->last_buf = 1;
1576 
1577     } else if (padding == 0) {
1578         /* TODO: do not allocate buffers instead */
1579         cl->buf->temporary = 0;
1580         cl->buf->sync = 1;
1581     }
1582 
1583     cl->next = NULL;
1584 
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         /* mark original buffers as sent */
1611 
1612         if (cl->buf->shadow) {
1613             if (cl->buf->last_shadow) {
1614                 b = cl->buf->shadow;
1615                 b->pos = b->last;
1616             }
1617 
1618             cl->buf->shadow = NULL;
1619         }
1620     }
1621 
1622     return rc;
1623 }
1624 
1625 
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         /* f->state == ngx_http_fastcgi_st_data */
1712 
1713         if (f->type == NGX_HTTP_FASTCGI_STDERR) {
1714 
1715             if (f->length) {
1716                 msg = u->buffer.pos;
1717 
1718                 if (u->buffer.pos + f->length <= u->buffer.last) {
1719                     u->buffer.pos += f->length;
1720                     f->length = 0;
1721                     f->state = ngx_http_fastcgi_st_padding;
1722 
1723                 } else {
1724                     f->length -= u->buffer.last - u->buffer.pos;
1725                     u->buffer.pos = u->buffer.last;
1726                 }
1727 
1728                 for (p = u->buffer.pos - 1; msg < p; p--) {
1729                     if (*p != LF && *p != CR && *p != '.' && *p != ' ') {
1730                         break;
1731                     }
1732                 }
1733 
1734                 p++;
1735 
1736                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1737                               "FastCGI sent in stderr: \"%*s\"", p - msg, msg);
1738 
1739                 flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
1740 
1741                 if (flcf->catch_stderr) {
1742                     pattern = flcf->catch_stderr->elts;
1743 
1744                     for (i = 0; i < flcf->catch_stderr->nelts; i++) {
1745                         if (ngx_strnstr(msg, (char *) pattern[i].data,
1746                                         p - msg)
1747                             != NULL)
1748                         {
1749                             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1750                         }
1751                     }
1752                 }
1753 
1754                 if (u->buffer.pos == u->buffer.last) {
1755 
1756                     if (!f->fastcgi_stdout) {
1757 
1758                         /*
1759                          * the special handling the large number
1760                          * of the PHP warnings to not allocate memory
1761                          */
1762 
1763 #if (NGX_HTTP_CACHE)
1764                         if (r->cache) {
1765                             u->buffer.pos = u->buffer.start
1766                                                      + r->cache->header_start;
1767                         } else {
1768                             u->buffer.pos = u->buffer.start;
1769                         }
1770 #else
1771                         u->buffer.pos = u->buffer.start;
1772 #endif
1773                         u->buffer.last = u->buffer.pos;
1774                         f->large_stderr = 1;
1775                     }
1776 
1777                     return NGX_AGAIN;
1778                 }
1779 
1780             } else {
1781                 f->state = ngx_http_fastcgi_st_padding;
1782             }
1783 
1784             continue;
1785         }
1786 
1787 
1788         /* f->type == NGX_HTTP_FASTCGI_STDOUT */
1789 
1790 #if (NGX_HTTP_CACHE)
1791 
1792         if (f->large_stderr && r->cache) {
1793             ssize_t                     len;
1794             ngx_http_fastcgi_header_t  *fh;
1795 
1796             start = u->buffer.start + r->cache->header_start;
1797 
1798             len = u->buffer.pos - start - 2 * sizeof(ngx_http_fastcgi_header_t);
1799 
1800             /*
1801              * A tail of large stderr output before HTTP header is placed
1802              * in a cache file without a FastCGI record header.
1803              * To workaround it we put a dummy FastCGI record header at the
1804              * start of the stderr output or update r->cache_header_start,
1805              * if there is no enough place for the record header.
1806              */
1807 
1808             if (len >= 0) {
1809                 fh = (ngx_http_fastcgi_header_t *) start;
1810                 fh->version = 1;
1811                 fh->type = NGX_HTTP_FASTCGI_STDERR;
1812                 fh->request_id_hi = 0;
1813                 fh->request_id_lo = 1;
1814                 fh->content_length_hi = (u_char) ((len >> 8) & 0xff);
1815                 fh->content_length_lo = (u_char) (len & 0xff);
1816                 fh->padding_length = 0;
1817                 fh->reserved = 0;
1818 
1819             } else {
1820                 r->cache->header_start += u->buffer.pos - start
1821                                           - sizeof(ngx_http_fastcgi_header_t);
1822             }
1823 
1824             f->large_stderr = 0;
1825         }
1826 
1827 #endif
1828 
1829         f->fastcgi_stdout = 1;
1830 
1831         start = u->buffer.pos;
1832 
1833         if (u->buffer.pos + f->length < u->buffer.last) {
1834 
1835             /*
1836              * set u->buffer.last to the end of the FastCGI record data
1837              * for ngx_http_parse_header_line()
1838              */
1839 
1840             last = u->buffer.last;
1841             u->buffer.last = u->buffer.pos + f->length;
1842 
1843         } else {
1844             last = NULL;
1845         }
1846 
1847         for ( ;; ) {
1848 
1849             part_start = u->buffer.pos;
1850             part_end = u->buffer.last;
1851 
1852             rc = ngx_http_parse_header_line(r, &u->buffer, 1);
1853 
1854             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1855                            "http fastcgi parser: %i", rc);
1856 
1857             if (rc == NGX_AGAIN) {
1858                 break;
1859             }
1860 
1861             if (rc == NGX_OK) {
1862 
1863                 /* a header line has been parsed successfully */
1864 
1865                 h = ngx_list_push(&u->headers_in.headers);
1866                 if (h == NULL) {
1867                     return NGX_ERROR;
1868                 }
1869 
1870                 if (f->split_parts && f->split_parts->nelts) {
1871 
1872                     part = f->split_parts->elts;
1873                     size = u->buffer.pos - part_start;
1874 
1875                     for (i = 0; i < f->split_parts->nelts; i++) {
1876                         size += part[i].end - part[i].start;
1877                     }
1878 
1879                     p = ngx_pnalloc(r->pool, size);
1880                     if (p == NULL) {
1881                         h->hash = 0;
1882                         return NGX_ERROR;
1883                     }
1884 
1885                     buf.pos = p;
1886 
1887                     for (i = 0; i < f->split_parts->nelts; i++) {
1888                         p = ngx_cpymem(p, part[i].start,
1889                                        part[i].end - part[i].start);
1890                     }
1891 
1892                     p = ngx_cpymem(p, part_start, u->buffer.pos - part_start);
1893 
1894                     buf.last = p;
1895 
1896                     f->split_parts->nelts = 0;
1897 
1898                     rc = ngx_http_parse_header_line(r, &buf, 1);
1899 
1900                     if (rc != NGX_OK) {
1901                         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
1902                                       "invalid header after joining "
1903                                       "FastCGI records");
1904                         h->hash = 0;
1905                         return NGX_ERROR;
1906                     }
1907 
1908                     h->key.len = r->header_name_end - r->header_name_start;
1909                     h->key.data = r->header_name_start;
1910                     h->key.data[h->key.len] = '\0';
1911 
1912                     h->value.len = r->header_end - r->header_start;
1913                     h->value.data = r->header_start;
1914                     h->value.data[h->value.len] = '\0';
1915 
1916                     h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
1917                     if (h->lowcase_key == NULL) {
1918                         return NGX_ERROR;
1919                     }
1920 
1921                 } else {
1922 
1923                     h->key.len = r->header_name_end - r->header_name_start;
1924                     h->value.len = r->header_end - r->header_start;
1925 
1926                     h->key.data = ngx_pnalloc(r->pool,
1927                                               h->key.len + 1 + h->value.len + 1
1928                                               + h->key.len);
1929                     if (h->key.data == NULL) {
1930                         h->hash = 0;
1931                         return NGX_ERROR;
1932                     }
1933 
1934                     h->value.data = h->key.data + h->key.len + 1;
1935                     h->lowcase_key = h->key.data + h->key.len + 1
1936                                      + h->value.len + 1;
1937 
1938                     ngx_memcpy(h->key.data, r->header_name_start, h->key.len);
1939                     h->key.data[h->key.len] = '\0';
1940                     ngx_memcpy(h->value.data, r->header_start, h->value.len);
1941                     h->value.data[h->value.len] = '\0';
1942                 }
1943 
1944                 h->hash = r->header_hash;
1945 
1946                 if (h->key.len == r->lowcase_index) {
1947                     ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
1948 
1949                 } else {
1950                     ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
1951                 }
1952 
1953                 hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
1954                                    h->lowcase_key, h->key.len);
1955 
1956                 if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1957                     return NGX_ERROR;
1958                 }
1959 
1960                 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1961                                "http fastcgi header: \"%V: %V\"",
1962                                &h->key, &h->value);
1963 
1964                 if (u->buffer.pos < u->buffer.last) {
1965                     continue;
1966                 }
1967 
1968                 /* the end of the FastCGI record */
1969 
1970                 break;
1971             }
1972 
1973             if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
1974 
1975                 /* a whole header has been parsed successfully */
1976 
1977                 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1978                                "http fastcgi header done");
1979 
1980                 if (u->headers_in.status) {
1981                     status_line = &u->headers_in.status->value;
1982 
1983                     status = ngx_atoi(status_line->data, 3);
1984 
1985                     if (status == NGX_ERROR) {
1986                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1987                                       "upstream sent invalid status \"%V\"",
1988                                       status_line);
1989                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1990                     }
1991 
1992                     u->headers_in.status_n = status;
1993                     u->headers_in.status_line = *status_line;
1994 
1995                 } else if (u->headers_in.location) {
1996                     u->headers_in.status_n = 302;
1997                     ngx_str_set(&u->headers_in.status_line,
1998                                 "302 Moved Temporarily");
1999 
2000                 } else {
2001                     u->headers_in.status_n = 200;
2002                     ngx_str_set(&u->headers_in.status_line, "200 OK");
2003                 }
2004 
2005                 if (u->state && u->state->status == 0) {
2006                     u->state->status = u->headers_in.status_n;
2007                 }
2008 
2009                 break;
2010             }
2011 
2012             /* there was error while a header line parsing */
2013 
2014             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2015                           "upstream sent invalid header");
2016 
2017             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
2018         }
2019 
2020         if (last) {
2021             u->buffer.last = last;
2022         }
2023 
2024         f->length -= u->buffer.pos - start;
2025 
2026         if (f->length == 0) {
2027             f->state = ngx_http_fastcgi_st_padding;
2028         }
2029 
2030         if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
2031             return NGX_OK;
2032         }
2033 
2034         if (rc == NGX_OK) {
2035             continue;
2036         }
2037 
2038         /* rc == NGX_AGAIN */
2039 
2040         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2041                        "upstream split a header line in FastCGI records");
2042 
2043         if (f->split_parts == NULL) {
2044             f->split_parts = ngx_array_create(r->pool, 1,
2045                                         sizeof(ngx_http_fastcgi_split_part_t));
2046             if (f->split_parts == NULL) {
2047                 return NGX_ERROR;
2048             }
2049         }
2050 
2051         part = ngx_array_push(f->split_parts);
2052         if (part == NULL) {
2053             return NGX_ERROR;
2054         }
2055 
2056         part->start = part_start;
2057         part->end = part_end;
2058 
2059         if (u->buffer.pos < u->buffer.last) {
2060             continue;
2061         }
2062 
2063         return NGX_AGAIN;
2064     }
2065 }
2066 
2067 
2068 static ngx_int_t
2069 ngx_http_fastcgi_input_filter_init(void *data)
2070 {
2071     ngx_http_request_t           *r = data;
2072     ngx_http_fastcgi_loc_conf_t  *flcf;
2073 
2074     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
2075 
2076     r->upstream->pipe->length = flcf->keep_conn ?
2077                                 (off_t) sizeof(ngx_http_fastcgi_header_t) : -1;
2078 
2079     return NGX_OK;
2080 }
2081 
2082 
2083 static ngx_int_t
2084 ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
2085 {
2086     u_char                       *m, *msg;
2087     ngx_int_t                     rc;
2088     ngx_buf_t                    *b, **prev;
2089     ngx_chain_t                  *cl;
2090     ngx_http_request_t           *r;
2091     ngx_http_fastcgi_ctx_t       *f;
2092     ngx_http_fastcgi_loc_conf_t  *flcf;
2093 
2094     if (buf->pos == buf->last) {
2095         return NGX_OK;
2096     }
2097 
2098     r = p->input_ctx;
2099     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
2100     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
2101 
2102     b = NULL;
2103     prev = &buf->shadow;
2104 
2105     f->pos = buf->pos;
2106     f->last = buf->last;
2107 
2108     for ( ;; ) {
2109         if (f->state < ngx_http_fastcgi_st_data) {
2110 
2111             rc = ngx_http_fastcgi_process_record(r, f);
2112 
2113             if (rc == NGX_AGAIN) {
2114                 break;
2115             }
2116 
2117             if (rc == NGX_ERROR) {
2118                 return NGX_ERROR;
2119             }
2120 
2121             if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) {
2122                 f->state = ngx_http_fastcgi_st_padding;
2123 
2124                 if (!flcf->keep_conn) {
2125                     p->upstream_done = 1;
2126                 }
2127 
2128                 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
2129                                "http fastcgi closed stdout");
2130 
2131                 continue;
2132             }
2133 
2134             if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
2135 
2136                 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
2137                                "http fastcgi sent end request");
2138 
2139                 if (!flcf->keep_conn) {
2140                     p->upstream_done = 1;
2141                     break;
2142                 }
2143 
2144                 continue;
2145             }
2146         }
2147 
2148 
2149         if (f->state == ngx_http_fastcgi_st_padding) {
2150 
2151             if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
2152 
2153                 if (f->pos + f->padding < f->last) {
2154                     p->upstream_done = 1;
2155                     break;
2156                 }
2157 
2158                 if (f->pos + f->padding == f->last) {
2159                     p->upstream_done = 1;
2160                     r->upstream->keepalive = 1;
2161                     break;
2162                 }
2163 
2164                 f->padding -= f->last - f->pos;
2165 
2166                 break;
2167             }
2168 
2169             if (f->pos + f->padding < f->last) {
2170                 f->state = ngx_http_fastcgi_st_version;
2171                 f->pos += f->padding;
2172 
2173                 continue;
2174             }
2175 
2176             if (f->pos + f->padding == f->last) {
2177                 f->state = ngx_http_fastcgi_st_version;
2178 
2179                 break;
2180             }
2181 
2182             f->padding -= f->last - f->pos;
2183 
2184             break;
2185         }
2186 
2187 
2188         /* f->state == ngx_http_fastcgi_st_data */
2189 
2190         if (f->type == NGX_HTTP_FASTCGI_STDERR) {
2191 
2192             if (f->length) {
2193 
2194                 if (f->pos == f->last) {
2195                     break;
2196                 }
2197 
2198                 msg = f->pos;
2199 
2200                 if (f->pos + f->length <= f->last) {
2201                     f->pos += f->length;
2202                     f->length = 0;
2203                     f->state = ngx_http_fastcgi_st_padding;
2204 
2205                 } else {
2206                     f->length -= f->last - f->pos;
2207                     f->pos = f->last;
2208                 }
2209 
2210                 for (m = f->pos - 1; msg < m; m--) {
2211                     if (*m != LF && *m != CR && *m != '.' && *m != ' ') {
2212                         break;
2213                     }
2214                 }
2215 
2216                 ngx_log_error(NGX_LOG_ERR, p->log, 0,
2217                               "FastCGI sent in stderr: \"%*s\"",
2218                               m + 1 - msg, msg);
2219 
2220             } else {
2221                 f->state = ngx_http_fastcgi_st_padding;
2222             }
2223 
2224             continue;
2225         }
2226 
2227         if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
2228 
2229             if (f->pos + f->length <= f->last) {
2230                 f->state = ngx_http_fastcgi_st_padding;
2231                 f->pos += f->length;
2232 
2233                 continue;
2234             }
2235 
2236             f->length -= f->last - f->pos;
2237 
2238             break;
2239         }
2240 
2241 
2242         /* f->type == NGX_HTTP_FASTCGI_STDOUT */
2243 
2244         if (f->pos == f->last) {
2245             break;
2246         }
2247 
2248         cl = ngx_chain_get_free_buf(p->pool, &p->free);
2249         if (cl == NULL) {
2250             return NGX_ERROR;
2251         }
2252 
2253         b = cl->buf;
2254 
2255         ngx_memzero(b, sizeof(ngx_buf_t));
2256 
2257         b->pos = f->pos;
2258         b->start = buf->start;
2259         b->end = buf->end;
2260         b->tag = p->tag;
2261         b->temporary = 1;
2262         b->recycled = 1;
2263 
2264         *prev = b;
2265         prev = &b->shadow;
2266 
2267         if (p->in) {
2268             *p->last_in = cl;
2269         } else {
2270             p->in = cl;
2271         }
2272         p->last_in = &cl->next;
2273 
2274 
2275         /* STUB */ b->num = buf->num;
2276 
2277         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
2278                        "input buf #%d %p", b->num, b->pos);
2279 
2280         if (f->pos + f->length <= f->last) {
2281             f->state = ngx_http_fastcgi_st_padding;
2282             f->pos += f->length;
2283             b->last = f->pos;
2284 
2285             continue;
2286         }
2287 
2288         f->length -= f->last - f->pos;
2289 
2290         b->last = f->last;
2291 
2292         break;
2293 
2294     }
2295 
2296     if (flcf->keep_conn) {
2297 
2298         /* set p->length, minimal amount of data we want to see */
2299 
2300         if (f->state < ngx_http_fastcgi_st_data) {
2301             p->length = 1;
2302 
2303         } else if (f->state == ngx_http_fastcgi_st_padding) {
2304             p->length = f->padding;
2305 
2306         } else {
2307             /* ngx_http_fastcgi_st_data */
2308 
2309             p->length = f->length;
2310         }
2311     }
2312 
2313     if (b) {
2314         b->shadow = buf;
2315         b->last_shadow = 1;
2316 
2317         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
2318                        "input buf %p %z", b->pos, b->last - b->pos);
2319 
2320         return NGX_OK;
2321     }
2322 
2323     /* there is no data record in the buf, add it to free chain */
2324 
2325     if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) {
2326         return NGX_ERROR;
2327     }
2328 
2329     return NGX_OK;
2330 }
2331 
2332 
2333 static ngx_int_t
2334 ngx_http_fastcgi_non_buffered_filter(void *data, ssize_t bytes)
2335 {
2336     u_char                  *m, *msg;
2337     ngx_int_t                rc;
2338     ngx_buf_t               *b, *buf;
2339     ngx_chain_t             *cl, **ll;
2340     ngx_http_request_t      *r;
2341     ngx_http_upstream_t     *u;
2342     ngx_http_fastcgi_ctx_t  *f;
2343 
2344     r = data;
2345     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
2346 
2347     u = r->upstream;
2348     buf = &u->buffer;
2349 
2350     buf->pos = buf->last;
2351     buf->last += bytes;
2352 
2353     for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
2354         ll = &cl->next;
2355     }
2356 
2357     f->pos = buf->pos;
2358     f->last = buf->last;
2359 
2360     for ( ;; ) {
2361         if (f->state < ngx_http_fastcgi_st_data) {
2362 
2363             rc = ngx_http_fastcgi_process_record(r, f);
2364 
2365             if (rc == NGX_AGAIN) {
2366                 break;
2367             }
2368 
2369             if (rc == NGX_ERROR) {
2370                 return NGX_ERROR;
2371             }
2372 
2373             if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) {
2374                 f->state = ngx_http_fastcgi_st_padding;
2375 
2376                 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2377                                "http fastcgi closed stdout");
2378 
2379                 continue;
2380             }
2381         }
2382 
2383         if (f->state == ngx_http_fastcgi_st_padding) {
2384 
2385             if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
2386 
2387                 if (f->pos + f->padding < f->last) {
2388                     u->length = 0;
2389                     break;
2390                 }
2391 
2392                 if (f->pos + f->padding == f->last) {
2393                     u->length = 0;
2394                     u->keepalive = 1;
2395                     break;
2396                 }
2397 
2398                 f->padding -= f->last - f->pos;
2399 
2400                 break;
2401             }
2402 
2403             if (f->pos + f->padding < f->last) {
2404                 f->state = ngx_http_fastcgi_st_version;
2405                 f->pos += f->padding;
2406 
2407                 continue;
2408             }
2409 
2410             if (f->pos + f->padding == f->last) {
2411                 f->state = ngx_http_fastcgi_st_version;
2412 
2413                 break;
2414             }
2415 
2416             f->padding -= f->last - f->pos;
2417 
2418             break;
2419         }
2420 
2421 
2422         /* f->state == ngx_http_fastcgi_st_data */
2423 
2424         if (f->type == NGX_HTTP_FASTCGI_STDERR) {
2425 
2426             if (f->length) {
2427 
2428                 if (f->pos == f->last) {
2429                     break;
2430                 }
2431 
2432                 msg = f->pos;
2433 
2434                 if (f->pos + f->length <= f->last) {
2435                     f->pos += f->length;
2436                     f->length = 0;
2437                     f->state = ngx_http_fastcgi_st_padding;
2438 
2439                 } else {
2440                     f->length -= f->last - f->pos;
2441                     f->pos = f->last;
2442                 }
2443 
2444                 for (m = f->pos - 1; msg < m; m--) {
2445                     if (*m != LF && *m != CR && *m != '.' && *m != ' ') {
2446                         break;
2447                     }
2448                 }
2449 
2450                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2451                               "FastCGI sent in stderr: \"%*s\"",
2452                               m + 1 - msg, msg);
2453 
2454             } else {
2455                 f->state = ngx_http_fastcgi_st_padding;
2456             }
2457 
2458             continue;
2459         }
2460 
2461         if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
2462 
2463             if (f->pos + f->length <= f->last) {
2464                 f->state = ngx_http_fastcgi_st_padding;
2465                 f->pos += f->length;
2466 
2467                 continue;
2468             }
2469 
2470             f->length -= f->last - f->pos;
2471 
2472             break;
2473         }
2474 
2475 
2476         /* f->type == NGX_HTTP_FASTCGI_STDOUT */
2477 
2478         if (f->pos == f->last) {
2479             break;
2480         }
2481 
2482         cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
2483         if (cl == NULL) {
2484             return NGX_ERROR;
2485         }
2486 
2487         *ll = cl;
2488         ll = &cl->next;
2489 
2490         b = cl->buf;
2491 
2492         b->flush = 1;
2493         b->memory = 1;
2494 
2495         b->pos = f->pos;
2496         b->tag = u->output.tag;
2497 
2498         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2499                        "http fastcgi output buf %p", b->pos);
2500 
2501         if (f->pos + f->length <= f->last) {
2502             f->state = ngx_http_fastcgi_st_padding;
2503             f->pos += f->length;
2504             b->last = f->pos;
2505 
2506             continue;
2507         }
2508 
2509         f->length -= f->last - f->pos;
2510         b->last = f->last;
2511 
2512         break;
2513     }
2514 
2515     return NGX_OK;
2516 }
2517 
2518 
2519 static ngx_int_t
2520 ngx_http_fastcgi_process_record(ngx_http_request_t *r,
2521     ngx_http_fastcgi_ctx_t *f)
2522 {
2523     u_char                     ch, *p;
2524     ngx_http_fastcgi_state_e   state;
2525 
2526     state = f->state;
2527 
2528     for (p = f->pos; p < f->last; p++) {
2529 
2530         ch = *p;
2531 
2532         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2533                        "http fastcgi record byte: %02Xd", ch);
2534 
2535         switch (state) {
2536 
2537         case ngx_http_fastcgi_st_version:
2538             if (ch != 1) {
2539                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2540                               "upstream sent unsupported FastCGI "
2541                               "protocol version: %d", ch);
2542                 return NGX_ERROR;
2543             }
2544             state = ngx_http_fastcgi_st_type;
2545             break;
2546 
2547         case ngx_http_fastcgi_st_type:
2548             switch (ch) {
2549             case NGX_HTTP_FASTCGI_STDOUT:
2550             case NGX_HTTP_FASTCGI_STDERR:
2551             case NGX_HTTP_FASTCGI_END_REQUEST:
2552                 f->type = (ngx_uint_t) ch;
2553                 break;
2554             default:
2555                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2556                               "upstream sent invalid FastCGI "
2557                               "record type: %d", ch);
2558                 return NGX_ERROR;
2559 
2560             }
2561             state = ngx_http_fastcgi_st_request_id_hi;
2562             break;
2563 
2564         /* we support the single request per connection */
2565 
2566         case ngx_http_fastcgi_st_request_id_hi:
2567             if (ch != 0) {
2568                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2569                               "upstream sent unexpected FastCGI "
2570                               "request id high byte: %d", ch);
2571                 return NGX_ERROR;
2572             }
2573             state = ngx_http_fastcgi_st_request_id_lo;
2574             break;
2575 
2576         case ngx_http_fastcgi_st_request_id_lo:
2577             if (ch != 1) {
2578                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2579                               "upstream sent unexpected FastCGI "
2580                               "request id low byte: %d", ch);
2581                 return NGX_ERROR;
2582             }
2583             state = ngx_http_fastcgi_st_content_length_hi;
2584             break;
2585 
2586         case ngx_http_fastcgi_st_content_length_hi:
2587             f->length = ch << 8;
2588             state = ngx_http_fastcgi_st_content_length_lo;
2589             break;
2590 
2591         case ngx_http_fastcgi_st_content_length_lo:
2592             f->length |= (size_t) ch;
2593             state = ngx_http_fastcgi_st_padding_length;
2594             break;
2595 
2596         case ngx_http_fastcgi_st_padding_length:
2597             f->padding = (size_t) ch;
2598             state = ngx_http_fastcgi_st_reserved;
2599             break;
2600 
2601         case ngx_http_fastcgi_st_reserved:
2602             state = ngx_http_fastcgi_st_data;
2603 
2604             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2605                            "http fastcgi record length: %z", f->length);
2606 
2607             f->pos = p + 1;
2608             f->state = state;
2609 
2610             return NGX_OK;
2611 
2612         /* suppress warning */
2613         case ngx_http_fastcgi_st_data:
2614         case ngx_http_fastcgi_st_padding:
2615             break;
2616         }
2617     }
2618 
2619     f->pos = p;
2620     f->state = state;
2621 
2622     return NGX_AGAIN;
2623 }
2624 
2625 
2626 static void
2627 ngx_http_fastcgi_abort_request(ngx_http_request_t *r)
2628 {
2629     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2630                    "abort http fastcgi request");
2631 
2632     return;
2633 }
2634 
2635 
2636 static void
2637 ngx_http_fastcgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
2638 {
2639     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2640                    "finalize http fastcgi request");
2641 
2642     return;
2643 }
2644 
2645 
2646 static ngx_int_t
2647 ngx_http_fastcgi_add_variables(ngx_conf_t *cf)
2648 {
2649     ngx_http_variable_t  *var, *v;
2650 
2651     for (v = ngx_http_fastcgi_vars; v->name.len; v++) {
2652         var = ngx_http_add_variable(cf, &v->name, v->flags);
2653         if (var == NULL) {
2654             return NGX_ERROR;
2655         }
2656 
2657         var->get_handler = v->get_handler;
2658         var->data = v->data;
2659     }
2660 
2661     return NGX_OK;
2662 }
2663 
2664 
2665 static void *
2666 ngx_http_fastcgi_create_main_conf(ngx_conf_t *cf)
2667 {
2668     ngx_http_fastcgi_main_conf_t  *conf;
2669 
2670     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_main_conf_t));
2671     if (conf == NULL) {
2672         return NULL;
2673     }
2674 
2675 #if (NGX_HTTP_CACHE)
2676     if (ngx_array_init(&conf->caches, cf->pool, 4,
2677                        sizeof(ngx_http_file_cache_t *))
2678         != NGX_OK)
2679     {
2680         return NULL;
2681     }
2682 #endif
2683 
2684     return conf;
2685 }
2686 
2687 
2688 static void *
2689 ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
2690 {
2691     ngx_http_fastcgi_loc_conf_t  *conf;
2692 
2693     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_loc_conf_t));
2694     if (conf == NULL) {
2695         return NULL;
2696     }
2697 
2698     /*
2699      * set by ngx_pcalloc():
2700      *
2701      *     conf->upstream.bufs.num = 0;
2702      *     conf->upstream.ignore_headers = 0;
2703      *     conf->upstream.next_upstream = 0;
2704      *     conf->upstream.cache_zone = NULL;
2705      *     conf->upstream.cache_use_stale = 0;
2706      *     conf->upstream.cache_methods = 0;
2707      *     conf->upstream.temp_path = NULL;
2708      *     conf->upstream.hide_headers_hash = { NULL, 0 };
2709      *     conf->upstream.store_lengths = NULL;
2710      *     conf->upstream.store_values = NULL;
2711      *
2712      *     conf->index.len = { 0, NULL };
2713      */
2714 
2715     conf->upstream.store = NGX_CONF_UNSET;
2716     conf->upstream.store_access = NGX_CONF_UNSET_UINT;
2717     conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
2718     conf->upstream.buffering = NGX_CONF_UNSET;
2719     conf->upstream.request_buffering = NGX_CONF_UNSET;
2720     conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
2721     conf->upstream.force_ranges = NGX_CONF_UNSET;
2722 
2723     conf->upstream.local = NGX_CONF_UNSET_PTR;
2724 
2725     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
2726     conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
2727     conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
2728     conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC;
2729 
2730     conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
2731     conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
2732     conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE;
2733 
2734     conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
2735     conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
2736     conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;
2737 
2738     conf->upstream.pass_request_headers = NGX_CONF_UNSET;
2739     conf->upstream.pass_request_body = NGX_CONF_UNSET;
2740 
2741 #if (NGX_HTTP_CACHE)
2742     conf->upstream.cache = NGX_CONF_UNSET;
2743     conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
2744     conf->upstream.cache_max_range_offset = NGX_CONF_UNSET;
2745     conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
2746     conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
2747     conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
2748     conf->upstream.cache_lock = NGX_CONF_UNSET;
2749     conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
2750     conf->upstream.cache_lock_age = NGX_CONF_UNSET_MSEC;
2751     conf->upstream.cache_revalidate = NGX_CONF_UNSET;
2752     conf->upstream.cache_background_update = NGX_CONF_UNSET;
2753 #endif
2754 
2755     conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
2756     conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
2757 
2758     conf->upstream.intercept_errors = NGX_CONF_UNSET;
2759 
2760     /* "fastcgi_cyclic_temp_file" is disabled */
2761     conf->upstream.cyclic_temp_file = 0;
2762 
2763     conf->upstream.change_buffering = 1;
2764 
2765     conf->catch_stderr = NGX_CONF_UNSET_PTR;
2766 
2767     conf->keep_conn = NGX_CONF_UNSET;
2768 
2769     ngx_str_set(&conf->upstream.module, "fastcgi");
2770 
2771     return conf;
2772 }
2773 
2774 
2775 static char *
2776 ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
2777 {
2778     ngx_http_fastcgi_loc_conf_t *prev = parent;
2779     ngx_http_fastcgi_loc_conf_t *conf = child;
2780 
2781     size_t                        size;
2782     ngx_int_t                     rc;
2783     ngx_hash_init_t               hash;
2784     ngx_http_core_loc_conf_t     *clcf;
2785 
2786 #if (NGX_HTTP_CACHE)
2787 
2788     if (conf->upstream.store > 0) {
2789         conf->upstream.cache = 0;
2790     }
2791 
2792     if (conf->upstream.cache > 0) {
2793         conf->upstream.store = 0;
2794     }
2795 
2796 #endif
2797 
2798     if (conf->upstream.store == NGX_CONF_UNSET) {
2799         ngx_conf_merge_value(conf->upstream.store,
2800                               prev->upstream.store, 0);
2801 
2802         conf->upstream.store_lengths = prev->upstream.store_lengths;
2803         conf->upstream.store_values = prev->upstream.store_values;
2804     }
2805 
2806     ngx_conf_merge_uint_value(conf->upstream.store_access,
2807                               prev->upstream.store_access, 0600);
2808 
2809     ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
2810                               prev->upstream.next_upstream_tries, 0);
2811 
2812     ngx_conf_merge_value(conf->upstream.buffering,
2813                               prev->upstream.buffering, 1);
2814 
2815     ngx_conf_merge_value(conf->upstream.request_buffering,
2816                               prev->upstream.request_buffering, 1);
2817 
2818     ngx_conf_merge_value(conf->upstream.ignore_client_abort,
2819                               prev->upstream.ignore_client_abort, 0);
2820 
2821     ngx_conf_merge_value(conf->upstream.force_ranges,
2822                               prev->upstream.force_ranges, 0);
2823 
2824     ngx_conf_merge_ptr_value(conf->upstream.local,
2825                               prev->upstream.local, NULL);
2826 
2827     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
2828                               prev->upstream.connect_timeout, 60000);
2829 
2830     ngx_conf_merge_msec_value(conf->upstream.send_timeout,
2831                               prev->upstream.send_timeout, 60000);
2832 
2833     ngx_conf_merge_msec_value(conf->upstream.read_timeout,
2834                               prev->upstream.read_timeout, 60000);
2835 
2836     ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
2837                               prev->upstream.next_upstream_timeout, 0);
2838 
2839     ngx_conf_merge_size_value(conf->upstream.send_lowat,
2840                               prev->upstream.send_lowat, 0);
2841 
2842     ngx_conf_merge_size_value(conf->upstream.buffer_size,
2843                               prev->upstream.buffer_size,
2844                               (size_t) ngx_pagesize);
2845 
2846     ngx_conf_merge_size_value(conf->upstream.limit_rate,
2847                               prev->upstream.limit_rate, 0);
2848 
2849 
2850     ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
2851                               8, ngx_pagesize);
2852 
2853     if (conf->upstream.bufs.num < 2) {
2854         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2855                            "there must be at least 2 \"fastcgi_buffers\"");
2856         return NGX_CONF_ERROR;
2857     }
2858 
2859 
2860     size = conf->upstream.buffer_size;
2861     if (size < conf->upstream.bufs.size) {
2862         size = conf->upstream.bufs.size;
2863     }
2864 
2865 
2866     ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
2867                               prev->upstream.busy_buffers_size_conf,
2868                               NGX_CONF_UNSET_SIZE);
2869 
2870     if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
2871         conf->upstream.busy_buffers_size = 2 * size;
2872     } else {
2873         conf->upstream.busy_buffers_size =
2874                                          conf->upstream.busy_buffers_size_conf;
2875     }
2876 
2877     if (conf->upstream.busy_buffers_size < size) {
2878         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2879              "\"fastcgi_busy_buffers_size\" must be equal to or greater than "
2880              "the maximum of the value of \"fastcgi_buffer_size\" and "
2881              "one of the \"fastcgi_buffers\"");
2882 
2883         return NGX_CONF_ERROR;
2884     }
2885 
2886     if (conf->upstream.busy_buffers_size
2887         > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
2888     {
2889         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2890              "\"fastcgi_busy_buffers_size\" must be less than "
2891              "the size of all \"fastcgi_buffers\" minus one buffer");
2892 
2893         return NGX_CONF_ERROR;
2894     }
2895 
2896 
2897     ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf,
2898                               prev->upstream.temp_file_write_size_conf,
2899                               NGX_CONF_UNSET_SIZE);
2900 
2901     if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
2902         conf->upstream.temp_file_write_size = 2 * size;
2903     } else {
2904         conf->upstream.temp_file_write_size =
2905                                       conf->upstream.temp_file_write_size_conf;
2906     }
2907 
2908     if (conf->upstream.temp_file_write_size < size) {
2909         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2910              "\"fastcgi_temp_file_write_size\" must be equal to or greater "
2911              "than the maximum of the value of \"fastcgi_buffer_size\" and "
2912              "one of the \"fastcgi_buffers\"");
2913 
2914         return NGX_CONF_ERROR;
2915     }
2916 
2917 
2918     ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf,
2919                               prev->upstream.max_temp_file_size_conf,
2920                               NGX_CONF_UNSET_SIZE);
2921 
2922     if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
2923         conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
2924     } else {
2925         conf->upstream.max_temp_file_size =
2926                                         conf->upstream.max_temp_file_size_conf;
2927     }
2928 
2929     if (conf->upstream.max_temp_file_size != 0
2930         && conf->upstream.max_temp_file_size < size)
2931     {
2932         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2933              "\"fastcgi_max_temp_file_size\" must be equal to zero to disable "
2934              "temporary files usage or must be equal to or greater than "
2935              "the maximum of the value of \"fastcgi_buffer_size\" and "
2936              "one of the \"fastcgi_buffers\"");
2937 
2938         return NGX_CONF_ERROR;
2939     }
2940 
2941 
2942     ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
2943                               prev->upstream.ignore_headers,
2944                               NGX_CONF_BITMASK_SET);
2945 
2946 
2947     ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
2948                               prev->upstream.next_upstream,
2949                               (NGX_CONF_BITMASK_SET
2950                                |NGX_HTTP_UPSTREAM_FT_ERROR
2951                                |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
2952 
2953     if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
2954         conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
2955                                        |NGX_HTTP_UPSTREAM_FT_OFF;
2956     }
2957 
2958     if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
2959                               prev->upstream.temp_path,
2960                               &ngx_http_fastcgi_temp_path)
2961         != NGX_OK)
2962     {
2963         return NGX_CONF_ERROR;
2964     }
2965 
2966 #if (NGX_HTTP_CACHE)
2967 
2968     if (conf->upstream.cache == NGX_CONF_UNSET) {
2969         ngx_conf_merge_value(conf->upstream.cache,
2970                               prev->upstream.cache, 0);
2971 
2972         conf->upstream.cache_zone = prev->upstream.cache_zone;
2973         conf->upstream.cache_value = prev->upstream.cache_value;
2974     }
2975 
2976     if (conf->upstream.cache_zone && conf->upstream.cache_zone->data == NULL) {
2977         ngx_shm_zone_t  *shm_zone;
2978 
2979         shm_zone = conf->upstream.cache_zone;
2980 
2981         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2982                            "\"fastcgi_cache\" zone \"%V\" is unknown",
2983                            &shm_zone->shm.name);
2984 
2985         return NGX_CONF_ERROR;
2986     }
2987 
2988     ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
2989                               prev->upstream.cache_min_uses, 1);
2990 
2991     ngx_conf_merge_off_value(conf->upstream.cache_max_range_offset,
2992                               prev->upstream.cache_max_range_offset,
2993                               NGX_MAX_OFF_T_VALUE);
2994 
2995     ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
2996                               prev->upstream.cache_use_stale,
2997                               (NGX_CONF_BITMASK_SET
2998                                |NGX_HTTP_UPSTREAM_FT_OFF));
2999 
3000     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
3001         conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
3002                                          |NGX_HTTP_UPSTREAM_FT_OFF;
3003     }
3004 
3005     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
3006         conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
3007     }
3008 
3009     if (conf->upstream.cache_methods == 0) {
3010         conf->upstream.cache_methods = prev->upstream.cache_methods;
3011     }
3012 
3013     conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD;
3014 
3015     ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
3016                              prev->upstream.cache_bypass, NULL);
3017 
3018     ngx_conf_merge_ptr_value(conf->upstream.no_cache,
3019                              prev->upstream.no_cache, NULL);
3020 
3021     ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
3022                              prev->upstream.cache_valid, NULL);
3023 
3024     if (conf->cache_key.value.data == NULL) {
3025         conf->cache_key = prev->cache_key;
3026     }
3027 
3028     if (conf->upstream.cache && conf->cache_key.value.data == NULL) {
3029         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
3030                            "no \"fastcgi_cache_key\" for \"fastcgi_cache\"");
3031     }
3032 
3033     ngx_conf_merge_value(conf->upstream.cache_lock,
3034                               prev->upstream.cache_lock, 0);
3035 
3036     ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
3037                               prev->upstream.cache_lock_timeout, 5000);
3038 
3039     ngx_conf_merge_msec_value(conf->upstream.cache_lock_age,
3040                               prev->upstream.cache_lock_age, 5000);
3041 
3042     ngx_conf_merge_value(conf->upstream.cache_revalidate,
3043                               prev->upstream.cache_revalidate, 0);
3044 
3045     ngx_conf_merge_value(conf->upstream.cache_background_update,
3046                               prev->upstream.cache_background_update, 0);
3047 
3048 #endif
3049 
3050     ngx_conf_merge_value(conf->upstream.pass_request_headers,
3051                               prev->upstream.pass_request_headers, 1);
3052     ngx_conf_merge_value(conf->upstream.pass_request_body,
3053                               prev->upstream.pass_request_body, 1);
3054 
3055     ngx_conf_merge_value(conf->upstream.intercept_errors,
3056                               prev->upstream.intercept_errors, 0);
3057 
3058     ngx_conf_merge_ptr_value(conf->catch_stderr, prev->catch_stderr, NULL);
3059 
3060     ngx_conf_merge_value(conf->keep_conn, prev->keep_conn, 0);
3061 
3062 
3063     ngx_conf_merge_str_value(conf->index, prev->index, "");
3064 
3065     hash.max_size = 512;
3066     hash.bucket_size = ngx_align(64, ngx_cacheline_size);
3067     hash.name = "fastcgi_hide_headers_hash";
3068 
3069     if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
3070              &prev->upstream, ngx_http_fastcgi_hide_headers, &hash)
3071         != NGX_OK)
3072     {
3073         return NGX_CONF_ERROR;
3074     }
3075 
3076     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
3077 
3078     if (clcf->noname
3079         && conf->upstream.upstream == NULL && conf->fastcgi_lengths == NULL)
3080     {
3081         conf->upstream.upstream = prev->upstream.upstream;
3082         conf->fastcgi_lengths = prev->fastcgi_lengths;
3083         conf->fastcgi_values = prev->fastcgi_values;
3084     }
3085 
3086     if (clcf->lmt_excpt && clcf->handler == NULL
3087         && (conf->upstream.upstream || conf->fastcgi_lengths))
3088     {
3089         clcf->handler = ngx_http_fastcgi_handler;
3090     }
3091 
3092 #if (NGX_PCRE)
3093     if (conf->split_regex == NULL) {
3094         conf->split_regex = prev->split_regex;
3095         conf->split_name = prev->split_name;
3096     }
3097 #endif
3098 
3099     if (conf->params_source == NULL) {
3100         conf->params = prev->params;
3101 #if (NGX_HTTP_CACHE)
3102         conf->params_cache = prev->params_cache;
3103 #endif
3104         conf->params_source = prev->params_source;
3105     }
3106 
3107     rc = ngx_http_fastcgi_init_params(cf, conf, &conf->params, NULL);
3108     if (rc != NGX_OK) {
3109         return NGX_CONF_ERROR;
3110     }
3111 
3112 #if (NGX_HTTP_CACHE)
3113 
3114     if (conf->upstream.cache) {
3115         rc = ngx_http_fastcgi_init_params(cf, conf, &conf->params_cache,
3116                                           ngx_http_fastcgi_cache_headers);
3117         if (rc != NGX_OK) {
3118             return NGX_CONF_ERROR;
3119         }
3120     }
3121 
3122 #endif
3123 
3124     /*
3125      * special handling to preserve conf->params in the "http" section
3126      * to inherit it to all servers
3127      */
3128 
3129     if (prev->params.hash.buckets == NULL
3130         && conf->params_source == prev->params_source)
3131     {
3132         prev->params = conf->params;
3133 #if (NGX_HTTP_CACHE)
3134         prev->params_cache = conf->params_cache;
3135 #endif
3136     }
3137 
3138     return NGX_CONF_OK;
3139 }
3140 
3141 
3142 static ngx_int_t
3143 ngx_http_fastcgi_init_params(ngx_conf_t *cf, ngx_http_fastcgi_loc_conf_t *conf,
3144     ngx_http_fastcgi_params_t *params, ngx_keyval_t *default_params)
3145 {
3146     u_char                       *p;
3147     size_t                        size;
3148     uintptr_t                    *code;
3149     ngx_uint_t                    i, nsrc;
3150     ngx_array_t                   headers_names, params_merged;
3151     ngx_keyval_t                 *h;
3152     ngx_hash_key_t               *hk;
3153     ngx_hash_init_t               hash;
3154     ngx_http_upstream_param_t    *src, *s;
3155     ngx_http_script_compile_t     sc;
3156     ngx_http_script_copy_code_t  *copy;
3157 
3158     if (params->hash.buckets) {
3159         return NGX_OK;
3160     }
3161 
3162     if (conf->params_source == NULL && default_params == NULL) {
3163         params->hash.buckets = (void *) 1;
3164         return NGX_OK;
3165     }
3166 
3167     params->lengths = ngx_array_create(cf->pool, 64, 1);
3168     if (params->lengths == NULL) {
3169         return NGX_ERROR;
3170     }
3171 
3172     params->values = ngx_array_create(cf->pool, 512, 1);
3173     if (params->values == NULL) {
3174         return NGX_ERROR;
3175     }
3176 
3177     if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
3178         != NGX_OK)
3179     {
3180         return NGX_ERROR;
3181     }
3182 
3183     if (conf->params_source) {
3184         src = conf->params_source->elts;
3185         nsrc = conf->params_source->nelts;
3186 
3187     } else {
3188         src = NULL;
3189         nsrc = 0;
3190     }
3191 
3192     if (default_params) {
3193         if (ngx_array_init(&params_merged, cf->temp_pool, 4,
3194                            sizeof(ngx_http_upstream_param_t))
3195             != NGX_OK)
3196         {
3197             return NGX_ERROR;
3198         }
3199 
3200         for (i = 0; i < nsrc; i++) {
3201 
3202             s = ngx_array_push(&params_merged);
3203             if (s == NULL) {
3204                 return NGX_ERROR;
3205             }
3206 
3207             *s = src[i];
3208         }
3209 
3210         h = default_params;
3211 
3212         while (h->key.len) {
3213 
3214             src = params_merged.elts;
3215             nsrc = params_merged.nelts;
3216 
3217             for (i = 0; i < nsrc; i++) {
3218                 if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
3219                     goto next;
3220                 }
3221             }
3222 
3223             s = ngx_array_push(&params_merged);
3224             if (s == NULL) {
3225                 return NGX_ERROR;
3226             }
3227 
3228             s->key = h->key;
3229             s->value = h->value;
3230             s->skip_empty = 1;
3231 
3232         next:
3233 
3234             h++;
3235         }
3236 
3237         src = params_merged.elts;
3238         nsrc = params_merged.nelts;
3239     }
3240 
3241     for (i = 0; i < nsrc; i++) {
3242 
3243         if (src[i].key.len > sizeof("HTTP_") - 1
3244             && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0)
3245         {
3246             hk = ngx_array_push(&headers_names);
3247             if (hk == NULL) {
3248                 return NGX_ERROR;
3249             }
3250 
3251             hk->key.len = src[i].key.len - 5;
3252             hk->key.data = src[i].key.data + 5;
3253             hk->key_hash = ngx_hash_key_lc(hk->key.data, hk->key.len);
3254             hk->value = (void *) 1;
3255 
3256             if (src[i].value.len == 0) {
3257                 continue;
3258             }
3259         }
3260 
3261         copy = ngx_array_push_n(params->lengths,
3262                                 sizeof(ngx_http_script_copy_code_t));
3263         if (copy == NULL) {
3264             return NGX_ERROR;
3265         }
3266 
3267         copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
3268         copy->len = src[i].key.len;
3269 
3270         copy = ngx_array_push_n(params->lengths,
3271                                 sizeof(ngx_http_script_copy_code_t));
3272         if (copy == NULL) {
3273             return NGX_ERROR;
3274         }
3275 
3276         copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
3277         copy->len = src[i].skip_empty;
3278 
3279 
3280         size = (sizeof(ngx_http_script_copy_code_t)
3281                 + src[i].key.len + sizeof(uintptr_t) - 1)
3282                & ~(sizeof(uintptr_t) - 1);
3283 
3284         copy = ngx_array_push_n(params->values, size);
3285         if (copy == NULL) {
3286             return NGX_ERROR;
3287         }
3288 
3289         copy->code = ngx_http_script_copy_code;
3290         copy->len = src[i].key.len;
3291 
3292         p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
3293         ngx_memcpy(p, src[i].key.data, src[i].key.len);
3294 
3295 
3296         ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3297 
3298         sc.cf = cf;
3299         sc.source = &src[i].value;
3300         sc.flushes = &params->flushes;
3301         sc.lengths = &params->lengths;
3302         sc.values = &params->values;
3303 
3304         if (ngx_http_script_compile(&sc) != NGX_OK) {
3305             return NGX_ERROR;
3306         }
3307 
3308         code = ngx_array_push_n(params->lengths, sizeof(uintptr_t));
3309         if (code == NULL) {
3310             return NGX_ERROR;
3311         }
3312 
3313         *code = (uintptr_t) NULL;
3314 
3315 
3316         code = ngx_array_push_n(params->values, sizeof(uintptr_t));
3317         if (code == NULL) {
3318             return NGX_ERROR;
3319         }
3320 
3321         *code = (uintptr_t) NULL;
3322     }
3323 
3324     code = ngx_array_push_n(params->lengths, sizeof(uintptr_t));
3325     if (code == NULL) {
3326         return NGX_ERROR;
3327     }
3328 
3329     *code = (uintptr_t) NULL;
3330 
3331     params->number = headers_names.nelts;
3332 
3333     hash.hash = &params->hash;
3334     hash.key = ngx_hash_key_lc;
3335     hash.max_size = 512;
3336     hash.bucket_size = 64;
3337     hash.name = "fastcgi_params_hash";
3338     hash.pool = cf->pool;
3339     hash.temp_pool = NULL;
3340 
3341     return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
3342 }
3343 
3344 
3345 static ngx_int_t
3346 ngx_http_fastcgi_script_name_variable(ngx_http_request_t *r,
3347     ngx_http_variable_value_t *v, uintptr_t data)
3348 {
3349     u_char                       *p;
3350     ngx_http_fastcgi_ctx_t       *f;
3351     ngx_http_fastcgi_loc_conf_t  *flcf;
3352 
3353     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
3354 
3355     f = ngx_http_fastcgi_split(r, flcf);
3356 
3357     if (f == NULL) {
3358         return NGX_ERROR;
3359     }
3360 
3361     if (f->script_name.len == 0
3362         || f->script_name.data[f->script_name.len - 1] != '/')
3363     {
3364         v->len = f->script_name.len;
3365         v->valid = 1;
3366         v->no_cacheable = 0;
3367         v->not_found = 0;
3368         v->data = f->script_name.data;
3369 
3370         return NGX_OK;
3371     }
3372 
3373     v->len = f->script_name.len + flcf->index.len;
3374 
3375     v->data = ngx_pnalloc(r->pool, v->len);
3376     if (v->data == NULL) {
3377         return NGX_ERROR;
3378     }
3379 
3380     p = ngx_copy(v->data, f->script_name.data, f->script_name.len);
3381     ngx_memcpy(p, flcf->index.data, flcf->index.len);
3382 
3383     return NGX_OK;
3384 }
3385 
3386 
3387 static ngx_int_t
3388 ngx_http_fastcgi_path_info_variable(ngx_http_request_t *r,
3389     ngx_http_variable_value_t *v, uintptr_t data)
3390 {
3391     ngx_http_fastcgi_ctx_t       *f;
3392     ngx_http_fastcgi_loc_conf_t  *flcf;
3393 
3394     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
3395 
3396     f = ngx_http_fastcgi_split(r, flcf);
3397 
3398     if (f == NULL) {
3399         return NGX_ERROR;
3400     }
3401 
3402     v->len = f->path_info.len;
3403     v->valid = 1;
3404     v->no_cacheable = 0;
3405     v->not_found = 0;
3406     v->data = f->path_info.data;
3407 
3408     return NGX_OK;
3409 }
3410 
3411 
3412 static ngx_http_fastcgi_ctx_t *
3413 ngx_http_fastcgi_split(ngx_http_request_t *r, ngx_http_fastcgi_loc_conf_t *flcf)
3414 {
3415     ngx_http_fastcgi_ctx_t       *f;
3416 #if (NGX_PCRE)
3417     ngx_int_t                     n;
3418     int                           captures[(1 + 2) * 3];
3419 
3420     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
3421 
3422     if (f == NULL) {
3423         f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
3424         if (f == NULL) {
3425             return NULL;
3426         }
3427 
3428         ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
3429     }
3430 
3431     if (f->script_name.len) {
3432         return f;
3433     }
3434 
3435     if (flcf->split_regex == NULL) {
3436         f->script_name = r->uri;
3437         return f;
3438     }
3439 
3440     n = ngx_regex_exec(flcf->split_regex, &r->uri, captures, (1 + 2) * 3);
3441 
3442     if (n >= 0) { /* match */
3443         f->script_name.len = captures[3] - captures[2];
3444         f->script_name.data = r->uri.data + captures[2];
3445 
3446         f->path_info.len = captures[5] - captures[4];
3447         f->path_info.data = r->uri.data + captures[4];
3448 
3449         return f;
3450     }
3451 
3452     if (n == NGX_REGEX_NO_MATCHED) {
3453         f->script_name = r->uri;
3454         return f;
3455     }
3456 
3457     ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
3458                   ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"",
3459                   n, &r->uri, &flcf->split_name);
3460     return NULL;
3461 
3462 #else
3463 
3464     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
3465 
3466     if (f == NULL) {
3467         f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
3468         if (f == NULL) {
3469             return NULL;
3470         }
3471 
3472         ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
3473     }
3474 
3475     f->script_name = r->uri;
3476 
3477     return f;
3478 
3479 #endif
3480 }
3481 
3482 
3483 static char *
3484 ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3485 {
3486     ngx_http_fastcgi_loc_conf_t *flcf = conf;
3487 
3488     ngx_url_t                   u;
3489     ngx_str_t                  *value, *url;
3490     ngx_uint_t                  n;
3491     ngx_http_core_loc_conf_t   *clcf;
3492     ngx_http_script_compile_t   sc;
3493 
3494     if (flcf->upstream.upstream || flcf->fastcgi_lengths) {
3495         return "is duplicate";
3496     }
3497 
3498     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
3499 
3500     clcf->handler = ngx_http_fastcgi_handler;
3501 
3502     if (clcf->name.data[clcf->name.len - 1] == '/') {
3503         clcf->auto_redirect = 1;
3504     }
3505 
3506     value = cf->args->elts;
3507 
3508     url = &value[1];
3509 
3510     n = ngx_http_script_variables_count(url);
3511 
3512     if (n) {
3513 
3514         ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3515 
3516         sc.cf = cf;
3517         sc.source = url;
3518         sc.lengths = &flcf->fastcgi_lengths;
3519         sc.values = &flcf->fastcgi_values;
3520         sc.variables = n;
3521         sc.complete_lengths = 1;
3522         sc.complete_values = 1;
3523 
3524         if (ngx_http_script_compile(&sc) != NGX_OK) {
3525             return NGX_CONF_ERROR;
3526         }
3527 
3528         return NGX_CONF_OK;
3529     }
3530 
3531     ngx_memzero(&u, sizeof(ngx_url_t));
3532 
3533     u.url = value[1];
3534     u.no_resolve = 1;
3535 
3536     flcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
3537     if (flcf->upstream.upstream == NULL) {
3538         return NGX_CONF_ERROR;
3539     }
3540 
3541     return NGX_CONF_OK;
3542 }
3543 
3544 
3545 static char *
3546 ngx_http_fastcgi_split_path_info(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3547 {
3548 #if (NGX_PCRE)
3549     ngx_http_fastcgi_loc_conf_t *flcf = conf;
3550 
3551     ngx_str_t            *value;
3552     ngx_regex_compile_t   rc;
3553     u_char                errstr[NGX_MAX_CONF_ERRSTR];
3554 
3555     value = cf->args->elts;
3556 
3557     flcf->split_name = value[1];
3558 
3559     ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
3560 
3561     rc.pattern = value[1];
3562     rc.pool = cf->pool;
3563     rc.err.len = NGX_MAX_CONF_ERRSTR;
3564     rc.err.data = errstr;
3565 
3566     if (ngx_regex_compile(&rc) != NGX_OK) {
3567         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err);
3568         return NGX_CONF_ERROR;
3569     }
3570 
3571     if (rc.captures != 2) {
3572         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3573                            "pattern \"%V\" must have 2 captures", &value[1]);
3574         return NGX_CONF_ERROR;
3575     }
3576 
3577     flcf->split_regex = rc.regex;
3578 
3579     return NGX_CONF_OK;
3580 
3581 #else
3582 
3583     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3584                        "\"%V\" requires PCRE library", &cmd->name);
3585     return NGX_CONF_ERROR;
3586 
3587 #endif
3588 }
3589 
3590 
3591 static char *
3592 ngx_http_fastcgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3593 {
3594     ngx_http_fastcgi_loc_conf_t *flcf = conf;
3595 
3596     ngx_str_t                  *value;
3597     ngx_http_script_compile_t   sc;
3598 
3599     if (flcf->upstream.store != NGX_CONF_UNSET) {
3600         return "is duplicate";
3601     }
3602 
3603     value = cf->args->elts;
3604 
3605     if (ngx_strcmp(value[1].data, "off") == 0) {
3606         flcf->upstream.store = 0;
3607         return NGX_CONF_OK;
3608     }
3609 
3610 #if (NGX_HTTP_CACHE)
3611     if (flcf->upstream.cache > 0) {
3612         return "is incompatible with \"fastcgi_cache\"";
3613     }
3614 #endif
3615 
3616     flcf->upstream.store = 1;
3617 
3618     if (ngx_strcmp(value[1].data, "on") == 0) {
3619         return NGX_CONF_OK;
3620     }
3621 
3622     /* include the terminating '\0' into script */
3623     value[1].len++;
3624 
3625     ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3626 
3627     sc.cf = cf;
3628     sc.source = &value[1];
3629     sc.lengths = &flcf->upstream.store_lengths;
3630     sc.values = &flcf->upstream.store_values;
3631     sc.variables = ngx_http_script_variables_count(&value[1]);
3632     sc.complete_lengths = 1;
3633     sc.complete_values = 1;
3634 
3635     if (ngx_http_script_compile(&sc) != NGX_OK) {
3636         return NGX_CONF_ERROR;
3637     }
3638 
3639     return NGX_CONF_OK;
3640 }
3641 
3642 
3643 #if (NGX_HTTP_CACHE)
3644 
3645 static char *
3646 ngx_http_fastcgi_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3647 {
3648     ngx_http_fastcgi_loc_conf_t *flcf = conf;
3649 
3650     ngx_str_t                         *value;
3651     ngx_http_complex_value_t           cv;
3652     ngx_http_compile_complex_value_t   ccv;
3653 
3654     value = cf->args->elts;
3655 
3656     if (flcf->upstream.cache != NGX_CONF_UNSET) {
3657         return "is duplicate";
3658     }
3659 
3660     if (ngx_strcmp(value[1].data, "off") == 0) {
3661         flcf->upstream.cache = 0;
3662         return NGX_CONF_OK;
3663     }
3664 
3665     if (flcf->upstream.store > 0) {
3666         return "is incompatible with \"fastcgi_store\"";
3667     }
3668 
3669     flcf->upstream.cache = 1;
3670 
3671     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3672 
3673     ccv.cf = cf;
3674     ccv.value = &value[1];
3675     ccv.complex_value = &cv;
3676 
3677     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3678         return NGX_CONF_ERROR;
3679     }
3680 
3681     if (cv.lengths != NULL) {
3682 
3683         flcf->upstream.cache_value = ngx_palloc(cf->pool,
3684                                              sizeof(ngx_http_complex_value_t));
3685         if (flcf->upstream.cache_value == NULL) {
3686             return NGX_CONF_ERROR;
3687         }
3688 
3689         *flcf->upstream.cache_value = cv;
3690 
3691         return NGX_CONF_OK;
3692     }
3693 
3694     flcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0,
3695                                                       &ngx_http_fastcgi_module);
3696     if (flcf->upstream.cache_zone == NULL) {
3697         return NGX_CONF_ERROR;
3698     }
3699 
3700     return NGX_CONF_OK;
3701 }
3702 
3703 
3704 static char *
3705 ngx_http_fastcgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3706 {
3707     ngx_http_fastcgi_loc_conf_t *flcf = conf;
3708 
3709     ngx_str_t                         *value;
3710     ngx_http_compile_complex_value_t   ccv;
3711 
3712     value = cf->args->elts;
3713 
3714     if (flcf->cache_key.value.data) {
3715         return "is duplicate";
3716     }
3717 
3718     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3719 
3720     ccv.cf = cf;
3721     ccv.value = &value[1];
3722     ccv.complex_value = &flcf->cache_key;
3723 
3724     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3725         return NGX_CONF_ERROR;
3726     }
3727 
3728     return NGX_CONF_OK;
3729 }
3730 
3731 #endif
3732 
3733 
3734 static char *
3735 ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post, void *data)
3736 {
3737 #if (NGX_FREEBSD)
3738     ssize_t *np = data;
3739 
3740     if ((u_long) *np >= ngx_freebsd_net_inet_tcp_sendspace) {
3741         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3742                            "\"fastcgi_send_lowat\" must be less than %d "
3743                            "(sysctl net.inet.tcp.sendspace)",
3744                            ngx_freebsd_net_inet_tcp_sendspace);
3745 
3746         return NGX_CONF_ERROR;
3747     }
3748 
3749 #elif !(NGX_HAVE_SO_SNDLOWAT)
3750     ssize_t *np = data;
3751 
3752     ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
3753                        "\"fastcgi_send_lowat\" is not supported, ignored");
3754 
3755     *np = 0;
3756 
3757 #endif
3758 
3759     return NGX_CONF_OK;
3760 }