Back to home page

Nginx displayed by LXR

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