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_null_string, NULL, NULL, 0, 0, 0 }
0635 };
0636 
0637 
0638 static ngx_str_t  ngx_http_fastcgi_hide_headers[] = {
0639     ngx_string("Status"),
0640     ngx_string("X-Accel-Expires"),
0641     ngx_string("X-Accel-Redirect"),
0642     ngx_string("X-Accel-Limit-Rate"),
0643     ngx_string("X-Accel-Buffering"),
0644     ngx_string("X-Accel-Charset"),
0645     ngx_null_string
0646 };
0647 
0648 
0649 #if (NGX_HTTP_CACHE)
0650 
0651 static ngx_keyval_t  ngx_http_fastcgi_cache_headers[] = {
0652     { ngx_string("HTTP_IF_MODIFIED_SINCE"),
0653       ngx_string("$upstream_cache_last_modified") },
0654     { ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") },
0655     { ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("$upstream_cache_etag") },
0656     { ngx_string("HTTP_IF_MATCH"), ngx_string("") },
0657     { ngx_string("HTTP_RANGE"), ngx_string("") },
0658     { ngx_string("HTTP_IF_RANGE"), ngx_string("") },
0659     { ngx_null_string, ngx_null_string }
0660 };
0661 
0662 #endif
0663 
0664 
0665 static ngx_path_init_t  ngx_http_fastcgi_temp_path = {
0666     ngx_string(NGX_HTTP_FASTCGI_TEMP_PATH), { 1, 2, 0 }
0667 };
0668 
0669 
0670 static ngx_int_t
0671 ngx_http_fastcgi_handler(ngx_http_request_t *r)
0672 {
0673     ngx_int_t                      rc;
0674     ngx_http_upstream_t           *u;
0675     ngx_http_fastcgi_ctx_t        *f;
0676     ngx_http_fastcgi_loc_conf_t   *flcf;
0677 #if (NGX_HTTP_CACHE)
0678     ngx_http_fastcgi_main_conf_t  *fmcf;
0679 #endif
0680 
0681     if (ngx_http_upstream_create(r) != NGX_OK) {
0682         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0683     }
0684 
0685     f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
0686     if (f == NULL) {
0687         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0688     }
0689 
0690     ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
0691 
0692     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
0693 
0694     if (flcf->fastcgi_lengths) {
0695         if (ngx_http_fastcgi_eval(r, flcf) != NGX_OK) {
0696             return NGX_HTTP_INTERNAL_SERVER_ERROR;
0697         }
0698     }
0699 
0700     u = r->upstream;
0701 
0702     ngx_str_set(&u->schema, "fastcgi://");
0703     u->output.tag = (ngx_buf_tag_t) &ngx_http_fastcgi_module;
0704 
0705     u->conf = &flcf->upstream;
0706 
0707 #if (NGX_HTTP_CACHE)
0708     fmcf = ngx_http_get_module_main_conf(r, ngx_http_fastcgi_module);
0709 
0710     u->caches = &fmcf->caches;
0711     u->create_key = ngx_http_fastcgi_create_key;
0712 #endif
0713 
0714     u->create_request = ngx_http_fastcgi_create_request;
0715     u->reinit_request = ngx_http_fastcgi_reinit_request;
0716     u->process_header = ngx_http_fastcgi_process_header;
0717     u->abort_request = ngx_http_fastcgi_abort_request;
0718     u->finalize_request = ngx_http_fastcgi_finalize_request;
0719     r->state = 0;
0720 
0721     u->buffering = flcf->upstream.buffering;
0722 
0723     u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
0724     if (u->pipe == NULL) {
0725         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0726     }
0727 
0728     u->pipe->input_filter = ngx_http_fastcgi_input_filter;
0729     u->pipe->input_ctx = r;
0730 
0731     u->input_filter_init = ngx_http_fastcgi_input_filter_init;
0732     u->input_filter = ngx_http_fastcgi_non_buffered_filter;
0733     u->input_filter_ctx = r;
0734 
0735     if (!flcf->upstream.request_buffering
0736         && flcf->upstream.pass_request_body)
0737     {
0738         r->request_body_no_buffering = 1;
0739     }
0740 
0741     rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
0742 
0743     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
0744         return rc;
0745     }
0746 
0747     return NGX_DONE;
0748 }
0749 
0750 
0751 static ngx_int_t
0752 ngx_http_fastcgi_eval(ngx_http_request_t *r, ngx_http_fastcgi_loc_conf_t *flcf)
0753 {
0754     ngx_url_t             url;
0755     ngx_http_upstream_t  *u;
0756 
0757     ngx_memzero(&url, sizeof(ngx_url_t));
0758 
0759     if (ngx_http_script_run(r, &url.url, flcf->fastcgi_lengths->elts, 0,
0760                             flcf->fastcgi_values->elts)
0761         == NULL)
0762     {
0763         return NGX_ERROR;
0764     }
0765 
0766     url.no_resolve = 1;
0767 
0768     if (ngx_parse_url(r->pool, &url) != NGX_OK) {
0769         if (url.err) {
0770             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
0771                           "%s in upstream \"%V\"", url.err, &url.url);
0772         }
0773 
0774         return NGX_ERROR;
0775     }
0776 
0777     u = r->upstream;
0778 
0779     u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
0780     if (u->resolved == NULL) {
0781         return NGX_ERROR;
0782     }
0783 
0784     if (url.addrs) {
0785         u->resolved->sockaddr = url.addrs[0].sockaddr;
0786         u->resolved->socklen = url.addrs[0].socklen;
0787         u->resolved->name = url.addrs[0].name;
0788         u->resolved->naddrs = 1;
0789     }
0790 
0791     u->resolved->host = url.host;
0792     u->resolved->port = url.port;
0793     u->resolved->no_port = url.no_port;
0794 
0795     return NGX_OK;
0796 }
0797 
0798 
0799 #if (NGX_HTTP_CACHE)
0800 
0801 static ngx_int_t
0802 ngx_http_fastcgi_create_key(ngx_http_request_t *r)
0803 {
0804     ngx_str_t                    *key;
0805     ngx_http_fastcgi_loc_conf_t  *flcf;
0806 
0807     key = ngx_array_push(&r->cache->keys);
0808     if (key == NULL) {
0809         return NGX_ERROR;
0810     }
0811 
0812     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
0813 
0814     if (ngx_http_complex_value(r, &flcf->cache_key, key) != NGX_OK) {
0815         return NGX_ERROR;
0816     }
0817 
0818     return NGX_OK;
0819 }
0820 
0821 #endif
0822 
0823 
0824 static ngx_int_t
0825 ngx_http_fastcgi_create_request(ngx_http_request_t *r)
0826 {
0827     off_t                         file_pos;
0828     u_char                        ch, *pos, *lowcase_key;
0829     size_t                        size, len, key_len, val_len, padding,
0830                                   allocated;
0831     ngx_uint_t                    i, n, next, hash, skip_empty, header_params;
0832     ngx_buf_t                    *b;
0833     ngx_chain_t                  *cl, *body;
0834     ngx_list_part_t              *part;
0835     ngx_table_elt_t              *header, **ignored;
0836     ngx_http_upstream_t          *u;
0837     ngx_http_script_code_pt       code;
0838     ngx_http_script_engine_t      e, le;
0839     ngx_http_fastcgi_header_t    *h;
0840     ngx_http_fastcgi_params_t    *params;
0841     ngx_http_fastcgi_loc_conf_t  *flcf;
0842     ngx_http_script_len_code_pt   lcode;
0843 
0844     len = 0;
0845     header_params = 0;
0846     ignored = NULL;
0847 
0848     u = r->upstream;
0849 
0850     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
0851 
0852 #if (NGX_HTTP_CACHE)
0853     params = u->cacheable ? &flcf->params_cache : &flcf->params;
0854 #else
0855     params = &flcf->params;
0856 #endif
0857 
0858     if (params->lengths) {
0859         ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
0860 
0861         ngx_http_script_flush_no_cacheable_variables(r, params->flushes);
0862         le.flushed = 1;
0863 
0864         le.ip = params->lengths->elts;
0865         le.request = r;
0866 
0867         while (*(uintptr_t *) le.ip) {
0868 
0869             lcode = *(ngx_http_script_len_code_pt *) le.ip;
0870             key_len = lcode(&le);
0871 
0872             lcode = *(ngx_http_script_len_code_pt *) le.ip;
0873             skip_empty = lcode(&le);
0874 
0875             for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
0876                 lcode = *(ngx_http_script_len_code_pt *) le.ip;
0877             }
0878             le.ip += sizeof(uintptr_t);
0879 
0880             if (skip_empty && val_len == 0) {
0881                 continue;
0882             }
0883 
0884             len += 1 + key_len + ((val_len > 127) ? 4 : 1) + val_len;
0885         }
0886     }
0887 
0888     if (flcf->upstream.pass_request_headers) {
0889 
0890         allocated = 0;
0891         lowcase_key = NULL;
0892 
0893         if (params->number) {
0894             n = 0;
0895             part = &r->headers_in.headers.part;
0896 
0897             while (part) {
0898                 n += part->nelts;
0899                 part = part->next;
0900             }
0901 
0902             ignored = ngx_palloc(r->pool, n * sizeof(void *));
0903             if (ignored == NULL) {
0904                 return NGX_ERROR;
0905             }
0906         }
0907 
0908         part = &r->headers_in.headers.part;
0909         header = part->elts;
0910 
0911         for (i = 0; /* 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                         return NGX_ERROR;
1882                     }
1883 
1884                     buf.pos = p;
1885 
1886                     for (i = 0; i < f->split_parts->nelts; i++) {
1887                         p = ngx_cpymem(p, part[i].start,
1888                                        part[i].end - part[i].start);
1889                     }
1890 
1891                     p = ngx_cpymem(p, part_start, u->buffer.pos - part_start);
1892 
1893                     buf.last = p;
1894 
1895                     f->split_parts->nelts = 0;
1896 
1897                     rc = ngx_http_parse_header_line(r, &buf, 1);
1898 
1899                     if (rc != NGX_OK) {
1900                         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
1901                                       "invalid header after joining "
1902                                       "FastCGI records");
1903                         return NGX_ERROR;
1904                     }
1905 
1906                     h->key.len = r->header_name_end - r->header_name_start;
1907                     h->key.data = r->header_name_start;
1908                     h->key.data[h->key.len] = '\0';
1909 
1910                     h->value.len = r->header_end - r->header_start;
1911                     h->value.data = r->header_start;
1912                     h->value.data[h->value.len] = '\0';
1913 
1914                     h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
1915                     if (h->lowcase_key == NULL) {
1916                         return NGX_ERROR;
1917                     }
1918 
1919                 } else {
1920 
1921                     h->key.len = r->header_name_end - r->header_name_start;
1922                     h->value.len = r->header_end - r->header_start;
1923 
1924                     h->key.data = ngx_pnalloc(r->pool,
1925                                               h->key.len + 1 + h->value.len + 1
1926                                               + h->key.len);
1927                     if (h->key.data == NULL) {
1928                         return NGX_ERROR;
1929                     }
1930 
1931                     h->value.data = h->key.data + h->key.len + 1;
1932                     h->lowcase_key = h->key.data + h->key.len + 1
1933                                      + h->value.len + 1;
1934 
1935                     ngx_memcpy(h->key.data, r->header_name_start, h->key.len);
1936                     h->key.data[h->key.len] = '\0';
1937                     ngx_memcpy(h->value.data, r->header_start, h->value.len);
1938                     h->value.data[h->value.len] = '\0';
1939                 }
1940 
1941                 h->hash = r->header_hash;
1942 
1943                 if (h->key.len == r->lowcase_index) {
1944                     ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
1945 
1946                 } else {
1947                     ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
1948                 }
1949 
1950                 hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
1951                                    h->lowcase_key, h->key.len);
1952 
1953                 if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1954                     return NGX_ERROR;
1955                 }
1956 
1957                 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1958                                "http fastcgi header: \"%V: %V\"",
1959                                &h->key, &h->value);
1960 
1961                 if (u->buffer.pos < u->buffer.last) {
1962                     continue;
1963                 }
1964 
1965                 /* the end of the FastCGI record */
1966 
1967                 break;
1968             }
1969 
1970             if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
1971 
1972                 /* a whole header has been parsed successfully */
1973 
1974                 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1975                                "http fastcgi header done");
1976 
1977                 if (u->headers_in.status) {
1978                     status_line = &u->headers_in.status->value;
1979 
1980                     status = ngx_atoi(status_line->data, 3);
1981 
1982                     if (status == NGX_ERROR) {
1983                         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1984                                       "upstream sent invalid status \"%V\"",
1985                                       status_line);
1986                         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1987                     }
1988 
1989                     u->headers_in.status_n = status;
1990                     u->headers_in.status_line = *status_line;
1991 
1992                 } else if (u->headers_in.location) {
1993                     u->headers_in.status_n = 302;
1994                     ngx_str_set(&u->headers_in.status_line,
1995                                 "302 Moved Temporarily");
1996 
1997                 } else {
1998                     u->headers_in.status_n = 200;
1999                     ngx_str_set(&u->headers_in.status_line, "200 OK");
2000                 }
2001 
2002                 if (u->state && u->state->status == 0) {
2003                     u->state->status = u->headers_in.status_n;
2004                 }
2005 
2006                 break;
2007             }
2008 
2009             /* there was error while a header line parsing */
2010 
2011             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2012                           "upstream sent invalid header");
2013 
2014             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
2015         }
2016 
2017         if (last) {
2018             u->buffer.last = last;
2019         }
2020 
2021         f->length -= u->buffer.pos - start;
2022 
2023         if (f->length == 0) {
2024             f->state = ngx_http_fastcgi_st_padding;
2025         }
2026 
2027         if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
2028             return NGX_OK;
2029         }
2030 
2031         if (rc == NGX_OK) {
2032             continue;
2033         }
2034 
2035         /* rc == NGX_AGAIN */
2036 
2037         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2038                        "upstream split a header line in FastCGI records");
2039 
2040         if (f->split_parts == NULL) {
2041             f->split_parts = ngx_array_create(r->pool, 1,
2042                                         sizeof(ngx_http_fastcgi_split_part_t));
2043             if (f->split_parts == NULL) {
2044                 return NGX_ERROR;
2045             }
2046         }
2047 
2048         part = ngx_array_push(f->split_parts);
2049         if (part == NULL) {
2050             return NGX_ERROR;
2051         }
2052 
2053         part->start = part_start;
2054         part->end = part_end;
2055 
2056         if (u->buffer.pos < u->buffer.last) {
2057             continue;
2058         }
2059 
2060         return NGX_AGAIN;
2061     }
2062 }
2063 
2064 
2065 static ngx_int_t
2066 ngx_http_fastcgi_input_filter_init(void *data)
2067 {
2068     ngx_http_request_t           *r = data;
2069     ngx_http_fastcgi_loc_conf_t  *flcf;
2070 
2071     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
2072 
2073     r->upstream->pipe->length = flcf->keep_conn ?
2074                                 (off_t) sizeof(ngx_http_fastcgi_header_t) : -1;
2075 
2076     return NGX_OK;
2077 }
2078 
2079 
2080 static ngx_int_t
2081 ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
2082 {
2083     u_char                       *m, *msg;
2084     ngx_int_t                     rc;
2085     ngx_buf_t                    *b, **prev;
2086     ngx_chain_t                  *cl;
2087     ngx_http_request_t           *r;
2088     ngx_http_fastcgi_ctx_t       *f;
2089     ngx_http_fastcgi_loc_conf_t  *flcf;
2090 
2091     if (buf->pos == buf->last) {
2092         return NGX_OK;
2093     }
2094 
2095     r = p->input_ctx;
2096     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
2097     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
2098 
2099     b = NULL;
2100     prev = &buf->shadow;
2101 
2102     f->pos = buf->pos;
2103     f->last = buf->last;
2104 
2105     for ( ;; ) {
2106         if (f->state < ngx_http_fastcgi_st_data) {
2107 
2108             rc = ngx_http_fastcgi_process_record(r, f);
2109 
2110             if (rc == NGX_AGAIN) {
2111                 break;
2112             }
2113 
2114             if (rc == NGX_ERROR) {
2115                 return NGX_ERROR;
2116             }
2117 
2118             if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) {
2119                 f->state = ngx_http_fastcgi_st_padding;
2120 
2121                 if (!flcf->keep_conn) {
2122                     p->upstream_done = 1;
2123                 }
2124 
2125                 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
2126                                "http fastcgi closed stdout");
2127 
2128                 continue;
2129             }
2130 
2131             if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
2132 
2133                 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
2134                                "http fastcgi sent end request");
2135 
2136                 if (!flcf->keep_conn) {
2137                     p->upstream_done = 1;
2138                     break;
2139                 }
2140 
2141                 continue;
2142             }
2143         }
2144 
2145 
2146         if (f->state == ngx_http_fastcgi_st_padding) {
2147 
2148             if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
2149 
2150                 if (f->pos + f->padding < f->last) {
2151                     p->upstream_done = 1;
2152                     break;
2153                 }
2154 
2155                 if (f->pos + f->padding == f->last) {
2156                     p->upstream_done = 1;
2157                     r->upstream->keepalive = 1;
2158                     break;
2159                 }
2160 
2161                 f->padding -= f->last - f->pos;
2162 
2163                 break;
2164             }
2165 
2166             if (f->pos + f->padding < f->last) {
2167                 f->state = ngx_http_fastcgi_st_version;
2168                 f->pos += f->padding;
2169 
2170                 continue;
2171             }
2172 
2173             if (f->pos + f->padding == f->last) {
2174                 f->state = ngx_http_fastcgi_st_version;
2175 
2176                 break;
2177             }
2178 
2179             f->padding -= f->last - f->pos;
2180 
2181             break;
2182         }
2183 
2184 
2185         /* f->state == ngx_http_fastcgi_st_data */
2186 
2187         if (f->type == NGX_HTTP_FASTCGI_STDERR) {
2188 
2189             if (f->length) {
2190 
2191                 if (f->pos == f->last) {
2192                     break;
2193                 }
2194 
2195                 msg = f->pos;
2196 
2197                 if (f->pos + f->length <= f->last) {
2198                     f->pos += f->length;
2199                     f->length = 0;
2200                     f->state = ngx_http_fastcgi_st_padding;
2201 
2202                 } else {
2203                     f->length -= f->last - f->pos;
2204                     f->pos = f->last;
2205                 }
2206 
2207                 for (m = f->pos - 1; msg < m; m--) {
2208                     if (*m != LF && *m != CR && *m != '.' && *m != ' ') {
2209                         break;
2210                     }
2211                 }
2212 
2213                 ngx_log_error(NGX_LOG_ERR, p->log, 0,
2214                               "FastCGI sent in stderr: \"%*s\"",
2215                               m + 1 - msg, msg);
2216 
2217             } else {
2218                 f->state = ngx_http_fastcgi_st_padding;
2219             }
2220 
2221             continue;
2222         }
2223 
2224         if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
2225 
2226             if (f->pos + f->length <= f->last) {
2227                 f->state = ngx_http_fastcgi_st_padding;
2228                 f->pos += f->length;
2229 
2230                 continue;
2231             }
2232 
2233             f->length -= f->last - f->pos;
2234 
2235             break;
2236         }
2237 
2238 
2239         /* f->type == NGX_HTTP_FASTCGI_STDOUT */
2240 
2241         if (f->pos == f->last) {
2242             break;
2243         }
2244 
2245         cl = ngx_chain_get_free_buf(p->pool, &p->free);
2246         if (cl == NULL) {
2247             return NGX_ERROR;
2248         }
2249 
2250         b = cl->buf;
2251 
2252         ngx_memzero(b, sizeof(ngx_buf_t));
2253 
2254         b->pos = f->pos;
2255         b->start = buf->start;
2256         b->end = buf->end;
2257         b->tag = p->tag;
2258         b->temporary = 1;
2259         b->recycled = 1;
2260 
2261         *prev = b;
2262         prev = &b->shadow;
2263 
2264         if (p->in) {
2265             *p->last_in = cl;
2266         } else {
2267             p->in = cl;
2268         }
2269         p->last_in = &cl->next;
2270 
2271 
2272         /* STUB */ b->num = buf->num;
2273 
2274         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
2275                        "input buf #%d %p", b->num, b->pos);
2276 
2277         if (f->pos + f->length <= f->last) {
2278             f->state = ngx_http_fastcgi_st_padding;
2279             f->pos += f->length;
2280             b->last = f->pos;
2281 
2282             continue;
2283         }
2284 
2285         f->length -= f->last - f->pos;
2286 
2287         b->last = f->last;
2288 
2289         break;
2290 
2291     }
2292 
2293     if (flcf->keep_conn) {
2294 
2295         /* set p->length, minimal amount of data we want to see */
2296 
2297         if (f->state < ngx_http_fastcgi_st_data) {
2298             p->length = 1;
2299 
2300         } else if (f->state == ngx_http_fastcgi_st_padding) {
2301             p->length = f->padding;
2302 
2303         } else {
2304             /* ngx_http_fastcgi_st_data */
2305 
2306             p->length = f->length;
2307         }
2308     }
2309 
2310     if (b) {
2311         b->shadow = buf;
2312         b->last_shadow = 1;
2313 
2314         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
2315                        "input buf %p %z", b->pos, b->last - b->pos);
2316 
2317         return NGX_OK;
2318     }
2319 
2320     /* there is no data record in the buf, add it to free chain */
2321 
2322     if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) {
2323         return NGX_ERROR;
2324     }
2325 
2326     return NGX_OK;
2327 }
2328 
2329 
2330 static ngx_int_t
2331 ngx_http_fastcgi_non_buffered_filter(void *data, ssize_t bytes)
2332 {
2333     u_char                  *m, *msg;
2334     ngx_int_t                rc;
2335     ngx_buf_t               *b, *buf;
2336     ngx_chain_t             *cl, **ll;
2337     ngx_http_request_t      *r;
2338     ngx_http_upstream_t     *u;
2339     ngx_http_fastcgi_ctx_t  *f;
2340 
2341     r = data;
2342     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
2343 
2344     u = r->upstream;
2345     buf = &u->buffer;
2346 
2347     buf->pos = buf->last;
2348     buf->last += bytes;
2349 
2350     for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
2351         ll = &cl->next;
2352     }
2353 
2354     f->pos = buf->pos;
2355     f->last = buf->last;
2356 
2357     for ( ;; ) {
2358         if (f->state < ngx_http_fastcgi_st_data) {
2359 
2360             rc = ngx_http_fastcgi_process_record(r, f);
2361 
2362             if (rc == NGX_AGAIN) {
2363                 break;
2364             }
2365 
2366             if (rc == NGX_ERROR) {
2367                 return NGX_ERROR;
2368             }
2369 
2370             if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) {
2371                 f->state = ngx_http_fastcgi_st_padding;
2372 
2373                 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2374                                "http fastcgi closed stdout");
2375 
2376                 continue;
2377             }
2378         }
2379 
2380         if (f->state == ngx_http_fastcgi_st_padding) {
2381 
2382             if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
2383 
2384                 if (f->pos + f->padding < f->last) {
2385                     u->length = 0;
2386                     break;
2387                 }
2388 
2389                 if (f->pos + f->padding == f->last) {
2390                     u->length = 0;
2391                     u->keepalive = 1;
2392                     break;
2393                 }
2394 
2395                 f->padding -= f->last - f->pos;
2396 
2397                 break;
2398             }
2399 
2400             if (f->pos + f->padding < f->last) {
2401                 f->state = ngx_http_fastcgi_st_version;
2402                 f->pos += f->padding;
2403 
2404                 continue;
2405             }
2406 
2407             if (f->pos + f->padding == f->last) {
2408                 f->state = ngx_http_fastcgi_st_version;
2409 
2410                 break;
2411             }
2412 
2413             f->padding -= f->last - f->pos;
2414 
2415             break;
2416         }
2417 
2418 
2419         /* f->state == ngx_http_fastcgi_st_data */
2420 
2421         if (f->type == NGX_HTTP_FASTCGI_STDERR) {
2422 
2423             if (f->length) {
2424 
2425                 if (f->pos == f->last) {
2426                     break;
2427                 }
2428 
2429                 msg = f->pos;
2430 
2431                 if (f->pos + f->length <= f->last) {
2432                     f->pos += f->length;
2433                     f->length = 0;
2434                     f->state = ngx_http_fastcgi_st_padding;
2435 
2436                 } else {
2437                     f->length -= f->last - f->pos;
2438                     f->pos = f->last;
2439                 }
2440 
2441                 for (m = f->pos - 1; msg < m; m--) {
2442                     if (*m != LF && *m != CR && *m != '.' && *m != ' ') {
2443                         break;
2444                     }
2445                 }
2446 
2447                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2448                               "FastCGI sent in stderr: \"%*s\"",
2449                               m + 1 - msg, msg);
2450 
2451             } else {
2452                 f->state = ngx_http_fastcgi_st_padding;
2453             }
2454 
2455             continue;
2456         }
2457 
2458         if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
2459 
2460             if (f->pos + f->length <= f->last) {
2461                 f->state = ngx_http_fastcgi_st_padding;
2462                 f->pos += f->length;
2463 
2464                 continue;
2465             }
2466 
2467             f->length -= f->last - f->pos;
2468 
2469             break;
2470         }
2471 
2472 
2473         /* f->type == NGX_HTTP_FASTCGI_STDOUT */
2474 
2475         if (f->pos == f->last) {
2476             break;
2477         }
2478 
2479         cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
2480         if (cl == NULL) {
2481             return NGX_ERROR;
2482         }
2483 
2484         *ll = cl;
2485         ll = &cl->next;
2486 
2487         b = cl->buf;
2488 
2489         b->flush = 1;
2490         b->memory = 1;
2491 
2492         b->pos = f->pos;
2493         b->tag = u->output.tag;
2494 
2495         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2496                        "http fastcgi output buf %p", b->pos);
2497 
2498         if (f->pos + f->length <= f->last) {
2499             f->state = ngx_http_fastcgi_st_padding;
2500             f->pos += f->length;
2501             b->last = f->pos;
2502 
2503             continue;
2504         }
2505 
2506         f->length -= f->last - f->pos;
2507         b->last = f->last;
2508 
2509         break;
2510     }
2511 
2512     /* provide continuous buffer for subrequests in memory */
2513 
2514     if (r->subrequest_in_memory) {
2515 
2516         cl = u->out_bufs;
2517 
2518         if (cl) {
2519             buf->pos = cl->buf->pos;
2520         }
2521 
2522         buf->last = buf->pos;
2523 
2524         for (cl = u->out_bufs; cl; cl = cl->next) {
2525             ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2526                            "http fastcgi in memory %p-%p %O",
2527                            cl->buf->pos, cl->buf->last, ngx_buf_size(cl->buf));
2528 
2529             if (buf->last == cl->buf->pos) {
2530                 buf->last = cl->buf->last;
2531                 continue;
2532             }
2533 
2534             buf->last = ngx_movemem(buf->last, cl->buf->pos,
2535                                     cl->buf->last - cl->buf->pos);
2536 
2537             cl->buf->pos = buf->last - (cl->buf->last - cl->buf->pos);
2538             cl->buf->last = buf->last;
2539         }
2540     }
2541 
2542     return NGX_OK;
2543 }
2544 
2545 
2546 static ngx_int_t
2547 ngx_http_fastcgi_process_record(ngx_http_request_t *r,
2548     ngx_http_fastcgi_ctx_t *f)
2549 {
2550     u_char                     ch, *p;
2551     ngx_http_fastcgi_state_e   state;
2552 
2553     state = f->state;
2554 
2555     for (p = f->pos; p < f->last; p++) {
2556 
2557         ch = *p;
2558 
2559         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2560                        "http fastcgi record byte: %02Xd", ch);
2561 
2562         switch (state) {
2563 
2564         case ngx_http_fastcgi_st_version:
2565             if (ch != 1) {
2566                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2567                               "upstream sent unsupported FastCGI "
2568                               "protocol version: %d", ch);
2569                 return NGX_ERROR;
2570             }
2571             state = ngx_http_fastcgi_st_type;
2572             break;
2573 
2574         case ngx_http_fastcgi_st_type:
2575             switch (ch) {
2576             case NGX_HTTP_FASTCGI_STDOUT:
2577             case NGX_HTTP_FASTCGI_STDERR:
2578             case NGX_HTTP_FASTCGI_END_REQUEST:
2579                 f->type = (ngx_uint_t) ch;
2580                 break;
2581             default:
2582                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2583                               "upstream sent invalid FastCGI "
2584                               "record type: %d", ch);
2585                 return NGX_ERROR;
2586 
2587             }
2588             state = ngx_http_fastcgi_st_request_id_hi;
2589             break;
2590 
2591         /* we support the single request per connection */
2592 
2593         case ngx_http_fastcgi_st_request_id_hi:
2594             if (ch != 0) {
2595                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2596                               "upstream sent unexpected FastCGI "
2597                               "request id high byte: %d", ch);
2598                 return NGX_ERROR;
2599             }
2600             state = ngx_http_fastcgi_st_request_id_lo;
2601             break;
2602 
2603         case ngx_http_fastcgi_st_request_id_lo:
2604             if (ch != 1) {
2605                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2606                               "upstream sent unexpected FastCGI "
2607                               "request id low byte: %d", ch);
2608                 return NGX_ERROR;
2609             }
2610             state = ngx_http_fastcgi_st_content_length_hi;
2611             break;
2612 
2613         case ngx_http_fastcgi_st_content_length_hi:
2614             f->length = ch << 8;
2615             state = ngx_http_fastcgi_st_content_length_lo;
2616             break;
2617 
2618         case ngx_http_fastcgi_st_content_length_lo:
2619             f->length |= (size_t) ch;
2620             state = ngx_http_fastcgi_st_padding_length;
2621             break;
2622 
2623         case ngx_http_fastcgi_st_padding_length:
2624             f->padding = (size_t) ch;
2625             state = ngx_http_fastcgi_st_reserved;
2626             break;
2627 
2628         case ngx_http_fastcgi_st_reserved:
2629             state = ngx_http_fastcgi_st_data;
2630 
2631             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2632                            "http fastcgi record length: %z", f->length);
2633 
2634             f->pos = p + 1;
2635             f->state = state;
2636 
2637             return NGX_OK;
2638 
2639         /* suppress warning */
2640         case ngx_http_fastcgi_st_data:
2641         case ngx_http_fastcgi_st_padding:
2642             break;
2643         }
2644     }
2645 
2646     f->state = state;
2647 
2648     return NGX_AGAIN;
2649 }
2650 
2651 
2652 static void
2653 ngx_http_fastcgi_abort_request(ngx_http_request_t *r)
2654 {
2655     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2656                    "abort http fastcgi request");
2657 
2658     return;
2659 }
2660 
2661 
2662 static void
2663 ngx_http_fastcgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
2664 {
2665     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
2666                    "finalize http fastcgi request");
2667 
2668     return;
2669 }
2670 
2671 
2672 static ngx_int_t
2673 ngx_http_fastcgi_add_variables(ngx_conf_t *cf)
2674 {
2675     ngx_http_variable_t  *var, *v;
2676 
2677     for (v = ngx_http_fastcgi_vars; v->name.len; v++) {
2678         var = ngx_http_add_variable(cf, &v->name, v->flags);
2679         if (var == NULL) {
2680             return NGX_ERROR;
2681         }
2682 
2683         var->get_handler = v->get_handler;
2684         var->data = v->data;
2685     }
2686 
2687     return NGX_OK;
2688 }
2689 
2690 
2691 static void *
2692 ngx_http_fastcgi_create_main_conf(ngx_conf_t *cf)
2693 {
2694     ngx_http_fastcgi_main_conf_t  *conf;
2695 
2696     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_main_conf_t));
2697     if (conf == NULL) {
2698         return NULL;
2699     }
2700 
2701 #if (NGX_HTTP_CACHE)
2702     if (ngx_array_init(&conf->caches, cf->pool, 4,
2703                        sizeof(ngx_http_file_cache_t *))
2704         != NGX_OK)
2705     {
2706         return NULL;
2707     }
2708 #endif
2709 
2710     return conf;
2711 }
2712 
2713 
2714 static void *
2715 ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
2716 {
2717     ngx_http_fastcgi_loc_conf_t  *conf;
2718 
2719     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_loc_conf_t));
2720     if (conf == NULL) {
2721         return NULL;
2722     }
2723 
2724     /*
2725      * set by ngx_pcalloc():
2726      *
2727      *     conf->upstream.bufs.num = 0;
2728      *     conf->upstream.ignore_headers = 0;
2729      *     conf->upstream.next_upstream = 0;
2730      *     conf->upstream.cache_zone = NULL;
2731      *     conf->upstream.cache_use_stale = 0;
2732      *     conf->upstream.cache_methods = 0;
2733      *     conf->upstream.temp_path = NULL;
2734      *     conf->upstream.hide_headers_hash = { NULL, 0 };
2735      *     conf->upstream.uri = { 0, NULL };
2736      *     conf->upstream.location = NULL;
2737      *     conf->upstream.store_lengths = NULL;
2738      *     conf->upstream.store_values = NULL;
2739      *
2740      *     conf->index.len = { 0, NULL };
2741      */
2742 
2743     conf->upstream.store = NGX_CONF_UNSET;
2744     conf->upstream.store_access = NGX_CONF_UNSET_UINT;
2745     conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
2746     conf->upstream.buffering = NGX_CONF_UNSET;
2747     conf->upstream.request_buffering = NGX_CONF_UNSET;
2748     conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
2749     conf->upstream.force_ranges = NGX_CONF_UNSET;
2750 
2751     conf->upstream.local = NGX_CONF_UNSET_PTR;
2752 
2753     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
2754     conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
2755     conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
2756     conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC;
2757 
2758     conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
2759     conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
2760     conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE;
2761 
2762     conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
2763     conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
2764     conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;
2765 
2766     conf->upstream.pass_request_headers = NGX_CONF_UNSET;
2767     conf->upstream.pass_request_body = NGX_CONF_UNSET;
2768 
2769 #if (NGX_HTTP_CACHE)
2770     conf->upstream.cache = NGX_CONF_UNSET;
2771     conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
2772     conf->upstream.cache_max_range_offset = NGX_CONF_UNSET;
2773     conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
2774     conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
2775     conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
2776     conf->upstream.cache_lock = NGX_CONF_UNSET;
2777     conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
2778     conf->upstream.cache_lock_age = NGX_CONF_UNSET_MSEC;
2779     conf->upstream.cache_revalidate = NGX_CONF_UNSET;
2780     conf->upstream.cache_background_update = NGX_CONF_UNSET;
2781 #endif
2782 
2783     conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
2784     conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
2785 
2786     conf->upstream.intercept_errors = NGX_CONF_UNSET;
2787 
2788     /* "fastcgi_cyclic_temp_file" is disabled */
2789     conf->upstream.cyclic_temp_file = 0;
2790 
2791     conf->upstream.change_buffering = 1;
2792 
2793     conf->catch_stderr = NGX_CONF_UNSET_PTR;
2794 
2795     conf->keep_conn = NGX_CONF_UNSET;
2796 
2797     ngx_str_set(&conf->upstream.module, "fastcgi");
2798 
2799     return conf;
2800 }
2801 
2802 
2803 static char *
2804 ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
2805 {
2806     ngx_http_fastcgi_loc_conf_t *prev = parent;
2807     ngx_http_fastcgi_loc_conf_t *conf = child;
2808 
2809     size_t                        size;
2810     ngx_int_t                     rc;
2811     ngx_hash_init_t               hash;
2812     ngx_http_core_loc_conf_t     *clcf;
2813 
2814 #if (NGX_HTTP_CACHE)
2815 
2816     if (conf->upstream.store > 0) {
2817         conf->upstream.cache = 0;
2818     }
2819 
2820     if (conf->upstream.cache > 0) {
2821         conf->upstream.store = 0;
2822     }
2823 
2824 #endif
2825 
2826     if (conf->upstream.store == NGX_CONF_UNSET) {
2827         ngx_conf_merge_value(conf->upstream.store,
2828                               prev->upstream.store, 0);
2829 
2830         conf->upstream.store_lengths = prev->upstream.store_lengths;
2831         conf->upstream.store_values = prev->upstream.store_values;
2832     }
2833 
2834     ngx_conf_merge_uint_value(conf->upstream.store_access,
2835                               prev->upstream.store_access, 0600);
2836 
2837     ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
2838                               prev->upstream.next_upstream_tries, 0);
2839 
2840     ngx_conf_merge_value(conf->upstream.buffering,
2841                               prev->upstream.buffering, 1);
2842 
2843     ngx_conf_merge_value(conf->upstream.request_buffering,
2844                               prev->upstream.request_buffering, 1);
2845 
2846     ngx_conf_merge_value(conf->upstream.ignore_client_abort,
2847                               prev->upstream.ignore_client_abort, 0);
2848 
2849     ngx_conf_merge_value(conf->upstream.force_ranges,
2850                               prev->upstream.force_ranges, 0);
2851 
2852     ngx_conf_merge_ptr_value(conf->upstream.local,
2853                               prev->upstream.local, NULL);
2854 
2855     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
2856                               prev->upstream.connect_timeout, 60000);
2857 
2858     ngx_conf_merge_msec_value(conf->upstream.send_timeout,
2859                               prev->upstream.send_timeout, 60000);
2860 
2861     ngx_conf_merge_msec_value(conf->upstream.read_timeout,
2862                               prev->upstream.read_timeout, 60000);
2863 
2864     ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
2865                               prev->upstream.next_upstream_timeout, 0);
2866 
2867     ngx_conf_merge_size_value(conf->upstream.send_lowat,
2868                               prev->upstream.send_lowat, 0);
2869 
2870     ngx_conf_merge_size_value(conf->upstream.buffer_size,
2871                               prev->upstream.buffer_size,
2872                               (size_t) ngx_pagesize);
2873 
2874     ngx_conf_merge_size_value(conf->upstream.limit_rate,
2875                               prev->upstream.limit_rate, 0);
2876 
2877 
2878     ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
2879                               8, ngx_pagesize);
2880 
2881     if (conf->upstream.bufs.num < 2) {
2882         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2883                            "there must be at least 2 \"fastcgi_buffers\"");
2884         return NGX_CONF_ERROR;
2885     }
2886 
2887 
2888     size = conf->upstream.buffer_size;
2889     if (size < conf->upstream.bufs.size) {
2890         size = conf->upstream.bufs.size;
2891     }
2892 
2893 
2894     ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
2895                               prev->upstream.busy_buffers_size_conf,
2896                               NGX_CONF_UNSET_SIZE);
2897 
2898     if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
2899         conf->upstream.busy_buffers_size = 2 * size;
2900     } else {
2901         conf->upstream.busy_buffers_size =
2902                                          conf->upstream.busy_buffers_size_conf;
2903     }
2904 
2905     if (conf->upstream.busy_buffers_size < size) {
2906         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2907              "\"fastcgi_busy_buffers_size\" must be equal to or greater than "
2908              "the maximum of the value of \"fastcgi_buffer_size\" and "
2909              "one of the \"fastcgi_buffers\"");
2910 
2911         return NGX_CONF_ERROR;
2912     }
2913 
2914     if (conf->upstream.busy_buffers_size
2915         > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
2916     {
2917         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2918              "\"fastcgi_busy_buffers_size\" must be less than "
2919              "the size of all \"fastcgi_buffers\" minus one buffer");
2920 
2921         return NGX_CONF_ERROR;
2922     }
2923 
2924 
2925     ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf,
2926                               prev->upstream.temp_file_write_size_conf,
2927                               NGX_CONF_UNSET_SIZE);
2928 
2929     if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
2930         conf->upstream.temp_file_write_size = 2 * size;
2931     } else {
2932         conf->upstream.temp_file_write_size =
2933                                       conf->upstream.temp_file_write_size_conf;
2934     }
2935 
2936     if (conf->upstream.temp_file_write_size < size) {
2937         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2938              "\"fastcgi_temp_file_write_size\" must be equal to or greater "
2939              "than the maximum of the value of \"fastcgi_buffer_size\" and "
2940              "one of the \"fastcgi_buffers\"");
2941 
2942         return NGX_CONF_ERROR;
2943     }
2944 
2945 
2946     ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf,
2947                               prev->upstream.max_temp_file_size_conf,
2948                               NGX_CONF_UNSET_SIZE);
2949 
2950     if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
2951         conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
2952     } else {
2953         conf->upstream.max_temp_file_size =
2954                                         conf->upstream.max_temp_file_size_conf;
2955     }
2956 
2957     if (conf->upstream.max_temp_file_size != 0
2958         && conf->upstream.max_temp_file_size < size)
2959     {
2960         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2961              "\"fastcgi_max_temp_file_size\" must be equal to zero to disable "
2962              "temporary files usage or must be equal to or greater than "
2963              "the maximum of the value of \"fastcgi_buffer_size\" and "
2964              "one of the \"fastcgi_buffers\"");
2965 
2966         return NGX_CONF_ERROR;
2967     }
2968 
2969 
2970     ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
2971                               prev->upstream.ignore_headers,
2972                               NGX_CONF_BITMASK_SET);
2973 
2974 
2975     ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
2976                               prev->upstream.next_upstream,
2977                               (NGX_CONF_BITMASK_SET
2978                                |NGX_HTTP_UPSTREAM_FT_ERROR
2979                                |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
2980 
2981     if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
2982         conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
2983                                        |NGX_HTTP_UPSTREAM_FT_OFF;
2984     }
2985 
2986     if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
2987                               prev->upstream.temp_path,
2988                               &ngx_http_fastcgi_temp_path)
2989         != NGX_OK)
2990     {
2991         return NGX_CONF_ERROR;
2992     }
2993 
2994 #if (NGX_HTTP_CACHE)
2995 
2996     if (conf->upstream.cache == NGX_CONF_UNSET) {
2997         ngx_conf_merge_value(conf->upstream.cache,
2998                               prev->upstream.cache, 0);
2999 
3000         conf->upstream.cache_zone = prev->upstream.cache_zone;
3001         conf->upstream.cache_value = prev->upstream.cache_value;
3002     }
3003 
3004     if (conf->upstream.cache_zone && conf->upstream.cache_zone->data == NULL) {
3005         ngx_shm_zone_t  *shm_zone;
3006 
3007         shm_zone = conf->upstream.cache_zone;
3008 
3009         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3010                            "\"fastcgi_cache\" zone \"%V\" is unknown",
3011                            &shm_zone->shm.name);
3012 
3013         return NGX_CONF_ERROR;
3014     }
3015 
3016     ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
3017                               prev->upstream.cache_min_uses, 1);
3018 
3019     ngx_conf_merge_off_value(conf->upstream.cache_max_range_offset,
3020                               prev->upstream.cache_max_range_offset,
3021                               NGX_MAX_OFF_T_VALUE);
3022 
3023     ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
3024                               prev->upstream.cache_use_stale,
3025                               (NGX_CONF_BITMASK_SET
3026                                |NGX_HTTP_UPSTREAM_FT_OFF));
3027 
3028     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
3029         conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
3030                                          |NGX_HTTP_UPSTREAM_FT_OFF;
3031     }
3032 
3033     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
3034         conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
3035     }
3036 
3037     if (conf->upstream.cache_methods == 0) {
3038         conf->upstream.cache_methods = prev->upstream.cache_methods;
3039     }
3040 
3041     conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD;
3042 
3043     ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
3044                              prev->upstream.cache_bypass, NULL);
3045 
3046     ngx_conf_merge_ptr_value(conf->upstream.no_cache,
3047                              prev->upstream.no_cache, NULL);
3048 
3049     ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
3050                              prev->upstream.cache_valid, NULL);
3051 
3052     if (conf->cache_key.value.data == NULL) {
3053         conf->cache_key = prev->cache_key;
3054     }
3055 
3056     if (conf->upstream.cache && conf->cache_key.value.data == NULL) {
3057         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
3058                            "no \"fastcgi_cache_key\" for \"fastcgi_cache\"");
3059     }
3060 
3061     ngx_conf_merge_value(conf->upstream.cache_lock,
3062                               prev->upstream.cache_lock, 0);
3063 
3064     ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
3065                               prev->upstream.cache_lock_timeout, 5000);
3066 
3067     ngx_conf_merge_msec_value(conf->upstream.cache_lock_age,
3068                               prev->upstream.cache_lock_age, 5000);
3069 
3070     ngx_conf_merge_value(conf->upstream.cache_revalidate,
3071                               prev->upstream.cache_revalidate, 0);
3072 
3073     ngx_conf_merge_value(conf->upstream.cache_background_update,
3074                               prev->upstream.cache_background_update, 0);
3075 
3076 #endif
3077 
3078     ngx_conf_merge_value(conf->upstream.pass_request_headers,
3079                               prev->upstream.pass_request_headers, 1);
3080     ngx_conf_merge_value(conf->upstream.pass_request_body,
3081                               prev->upstream.pass_request_body, 1);
3082 
3083     ngx_conf_merge_value(conf->upstream.intercept_errors,
3084                               prev->upstream.intercept_errors, 0);
3085 
3086     ngx_conf_merge_ptr_value(conf->catch_stderr, prev->catch_stderr, NULL);
3087 
3088     ngx_conf_merge_value(conf->keep_conn, prev->keep_conn, 0);
3089 
3090 
3091     ngx_conf_merge_str_value(conf->index, prev->index, "");
3092 
3093     hash.max_size = 512;
3094     hash.bucket_size = ngx_align(64, ngx_cacheline_size);
3095     hash.name = "fastcgi_hide_headers_hash";
3096 
3097     if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
3098              &prev->upstream, ngx_http_fastcgi_hide_headers, &hash)
3099         != NGX_OK)
3100     {
3101         return NGX_CONF_ERROR;
3102     }
3103 
3104     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
3105 
3106     if (clcf->noname
3107         && conf->upstream.upstream == NULL && conf->fastcgi_lengths == NULL)
3108     {
3109         conf->upstream.upstream = prev->upstream.upstream;
3110         conf->fastcgi_lengths = prev->fastcgi_lengths;
3111         conf->fastcgi_values = prev->fastcgi_values;
3112     }
3113 
3114     if (clcf->lmt_excpt && clcf->handler == NULL
3115         && (conf->upstream.upstream || conf->fastcgi_lengths))
3116     {
3117         clcf->handler = ngx_http_fastcgi_handler;
3118     }
3119 
3120 #if (NGX_PCRE)
3121     if (conf->split_regex == NULL) {
3122         conf->split_regex = prev->split_regex;
3123         conf->split_name = prev->split_name;
3124     }
3125 #endif
3126 
3127     if (conf->params_source == NULL) {
3128         conf->params = prev->params;
3129 #if (NGX_HTTP_CACHE)
3130         conf->params_cache = prev->params_cache;
3131 #endif
3132         conf->params_source = prev->params_source;
3133     }
3134 
3135     rc = ngx_http_fastcgi_init_params(cf, conf, &conf->params, NULL);
3136     if (rc != NGX_OK) {
3137         return NGX_CONF_ERROR;
3138     }
3139 
3140 #if (NGX_HTTP_CACHE)
3141 
3142     if (conf->upstream.cache) {
3143         rc = ngx_http_fastcgi_init_params(cf, conf, &conf->params_cache,
3144                                           ngx_http_fastcgi_cache_headers);
3145         if (rc != NGX_OK) {
3146             return NGX_CONF_ERROR;
3147         }
3148     }
3149 
3150 #endif
3151 
3152     /*
3153      * special handling to preserve conf->params in the "http" section
3154      * to inherit it to all servers
3155      */
3156 
3157     if (prev->params.hash.buckets == NULL
3158         && conf->params_source == prev->params_source)
3159     {
3160         prev->params = conf->params;
3161 #if (NGX_HTTP_CACHE)
3162         prev->params_cache = conf->params_cache;
3163 #endif
3164     }
3165 
3166     return NGX_CONF_OK;
3167 }
3168 
3169 
3170 static ngx_int_t
3171 ngx_http_fastcgi_init_params(ngx_conf_t *cf, ngx_http_fastcgi_loc_conf_t *conf,
3172     ngx_http_fastcgi_params_t *params, ngx_keyval_t *default_params)
3173 {
3174     u_char                       *p;
3175     size_t                        size;
3176     uintptr_t                    *code;
3177     ngx_uint_t                    i, nsrc;
3178     ngx_array_t                   headers_names, params_merged;
3179     ngx_keyval_t                 *h;
3180     ngx_hash_key_t               *hk;
3181     ngx_hash_init_t               hash;
3182     ngx_http_upstream_param_t    *src, *s;
3183     ngx_http_script_compile_t     sc;
3184     ngx_http_script_copy_code_t  *copy;
3185 
3186     if (params->hash.buckets) {
3187         return NGX_OK;
3188     }
3189 
3190     if (conf->params_source == NULL && default_params == NULL) {
3191         params->hash.buckets = (void *) 1;
3192         return NGX_OK;
3193     }
3194 
3195     params->lengths = ngx_array_create(cf->pool, 64, 1);
3196     if (params->lengths == NULL) {
3197         return NGX_ERROR;
3198     }
3199 
3200     params->values = ngx_array_create(cf->pool, 512, 1);
3201     if (params->values == NULL) {
3202         return NGX_ERROR;
3203     }
3204 
3205     if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
3206         != NGX_OK)
3207     {
3208         return NGX_ERROR;
3209     }
3210 
3211     if (conf->params_source) {
3212         src = conf->params_source->elts;
3213         nsrc = conf->params_source->nelts;
3214 
3215     } else {
3216         src = NULL;
3217         nsrc = 0;
3218     }
3219 
3220     if (default_params) {
3221         if (ngx_array_init(&params_merged, cf->temp_pool, 4,
3222                            sizeof(ngx_http_upstream_param_t))
3223             != NGX_OK)
3224         {
3225             return NGX_ERROR;
3226         }
3227 
3228         for (i = 0; i < nsrc; i++) {
3229 
3230             s = ngx_array_push(&params_merged);
3231             if (s == NULL) {
3232                 return NGX_ERROR;
3233             }
3234 
3235             *s = src[i];
3236         }
3237 
3238         h = default_params;
3239 
3240         while (h->key.len) {
3241 
3242             src = params_merged.elts;
3243             nsrc = params_merged.nelts;
3244 
3245             for (i = 0; i < nsrc; i++) {
3246                 if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
3247                     goto next;
3248                 }
3249             }
3250 
3251             s = ngx_array_push(&params_merged);
3252             if (s == NULL) {
3253                 return NGX_ERROR;
3254             }
3255 
3256             s->key = h->key;
3257             s->value = h->value;
3258             s->skip_empty = 1;
3259 
3260         next:
3261 
3262             h++;
3263         }
3264 
3265         src = params_merged.elts;
3266         nsrc = params_merged.nelts;
3267     }
3268 
3269     for (i = 0; i < nsrc; i++) {
3270 
3271         if (src[i].key.len > sizeof("HTTP_") - 1
3272             && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0)
3273         {
3274             hk = ngx_array_push(&headers_names);
3275             if (hk == NULL) {
3276                 return NGX_ERROR;
3277             }
3278 
3279             hk->key.len = src[i].key.len - 5;
3280             hk->key.data = src[i].key.data + 5;
3281             hk->key_hash = ngx_hash_key_lc(hk->key.data, hk->key.len);
3282             hk->value = (void *) 1;
3283 
3284             if (src[i].value.len == 0) {
3285                 continue;
3286             }
3287         }
3288 
3289         copy = ngx_array_push_n(params->lengths,
3290                                 sizeof(ngx_http_script_copy_code_t));
3291         if (copy == NULL) {
3292             return NGX_ERROR;
3293         }
3294 
3295         copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
3296         copy->len = src[i].key.len;
3297 
3298         copy = ngx_array_push_n(params->lengths,
3299                                 sizeof(ngx_http_script_copy_code_t));
3300         if (copy == NULL) {
3301             return NGX_ERROR;
3302         }
3303 
3304         copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
3305         copy->len = src[i].skip_empty;
3306 
3307 
3308         size = (sizeof(ngx_http_script_copy_code_t)
3309                 + src[i].key.len + sizeof(uintptr_t) - 1)
3310                & ~(sizeof(uintptr_t) - 1);
3311 
3312         copy = ngx_array_push_n(params->values, size);
3313         if (copy == NULL) {
3314             return NGX_ERROR;
3315         }
3316 
3317         copy->code = ngx_http_script_copy_code;
3318         copy->len = src[i].key.len;
3319 
3320         p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
3321         ngx_memcpy(p, src[i].key.data, src[i].key.len);
3322 
3323 
3324         ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3325 
3326         sc.cf = cf;
3327         sc.source = &src[i].value;
3328         sc.flushes = &params->flushes;
3329         sc.lengths = &params->lengths;
3330         sc.values = &params->values;
3331 
3332         if (ngx_http_script_compile(&sc) != NGX_OK) {
3333             return NGX_ERROR;
3334         }
3335 
3336         code = ngx_array_push_n(params->lengths, sizeof(uintptr_t));
3337         if (code == NULL) {
3338             return NGX_ERROR;
3339         }
3340 
3341         *code = (uintptr_t) NULL;
3342 
3343 
3344         code = ngx_array_push_n(params->values, sizeof(uintptr_t));
3345         if (code == NULL) {
3346             return NGX_ERROR;
3347         }
3348 
3349         *code = (uintptr_t) NULL;
3350     }
3351 
3352     code = ngx_array_push_n(params->lengths, sizeof(uintptr_t));
3353     if (code == NULL) {
3354         return NGX_ERROR;
3355     }
3356 
3357     *code = (uintptr_t) NULL;
3358 
3359     params->number = headers_names.nelts;
3360 
3361     hash.hash = &params->hash;
3362     hash.key = ngx_hash_key_lc;
3363     hash.max_size = 512;
3364     hash.bucket_size = 64;
3365     hash.name = "fastcgi_params_hash";
3366     hash.pool = cf->pool;
3367     hash.temp_pool = NULL;
3368 
3369     return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
3370 }
3371 
3372 
3373 static ngx_int_t
3374 ngx_http_fastcgi_script_name_variable(ngx_http_request_t *r,
3375     ngx_http_variable_value_t *v, uintptr_t data)
3376 {
3377     u_char                       *p;
3378     ngx_http_fastcgi_ctx_t       *f;
3379     ngx_http_fastcgi_loc_conf_t  *flcf;
3380 
3381     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
3382 
3383     f = ngx_http_fastcgi_split(r, flcf);
3384 
3385     if (f == NULL) {
3386         return NGX_ERROR;
3387     }
3388 
3389     if (f->script_name.len == 0
3390         || f->script_name.data[f->script_name.len - 1] != '/')
3391     {
3392         v->len = f->script_name.len;
3393         v->valid = 1;
3394         v->no_cacheable = 0;
3395         v->not_found = 0;
3396         v->data = f->script_name.data;
3397 
3398         return NGX_OK;
3399     }
3400 
3401     v->len = f->script_name.len + flcf->index.len;
3402 
3403     v->data = ngx_pnalloc(r->pool, v->len);
3404     if (v->data == NULL) {
3405         return NGX_ERROR;
3406     }
3407 
3408     p = ngx_copy(v->data, f->script_name.data, f->script_name.len);
3409     ngx_memcpy(p, flcf->index.data, flcf->index.len);
3410 
3411     return NGX_OK;
3412 }
3413 
3414 
3415 static ngx_int_t
3416 ngx_http_fastcgi_path_info_variable(ngx_http_request_t *r,
3417     ngx_http_variable_value_t *v, uintptr_t data)
3418 {
3419     ngx_http_fastcgi_ctx_t       *f;
3420     ngx_http_fastcgi_loc_conf_t  *flcf;
3421 
3422     flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
3423 
3424     f = ngx_http_fastcgi_split(r, flcf);
3425 
3426     if (f == NULL) {
3427         return NGX_ERROR;
3428     }
3429 
3430     v->len = f->path_info.len;
3431     v->valid = 1;
3432     v->no_cacheable = 0;
3433     v->not_found = 0;
3434     v->data = f->path_info.data;
3435 
3436     return NGX_OK;
3437 }
3438 
3439 
3440 static ngx_http_fastcgi_ctx_t *
3441 ngx_http_fastcgi_split(ngx_http_request_t *r, ngx_http_fastcgi_loc_conf_t *flcf)
3442 {
3443     ngx_http_fastcgi_ctx_t       *f;
3444 #if (NGX_PCRE)
3445     ngx_int_t                     n;
3446     int                           captures[(1 + 2) * 3];
3447 
3448     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
3449 
3450     if (f == NULL) {
3451         f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
3452         if (f == NULL) {
3453             return NULL;
3454         }
3455 
3456         ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
3457     }
3458 
3459     if (f->script_name.len) {
3460         return f;
3461     }
3462 
3463     if (flcf->split_regex == NULL) {
3464         f->script_name = r->uri;
3465         return f;
3466     }
3467 
3468     n = ngx_regex_exec(flcf->split_regex, &r->uri, captures, (1 + 2) * 3);
3469 
3470     if (n >= 0) { /* match */
3471         f->script_name.len = captures[3] - captures[2];
3472         f->script_name.data = r->uri.data + captures[2];
3473 
3474         f->path_info.len = captures[5] - captures[4];
3475         f->path_info.data = r->uri.data + captures[4];
3476 
3477         return f;
3478     }
3479 
3480     if (n == NGX_REGEX_NO_MATCHED) {
3481         f->script_name = r->uri;
3482         return f;
3483     }
3484 
3485     ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
3486                   ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"",
3487                   n, &r->uri, &flcf->split_name);
3488     return NULL;
3489 
3490 #else
3491 
3492     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
3493 
3494     if (f == NULL) {
3495         f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t));
3496         if (f == NULL) {
3497             return NULL;
3498         }
3499 
3500         ngx_http_set_ctx(r, f, ngx_http_fastcgi_module);
3501     }
3502 
3503     f->script_name = r->uri;
3504 
3505     return f;
3506 
3507 #endif
3508 }
3509 
3510 
3511 static char *
3512 ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3513 {
3514     ngx_http_fastcgi_loc_conf_t *flcf = conf;
3515 
3516     ngx_url_t                   u;
3517     ngx_str_t                  *value, *url;
3518     ngx_uint_t                  n;
3519     ngx_http_core_loc_conf_t   *clcf;
3520     ngx_http_script_compile_t   sc;
3521 
3522     if (flcf->upstream.upstream || flcf->fastcgi_lengths) {
3523         return "is duplicate";
3524     }
3525 
3526     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
3527 
3528     clcf->handler = ngx_http_fastcgi_handler;
3529 
3530     if (clcf->name.data[clcf->name.len - 1] == '/') {
3531         clcf->auto_redirect = 1;
3532     }
3533 
3534     value = cf->args->elts;
3535 
3536     url = &value[1];
3537 
3538     n = ngx_http_script_variables_count(url);
3539 
3540     if (n) {
3541 
3542         ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3543 
3544         sc.cf = cf;
3545         sc.source = url;
3546         sc.lengths = &flcf->fastcgi_lengths;
3547         sc.values = &flcf->fastcgi_values;
3548         sc.variables = n;
3549         sc.complete_lengths = 1;
3550         sc.complete_values = 1;
3551 
3552         if (ngx_http_script_compile(&sc) != NGX_OK) {
3553             return NGX_CONF_ERROR;
3554         }
3555 
3556         return NGX_CONF_OK;
3557     }
3558 
3559     ngx_memzero(&u, sizeof(ngx_url_t));
3560 
3561     u.url = value[1];
3562     u.no_resolve = 1;
3563 
3564     flcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
3565     if (flcf->upstream.upstream == NULL) {
3566         return NGX_CONF_ERROR;
3567     }
3568 
3569     return NGX_CONF_OK;
3570 }
3571 
3572 
3573 static char *
3574 ngx_http_fastcgi_split_path_info(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3575 {
3576 #if (NGX_PCRE)
3577     ngx_http_fastcgi_loc_conf_t *flcf = conf;
3578 
3579     ngx_str_t            *value;
3580     ngx_regex_compile_t   rc;
3581     u_char                errstr[NGX_MAX_CONF_ERRSTR];
3582 
3583     value = cf->args->elts;
3584 
3585     flcf->split_name = value[1];
3586 
3587     ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
3588 
3589     rc.pattern = value[1];
3590     rc.pool = cf->pool;
3591     rc.err.len = NGX_MAX_CONF_ERRSTR;
3592     rc.err.data = errstr;
3593 
3594     if (ngx_regex_compile(&rc) != NGX_OK) {
3595         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc.err);
3596         return NGX_CONF_ERROR;
3597     }
3598 
3599     if (rc.captures != 2) {
3600         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3601                            "pattern \"%V\" must have 2 captures", &value[1]);
3602         return NGX_CONF_ERROR;
3603     }
3604 
3605     flcf->split_regex = rc.regex;
3606 
3607     return NGX_CONF_OK;
3608 
3609 #else
3610 
3611     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3612                        "\"%V\" requires PCRE library", &cmd->name);
3613     return NGX_CONF_ERROR;
3614 
3615 #endif
3616 }
3617 
3618 
3619 static char *
3620 ngx_http_fastcgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3621 {
3622     ngx_http_fastcgi_loc_conf_t *flcf = conf;
3623 
3624     ngx_str_t                  *value;
3625     ngx_http_script_compile_t   sc;
3626 
3627     if (flcf->upstream.store != NGX_CONF_UNSET) {
3628         return "is duplicate";
3629     }
3630 
3631     value = cf->args->elts;
3632 
3633     if (ngx_strcmp(value[1].data, "off") == 0) {
3634         flcf->upstream.store = 0;
3635         return NGX_CONF_OK;
3636     }
3637 
3638 #if (NGX_HTTP_CACHE)
3639     if (flcf->upstream.cache > 0) {
3640         return "is incompatible with \"fastcgi_cache\"";
3641     }
3642 #endif
3643 
3644     flcf->upstream.store = 1;
3645 
3646     if (ngx_strcmp(value[1].data, "on") == 0) {
3647         return NGX_CONF_OK;
3648     }
3649 
3650     /* include the terminating '\0' into script */
3651     value[1].len++;
3652 
3653     ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
3654 
3655     sc.cf = cf;
3656     sc.source = &value[1];
3657     sc.lengths = &flcf->upstream.store_lengths;
3658     sc.values = &flcf->upstream.store_values;
3659     sc.variables = ngx_http_script_variables_count(&value[1]);
3660     sc.complete_lengths = 1;
3661     sc.complete_values = 1;
3662 
3663     if (ngx_http_script_compile(&sc) != NGX_OK) {
3664         return NGX_CONF_ERROR;
3665     }
3666 
3667     return NGX_CONF_OK;
3668 }
3669 
3670 
3671 #if (NGX_HTTP_CACHE)
3672 
3673 static char *
3674 ngx_http_fastcgi_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3675 {
3676     ngx_http_fastcgi_loc_conf_t *flcf = conf;
3677 
3678     ngx_str_t                         *value;
3679     ngx_http_complex_value_t           cv;
3680     ngx_http_compile_complex_value_t   ccv;
3681 
3682     value = cf->args->elts;
3683 
3684     if (flcf->upstream.cache != NGX_CONF_UNSET) {
3685         return "is duplicate";
3686     }
3687 
3688     if (ngx_strcmp(value[1].data, "off") == 0) {
3689         flcf->upstream.cache = 0;
3690         return NGX_CONF_OK;
3691     }
3692 
3693     if (flcf->upstream.store > 0) {
3694         return "is incompatible with \"fastcgi_store\"";
3695     }
3696 
3697     flcf->upstream.cache = 1;
3698 
3699     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3700 
3701     ccv.cf = cf;
3702     ccv.value = &value[1];
3703     ccv.complex_value = &cv;
3704 
3705     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3706         return NGX_CONF_ERROR;
3707     }
3708 
3709     if (cv.lengths != NULL) {
3710 
3711         flcf->upstream.cache_value = ngx_palloc(cf->pool,
3712                                              sizeof(ngx_http_complex_value_t));
3713         if (flcf->upstream.cache_value == NULL) {
3714             return NGX_CONF_ERROR;
3715         }
3716 
3717         *flcf->upstream.cache_value = cv;
3718 
3719         return NGX_CONF_OK;
3720     }
3721 
3722     flcf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0,
3723                                                       &ngx_http_fastcgi_module);
3724     if (flcf->upstream.cache_zone == NULL) {
3725         return NGX_CONF_ERROR;
3726     }
3727 
3728     return NGX_CONF_OK;
3729 }
3730 
3731 
3732 static char *
3733 ngx_http_fastcgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
3734 {
3735     ngx_http_fastcgi_loc_conf_t *flcf = conf;
3736 
3737     ngx_str_t                         *value;
3738     ngx_http_compile_complex_value_t   ccv;
3739 
3740     value = cf->args->elts;
3741 
3742     if (flcf->cache_key.value.data) {
3743         return "is duplicate";
3744     }
3745 
3746     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
3747 
3748     ccv.cf = cf;
3749     ccv.value = &value[1];
3750     ccv.complex_value = &flcf->cache_key;
3751 
3752     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
3753         return NGX_CONF_ERROR;
3754     }
3755 
3756     return NGX_CONF_OK;
3757 }
3758 
3759 #endif
3760 
3761 
3762 static char *
3763 ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post, void *data)
3764 {
3765 #if (NGX_FREEBSD)
3766     ssize_t *np = data;
3767 
3768     if ((u_long) *np >= ngx_freebsd_net_inet_tcp_sendspace) {
3769         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
3770                            "\"fastcgi_send_lowat\" must be less than %d "
3771                            "(sysctl net.inet.tcp.sendspace)",
3772                            ngx_freebsd_net_inet_tcp_sendspace);
3773 
3774         return NGX_CONF_ERROR;
3775     }
3776 
3777 #elif !(NGX_HAVE_SO_SNDLOWAT)
3778     ssize_t *np = data;
3779 
3780     ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
3781                        "\"fastcgi_send_lowat\" is not supported, ignored");
3782 
3783     *np = 0;
3784 
3785 #endif
3786 
3787     return NGX_CONF_OK;
3788 }