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                 h->hash = 0;
1044                 return NGX_ERROR;
1045             }
1046 
1047             h->value.data = h->key.data + h->key.len + 1;
1048             h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;
1049 
1050             ngx_memcpy(h->key.data, r->header_name_start, h->key.len);
1051             h->key.data[h->key.len] = '\0';
1052             ngx_memcpy(h->value.data, r->header_start, h->value.len);
1053             h->value.data[h->value.len] = '\0';
1054 
1055             if (h->key.len == r->lowcase_index) {
1056                 ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
1057 
1058             } else {
1059                 ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
1060             }
1061 
1062             hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
1063                                h->lowcase_key, h->key.len);
1064 
1065             if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1066                 return NGX_ERROR;
1067             }
1068 
1069             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1070                            "http scgi header: \"%V: %V\"", &h->key, &h->value);
1071 
1072             continue;
1073         }
1074 
1075         if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
1076 
1077             /* a whole header has been parsed successfully */
1078 
1079             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1080                            "http scgi header done");
1081 
1082             u = r->upstream;
1083 
1084             if (u->headers_in.status_n) {
1085                 goto done;
1086             }
1087 
1088             if (u->headers_in.status) {
1089                 status_line = &u->headers_in.status->value;
1090 
1091                 status = ngx_atoi(status_line->data, 3);
1092                 if (status == NGX_ERROR) {
1093                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1094                                   "upstream sent invalid status \"%V\"",
1095                                   status_line);
1096                     return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1097                 }
1098 
1099                 u->headers_in.status_n = status;
1100                 u->headers_in.status_line = *status_line;
1101 
1102             } else if (u->headers_in.location) {
1103                 u->headers_in.status_n = 302;
1104                 ngx_str_set(&u->headers_in.status_line,
1105                             "302 Moved Temporarily");
1106 
1107             } else {
1108                 u->headers_in.status_n = 200;
1109                 ngx_str_set(&u->headers_in.status_line, "200 OK");
1110             }
1111 
1112             if (u->state && u->state->status == 0) {
1113                 u->state->status = u->headers_in.status_n;
1114             }
1115 
1116         done:
1117 
1118             if (u->headers_in.status_n == NGX_HTTP_SWITCHING_PROTOCOLS
1119                 && r->headers_in.upgrade)
1120             {
1121                 u->upgrade = 1;
1122             }
1123 
1124             return NGX_OK;
1125         }
1126 
1127         if (rc == NGX_AGAIN) {
1128             return NGX_AGAIN;
1129         }
1130 
1131         /* there was error while a header line parsing */
1132 
1133         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1134                       "upstream sent invalid header");
1135 
1136         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
1137     }
1138 }
1139 
1140 
1141 static void
1142 ngx_http_scgi_abort_request(ngx_http_request_t *r)
1143 {
1144     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1145                    "abort http scgi request");
1146 
1147     return;
1148 }
1149 
1150 
1151 static void
1152 ngx_http_scgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
1153 {
1154     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1155                    "finalize http scgi request");
1156 
1157     return;
1158 }
1159 
1160 
1161 static void *
1162 ngx_http_scgi_create_main_conf(ngx_conf_t *cf)
1163 {
1164     ngx_http_scgi_main_conf_t  *conf;
1165 
1166     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_scgi_main_conf_t));
1167     if (conf == NULL) {
1168         return NULL;
1169     }
1170 
1171 #if (NGX_HTTP_CACHE)
1172     if (ngx_array_init(&conf->caches, cf->pool, 4,
1173                        sizeof(ngx_http_file_cache_t *))
1174         != NGX_OK)
1175     {
1176         return NULL;
1177     }
1178 #endif
1179 
1180     return conf;
1181 }
1182 
1183 
1184 static void *
1185 ngx_http_scgi_create_loc_conf(ngx_conf_t *cf)
1186 {
1187     ngx_http_scgi_loc_conf_t  *conf;
1188 
1189     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_scgi_loc_conf_t));
1190     if (conf == NULL) {
1191         return NULL;
1192     }
1193 
1194     conf->upstream.store = NGX_CONF_UNSET;
1195     conf->upstream.store_access = NGX_CONF_UNSET_UINT;
1196     conf->upstream.next_upstream_tries = NGX_CONF_UNSET_UINT;
1197     conf->upstream.buffering = NGX_CONF_UNSET;
1198     conf->upstream.request_buffering = NGX_CONF_UNSET;
1199     conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
1200     conf->upstream.force_ranges = NGX_CONF_UNSET;
1201 
1202     conf->upstream.local = NGX_CONF_UNSET_PTR;
1203 
1204     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
1205     conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
1206     conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
1207     conf->upstream.next_upstream_timeout = NGX_CONF_UNSET_MSEC;
1208 
1209     conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
1210     conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
1211     conf->upstream.limit_rate = NGX_CONF_UNSET_SIZE;
1212 
1213     conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
1214     conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
1215     conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;
1216 
1217     conf->upstream.pass_request_headers = NGX_CONF_UNSET;
1218     conf->upstream.pass_request_body = NGX_CONF_UNSET;
1219 
1220 #if (NGX_HTTP_CACHE)
1221     conf->upstream.cache = NGX_CONF_UNSET;
1222     conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
1223     conf->upstream.cache_max_range_offset = NGX_CONF_UNSET;
1224     conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
1225     conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
1226     conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
1227     conf->upstream.cache_lock = NGX_CONF_UNSET;
1228     conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
1229     conf->upstream.cache_lock_age = NGX_CONF_UNSET_MSEC;
1230     conf->upstream.cache_revalidate = NGX_CONF_UNSET;
1231     conf->upstream.cache_background_update = NGX_CONF_UNSET;
1232 #endif
1233 
1234     conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
1235     conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
1236 
1237     conf->upstream.intercept_errors = NGX_CONF_UNSET;
1238 
1239     /* "scgi_cyclic_temp_file" is disabled */
1240     conf->upstream.cyclic_temp_file = 0;
1241 
1242     conf->upstream.change_buffering = 1;
1243 
1244     ngx_str_set(&conf->upstream.module, "scgi");
1245 
1246     return conf;
1247 }
1248 
1249 
1250 static char *
1251 ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
1252 {
1253     ngx_http_scgi_loc_conf_t *prev = parent;
1254     ngx_http_scgi_loc_conf_t *conf = child;
1255 
1256     size_t                        size;
1257     ngx_int_t                     rc;
1258     ngx_hash_init_t               hash;
1259     ngx_http_core_loc_conf_t     *clcf;
1260 
1261 #if (NGX_HTTP_CACHE)
1262 
1263     if (conf->upstream.store > 0) {
1264         conf->upstream.cache = 0;
1265     }
1266 
1267     if (conf->upstream.cache > 0) {
1268         conf->upstream.store = 0;
1269     }
1270 
1271 #endif
1272 
1273     if (conf->upstream.store == NGX_CONF_UNSET) {
1274         ngx_conf_merge_value(conf->upstream.store, prev->upstream.store, 0);
1275 
1276         conf->upstream.store_lengths = prev->upstream.store_lengths;
1277         conf->upstream.store_values = prev->upstream.store_values;
1278     }
1279 
1280     ngx_conf_merge_uint_value(conf->upstream.store_access,
1281                               prev->upstream.store_access, 0600);
1282 
1283     ngx_conf_merge_uint_value(conf->upstream.next_upstream_tries,
1284                               prev->upstream.next_upstream_tries, 0);
1285 
1286     ngx_conf_merge_value(conf->upstream.buffering,
1287                               prev->upstream.buffering, 1);
1288 
1289     ngx_conf_merge_value(conf->upstream.request_buffering,
1290                               prev->upstream.request_buffering, 1);
1291 
1292     ngx_conf_merge_value(conf->upstream.ignore_client_abort,
1293                               prev->upstream.ignore_client_abort, 0);
1294 
1295     ngx_conf_merge_value(conf->upstream.force_ranges,
1296                               prev->upstream.force_ranges, 0);
1297 
1298     ngx_conf_merge_ptr_value(conf->upstream.local,
1299                               prev->upstream.local, NULL);
1300 
1301     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
1302                               prev->upstream.connect_timeout, 60000);
1303 
1304     ngx_conf_merge_msec_value(conf->upstream.send_timeout,
1305                               prev->upstream.send_timeout, 60000);
1306 
1307     ngx_conf_merge_msec_value(conf->upstream.read_timeout,
1308                               prev->upstream.read_timeout, 60000);
1309 
1310     ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
1311                               prev->upstream.next_upstream_timeout, 0);
1312 
1313     ngx_conf_merge_size_value(conf->upstream.send_lowat,
1314                               prev->upstream.send_lowat, 0);
1315 
1316     ngx_conf_merge_size_value(conf->upstream.buffer_size,
1317                               prev->upstream.buffer_size,
1318                               (size_t) ngx_pagesize);
1319 
1320     ngx_conf_merge_size_value(conf->upstream.limit_rate,
1321                               prev->upstream.limit_rate, 0);
1322 
1323 
1324     ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
1325                               8, ngx_pagesize);
1326 
1327     if (conf->upstream.bufs.num < 2) {
1328         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1329                            "there must be at least 2 \"scgi_buffers\"");
1330         return NGX_CONF_ERROR;
1331     }
1332 
1333 
1334     size = conf->upstream.buffer_size;
1335     if (size < conf->upstream.bufs.size) {
1336         size = conf->upstream.bufs.size;
1337     }
1338 
1339 
1340     ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
1341                               prev->upstream.busy_buffers_size_conf,
1342                               NGX_CONF_UNSET_SIZE);
1343 
1344     if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
1345         conf->upstream.busy_buffers_size = 2 * size;
1346     } else {
1347         conf->upstream.busy_buffers_size =
1348             conf->upstream.busy_buffers_size_conf;
1349     }
1350 
1351     if (conf->upstream.busy_buffers_size < size) {
1352         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1353             "\"scgi_busy_buffers_size\" must be equal to or greater "
1354             "than the maximum of the value of \"scgi_buffer_size\" and "
1355             "one of the \"scgi_buffers\"");
1356 
1357         return NGX_CONF_ERROR;
1358     }
1359 
1360     if (conf->upstream.busy_buffers_size
1361         > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
1362     {
1363         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1364             "\"scgi_busy_buffers_size\" must be less than "
1365             "the size of all \"scgi_buffers\" minus one buffer");
1366 
1367         return NGX_CONF_ERROR;
1368     }
1369 
1370 
1371     ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf,
1372                               prev->upstream.temp_file_write_size_conf,
1373                               NGX_CONF_UNSET_SIZE);
1374 
1375     if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
1376         conf->upstream.temp_file_write_size = 2 * size;
1377     } else {
1378         conf->upstream.temp_file_write_size =
1379             conf->upstream.temp_file_write_size_conf;
1380     }
1381 
1382     if (conf->upstream.temp_file_write_size < size) {
1383         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1384             "\"scgi_temp_file_write_size\" must be equal to or greater than "
1385             "the maximum of the value of \"scgi_buffer_size\" and "
1386             "one of the \"scgi_buffers\"");
1387 
1388         return NGX_CONF_ERROR;
1389     }
1390 
1391 
1392     ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf,
1393                               prev->upstream.max_temp_file_size_conf,
1394                               NGX_CONF_UNSET_SIZE);
1395 
1396     if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
1397         conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
1398     } else {
1399         conf->upstream.max_temp_file_size =
1400             conf->upstream.max_temp_file_size_conf;
1401     }
1402 
1403     if (conf->upstream.max_temp_file_size != 0
1404         && conf->upstream.max_temp_file_size < size)
1405     {
1406         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1407             "\"scgi_max_temp_file_size\" must be equal to zero to disable "
1408             "temporary files usage or must be equal to or greater than "
1409             "the maximum of the value of \"scgi_buffer_size\" and "
1410             "one of the \"scgi_buffers\"");
1411 
1412         return NGX_CONF_ERROR;
1413     }
1414 
1415 
1416     ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
1417                                  prev->upstream.ignore_headers,
1418                                  NGX_CONF_BITMASK_SET);
1419 
1420 
1421     ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
1422                                  prev->upstream.next_upstream,
1423                                  (NGX_CONF_BITMASK_SET
1424                                   |NGX_HTTP_UPSTREAM_FT_ERROR
1425                                   |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
1426 
1427     if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
1428         conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
1429                                        |NGX_HTTP_UPSTREAM_FT_OFF;
1430     }
1431 
1432     if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
1433                                   prev->upstream.temp_path,
1434                                   &ngx_http_scgi_temp_path)
1435         != NGX_OK)
1436     {
1437         return NGX_CONF_ERROR;
1438     }
1439 
1440 #if (NGX_HTTP_CACHE)
1441 
1442     if (conf->upstream.cache == NGX_CONF_UNSET) {
1443         ngx_conf_merge_value(conf->upstream.cache,
1444                               prev->upstream.cache, 0);
1445 
1446         conf->upstream.cache_zone = prev->upstream.cache_zone;
1447         conf->upstream.cache_value = prev->upstream.cache_value;
1448     }
1449 
1450     if (conf->upstream.cache_zone && conf->upstream.cache_zone->data == NULL) {
1451         ngx_shm_zone_t  *shm_zone;
1452 
1453         shm_zone = conf->upstream.cache_zone;
1454 
1455         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1456                            "\"scgi_cache\" zone \"%V\" is unknown",
1457                            &shm_zone->shm.name);
1458 
1459         return NGX_CONF_ERROR;
1460     }
1461 
1462     ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
1463                               prev->upstream.cache_min_uses, 1);
1464 
1465     ngx_conf_merge_off_value(conf->upstream.cache_max_range_offset,
1466                               prev->upstream.cache_max_range_offset,
1467                               NGX_MAX_OFF_T_VALUE);
1468 
1469     ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
1470                               prev->upstream.cache_use_stale,
1471                               (NGX_CONF_BITMASK_SET
1472                                |NGX_HTTP_UPSTREAM_FT_OFF));
1473 
1474     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
1475         conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
1476                                          |NGX_HTTP_UPSTREAM_FT_OFF;
1477     }
1478 
1479     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
1480         conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
1481     }
1482 
1483     if (conf->upstream.cache_methods == 0) {
1484         conf->upstream.cache_methods = prev->upstream.cache_methods;
1485     }
1486 
1487     conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD;
1488 
1489     ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
1490                              prev->upstream.cache_bypass, NULL);
1491 
1492     ngx_conf_merge_ptr_value(conf->upstream.no_cache,
1493                              prev->upstream.no_cache, NULL);
1494 
1495     ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
1496                              prev->upstream.cache_valid, NULL);
1497 
1498     if (conf->cache_key.value.data == NULL) {
1499         conf->cache_key = prev->cache_key;
1500     }
1501 
1502     if (conf->upstream.cache && conf->cache_key.value.data == NULL) {
1503         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
1504                            "no \"scgi_cache_key\" for \"scgi_cache\"");
1505     }
1506 
1507     ngx_conf_merge_value(conf->upstream.cache_lock,
1508                               prev->upstream.cache_lock, 0);
1509 
1510     ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
1511                               prev->upstream.cache_lock_timeout, 5000);
1512 
1513     ngx_conf_merge_msec_value(conf->upstream.cache_lock_age,
1514                               prev->upstream.cache_lock_age, 5000);
1515 
1516     ngx_conf_merge_value(conf->upstream.cache_revalidate,
1517                               prev->upstream.cache_revalidate, 0);
1518 
1519     ngx_conf_merge_value(conf->upstream.cache_background_update,
1520                               prev->upstream.cache_background_update, 0);
1521 
1522 #endif
1523 
1524     ngx_conf_merge_value(conf->upstream.pass_request_headers,
1525                          prev->upstream.pass_request_headers, 1);
1526     ngx_conf_merge_value(conf->upstream.pass_request_body,
1527                          prev->upstream.pass_request_body, 1);
1528 
1529     ngx_conf_merge_value(conf->upstream.intercept_errors,
1530                          prev->upstream.intercept_errors, 0);
1531 
1532     hash.max_size = 512;
1533     hash.bucket_size = ngx_align(64, ngx_cacheline_size);
1534     hash.name = "scgi_hide_headers_hash";
1535 
1536     if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
1537             &prev->upstream, ngx_http_scgi_hide_headers, &hash)
1538         != NGX_OK)
1539     {
1540         return NGX_CONF_ERROR;
1541     }
1542 
1543     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
1544 
1545     if (clcf->noname
1546         && conf->upstream.upstream == NULL && conf->scgi_lengths == NULL)
1547     {
1548         conf->upstream.upstream = prev->upstream.upstream;
1549         conf->scgi_lengths = prev->scgi_lengths;
1550         conf->scgi_values = prev->scgi_values;
1551     }
1552 
1553     if (clcf->lmt_excpt && clcf->handler == NULL
1554         && (conf->upstream.upstream || conf->scgi_lengths))
1555     {
1556         clcf->handler = ngx_http_scgi_handler;
1557     }
1558 
1559     if (conf->params_source == NULL) {
1560         conf->params = prev->params;
1561 #if (NGX_HTTP_CACHE)
1562         conf->params_cache = prev->params_cache;
1563 #endif
1564         conf->params_source = prev->params_source;
1565     }
1566 
1567     rc = ngx_http_scgi_init_params(cf, conf, &conf->params, NULL);
1568     if (rc != NGX_OK) {
1569         return NGX_CONF_ERROR;
1570     }
1571 
1572 #if (NGX_HTTP_CACHE)
1573 
1574     if (conf->upstream.cache) {
1575         rc = ngx_http_scgi_init_params(cf, conf, &conf->params_cache,
1576                                        ngx_http_scgi_cache_headers);
1577         if (rc != NGX_OK) {
1578             return NGX_CONF_ERROR;
1579         }
1580     }
1581 
1582 #endif
1583 
1584     /*
1585      * special handling to preserve conf->params in the "http" section
1586      * to inherit it to all servers
1587      */
1588 
1589     if (prev->params.hash.buckets == NULL
1590         && conf->params_source == prev->params_source)
1591     {
1592         prev->params = conf->params;
1593 #if (NGX_HTTP_CACHE)
1594         prev->params_cache = conf->params_cache;
1595 #endif
1596     }
1597 
1598     return NGX_CONF_OK;
1599 }
1600 
1601 
1602 static ngx_int_t
1603 ngx_http_scgi_init_params(ngx_conf_t *cf, ngx_http_scgi_loc_conf_t *conf,
1604     ngx_http_scgi_params_t *params, ngx_keyval_t *default_params)
1605 {
1606     u_char                       *p;
1607     size_t                        size;
1608     uintptr_t                    *code;
1609     ngx_uint_t                    i, nsrc;
1610     ngx_array_t                   headers_names, params_merged;
1611     ngx_keyval_t                 *h;
1612     ngx_hash_key_t               *hk;
1613     ngx_hash_init_t               hash;
1614     ngx_http_upstream_param_t    *src, *s;
1615     ngx_http_script_compile_t     sc;
1616     ngx_http_script_copy_code_t  *copy;
1617 
1618     if (params->hash.buckets) {
1619         return NGX_OK;
1620     }
1621 
1622     if (conf->params_source == NULL && default_params == NULL) {
1623         params->hash.buckets = (void *) 1;
1624         return NGX_OK;
1625     }
1626 
1627     params->lengths = ngx_array_create(cf->pool, 64, 1);
1628     if (params->lengths == NULL) {
1629         return NGX_ERROR;
1630     }
1631 
1632     params->values = ngx_array_create(cf->pool, 512, 1);
1633     if (params->values == NULL) {
1634         return NGX_ERROR;
1635     }
1636 
1637     if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
1638         != NGX_OK)
1639     {
1640         return NGX_ERROR;
1641     }
1642 
1643     if (conf->params_source) {
1644         src = conf->params_source->elts;
1645         nsrc = conf->params_source->nelts;
1646 
1647     } else {
1648         src = NULL;
1649         nsrc = 0;
1650     }
1651 
1652     if (default_params) {
1653         if (ngx_array_init(&params_merged, cf->temp_pool, 4,
1654                            sizeof(ngx_http_upstream_param_t))
1655             != NGX_OK)
1656         {
1657             return NGX_ERROR;
1658         }
1659 
1660         for (i = 0; i < nsrc; i++) {
1661 
1662             s = ngx_array_push(&params_merged);
1663             if (s == NULL) {
1664                 return NGX_ERROR;
1665             }
1666 
1667             *s = src[i];
1668         }
1669 
1670         h = default_params;
1671 
1672         while (h->key.len) {
1673 
1674             src = params_merged.elts;
1675             nsrc = params_merged.nelts;
1676 
1677             for (i = 0; i < nsrc; i++) {
1678                 if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
1679                     goto next;
1680                 }
1681             }
1682 
1683             s = ngx_array_push(&params_merged);
1684             if (s == NULL) {
1685                 return NGX_ERROR;
1686             }
1687 
1688             s->key = h->key;
1689             s->value = h->value;
1690             s->skip_empty = 1;
1691 
1692         next:
1693 
1694             h++;
1695         }
1696 
1697         src = params_merged.elts;
1698         nsrc = params_merged.nelts;
1699     }
1700 
1701     for (i = 0; i < nsrc; i++) {
1702 
1703         if (src[i].key.len > sizeof("HTTP_") - 1
1704             && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0)
1705         {
1706             hk = ngx_array_push(&headers_names);
1707             if (hk == NULL) {
1708                 return NGX_ERROR;
1709             }
1710 
1711             hk->key.len = src[i].key.len - 5;
1712             hk->key.data = src[i].key.data + 5;
1713             hk->key_hash = ngx_hash_key_lc(hk->key.data, hk->key.len);
1714             hk->value = (void *) 1;
1715 
1716             if (src[i].value.len == 0) {
1717                 continue;
1718             }
1719         }
1720 
1721         copy = ngx_array_push_n(params->lengths,
1722                                 sizeof(ngx_http_script_copy_code_t));
1723         if (copy == NULL) {
1724             return NGX_ERROR;
1725         }
1726 
1727         copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
1728         copy->len = src[i].key.len + 1;
1729 
1730         copy = ngx_array_push_n(params->lengths,
1731                                 sizeof(ngx_http_script_copy_code_t));
1732         if (copy == NULL) {
1733             return NGX_ERROR;
1734         }
1735 
1736         copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
1737         copy->len = src[i].skip_empty;
1738 
1739 
1740         size = (sizeof(ngx_http_script_copy_code_t)
1741                 + src[i].key.len + 1 + sizeof(uintptr_t) - 1)
1742                & ~(sizeof(uintptr_t) - 1);
1743 
1744         copy = ngx_array_push_n(params->values, size);
1745         if (copy == NULL) {
1746             return NGX_ERROR;
1747         }
1748 
1749         copy->code = ngx_http_script_copy_code;
1750         copy->len = src[i].key.len + 1;
1751 
1752         p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
1753         (void) ngx_cpystrn(p, src[i].key.data, src[i].key.len + 1);
1754 
1755 
1756         ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
1757 
1758         sc.cf = cf;
1759         sc.source = &src[i].value;
1760         sc.flushes = &params->flushes;
1761         sc.lengths = &params->lengths;
1762         sc.values = &params->values;
1763 
1764         if (ngx_http_script_compile(&sc) != NGX_OK) {
1765             return NGX_ERROR;
1766         }
1767 
1768         code = ngx_array_push_n(params->lengths, sizeof(uintptr_t));
1769         if (code == NULL) {
1770             return NGX_ERROR;
1771         }
1772 
1773         *code = (uintptr_t) NULL;
1774 
1775 
1776         code = ngx_array_push_n(params->values, sizeof(uintptr_t));
1777         if (code == NULL) {
1778             return NGX_ERROR;
1779         }
1780 
1781         *code = (uintptr_t) NULL;
1782     }
1783 
1784     code = ngx_array_push_n(params->lengths, sizeof(uintptr_t));
1785     if (code == NULL) {
1786         return NGX_ERROR;
1787     }
1788 
1789     *code = (uintptr_t) NULL;
1790 
1791     params->number = headers_names.nelts;
1792 
1793     hash.hash = &params->hash;
1794     hash.key = ngx_hash_key_lc;
1795     hash.max_size = 512;
1796     hash.bucket_size = 64;
1797     hash.name = "scgi_params_hash";
1798     hash.pool = cf->pool;
1799     hash.temp_pool = NULL;
1800 
1801     return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
1802 }
1803 
1804 
1805 static char *
1806 ngx_http_scgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1807 {
1808     ngx_http_scgi_loc_conf_t *scf = conf;
1809 
1810     ngx_url_t                   u;
1811     ngx_str_t                  *value, *url;
1812     ngx_uint_t                  n;
1813     ngx_http_core_loc_conf_t   *clcf;
1814     ngx_http_script_compile_t   sc;
1815 
1816     if (scf->upstream.upstream || scf->scgi_lengths) {
1817         return "is duplicate";
1818     }
1819 
1820     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
1821     clcf->handler = ngx_http_scgi_handler;
1822 
1823     value = cf->args->elts;
1824 
1825     url = &value[1];
1826 
1827     n = ngx_http_script_variables_count(url);
1828 
1829     if (n) {
1830 
1831         ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
1832 
1833         sc.cf = cf;
1834         sc.source = url;
1835         sc.lengths = &scf->scgi_lengths;
1836         sc.values = &scf->scgi_values;
1837         sc.variables = n;
1838         sc.complete_lengths = 1;
1839         sc.complete_values = 1;
1840 
1841         if (ngx_http_script_compile(&sc) != NGX_OK) {
1842             return NGX_CONF_ERROR;
1843         }
1844 
1845         return NGX_CONF_OK;
1846     }
1847 
1848     ngx_memzero(&u, sizeof(ngx_url_t));
1849 
1850     u.url = value[1];
1851     u.no_resolve = 1;
1852 
1853     scf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
1854     if (scf->upstream.upstream == NULL) {
1855         return NGX_CONF_ERROR;
1856     }
1857 
1858     if (clcf->name.data[clcf->name.len - 1] == '/') {
1859         clcf->auto_redirect = 1;
1860     }
1861 
1862     return NGX_CONF_OK;
1863 }
1864 
1865 
1866 static char *
1867 ngx_http_scgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1868 {
1869     ngx_http_scgi_loc_conf_t *scf = conf;
1870 
1871     ngx_str_t                  *value;
1872     ngx_http_script_compile_t   sc;
1873 
1874     if (scf->upstream.store != NGX_CONF_UNSET) {
1875         return "is duplicate";
1876     }
1877 
1878     value = cf->args->elts;
1879 
1880     if (ngx_strcmp(value[1].data, "off") == 0) {
1881         scf->upstream.store = 0;
1882         return NGX_CONF_OK;
1883     }
1884 
1885 #if (NGX_HTTP_CACHE)
1886     if (scf->upstream.cache > 0) {
1887         return "is incompatible with \"scgi_cache\"";
1888     }
1889 #endif
1890 
1891     scf->upstream.store = 1;
1892 
1893     if (ngx_strcmp(value[1].data, "on") == 0) {
1894         return NGX_CONF_OK;
1895     }
1896 
1897     /* include the terminating '\0' into script */
1898     value[1].len++;
1899 
1900     ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
1901 
1902     sc.cf = cf;
1903     sc.source = &value[1];
1904     sc.lengths = &scf->upstream.store_lengths;
1905     sc.values = &scf->upstream.store_values;
1906     sc.variables = ngx_http_script_variables_count(&value[1]);
1907     sc.complete_lengths = 1;
1908     sc.complete_values = 1;
1909 
1910     if (ngx_http_script_compile(&sc) != NGX_OK) {
1911         return NGX_CONF_ERROR;
1912     }
1913 
1914     return NGX_CONF_OK;
1915 }
1916 
1917 
1918 #if (NGX_HTTP_CACHE)
1919 
1920 static char *
1921 ngx_http_scgi_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1922 {
1923     ngx_http_scgi_loc_conf_t *scf = conf;
1924 
1925     ngx_str_t                         *value;
1926     ngx_http_complex_value_t           cv;
1927     ngx_http_compile_complex_value_t   ccv;
1928 
1929     value = cf->args->elts;
1930 
1931     if (scf->upstream.cache != NGX_CONF_UNSET) {
1932         return "is duplicate";
1933     }
1934 
1935     if (ngx_strcmp(value[1].data, "off") == 0) {
1936         scf->upstream.cache = 0;
1937         return NGX_CONF_OK;
1938     }
1939 
1940     if (scf->upstream.store > 0) {
1941         return "is incompatible with \"scgi_store\"";
1942     }
1943 
1944     scf->upstream.cache = 1;
1945 
1946     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
1947 
1948     ccv.cf = cf;
1949     ccv.value = &value[1];
1950     ccv.complex_value = &cv;
1951 
1952     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
1953         return NGX_CONF_ERROR;
1954     }
1955 
1956     if (cv.lengths != NULL) {
1957 
1958         scf->upstream.cache_value = ngx_palloc(cf->pool,
1959                                              sizeof(ngx_http_complex_value_t));
1960         if (scf->upstream.cache_value == NULL) {
1961             return NGX_CONF_ERROR;
1962         }
1963 
1964         *scf->upstream.cache_value = cv;
1965 
1966         return NGX_CONF_OK;
1967     }
1968 
1969     scf->upstream.cache_zone = ngx_shared_memory_add(cf, &value[1], 0,
1970                                                      &ngx_http_scgi_module);
1971     if (scf->upstream.cache_zone == NULL) {
1972         return NGX_CONF_ERROR;
1973     }
1974 
1975     return NGX_CONF_OK;
1976 }
1977 
1978 
1979 static char *
1980 ngx_http_scgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1981 {
1982     ngx_http_scgi_loc_conf_t *scf = conf;
1983 
1984     ngx_str_t                         *value;
1985     ngx_http_compile_complex_value_t   ccv;
1986 
1987     value = cf->args->elts;
1988 
1989     if (scf->cache_key.value.data) {
1990         return "is duplicate";
1991     }
1992 
1993     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
1994 
1995     ccv.cf = cf;
1996     ccv.value = &value[1];
1997     ccv.complex_value = &scf->cache_key;
1998 
1999     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
2000         return NGX_CONF_ERROR;
2001     }
2002 
2003     return NGX_CONF_OK;
2004 }
2005 
2006 #endif