Back to home page

Nginx displayed by LXR

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

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
0005  * Copyright (C) Manlio Perillo (manlio.perillo@gmail.com)
0006  */
0007 
0008 
0009 #include <ngx_config.h>
0010 #include <ngx_core.h>
0011 #include <ngx_http.h>
0012 
0013 
0014 typedef struct {
0015     ngx_array_t                caches;  /* ngx_http_file_cache_t * */
0016 } ngx_http_scgi_main_conf_t;
0017 
0018 
0019 typedef struct {
0020     ngx_array_t               *flushes;
0021     ngx_array_t               *lengths;
0022     ngx_array_t               *values;
0023     ngx_uint_t                 number;
0024     ngx_hash_t                 hash;
0025 } ngx_http_scgi_params_t;
0026 
0027 
0028 typedef struct {
0029     ngx_http_upstream_conf_t   upstream;
0030 
0031     ngx_http_scgi_params_t     params;
0032 #if (NGX_HTTP_CACHE)
0033     ngx_http_scgi_params_t     params_cache;
0034 #endif
0035     ngx_array_t               *params_source;
0036 
0037     ngx_array_t               *scgi_lengths;
0038     ngx_array_t               *scgi_values;
0039 
0040 #if (NGX_HTTP_CACHE)
0041     ngx_http_complex_value_t   cache_key;
0042 #endif
0043 } ngx_http_scgi_loc_conf_t;
0044 
0045 
0046 static ngx_int_t ngx_http_scgi_eval(ngx_http_request_t *r,
0047     ngx_http_scgi_loc_conf_t *scf);
0048 static ngx_int_t ngx_http_scgi_create_request(ngx_http_request_t *r);
0049 static ngx_int_t ngx_http_scgi_reinit_request(ngx_http_request_t *r);
0050 static ngx_int_t ngx_http_scgi_process_status_line(ngx_http_request_t *r);
0051 static ngx_int_t ngx_http_scgi_process_header(ngx_http_request_t *r);
0052 static void ngx_http_scgi_abort_request(ngx_http_request_t *r);
0053 static void ngx_http_scgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc);
0054 
0055 static void *ngx_http_scgi_create_main_conf(ngx_conf_t *cf);
0056 static void *ngx_http_scgi_create_loc_conf(ngx_conf_t *cf);
0057 static char *ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent,
0058     void *child);
0059 static ngx_int_t ngx_http_scgi_init_params(ngx_conf_t *cf,
0060     ngx_http_scgi_loc_conf_t *conf, ngx_http_scgi_params_t *params,
0061     ngx_keyval_t *default_params);
0062 
0063 static char *ngx_http_scgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
0064 static char *ngx_http_scgi_store(ngx_conf_t *cf, ngx_command_t *cmd,
0065     void *conf);
0066 
0067 #if (NGX_HTTP_CACHE)
0068 static ngx_int_t ngx_http_scgi_create_key(ngx_http_request_t *r);
0069 static char *ngx_http_scgi_cache(ngx_conf_t *cf, ngx_command_t *cmd,
0070     void *conf);
0071 static char *ngx_http_scgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd,
0072     void *conf);
0073 #endif
0074 
0075 
0076 static ngx_conf_bitmask_t ngx_http_scgi_next_upstream_masks[] = {
0077     { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
0078     { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
0079     { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
0080     { ngx_string("non_idempotent"), NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT },
0081     { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
0082     { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
0083     { ngx_string("http_403"), NGX_HTTP_UPSTREAM_FT_HTTP_403 },
0084     { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
0085     { ngx_string("http_429"), NGX_HTTP_UPSTREAM_FT_HTTP_429 },
0086     { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING },
0087     { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
0088     { ngx_null_string, 0 }
0089 };
0090 
0091 
0092 ngx_module_t  ngx_http_scgi_module;
0093 
0094 
0095 static ngx_command_t ngx_http_scgi_commands[] = {
0096 
0097     { ngx_string("scgi_pass"),
0098       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
0099       ngx_http_scgi_pass,
0100       NGX_HTTP_LOC_CONF_OFFSET,
0101       0,
0102       NULL },
0103 
0104     { ngx_string("scgi_store"),
0105       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0106       ngx_http_scgi_store,
0107       NGX_HTTP_LOC_CONF_OFFSET,
0108       0,
0109       NULL },
0110 
0111     { ngx_string("scgi_store_access"),
0112       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
0113       ngx_conf_set_access_slot,
0114       NGX_HTTP_LOC_CONF_OFFSET,
0115       offsetof(ngx_http_scgi_loc_conf_t, upstream.store_access),
0116       NULL },
0117 
0118     { ngx_string("scgi_buffering"),
0119       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0120       ngx_conf_set_flag_slot,
0121       NGX_HTTP_LOC_CONF_OFFSET,
0122       offsetof(ngx_http_scgi_loc_conf_t, upstream.buffering),
0123       NULL },
0124 
0125     { ngx_string("scgi_request_buffering"),
0126       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0127       ngx_conf_set_flag_slot,
0128       NGX_HTTP_LOC_CONF_OFFSET,
0129       offsetof(ngx_http_scgi_loc_conf_t, upstream.request_buffering),
0130       NULL },
0131 
0132     { ngx_string("scgi_ignore_client_abort"),
0133       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0134       ngx_conf_set_flag_slot,
0135       NGX_HTTP_LOC_CONF_OFFSET,
0136       offsetof(ngx_http_scgi_loc_conf_t, upstream.ignore_client_abort),
0137       NULL },
0138 
0139     { ngx_string("scgi_bind"),
0140       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
0141       ngx_http_upstream_bind_set_slot,
0142       NGX_HTTP_LOC_CONF_OFFSET,
0143       offsetof(ngx_http_scgi_loc_conf_t, upstream.local),
0144       NULL },
0145 
0146     { ngx_string("scgi_connect_timeout"),
0147       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0148       ngx_conf_set_msec_slot,
0149       NGX_HTTP_LOC_CONF_OFFSET,
0150       offsetof(ngx_http_scgi_loc_conf_t, upstream.connect_timeout),
0151       NULL },
0152 
0153     { ngx_string("scgi_send_timeout"),
0154       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0155       ngx_conf_set_msec_slot,
0156       NGX_HTTP_LOC_CONF_OFFSET,
0157       offsetof(ngx_http_scgi_loc_conf_t, upstream.send_timeout),
0158       NULL },
0159 
0160     { ngx_string("scgi_buffer_size"),
0161       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0162       ngx_conf_set_size_slot,
0163       NGX_HTTP_LOC_CONF_OFFSET,
0164       offsetof(ngx_http_scgi_loc_conf_t, upstream.buffer_size),
0165       NULL },
0166 
0167     { ngx_string("scgi_pass_request_headers"),
0168       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0169       ngx_conf_set_flag_slot,
0170       NGX_HTTP_LOC_CONF_OFFSET,
0171       offsetof(ngx_http_scgi_loc_conf_t, upstream.pass_request_headers),
0172       NULL },
0173 
0174     { ngx_string("scgi_pass_request_body"),
0175       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0176       ngx_conf_set_flag_slot,
0177       NGX_HTTP_LOC_CONF_OFFSET,
0178       offsetof(ngx_http_scgi_loc_conf_t, upstream.pass_request_body),
0179       NULL },
0180 
0181     { ngx_string("scgi_intercept_errors"),
0182       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0183       ngx_conf_set_flag_slot,
0184       NGX_HTTP_LOC_CONF_OFFSET,
0185       offsetof(ngx_http_scgi_loc_conf_t, upstream.intercept_errors),
0186       NULL },
0187 
0188     { ngx_string("scgi_read_timeout"),
0189       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0190       ngx_conf_set_msec_slot,
0191       NGX_HTTP_LOC_CONF_OFFSET,
0192       offsetof(ngx_http_scgi_loc_conf_t, upstream.read_timeout),
0193       NULL },
0194 
0195     { ngx_string("scgi_buffers"),
0196       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
0197       ngx_conf_set_bufs_slot,
0198       NGX_HTTP_LOC_CONF_OFFSET,
0199       offsetof(ngx_http_scgi_loc_conf_t, upstream.bufs),
0200       NULL },
0201 
0202     { ngx_string("scgi_busy_buffers_size"),
0203       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0204       ngx_conf_set_size_slot,
0205       NGX_HTTP_LOC_CONF_OFFSET,
0206       offsetof(ngx_http_scgi_loc_conf_t, upstream.busy_buffers_size_conf),
0207       NULL },
0208 
0209     { ngx_string("scgi_force_ranges"),
0210       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0211       ngx_conf_set_flag_slot,
0212       NGX_HTTP_LOC_CONF_OFFSET,
0213       offsetof(ngx_http_scgi_loc_conf_t, upstream.force_ranges),
0214       NULL },
0215 
0216     { ngx_string("scgi_limit_rate"),
0217       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0218       ngx_conf_set_size_slot,
0219       NGX_HTTP_LOC_CONF_OFFSET,
0220       offsetof(ngx_http_scgi_loc_conf_t, upstream.limit_rate),
0221       NULL },
0222 
0223 #if (NGX_HTTP_CACHE)
0224 
0225     { ngx_string("scgi_cache"),
0226       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0227       ngx_http_scgi_cache,
0228       NGX_HTTP_LOC_CONF_OFFSET,
0229       0,
0230       NULL },
0231 
0232     { ngx_string("scgi_cache_key"),
0233       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0234       ngx_http_scgi_cache_key,
0235       NGX_HTTP_LOC_CONF_OFFSET,
0236       0,
0237       NULL },
0238 
0239     { ngx_string("scgi_cache_path"),
0240       NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
0241       ngx_http_file_cache_set_slot,
0242       NGX_HTTP_MAIN_CONF_OFFSET,
0243       offsetof(ngx_http_scgi_main_conf_t, caches),
0244       &ngx_http_scgi_module },
0245 
0246     { ngx_string("scgi_cache_bypass"),
0247       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
0248       ngx_http_set_predicate_slot,
0249       NGX_HTTP_LOC_CONF_OFFSET,
0250       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_bypass),
0251       NULL },
0252 
0253     { ngx_string("scgi_no_cache"),
0254       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
0255       ngx_http_set_predicate_slot,
0256       NGX_HTTP_LOC_CONF_OFFSET,
0257       offsetof(ngx_http_scgi_loc_conf_t, upstream.no_cache),
0258       NULL },
0259 
0260     { ngx_string("scgi_cache_valid"),
0261       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
0262       ngx_http_file_cache_valid_set_slot,
0263       NGX_HTTP_LOC_CONF_OFFSET,
0264       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_valid),
0265       NULL },
0266 
0267     { ngx_string("scgi_cache_min_uses"),
0268       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0269       ngx_conf_set_num_slot,
0270       NGX_HTTP_LOC_CONF_OFFSET,
0271       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_min_uses),
0272       NULL },
0273 
0274     { ngx_string("scgi_cache_max_range_offset"),
0275       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0276       ngx_conf_set_off_slot,
0277       NGX_HTTP_LOC_CONF_OFFSET,
0278       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_max_range_offset),
0279       NULL },
0280 
0281     { ngx_string("scgi_cache_use_stale"),
0282       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
0283       ngx_conf_set_bitmask_slot,
0284       NGX_HTTP_LOC_CONF_OFFSET,
0285       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_use_stale),
0286       &ngx_http_scgi_next_upstream_masks },
0287 
0288     { ngx_string("scgi_cache_methods"),
0289       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
0290       ngx_conf_set_bitmask_slot,
0291       NGX_HTTP_LOC_CONF_OFFSET,
0292       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_methods),
0293       &ngx_http_upstream_cache_method_mask },
0294 
0295     { ngx_string("scgi_cache_lock"),
0296       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0297       ngx_conf_set_flag_slot,
0298       NGX_HTTP_LOC_CONF_OFFSET,
0299       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_lock),
0300       NULL },
0301 
0302     { ngx_string("scgi_cache_lock_timeout"),
0303       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0304       ngx_conf_set_msec_slot,
0305       NGX_HTTP_LOC_CONF_OFFSET,
0306       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_lock_timeout),
0307       NULL },
0308 
0309     { ngx_string("scgi_cache_lock_age"),
0310       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0311       ngx_conf_set_msec_slot,
0312       NGX_HTTP_LOC_CONF_OFFSET,
0313       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_lock_age),
0314       NULL },
0315 
0316     { ngx_string("scgi_cache_revalidate"),
0317       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0318       ngx_conf_set_flag_slot,
0319       NGX_HTTP_LOC_CONF_OFFSET,
0320       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_revalidate),
0321       NULL },
0322 
0323     { ngx_string("scgi_cache_background_update"),
0324       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0325       ngx_conf_set_flag_slot,
0326       NGX_HTTP_LOC_CONF_OFFSET,
0327       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_background_update),
0328       NULL },
0329 
0330 #endif
0331 
0332     { ngx_string("scgi_temp_path"),
0333       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
0334       ngx_conf_set_path_slot,
0335       NGX_HTTP_LOC_CONF_OFFSET,
0336       offsetof(ngx_http_scgi_loc_conf_t, upstream.temp_path),
0337       NULL },
0338 
0339     { ngx_string("scgi_max_temp_file_size"),
0340       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0341       ngx_conf_set_size_slot,
0342       NGX_HTTP_LOC_CONF_OFFSET,
0343       offsetof(ngx_http_scgi_loc_conf_t, upstream.max_temp_file_size_conf),
0344       NULL },
0345 
0346     { ngx_string("scgi_temp_file_write_size"),
0347       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0348       ngx_conf_set_size_slot,
0349       NGX_HTTP_LOC_CONF_OFFSET,
0350       offsetof(ngx_http_scgi_loc_conf_t, upstream.temp_file_write_size_conf),
0351       NULL },
0352 
0353     { ngx_string("scgi_next_upstream"),
0354       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
0355       ngx_conf_set_bitmask_slot,
0356       NGX_HTTP_LOC_CONF_OFFSET,
0357       offsetof(ngx_http_scgi_loc_conf_t, upstream.next_upstream),
0358       &ngx_http_scgi_next_upstream_masks },
0359 
0360     { ngx_string("scgi_next_upstream_tries"),
0361       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0362       ngx_conf_set_num_slot,
0363       NGX_HTTP_LOC_CONF_OFFSET,
0364       offsetof(ngx_http_scgi_loc_conf_t, upstream.next_upstream_tries),
0365       NULL },
0366 
0367     { ngx_string("scgi_next_upstream_timeout"),
0368       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0369       ngx_conf_set_msec_slot,
0370       NGX_HTTP_LOC_CONF_OFFSET,
0371       offsetof(ngx_http_scgi_loc_conf_t, upstream.next_upstream_timeout),
0372       NULL },
0373 
0374     { ngx_string("scgi_param"),
0375       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE23,
0376       ngx_http_upstream_param_set_slot,
0377       NGX_HTTP_LOC_CONF_OFFSET,
0378       offsetof(ngx_http_scgi_loc_conf_t, params_source),
0379       NULL },
0380 
0381     { ngx_string("scgi_pass_header"),
0382       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0383       ngx_conf_set_str_array_slot,
0384       NGX_HTTP_LOC_CONF_OFFSET,
0385       offsetof(ngx_http_scgi_loc_conf_t, upstream.pass_headers),
0386       NULL },
0387 
0388     { ngx_string("scgi_hide_header"),
0389       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0390       ngx_conf_set_str_array_slot,
0391       NGX_HTTP_LOC_CONF_OFFSET,
0392       offsetof(ngx_http_scgi_loc_conf_t, upstream.hide_headers),
0393       NULL },
0394 
0395     { ngx_string("scgi_ignore_headers"),
0396       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
0397       ngx_conf_set_bitmask_slot,
0398       NGX_HTTP_LOC_CONF_OFFSET,
0399       offsetof(ngx_http_scgi_loc_conf_t, upstream.ignore_headers),
0400       &ngx_http_upstream_ignore_headers_masks },
0401 
0402       ngx_null_command
0403 };
0404 
0405 
0406 static ngx_http_module_t ngx_http_scgi_module_ctx = {
0407     NULL,                                  /* preconfiguration */
0408     NULL,                                  /* postconfiguration */
0409 
0410     ngx_http_scgi_create_main_conf,        /* create main configuration */
0411     NULL,                                  /* init main configuration */
0412 
0413     NULL,                                  /* create server configuration */
0414     NULL,                                  /* merge server configuration */
0415 
0416     ngx_http_scgi_create_loc_conf,         /* create location configuration */
0417     ngx_http_scgi_merge_loc_conf           /* merge location configuration */
0418 };
0419 
0420 
0421 ngx_module_t ngx_http_scgi_module = {
0422     NGX_MODULE_V1,
0423     &ngx_http_scgi_module_ctx,             /* module context */
0424     ngx_http_scgi_commands,                /* module directives */
0425     NGX_HTTP_MODULE,                       /* module type */
0426     NULL,                                  /* init master */
0427     NULL,                                  /* init module */
0428     NULL,                                  /* init process */
0429     NULL,                                  /* init thread */
0430     NULL,                                  /* exit thread */
0431     NULL,                                  /* exit process */
0432     NULL,                                  /* exit master */
0433     NGX_MODULE_V1_PADDING
0434 };
0435 
0436 
0437 static ngx_str_t ngx_http_scgi_hide_headers[] = {
0438     ngx_string("Status"),
0439     ngx_string("X-Accel-Expires"),
0440     ngx_string("X-Accel-Redirect"),
0441     ngx_string("X-Accel-Limit-Rate"),
0442     ngx_string("X-Accel-Buffering"),
0443     ngx_string("X-Accel-Charset"),
0444     ngx_null_string
0445 };
0446 
0447 
0448 #if (NGX_HTTP_CACHE)
0449 
0450 static ngx_keyval_t  ngx_http_scgi_cache_headers[] = {
0451     { ngx_string("HTTP_IF_MODIFIED_SINCE"),
0452       ngx_string("$upstream_cache_last_modified") },
0453     { ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") },
0454     { ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("$upstream_cache_etag") },
0455     { ngx_string("HTTP_IF_MATCH"), ngx_string("") },
0456     { ngx_string("HTTP_RANGE"), ngx_string("") },
0457     { ngx_string("HTTP_IF_RANGE"), ngx_string("") },
0458     { ngx_null_string, ngx_null_string }
0459 };
0460 
0461 #endif
0462 
0463 
0464 static ngx_path_init_t ngx_http_scgi_temp_path = {
0465     ngx_string(NGX_HTTP_SCGI_TEMP_PATH), { 1, 2, 0 }
0466 };
0467 
0468 
0469 static ngx_int_t
0470 ngx_http_scgi_handler(ngx_http_request_t *r)
0471 {
0472     ngx_int_t                   rc;
0473     ngx_http_status_t          *status;
0474     ngx_http_upstream_t        *u;
0475     ngx_http_scgi_loc_conf_t   *scf;
0476 #if (NGX_HTTP_CACHE)
0477     ngx_http_scgi_main_conf_t  *smcf;
0478 #endif
0479 
0480     if (ngx_http_upstream_create(r) != NGX_OK) {
0481         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0482     }
0483 
0484     status = ngx_pcalloc(r->pool, sizeof(ngx_http_status_t));
0485     if (status == NULL) {
0486         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0487     }
0488 
0489     ngx_http_set_ctx(r, status, ngx_http_scgi_module);
0490 
0491     scf = ngx_http_get_module_loc_conf(r, ngx_http_scgi_module);
0492 
0493     if (scf->scgi_lengths) {
0494         if (ngx_http_scgi_eval(r, scf) != NGX_OK) {
0495             return NGX_HTTP_INTERNAL_SERVER_ERROR;
0496         }
0497     }
0498 
0499     u = r->upstream;
0500 
0501     ngx_str_set(&u->schema, "scgi://");
0502     u->output.tag = (ngx_buf_tag_t) &ngx_http_scgi_module;
0503 
0504     u->conf = &scf->upstream;
0505 
0506 #if (NGX_HTTP_CACHE)
0507     smcf = ngx_http_get_module_main_conf(r, ngx_http_scgi_module);
0508 
0509     u->caches = &smcf->caches;
0510     u->create_key = ngx_http_scgi_create_key;
0511 #endif
0512 
0513     u->create_request = ngx_http_scgi_create_request;
0514     u->reinit_request = ngx_http_scgi_reinit_request;
0515     u->process_header = ngx_http_scgi_process_status_line;
0516     u->abort_request = ngx_http_scgi_abort_request;
0517     u->finalize_request = ngx_http_scgi_finalize_request;
0518     r->state = 0;
0519 
0520     u->buffering = scf->upstream.buffering;
0521 
0522     u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
0523     if (u->pipe == NULL) {
0524         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0525     }
0526 
0527     u->pipe->input_filter = ngx_event_pipe_copy_input_filter;
0528     u->pipe->input_ctx = r;
0529 
0530     if (!scf->upstream.request_buffering
0531         && scf->upstream.pass_request_body
0532         && !r->headers_in.chunked)
0533     {
0534         r->request_body_no_buffering = 1;
0535     }
0536 
0537     rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
0538 
0539     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
0540         return rc;
0541     }
0542 
0543     return NGX_DONE;
0544 }
0545 
0546 
0547 static ngx_int_t
0548 ngx_http_scgi_eval(ngx_http_request_t *r, ngx_http_scgi_loc_conf_t * scf)
0549 {
0550     ngx_url_t             url;
0551     ngx_http_upstream_t  *u;
0552 
0553     ngx_memzero(&url, sizeof(ngx_url_t));
0554 
0555     if (ngx_http_script_run(r, &url.url, scf->scgi_lengths->elts, 0,
0556                             scf->scgi_values->elts)
0557         == NULL)
0558     {
0559         return NGX_ERROR;
0560     }
0561 
0562     url.no_resolve = 1;
0563 
0564     if (ngx_parse_url(r->pool, &url) != NGX_OK) {
0565         if (url.err) {
0566             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
0567                           "%s in upstream \"%V\"", url.err, &url.url);
0568         }
0569 
0570         return NGX_ERROR;
0571     }
0572 
0573     u = r->upstream;
0574 
0575     u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
0576     if (u->resolved == NULL) {
0577         return NGX_ERROR;
0578     }
0579 
0580     if (url.addrs) {
0581         u->resolved->sockaddr = url.addrs[0].sockaddr;
0582         u->resolved->socklen = url.addrs[0].socklen;
0583         u->resolved->name = url.addrs[0].name;
0584         u->resolved->naddrs = 1;
0585     }
0586 
0587     u->resolved->host = url.host;
0588     u->resolved->port = url.port;
0589     u->resolved->no_port = url.no_port;
0590 
0591     return NGX_OK;
0592 }
0593 
0594 
0595 #if (NGX_HTTP_CACHE)
0596 
0597 static ngx_int_t
0598 ngx_http_scgi_create_key(ngx_http_request_t *r)
0599 {
0600     ngx_str_t                 *key;
0601     ngx_http_scgi_loc_conf_t  *scf;
0602 
0603     key = ngx_array_push(&r->cache->keys);
0604     if (key == NULL) {
0605         return NGX_ERROR;
0606     }
0607 
0608     scf = ngx_http_get_module_loc_conf(r, ngx_http_scgi_module);
0609 
0610     if (ngx_http_complex_value(r, &scf->cache_key, key) != NGX_OK) {
0611         return NGX_ERROR;
0612     }
0613 
0614     return NGX_OK;
0615 }
0616 
0617 #endif
0618 
0619 
0620 static ngx_int_t
0621 ngx_http_scgi_create_request(ngx_http_request_t *r)
0622 {
0623     off_t                         content_length_n;
0624     u_char                        ch, *key, *val, *lowcase_key;
0625     size_t                        len, key_len, val_len, allocated;
0626     ngx_buf_t                    *b;
0627     ngx_str_t                     content_length;
0628     ngx_uint_t                    i, n, hash, skip_empty, header_params;
0629     ngx_chain_t                  *cl, *body;
0630     ngx_list_part_t              *part;
0631     ngx_table_elt_t              *header, **ignored;
0632     ngx_http_scgi_params_t       *params;
0633     ngx_http_script_code_pt       code;
0634     ngx_http_script_engine_t      e, le;
0635     ngx_http_scgi_loc_conf_t     *scf;
0636     ngx_http_script_len_code_pt   lcode;
0637     u_char                        buffer[NGX_OFF_T_LEN];
0638 
0639     content_length_n = 0;
0640     body = r->upstream->request_bufs;
0641 
0642     while (body) {
0643         content_length_n += ngx_buf_size(body->buf);
0644         body = body->next;
0645     }
0646 
0647     content_length.data = buffer;
0648     content_length.len = ngx_sprintf(buffer, "%O", content_length_n) - buffer;
0649 
0650     len = sizeof("CONTENT_LENGTH") + content_length.len + 1;
0651 
0652     header_params = 0;
0653     ignored = NULL;
0654 
0655     scf = ngx_http_get_module_loc_conf(r, ngx_http_scgi_module);
0656 
0657 #if (NGX_HTTP_CACHE)
0658     params = r->upstream->cacheable ? &scf->params_cache : &scf->params;
0659 #else
0660     params = &scf->params;
0661 #endif
0662 
0663     if (params->lengths) {
0664         ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
0665 
0666         ngx_http_script_flush_no_cacheable_variables(r, params->flushes);
0667         le.flushed = 1;
0668 
0669         le.ip = params->lengths->elts;
0670         le.request = r;
0671 
0672         while (*(uintptr_t *) le.ip) {
0673 
0674             lcode = *(ngx_http_script_len_code_pt *) le.ip;
0675             key_len = lcode(&le);
0676 
0677             lcode = *(ngx_http_script_len_code_pt *) le.ip;
0678             skip_empty = lcode(&le);
0679 
0680             for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
0681                 lcode = *(ngx_http_script_len_code_pt *) le.ip;
0682             }
0683             le.ip += sizeof(uintptr_t);
0684 
0685             if (skip_empty && val_len == 0) {
0686                 continue;
0687             }
0688 
0689             len += key_len + val_len + 1;
0690         }
0691     }
0692 
0693     if (scf->upstream.pass_request_headers) {
0694 
0695         allocated = 0;
0696         lowcase_key = NULL;
0697 
0698         if (params->number) {
0699             n = 0;
0700             part = &r->headers_in.headers.part;
0701 
0702             while (part) {
0703                 n += part->nelts;
0704                 part = part->next;
0705             }
0706 
0707             ignored = ngx_palloc(r->pool, n * sizeof(void *));
0708             if (ignored == NULL) {
0709                 return NGX_ERROR;
0710             }
0711         }
0712 
0713         part = &r->headers_in.headers.part;
0714         header = part->elts;
0715 
0716         for (i = 0; /* void */; i++) {
0717 
0718             if (i >= part->nelts) {
0719                 if (part->next == NULL) {
0720                     break;
0721                 }
0722 
0723                 part = part->next;
0724                 header = part->elts;
0725                 i = 0;
0726             }
0727 
0728             if (params->number) {
0729                 if (allocated < header[i].key.len) {
0730                     allocated = header[i].key.len + 16;
0731                     lowcase_key = ngx_pnalloc(r->pool, allocated);
0732                     if (lowcase_key == NULL) {
0733                         return NGX_ERROR;
0734                     }
0735                 }
0736 
0737                 hash = 0;
0738 
0739                 for (n = 0; n < header[i].key.len; n++) {
0740                     ch = header[i].key.data[n];
0741 
0742                     if (ch >= 'A' && ch <= 'Z') {
0743                         ch |= 0x20;
0744 
0745                     } else if (ch == '-') {
0746                         ch = '_';
0747                     }
0748 
0749                     hash = ngx_hash(hash, ch);
0750                     lowcase_key[n] = ch;
0751                 }
0752 
0753                 if (ngx_hash_find(&params->hash, hash, lowcase_key, n)) {
0754                     ignored[header_params++] = &header[i];
0755                     continue;
0756                 }
0757             }
0758 
0759             len += sizeof("HTTP_") - 1 + header[i].key.len + 1
0760                 + header[i].value.len + 1;
0761         }
0762     }
0763 
0764     /* netstring: "length:" + packet + "," */
0765 
0766     b = ngx_create_temp_buf(r->pool, NGX_SIZE_T_LEN + 1 + len + 1);
0767     if (b == NULL) {
0768         return NGX_ERROR;
0769     }
0770 
0771     cl = ngx_alloc_chain_link(r->pool);
0772     if (cl == NULL) {
0773         return NGX_ERROR;
0774     }
0775 
0776     cl->buf = b;
0777 
0778     b->last = ngx_sprintf(b->last, "%ui:CONTENT_LENGTH%Z%V%Z",
0779                           len, &content_length);
0780 
0781     if (params->lengths) {
0782         ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
0783 
0784         e.ip = params->values->elts;
0785         e.pos = b->last;
0786         e.request = r;
0787         e.flushed = 1;
0788 
0789         le.ip = params->lengths->elts;
0790 
0791         while (*(uintptr_t *) le.ip) {
0792 
0793             lcode = *(ngx_http_script_len_code_pt *) le.ip;
0794             lcode(&le); /* key length */
0795 
0796             lcode = *(ngx_http_script_len_code_pt *) le.ip;
0797             skip_empty = lcode(&le);
0798 
0799             for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
0800                 lcode = *(ngx_http_script_len_code_pt *) le.ip;
0801             }
0802             le.ip += sizeof(uintptr_t);
0803 
0804             if (skip_empty && val_len == 0) {
0805                 e.skip = 1;
0806 
0807                 while (*(uintptr_t *) e.ip) {
0808                     code = *(ngx_http_script_code_pt *) e.ip;
0809                     code((ngx_http_script_engine_t *) &e);
0810                 }
0811                 e.ip += sizeof(uintptr_t);
0812 
0813                 e.skip = 0;
0814 
0815                 continue;
0816             }
0817 
0818 #if (NGX_DEBUG)
0819             key = e.pos;
0820 #endif
0821             code = *(ngx_http_script_code_pt *) e.ip;
0822             code((ngx_http_script_engine_t *) & e);
0823 
0824 #if (NGX_DEBUG)
0825             val = e.pos;
0826 #endif
0827             while (*(uintptr_t *) e.ip) {
0828                 code = *(ngx_http_script_code_pt *) e.ip;
0829                 code((ngx_http_script_engine_t *) &e);
0830             }
0831             *e.pos++ = '\0';
0832             e.ip += sizeof(uintptr_t);
0833 
0834             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0835                            "scgi param: \"%s: %s\"", key, val);
0836         }
0837 
0838         b->last = e.pos;
0839     }
0840 
0841     if (scf->upstream.pass_request_headers) {
0842 
0843         part = &r->headers_in.headers.part;
0844         header = part->elts;
0845 
0846         for (i = 0; /* void */; i++) {
0847 
0848             if (i >= part->nelts) {
0849                 if (part->next == NULL) {
0850                     break;
0851                 }
0852 
0853                 part = part->next;
0854                 header = part->elts;
0855                 i = 0;
0856             }
0857 
0858             for (n = 0; n < header_params; n++) {
0859                 if (&header[i] == ignored[n]) {
0860                     goto next;
0861                 }
0862             }
0863 
0864             key = b->last;
0865             b->last = ngx_cpymem(key, "HTTP_", sizeof("HTTP_") - 1);
0866 
0867             for (n = 0; n < header[i].key.len; n++) {
0868                 ch = header[i].key.data[n];
0869 
0870                 if (ch >= 'a' && ch <= 'z') {
0871                     ch &= ~0x20;
0872 
0873                 } else if (ch == '-') {
0874                     ch = '_';
0875                 }
0876 
0877                 *b->last++ = ch;
0878             }
0879 
0880             *b->last++ = (u_char) 0;
0881 
0882             val = b->last;
0883             b->last = ngx_copy(val, header[i].value.data, header[i].value.len);
0884             *b->last++ = (u_char) 0;
0885 
0886             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0887                            "scgi param: \"%s: %s\"", key, val);
0888 
0889         next:
0890 
0891             continue;
0892         }
0893     }
0894 
0895     *b->last++ = (u_char) ',';
0896 
0897     if (r->request_body_no_buffering) {
0898         r->upstream->request_bufs = cl;
0899 
0900     } else if (scf->upstream.pass_request_body) {
0901         body = r->upstream->request_bufs;
0902         r->upstream->request_bufs = cl;
0903 
0904         while (body) {
0905             b = ngx_alloc_buf(r->pool);
0906             if (b == NULL) {
0907                 return NGX_ERROR;
0908             }
0909 
0910             ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
0911 
0912             cl->next = ngx_alloc_chain_link(r->pool);
0913             if (cl->next == NULL) {
0914                 return NGX_ERROR;
0915             }
0916 
0917             cl = cl->next;
0918             cl->buf = b;
0919 
0920             body = body->next;
0921         }
0922 
0923     } else {
0924         r->upstream->request_bufs = cl;
0925     }
0926 
0927     cl->next = NULL;
0928 
0929     return NGX_OK;
0930 }
0931 
0932 
0933 static ngx_int_t
0934 ngx_http_scgi_reinit_request(ngx_http_request_t *r)
0935 {
0936     ngx_http_status_t  *status;
0937 
0938     status = ngx_http_get_module_ctx(r, ngx_http_scgi_module);
0939 
0940     if (status == NULL) {
0941         return NGX_OK;
0942     }
0943 
0944     status->code = 0;
0945     status->count = 0;
0946     status->start = NULL;
0947     status->end = NULL;
0948 
0949     r->upstream->process_header = ngx_http_scgi_process_status_line;
0950     r->state = 0;
0951 
0952     return NGX_OK;
0953 }
0954 
0955 
0956 static ngx_int_t
0957 ngx_http_scgi_process_status_line(ngx_http_request_t *r)
0958 {
0959     size_t                len;
0960     ngx_int_t             rc;
0961     ngx_http_status_t    *status;
0962     ngx_http_upstream_t  *u;
0963 
0964     status = ngx_http_get_module_ctx(r, ngx_http_scgi_module);
0965 
0966     if (status == NULL) {
0967         return NGX_ERROR;
0968     }
0969 
0970     u = r->upstream;
0971 
0972     rc = ngx_http_parse_status_line(r, &u->buffer, status);
0973 
0974     if (rc == NGX_AGAIN) {
0975         return rc;
0976     }
0977 
0978     if (rc == NGX_ERROR) {
0979         u->process_header = ngx_http_scgi_process_header;
0980         return ngx_http_scgi_process_header(r);
0981     }
0982 
0983     if (u->state && u->state->status == 0) {
0984         u->state->status = status->code;
0985     }
0986 
0987     u->headers_in.status_n = status->code;
0988 
0989     len = status->end - status->start;
0990     u->headers_in.status_line.len = len;
0991 
0992     u->headers_in.status_line.data = ngx_pnalloc(r->pool, len);
0993     if (u->headers_in.status_line.data == NULL) {
0994         return NGX_ERROR;
0995     }
0996 
0997     ngx_memcpy(u->headers_in.status_line.data, status->start, len);
0998 
0999     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1000                    "http scgi status %ui \"%V\"",
1001                    u->headers_in.status_n, &u->headers_in.status_line);
1002 
1003     u->process_header = ngx_http_scgi_process_header;
1004 
1005     return ngx_http_scgi_process_header(r);
1006 }
1007 
1008 
1009 static ngx_int_t
1010 ngx_http_scgi_process_header(ngx_http_request_t *r)
1011 {
1012     ngx_str_t                      *status_line;
1013     ngx_int_t                       rc, status;
1014     ngx_table_elt_t                *h;
1015     ngx_http_upstream_t            *u;
1016     ngx_http_upstream_header_t     *hh;
1017     ngx_http_upstream_main_conf_t  *umcf;
1018 
1019     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
1020 
1021     for ( ;; ) {
1022 
1023         rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);
1024 
1025         if (rc == NGX_OK) {
1026 
1027             /* a header line has been parsed successfully */
1028 
1029             h = ngx_list_push(&r->upstream->headers_in.headers);
1030             if (h == NULL) {
1031                 return NGX_ERROR;
1032             }
1033 
1034             h->hash = r->header_hash;
1035 
1036             h->key.len = r->header_name_end - r->header_name_start;
1037             h->value.len = r->header_end - r->header_start;
1038 
1039             h->key.data = ngx_pnalloc(r->pool,
1040                                       h->key.len + 1 + h->value.len + 1
1041                                       + h->key.len);
1042             if (h->key.data == NULL) {
1043                 return NGX_ERROR;
1044             }
1045 
1046             h->value.data = h->key.data + h->key.len + 1;
1047             h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;
1048 
1049             ngx_memcpy(h->key.data, r->header_name_start, h->key.len);
1050             h->key.data[h->key.len] = '\0';
1051             ngx_memcpy(h->value.data, r->header_start, h->value.len);
1052             h->value.data[h->value.len] = '\0';
1053 
1054             if (h->key.len == r->lowcase_index) {
1055                 ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
1056 
1057             } else {
1058                 ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
1059             }
1060 
1061             hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
1062                                h->lowcase_key, h->key.len);
1063 
1064             if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1065                 return NGX_ERROR;
1066             }
1067 
1068             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1069                            "http scgi header: \"%V: %V\"", &h->key, &h->value);
1070 
1071             continue;
1072         }
1073 
1074         if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
1075 
1076             /* a whole header has been parsed successfully */
1077 
1078             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1079                            "http scgi header done");
1080 
1081             u = r->upstream;
1082 
1083             if (u->headers_in.status_n) {
1084                 goto done;
1085             }
1086 
1087             if (u->headers_in.status) {
1088                 status_line = &u->headers_in.status->value;
1089 
1090                 status = ngx_atoi(status_line->data, 3);
1091                 if (status == NGX_ERROR) {
1092                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1093                                   "upstream sent invalid status \"%V\"",
1094                                   status_line);
1095                     return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1096                 }
1097 
1098                 u->headers_in.status_n = status;
1099                 u->headers_in.status_line = *status_line;
1100 
1101             } else if (u->headers_in.location) {
1102                 u->headers_in.status_n = 302;
1103                 ngx_str_set(&u->headers_in.status_line,
1104                             "302 Moved Temporarily");
1105 
1106             } else {
1107                 u->headers_in.status_n = 200;
1108                 ngx_str_set(&u->headers_in.status_line, "200 OK");
1109             }
1110 
1111             if (u->state && u->state->status == 0) {
1112                 u->state->status = u->headers_in.status_n;
1113             }
1114 
1115         done:
1116 
1117             if (u->headers_in.status_n == NGX_HTTP_SWITCHING_PROTOCOLS
1118                 && r->headers_in.upgrade)
1119             {
1120                 u->upgrade = 1;
1121             }
1122 
1123             return NGX_OK;
1124         }
1125 
1126         if (rc == NGX_AGAIN) {
1127             return NGX_AGAIN;
1128         }
1129 
1130         /* there was error while a header line parsing */
1131 
1132         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1133                       "upstream sent invalid header");
1134 
1135         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1136     }
1137 }
1138 
1139 
1140 static void
1141 ngx_http_scgi_abort_request(ngx_http_request_t *r)
1142 {
1143     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1144                    "abort http scgi request");
1145 
1146     return;
1147 }
1148 
1149 
1150 static void
1151 ngx_http_scgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
1152 {
1153     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1154                    "finalize http scgi request");
1155 
1156     return;
1157 }
1158 
1159 
1160 static void *
1161 ngx_http_scgi_create_main_conf(ngx_conf_t *cf)
1162 {
1163     ngx_http_scgi_main_conf_t  *conf;
1164 
1165     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_scgi_main_conf_t));
1166     if (conf == NULL) {
1167         return NULL;
1168     }
1169 
1170 #if (NGX_HTTP_CACHE)
1171     if (ngx_array_init(&conf->caches, cf->pool, 4,
1172                        sizeof(ngx_http_file_cache_t *))
1173         != NGX_OK)
1174     {
1175         return NULL;
1176     }
1177 #endif
1178 
1179     return conf;
1180 }
1181 
1182 
1183 static void *
1184 ngx_http_scgi_create_loc_conf(ngx_conf_t *cf)
1185 {
1186     ngx_http_scgi_loc_conf_t  *conf;
1187 
1188     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_scgi_loc_conf_t));
1189     if (conf == NULL) {
1190         return NULL;
1191     }
1192 
1193     conf->upstream.store = NGX_CONF_UNSET;
1194     conf->upstream.store_access = NGX_CONF_UNSET_UINT;
1195     conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
1196     conf->upstream.buffering = NGX_CONF_UNSET;
1197     conf->upstream.request_buffering = NGX_CONF_UNSET;
1198     conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
1199     conf->upstream.force_ranges = NGX_CONF_UNSET;
1200 
1201     conf->upstream.local = NGX_CONF_UNSET_PTR;
1202 
1203     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
1204     conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
1205     conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
1206     conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC;
1207 
1208     conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
1209     conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
1210     conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE;
1211 
1212     conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
1213     conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
1214     conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;
1215 
1216     conf->upstream.pass_request_headers = NGX_CONF_UNSET;
1217     conf->upstream.pass_request_body = NGX_CONF_UNSET;
1218 
1219 #if (NGX_HTTP_CACHE)
1220     conf->upstream.cache = NGX_CONF_UNSET;
1221     conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
1222     conf->upstream.cache_max_range_offset = NGX_CONF_UNSET;
1223     conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
1224     conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
1225     conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
1226     conf->upstream.cache_lock = NGX_CONF_UNSET;
1227     conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
1228     conf->upstream.cache_lock_age = NGX_CONF_UNSET_MSEC;
1229     conf->upstream.cache_revalidate = NGX_CONF_UNSET;
1230     conf->upstream.cache_background_update = NGX_CONF_UNSET;
1231 #endif
1232 
1233     conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
1234     conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
1235 
1236     conf->upstream.intercept_errors = NGX_CONF_UNSET;
1237 
1238     /* "scgi_cyclic_temp_file" is disabled */
1239     conf->upstream.cyclic_temp_file = 0;
1240 
1241     conf->upstream.change_buffering = 1;
1242 
1243     ngx_str_set(&conf->upstream.module, "scgi");
1244 
1245     return conf;
1246 }
1247 
1248 
1249 static char *
1250 ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
1251 {
1252     ngx_http_scgi_loc_conf_t *prev = parent;
1253     ngx_http_scgi_loc_conf_t *conf = child;
1254 
1255     size_t                        size;
1256     ngx_int_t                     rc;
1257     ngx_hash_init_t               hash;
1258     ngx_http_core_loc_conf_t     *clcf;
1259 
1260 #if (NGX_HTTP_CACHE)
1261 
1262     if (conf->upstream.store > 0) {
1263         conf->upstream.cache = 0;
1264     }
1265 
1266     if (conf->upstream.cache > 0) {
1267         conf->upstream.store = 0;
1268     }
1269 
1270 #endif
1271 
1272     if (conf->upstream.store == NGX_CONF_UNSET) {
1273         ngx_conf_merge_value(conf->upstream.store, prev->upstream.store, 0);
1274 
1275         conf->upstream.store_lengths = prev->upstream.store_lengths;
1276         conf->upstream.store_values = prev->upstream.store_values;
1277     }
1278 
1279     ngx_conf_merge_uint_value(conf->upstream.store_access,
1280                               prev->upstream.store_access, 0600);
1281 
1282     ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
1283                               prev->upstream.next_upstream_tries, 0);
1284 
1285     ngx_conf_merge_value(conf->upstream.buffering,
1286                               prev->upstream.buffering, 1);
1287 
1288     ngx_conf_merge_value(conf->upstream.request_buffering,
1289                               prev->upstream.request_buffering, 1);
1290 
1291     ngx_conf_merge_value(conf->upstream.ignore_client_abort,
1292                               prev->upstream.ignore_client_abort, 0);
1293 
1294     ngx_conf_merge_value(conf->upstream.force_ranges,
1295                               prev->upstream.force_ranges, 0);
1296 
1297     ngx_conf_merge_ptr_value(conf->upstream.local,
1298                               prev->upstream.local, NULL);
1299 
1300     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
1301                               prev->upstream.connect_timeout, 60000);
1302 
1303     ngx_conf_merge_msec_value(conf->upstream.send_timeout,
1304                               prev->upstream.send_timeout, 60000);
1305 
1306     ngx_conf_merge_msec_value(conf->upstream.read_timeout,
1307                               prev->upstream.read_timeout, 60000);
1308 
1309     ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
1310                               prev->upstream.next_upstream_timeout, 0);
1311 
1312     ngx_conf_merge_size_value(conf->upstream.send_lowat,
1313                               prev->upstream.send_lowat, 0);
1314 
1315     ngx_conf_merge_size_value(conf->upstream.buffer_size,
1316                               prev->upstream.buffer_size,
1317                               (size_t) ngx_pagesize);
1318 
1319     ngx_conf_merge_size_value(conf->upstream.limit_rate,
1320                               prev->upstream.limit_rate, 0);
1321 
1322 
1323     ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
1324                               8, ngx_pagesize);
1325 
1326     if (conf->upstream.bufs.num < 2) {
1327         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1328                            "there must be at least 2 \"scgi_buffers\"");
1329         return NGX_CONF_ERROR;
1330     }
1331 
1332 
1333     size = conf->upstream.buffer_size;
1334     if (size < conf->upstream.bufs.size) {
1335         size = conf->upstream.bufs.size;
1336     }
1337 
1338 
1339     ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
1340                               prev->upstream.busy_buffers_size_conf,
1341                               NGX_CONF_UNSET_SIZE);
1342 
1343     if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
1344         conf->upstream.busy_buffers_size = 2 * size;
1345     } else {
1346         conf->upstream.busy_buffers_size =
1347             conf->upstream.busy_buffers_size_conf;
1348     }
1349 
1350     if (conf->upstream.busy_buffers_size < size) {
1351         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1352             "\"scgi_busy_buffers_size\" must be equal to or greater "
1353             "than the maximum of the value of \"scgi_buffer_size\" and "
1354             "one of the \"scgi_buffers\"");
1355 
1356         return NGX_CONF_ERROR;
1357     }
1358 
1359     if (conf->upstream.busy_buffers_size
1360         > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
1361     {
1362         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1363             "\"scgi_busy_buffers_size\" must be less than "
1364             "the size of all \"scgi_buffers\" minus one buffer");
1365 
1366         return NGX_CONF_ERROR;
1367     }
1368 
1369 
1370     ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf,
1371                               prev->upstream.temp_file_write_size_conf,
1372                               NGX_CONF_UNSET_SIZE);
1373 
1374     if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
1375         conf->upstream.temp_file_write_size = 2 * size;
1376     } else {
1377         conf->upstream.temp_file_write_size =
1378             conf->upstream.temp_file_write_size_conf;
1379     }
1380 
1381     if (conf->upstream.temp_file_write_size < size) {
1382         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1383             "\"scgi_temp_file_write_size\" must be equal to or greater than "
1384             "the maximum of the value of \"scgi_buffer_size\" and "
1385             "one of the \"scgi_buffers\"");
1386 
1387         return NGX_CONF_ERROR;
1388     }
1389 
1390 
1391     ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf,
1392                               prev->upstream.max_temp_file_size_conf,
1393                               NGX_CONF_UNSET_SIZE);
1394 
1395     if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
1396         conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
1397     } else {
1398         conf->upstream.max_temp_file_size =
1399             conf->upstream.max_temp_file_size_conf;
1400     }
1401 
1402     if (conf->upstream.max_temp_file_size != 0
1403         && conf->upstream.max_temp_file_size < size)
1404     {
1405         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1406             "\"scgi_max_temp_file_size\" must be equal to zero to disable "
1407             "temporary files usage or must be equal to or greater than "
1408             "the maximum of the value of \"scgi_buffer_size\" and "
1409             "one of the \"scgi_buffers\"");
1410 
1411         return NGX_CONF_ERROR;
1412     }
1413 
1414 
1415     ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
1416                                  prev->upstream.ignore_headers,
1417                                  NGX_CONF_BITMASK_SET);
1418 
1419 
1420     ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
1421                                  prev->upstream.next_upstream,
1422                                  (NGX_CONF_BITMASK_SET
1423                                   |NGX_HTTP_UPSTREAM_FT_ERROR
1424                                   |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
1425 
1426     if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
1427         conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
1428                                        |NGX_HTTP_UPSTREAM_FT_OFF;
1429     }
1430 
1431     if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
1432                                   prev->upstream.temp_path,
1433                                   &ngx_http_scgi_temp_path)
1434         != NGX_OK)
1435     {
1436         return NGX_CONF_ERROR;
1437     }
1438 
1439 #if (NGX_HTTP_CACHE)
1440 
1441     if (conf->upstream.cache == NGX_CONF_UNSET) {
1442         ngx_conf_merge_value(conf->upstream.cache,
1443                               prev->upstream.cache, 0);
1444 
1445         conf->upstream.cache_zone = prev->upstream.cache_zone;
1446         conf->upstream.cache_value = prev->upstream.cache_value;
1447     }
1448 
1449     if (conf->upstream.cache_zone && conf->upstream.cache_zone->data == NULL) {
1450         ngx_shm_zone_t  *shm_zone;
1451 
1452         shm_zone = conf->upstream.cache_zone;
1453 
1454         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1455                            "\"scgi_cache\" zone \"%V\" is unknown",
1456                            &shm_zone->shm.name);
1457 
1458         return NGX_CONF_ERROR;
1459     }
1460 
1461     ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
1462                               prev->upstream.cache_min_uses, 1);
1463 
1464     ngx_conf_merge_off_value(conf->upstream.cache_max_range_offset,
1465                               prev->upstream.cache_max_range_offset,
1466                               NGX_MAX_OFF_T_VALUE);
1467 
1468     ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
1469                               prev->upstream.cache_use_stale,
1470                               (NGX_CONF_BITMASK_SET
1471                                |NGX_HTTP_UPSTREAM_FT_OFF));
1472 
1473     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
1474         conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
1475                                          |NGX_HTTP_UPSTREAM_FT_OFF;
1476     }
1477 
1478     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
1479         conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
1480     }
1481 
1482     if (conf->upstream.cache_methods == 0) {
1483         conf->upstream.cache_methods = prev->upstream.cache_methods;
1484     }
1485 
1486     conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD;
1487 
1488     ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
1489                              prev->upstream.cache_bypass, NULL);
1490 
1491     ngx_conf_merge_ptr_value(conf->upstream.no_cache,
1492                              prev->upstream.no_cache, NULL);
1493 
1494     ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
1495                              prev->upstream.cache_valid, NULL);
1496 
1497     if (conf->cache_key.value.data == NULL) {
1498         conf->cache_key = prev->cache_key;
1499     }
1500 
1501     if (conf->upstream.cache && conf->cache_key.value.data == NULL) {
1502         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
1503                            "no \"scgi_cache_key\" for \"scgi_cache\"");
1504     }
1505 
1506     ngx_conf_merge_value(conf->upstream.cache_lock,
1507                               prev->upstream.cache_lock, 0);
1508 
1509     ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
1510                               prev->upstream.cache_lock_timeout, 5000);
1511 
1512     ngx_conf_merge_msec_value(conf->upstream.cache_lock_age,
1513                               prev->upstream.cache_lock_age, 5000);
1514 
1515     ngx_conf_merge_value(conf->upstream.cache_revalidate,
1516                               prev->upstream.cache_revalidate, 0);
1517 
1518     ngx_conf_merge_value(conf->upstream.cache_background_update,
1519                               prev->upstream.cache_background_update, 0);
1520 
1521 #endif
1522 
1523     ngx_conf_merge_value(conf->upstream.pass_request_headers,
1524                          prev->upstream.pass_request_headers, 1);
1525     ngx_conf_merge_value(conf->upstream.pass_request_body,
1526                          prev->upstream.pass_request_body, 1);
1527 
1528     ngx_conf_merge_value(conf->upstream.intercept_errors,
1529                          prev->upstream.intercept_errors, 0);
1530 
1531     hash.max_size = 512;
1532     hash.bucket_size = ngx_align(64, ngx_cacheline_size);
1533     hash.name = "scgi_hide_headers_hash";
1534 
1535     if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
1536             &prev->upstream, ngx_http_scgi_hide_headers, &hash)
1537         != NGX_OK)
1538     {
1539         return NGX_CONF_ERROR;
1540     }
1541 
1542     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
1543 
1544     if (clcf->noname
1545         && conf->upstream.upstream == NULL && conf->scgi_lengths == NULL)
1546     {
1547         conf->upstream.upstream = prev->upstream.upstream;
1548         conf->scgi_lengths = prev->scgi_lengths;
1549         conf->scgi_values = prev->scgi_values;
1550     }
1551 
1552     if (clcf->lmt_excpt && clcf->handler == NULL
1553         && (conf->upstream.upstream || conf->scgi_lengths))
1554     {
1555         clcf->handler = ngx_http_scgi_handler;
1556     }
1557 
1558     if (conf->params_source == NULL) {
1559         conf->params = prev->params;
1560 #if (NGX_HTTP_CACHE)
1561         conf->params_cache = prev->params_cache;
1562 #endif
1563         conf->params_source = prev->params_source;
1564     }
1565 
1566     rc = ngx_http_scgi_init_params(cf, conf, &conf->params, NULL);
1567     if (rc != NGX_OK) {
1568         return NGX_CONF_ERROR;
1569     }
1570 
1571 #if (NGX_HTTP_CACHE)
1572 
1573     if (conf->upstream.cache) {
1574         rc = ngx_http_scgi_init_params(cf, conf, &conf->params_cache,
1575                                        ngx_http_scgi_cache_headers);
1576         if (rc != NGX_OK) {
1577             return NGX_CONF_ERROR;
1578         }
1579     }
1580 
1581 #endif
1582 
1583     /*
1584      * special handling to preserve conf->params in the "http" section
1585      * to inherit it to all servers
1586      */
1587 
1588     if (prev->params.hash.buckets == NULL
1589         && conf->params_source == prev->params_source)
1590     {
1591         prev->params = conf->params;
1592 #if (NGX_HTTP_CACHE)
1593         prev->params_cache = conf->params_cache;
1594 #endif
1595     }
1596 
1597     return NGX_CONF_OK;
1598 }
1599 
1600 
1601 static ngx_int_t
1602 ngx_http_scgi_init_params(ngx_conf_t *cf, ngx_http_scgi_loc_conf_t *conf,
1603     ngx_http_scgi_params_t *params, ngx_keyval_t *default_params)
1604 {
1605     u_char                       *p;
1606     size_t                        size;
1607     uintptr_t                    *code;
1608     ngx_uint_t                    i, nsrc;
1609     ngx_array_t                   headers_names, params_merged;
1610     ngx_keyval_t                 *h;
1611     ngx_hash_key_t               *hk;
1612     ngx_hash_init_t               hash;
1613     ngx_http_upstream_param_t    *src, *s;
1614     ngx_http_script_compile_t     sc;
1615     ngx_http_script_copy_code_t  *copy;
1616 
1617     if (params->hash.buckets) {
1618         return NGX_OK;
1619     }
1620 
1621     if (conf->params_source == NULL && default_params == NULL) {
1622         params->hash.buckets = (void *) 1;
1623         return NGX_OK;
1624     }
1625 
1626     params->lengths = ngx_array_create(cf->pool, 64, 1);
1627     if (params->lengths == NULL) {
1628         return NGX_ERROR;
1629     }
1630 
1631     params->values = ngx_array_create(cf->pool, 512, 1);
1632     if (params->values == NULL) {
1633         return NGX_ERROR;
1634     }
1635 
1636     if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
1637         != NGX_OK)
1638     {
1639         return NGX_ERROR;
1640     }
1641 
1642     if (conf->params_source) {
1643         src = conf->params_source->elts;
1644         nsrc = conf->params_source->nelts;
1645 
1646     } else {
1647         src = NULL;
1648         nsrc = 0;
1649     }
1650 
1651     if (default_params) {
1652         if (ngx_array_init(&params_merged, cf->temp_pool, 4,
1653                            sizeof(ngx_http_upstream_param_t))
1654             != NGX_OK)
1655         {
1656             return NGX_ERROR;
1657         }
1658 
1659         for (i = 0; i < nsrc; i++) {
1660 
1661             s = ngx_array_push(&params_merged);
1662             if (s == NULL) {
1663                 return NGX_ERROR;
1664             }
1665 
1666             *s = src[i];
1667         }
1668 
1669         h = default_params;
1670 
1671         while (h->key.len) {
1672 
1673             src = params_merged.elts;
1674             nsrc = params_merged.nelts;
1675 
1676             for (i = 0; i < nsrc; i++) {
1677                 if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
1678                     goto next;
1679                 }
1680             }
1681 
1682             s = ngx_array_push(&params_merged);
1683             if (s == NULL) {
1684                 return NGX_ERROR;
1685             }
1686 
1687             s->key = h->key;
1688             s->value = h->value;
1689             s->skip_empty = 1;
1690 
1691         next:
1692 
1693             h++;
1694         }
1695 
1696         src = params_merged.elts;
1697         nsrc = params_merged.nelts;
1698     }
1699 
1700     for (i = 0; i < nsrc; i++) {
1701 
1702         if (src[i].key.len > sizeof("HTTP_") - 1
1703             && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0)
1704         {
1705             hk = ngx_array_push(&headers_names);
1706             if (hk == NULL) {
1707                 return NGX_ERROR;
1708             }
1709 
1710             hk->key.len = src[i].key.len - 5;
1711             hk->key.data = src[i].key.data + 5;
1712             hk->key_hash = ngx_hash_key_lc(hk->key.data, hk->key.len);
1713             hk->value = (void *) 1;
1714 
1715             if (src[i].value.len == 0) {
1716                 continue;
1717             }
1718         }
1719 
1720         copy = ngx_array_push_n(params->lengths,
1721                                 sizeof(ngx_http_script_copy_code_t));
1722         if (copy == NULL) {
1723             return NGX_ERROR;
1724         }
1725 
1726         copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
1727         copy->len = src[i].key.len + 1;
1728 
1729         copy = ngx_array_push_n(params->lengths,
1730                                 sizeof(ngx_http_script_copy_code_t));
1731         if (copy == NULL) {
1732             return NGX_ERROR;
1733         }
1734 
1735         copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
1736         copy->len = src[i].skip_empty;
1737 
1738 
1739         size = (sizeof(ngx_http_script_copy_code_t)
1740                 + src[i].key.len + 1 + sizeof(uintptr_t) - 1)
1741                & ~(sizeof(uintptr_t) - 1);
1742 
1743         copy = ngx_array_push_n(params->values, size);
1744         if (copy == NULL) {
1745             return NGX_ERROR;
1746         }
1747 
1748         copy->code = ngx_http_script_copy_code;
1749         copy->len = src[i].key.len + 1;
1750 
1751         p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
1752         (void) ngx_cpystrn(p, src[i].key.data, src[i].key.len + 1);
1753 
1754 
1755         ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
1756 
1757         sc.cf = cf;
1758         sc.source = &src[i].value;
1759         sc.flushes = &params->flushes;
1760         sc.lengths = &params->lengths;
1761         sc.values = &params->values;
1762 
1763         if (ngx_http_script_compile(&sc) != NGX_OK) {
1764             return NGX_ERROR;
1765         }
1766 
1767         code = ngx_array_push_n(params->lengths, sizeof(uintptr_t));
1768         if (code == NULL) {
1769             return NGX_ERROR;
1770         }
1771 
1772         *code = (uintptr_t) NULL;
1773 
1774 
1775         code = ngx_array_push_n(params->values, sizeof(uintptr_t));
1776         if (code == NULL) {
1777             return NGX_ERROR;
1778         }
1779 
1780         *code = (uintptr_t) NULL;
1781     }
1782 
1783     code = ngx_array_push_n(params->lengths, sizeof(uintptr_t));
1784     if (code == NULL) {
1785         return NGX_ERROR;
1786     }
1787 
1788     *code = (uintptr_t) NULL;
1789 
1790     params->number = headers_names.nelts;
1791 
1792     hash.hash = &params->hash;
1793     hash.key = ngx_hash_key_lc;
1794     hash.max_size = 512;
1795     hash.bucket_size = 64;
1796     hash.name = "scgi_params_hash";
1797     hash.pool = cf->pool;
1798     hash.temp_pool = NULL;
1799 
1800     return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
1801 }
1802 
1803 
1804 static char *
1805 ngx_http_scgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1806 {
1807     ngx_http_scgi_loc_conf_t *scf = conf;
1808 
1809     ngx_url_t                   u;
1810     ngx_str_t                  *value, *url;
1811     ngx_uint_t                  n;
1812     ngx_http_core_loc_conf_t   *clcf;
1813     ngx_http_script_compile_t   sc;
1814 
1815     if (scf->upstream.upstream || scf->scgi_lengths) {
1816         return "is duplicate";
1817     }
1818 
1819     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
1820     clcf->handler = ngx_http_scgi_handler;
1821 
1822     value = cf->args->elts;
1823 
1824     url = &value[1];
1825 
1826     n = ngx_http_script_variables_count(url);
1827 
1828     if (n) {
1829 
1830         ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
1831 
1832         sc.cf = cf;
1833         sc.source = url;
1834         sc.lengths = &scf->scgi_lengths;
1835         sc.values = &scf->scgi_values;
1836         sc.variables = n;
1837         sc.complete_lengths = 1;
1838         sc.complete_values = 1;
1839 
1840         if (ngx_http_script_compile(&sc) != NGX_OK) {
1841             return NGX_CONF_ERROR;
1842         }
1843 
1844         return NGX_CONF_OK;
1845     }
1846 
1847     ngx_memzero(&u, sizeof(ngx_url_t));
1848 
1849     u.url = value[1];
1850     u.no_resolve = 1;
1851 
1852     scf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
1853     if (scf->upstream.upstream == NULL) {
1854         return NGX_CONF_ERROR;
1855     }
1856 
1857     if (clcf->name.data[clcf->name.len - 1] == '/') {
1858         clcf->auto_redirect = 1;
1859     }
1860 
1861     return NGX_CONF_OK;
1862 }
1863 
1864 
1865 static char *
1866 ngx_http_scgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1867 {
1868     ngx_http_scgi_loc_conf_t *scf = conf;
1869 
1870     ngx_str_t                  *value;
1871     ngx_http_script_compile_t   sc;
1872 
1873     if (scf->upstream.store != NGX_CONF_UNSET) {
1874         return "is duplicate";
1875     }
1876 
1877     value = cf->args->elts;
1878 
1879     if (ngx_strcmp(value[1].data, "off") == 0) {
1880         scf->upstream.store = 0;
1881         return NGX_CONF_OK;
1882     }
1883 
1884 #if (NGX_HTTP_CACHE)
1885     if (scf->upstream.cache > 0) {
1886         return "is incompatible with \"scgi_cache\"";
1887     }
1888 #endif
1889 
1890     scf->upstream.store = 1;
1891 
1892     if (ngx_strcmp(value[1].data, "on") == 0) {
1893         return NGX_CONF_OK;
1894     }
1895 
1896     /* include the terminating '\0' into script */
1897     value[1].len++;
1898 
1899     ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
1900 
1901     sc.cf = cf;
1902     sc.source = &value[1];
1903     sc.lengths = &scf->upstream.store_lengths;
1904     sc.values = &scf->upstream.store_values;
1905     sc.variables = ngx_http_script_variables_count(&value[1]);
1906     sc.complete_lengths = 1;
1907     sc.complete_values = 1;
1908 
1909     if (ngx_http_script_compile(&sc) != NGX_OK) {
1910         return NGX_CONF_ERROR;
1911     }
1912 
1913     return NGX_CONF_OK;
1914 }
1915 
1916 
1917 #if (NGX_HTTP_CACHE)
1918 
1919 static char *
1920 ngx_http_scgi_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1921 {
1922     ngx_http_scgi_loc_conf_t *scf = conf;
1923 
1924     ngx_str_t                         *value;
1925     ngx_http_complex_value_t           cv;
1926     ngx_http_compile_complex_value_t   ccv;
1927 
1928     value = cf->args->elts;
1929 
1930     if (scf->upstream.cache != NGX_CONF_UNSET) {
1931         return "is duplicate";
1932     }
1933 
1934     if (ngx_strcmp(value[1].data, "off") == 0) {
1935         scf->upstream.cache = 0;
1936         return NGX_CONF_OK;
1937     }
1938 
1939     if (scf->upstream.store > 0) {
1940         return "is incompatible with \"scgi_store\"";
1941     }
1942 
1943     scf->upstream.cache = 1;
1944 
1945     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
1946 
1947     ccv.cf = cf;
1948     ccv.value = &value[1];
1949     ccv.complex_value = &cv;
1950 
1951     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
1952         return NGX_CONF_ERROR;
1953     }
1954 
1955     if (cv.lengths != NULL) {
1956 
1957         scf->upstream.cache_value = ngx_palloc(cf->pool,
1958                                              sizeof(ngx_http_complex_value_t));
1959         if (scf->upstream.cache_value == NULL) {
1960             return NGX_CONF_ERROR;
1961         }
1962 
1963         *scf->upstream.cache_value = cv;
1964 
1965         return NGX_CONF_OK;
1966     }
1967 
1968     scf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0,
1969                                                      &ngx_http_scgi_module);
1970     if (scf->upstream.cache_zone == NULL) {
1971         return NGX_CONF_ERROR;
1972     }
1973 
1974     return NGX_CONF_OK;
1975 }
1976 
1977 
1978 static char *
1979 ngx_http_scgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1980 {
1981     ngx_http_scgi_loc_conf_t *scf = conf;
1982 
1983     ngx_str_t                         *value;
1984     ngx_http_compile_complex_value_t   ccv;
1985 
1986     value = cf->args->elts;
1987 
1988     if (scf->cache_key.value.data) {
1989         return "is duplicate";
1990     }
1991 
1992     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
1993 
1994     ccv.cf = cf;
1995     ccv.value = &value[1];
1996     ccv.complex_value = &scf->cache_key;
1997 
1998     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
1999         return NGX_CONF_ERROR;
2000     }
2001 
2002     return NGX_CONF_OK;
2003 }
2004 
2005 #endif