Annotation of embedaddon/nginx/src/http/modules/ngx_http_scgi_module.c, revision 1.1.1.1

1.1       misho       1: 
                      2: /*
                      3:  * Copyright (C) Igor Sysoev
                      4:  * Copyright (C) Nginx, Inc.
                      5:  * Copyright (C) Manlio Perillo (manlio.perillo@gmail.com)
                      6:  */
                      7: 
                      8: 
                      9: #include <ngx_config.h>
                     10: #include <ngx_core.h>
                     11: #include <ngx_http.h>
                     12: 
                     13: 
                     14: typedef struct {
                     15:     ngx_http_upstream_conf_t   upstream;
                     16: 
                     17:     ngx_array_t               *flushes;
                     18:     ngx_array_t               *params_len;
                     19:     ngx_array_t               *params;
                     20:     ngx_array_t               *params_source;
                     21: 
                     22:     ngx_hash_t                 headers_hash;
                     23:     ngx_uint_t                 header_params;
                     24: 
                     25:     ngx_array_t               *scgi_lengths;
                     26:     ngx_array_t               *scgi_values;
                     27: 
                     28: #if (NGX_HTTP_CACHE)
                     29:     ngx_http_complex_value_t   cache_key;
                     30: #endif
                     31: } ngx_http_scgi_loc_conf_t;
                     32: 
                     33: 
                     34: static ngx_int_t ngx_http_scgi_eval(ngx_http_request_t *r,
                     35:     ngx_http_scgi_loc_conf_t *scf);
                     36: static ngx_int_t ngx_http_scgi_create_request(ngx_http_request_t *r);
                     37: static ngx_int_t ngx_http_scgi_reinit_request(ngx_http_request_t *r);
                     38: static ngx_int_t ngx_http_scgi_process_status_line(ngx_http_request_t *r);
                     39: static ngx_int_t ngx_http_scgi_process_header(ngx_http_request_t *r);
                     40: static void ngx_http_scgi_abort_request(ngx_http_request_t *r);
                     41: static void ngx_http_scgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc);
                     42: 
                     43: static void *ngx_http_scgi_create_loc_conf(ngx_conf_t *cf);
                     44: static char *ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent,
                     45:     void *child);
                     46: static ngx_int_t ngx_http_scgi_merge_params(ngx_conf_t *cf,
                     47:     ngx_http_scgi_loc_conf_t *conf, ngx_http_scgi_loc_conf_t *prev);
                     48: 
                     49: static char *ngx_http_scgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
                     50: static char *ngx_http_scgi_store(ngx_conf_t *cf, ngx_command_t *cmd,
                     51:     void *conf);
                     52: 
                     53: #if (NGX_HTTP_CACHE)
                     54: static ngx_int_t ngx_http_scgi_create_key(ngx_http_request_t *r);
                     55: static char *ngx_http_scgi_cache(ngx_conf_t *cf, ngx_command_t *cmd,
                     56:     void *conf);
                     57: static char *ngx_http_scgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd,
                     58:     void *conf);
                     59: #endif
                     60: 
                     61: 
                     62: static ngx_conf_bitmask_t ngx_http_scgi_next_upstream_masks[] = {
                     63:     { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
                     64:     { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
                     65:     { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
                     66:     { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
                     67:     { ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
                     68:     { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
                     69:     { ngx_string("updating"), NGX_HTTP_UPSTREAM_FT_UPDATING },
                     70:     { ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
                     71:     { ngx_null_string, 0 }
                     72: };
                     73: 
                     74: 
                     75: ngx_module_t  ngx_http_scgi_module;
                     76: 
                     77: 
                     78: static ngx_command_t ngx_http_scgi_commands[] = {
                     79: 
                     80:     { ngx_string("scgi_pass"),
                     81:       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
                     82:       ngx_http_scgi_pass,
                     83:       NGX_HTTP_LOC_CONF_OFFSET,
                     84:       0,
                     85:       NULL },
                     86: 
                     87:     { ngx_string("scgi_store"),
                     88:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
                     89:       ngx_http_scgi_store,
                     90:       NGX_HTTP_LOC_CONF_OFFSET,
                     91:       0,
                     92:       NULL },
                     93: 
                     94:     { ngx_string("scgi_store_access"),
                     95:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
                     96:       ngx_conf_set_access_slot,
                     97:       NGX_HTTP_LOC_CONF_OFFSET,
                     98:       offsetof(ngx_http_scgi_loc_conf_t, upstream.store_access),
                     99:       NULL },
                    100: 
                    101:     { ngx_string("scgi_buffering"),
                    102:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
                    103:       ngx_conf_set_flag_slot,
                    104:       NGX_HTTP_LOC_CONF_OFFSET,
                    105:       offsetof(ngx_http_scgi_loc_conf_t, upstream.buffering),
                    106:       NULL },
                    107: 
                    108:     { ngx_string("scgi_ignore_client_abort"),
                    109:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
                    110:       ngx_conf_set_flag_slot,
                    111:       NGX_HTTP_LOC_CONF_OFFSET,
                    112:       offsetof(ngx_http_scgi_loc_conf_t, upstream.ignore_client_abort),
                    113:       NULL },
                    114: 
                    115:     { ngx_string("scgi_bind"),
                    116:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
                    117:       ngx_http_upstream_bind_set_slot,
                    118:       NGX_HTTP_LOC_CONF_OFFSET,
                    119:       offsetof(ngx_http_scgi_loc_conf_t, upstream.local),
                    120:       NULL },
                    121: 
                    122:     { ngx_string("scgi_connect_timeout"),
                    123:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
                    124:       ngx_conf_set_msec_slot,
                    125:       NGX_HTTP_LOC_CONF_OFFSET,
                    126:       offsetof(ngx_http_scgi_loc_conf_t, upstream.connect_timeout),
                    127:       NULL },
                    128: 
                    129:     { ngx_string("scgi_send_timeout"),
                    130:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
                    131:       ngx_conf_set_msec_slot,
                    132:       NGX_HTTP_LOC_CONF_OFFSET,
                    133:       offsetof(ngx_http_scgi_loc_conf_t, upstream.send_timeout),
                    134:       NULL },
                    135: 
                    136:     { ngx_string("scgi_buffer_size"),
                    137:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
                    138:       ngx_conf_set_size_slot,
                    139:       NGX_HTTP_LOC_CONF_OFFSET,
                    140:       offsetof(ngx_http_scgi_loc_conf_t, upstream.buffer_size),
                    141:       NULL },
                    142: 
                    143:     { ngx_string("scgi_pass_request_headers"),
                    144:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
                    145:       ngx_conf_set_flag_slot,
                    146:       NGX_HTTP_LOC_CONF_OFFSET,
                    147:       offsetof(ngx_http_scgi_loc_conf_t, upstream.pass_request_headers),
                    148:       NULL },
                    149: 
                    150:     { ngx_string("scgi_pass_request_body"),
                    151:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
                    152:       ngx_conf_set_flag_slot,
                    153:       NGX_HTTP_LOC_CONF_OFFSET,
                    154:       offsetof(ngx_http_scgi_loc_conf_t, upstream.pass_request_body),
                    155:       NULL },
                    156: 
                    157:     { ngx_string("scgi_intercept_errors"),
                    158:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
                    159:       ngx_conf_set_flag_slot,
                    160:       NGX_HTTP_LOC_CONF_OFFSET,
                    161:       offsetof(ngx_http_scgi_loc_conf_t, upstream.intercept_errors),
                    162:       NULL },
                    163: 
                    164:     { ngx_string("scgi_read_timeout"),
                    165:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
                    166:       ngx_conf_set_msec_slot,
                    167:       NGX_HTTP_LOC_CONF_OFFSET,
                    168:       offsetof(ngx_http_scgi_loc_conf_t, upstream.read_timeout),
                    169:       NULL },
                    170: 
                    171:     { ngx_string("scgi_buffers"),
                    172:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
                    173:       ngx_conf_set_bufs_slot,
                    174:       NGX_HTTP_LOC_CONF_OFFSET,
                    175:       offsetof(ngx_http_scgi_loc_conf_t, upstream.bufs),
                    176:       NULL },
                    177: 
                    178:     { ngx_string("scgi_busy_buffers_size"),
                    179:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
                    180:       ngx_conf_set_size_slot,
                    181:       NGX_HTTP_LOC_CONF_OFFSET,
                    182:       offsetof(ngx_http_scgi_loc_conf_t, upstream.busy_buffers_size_conf),
                    183:       NULL },
                    184: 
                    185: #if (NGX_HTTP_CACHE)
                    186: 
                    187:     { ngx_string("scgi_cache"),
                    188:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
                    189:       ngx_http_scgi_cache,
                    190:       NGX_HTTP_LOC_CONF_OFFSET,
                    191:       0,
                    192:       NULL },
                    193: 
                    194:     { ngx_string("scgi_cache_key"),
                    195:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
                    196:       ngx_http_scgi_cache_key,
                    197:       NGX_HTTP_LOC_CONF_OFFSET,
                    198:       0,
                    199:       NULL },
                    200: 
                    201:     { ngx_string("scgi_cache_path"),
                    202:       NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
                    203:       ngx_http_file_cache_set_slot,
                    204:       0,
                    205:       0,
                    206:       &ngx_http_scgi_module },
                    207: 
                    208:     { ngx_string("scgi_cache_bypass"),
                    209:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
                    210:       ngx_http_set_predicate_slot,
                    211:       NGX_HTTP_LOC_CONF_OFFSET,
                    212:       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_bypass),
                    213:       NULL },
                    214: 
                    215:     { ngx_string("scgi_no_cache"),
                    216:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
                    217:       ngx_http_set_predicate_slot,
                    218:       NGX_HTTP_LOC_CONF_OFFSET,
                    219:       offsetof(ngx_http_scgi_loc_conf_t, upstream.no_cache),
                    220:       NULL },
                    221: 
                    222:     { ngx_string("scgi_cache_valid"),
                    223:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
                    224:       ngx_http_file_cache_valid_set_slot,
                    225:       NGX_HTTP_LOC_CONF_OFFSET,
                    226:       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_valid),
                    227:       NULL },
                    228: 
                    229:     { ngx_string("scgi_cache_min_uses"),
                    230:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
                    231:       ngx_conf_set_num_slot,
                    232:       NGX_HTTP_LOC_CONF_OFFSET,
                    233:       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_min_uses),
                    234:       NULL },
                    235: 
                    236:     { ngx_string("scgi_cache_use_stale"),
                    237:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
                    238:       ngx_conf_set_bitmask_slot,
                    239:       NGX_HTTP_LOC_CONF_OFFSET,
                    240:       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_use_stale),
                    241:       &ngx_http_scgi_next_upstream_masks },
                    242: 
                    243:     { ngx_string("scgi_cache_methods"),
                    244:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
                    245:       ngx_conf_set_bitmask_slot,
                    246:       NGX_HTTP_LOC_CONF_OFFSET,
                    247:       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_methods),
                    248:       &ngx_http_upstream_cache_method_mask },
                    249: 
                    250:     { ngx_string("scgi_cache_lock"),
                    251:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
                    252:       ngx_conf_set_flag_slot,
                    253:       NGX_HTTP_LOC_CONF_OFFSET,
                    254:       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_lock),
                    255:       NULL },
                    256: 
                    257:     { ngx_string("scgi_cache_lock_timeout"),
                    258:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
                    259:       ngx_conf_set_msec_slot,
                    260:       NGX_HTTP_LOC_CONF_OFFSET,
                    261:       offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_lock_timeout),
                    262:       NULL },
                    263: 
                    264: #endif
                    265: 
                    266:     { ngx_string("scgi_temp_path"),
                    267:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
                    268:       ngx_conf_set_path_slot,
                    269:       NGX_HTTP_LOC_CONF_OFFSET,
                    270:       offsetof(ngx_http_scgi_loc_conf_t, upstream.temp_path),
                    271:       NULL },
                    272: 
                    273:     { ngx_string("scgi_max_temp_file_size"),
                    274:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
                    275:       ngx_conf_set_size_slot,
                    276:       NGX_HTTP_LOC_CONF_OFFSET,
                    277:       offsetof(ngx_http_scgi_loc_conf_t, upstream.max_temp_file_size_conf),
                    278:       NULL },
                    279: 
                    280:     { ngx_string("scgi_temp_file_write_size"),
                    281:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
                    282:       ngx_conf_set_size_slot,
                    283:       NGX_HTTP_LOC_CONF_OFFSET,
                    284:       offsetof(ngx_http_scgi_loc_conf_t, upstream.temp_file_write_size_conf),
                    285:       NULL },
                    286: 
                    287:     { ngx_string("scgi_next_upstream"),
                    288:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
                    289:       ngx_conf_set_bitmask_slot,
                    290:       NGX_HTTP_LOC_CONF_OFFSET,
                    291:       offsetof(ngx_http_scgi_loc_conf_t, upstream.next_upstream),
                    292:       &ngx_http_scgi_next_upstream_masks },
                    293: 
                    294:     { ngx_string("scgi_param"),
                    295:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE23,
                    296:       ngx_http_upstream_param_set_slot,
                    297:       NGX_HTTP_LOC_CONF_OFFSET,
                    298:       offsetof(ngx_http_scgi_loc_conf_t, params_source),
                    299:       NULL },
                    300: 
                    301:     { ngx_string("scgi_pass_header"),
                    302:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
                    303:       ngx_conf_set_str_array_slot,
                    304:       NGX_HTTP_LOC_CONF_OFFSET,
                    305:       offsetof(ngx_http_scgi_loc_conf_t, upstream.pass_headers),
                    306:       NULL },
                    307: 
                    308:     { ngx_string("scgi_hide_header"),
                    309:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
                    310:       ngx_conf_set_str_array_slot,
                    311:       NGX_HTTP_LOC_CONF_OFFSET,
                    312:       offsetof(ngx_http_scgi_loc_conf_t, upstream.hide_headers),
                    313:       NULL },
                    314: 
                    315:     { ngx_string("scgi_ignore_headers"),
                    316:       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
                    317:       ngx_conf_set_bitmask_slot,
                    318:       NGX_HTTP_LOC_CONF_OFFSET,
                    319:       offsetof(ngx_http_scgi_loc_conf_t, upstream.ignore_headers),
                    320:       &ngx_http_upstream_ignore_headers_masks },
                    321: 
                    322:       ngx_null_command
                    323: };
                    324: 
                    325: 
                    326: static ngx_http_module_t ngx_http_scgi_module_ctx = {
                    327:     NULL,                                  /* preconfiguration */
                    328:     NULL,                                  /* postconfiguration */
                    329: 
                    330:     NULL,                                  /* create main configuration */
                    331:     NULL,                                  /* init main configuration */
                    332: 
                    333:     NULL,                                  /* create server configuration */
                    334:     NULL,                                  /* merge server configuration */
                    335: 
                    336:     ngx_http_scgi_create_loc_conf,         /* create location configuration */
                    337:     ngx_http_scgi_merge_loc_conf           /* merge location configuration */
                    338: };
                    339: 
                    340: 
                    341: ngx_module_t ngx_http_scgi_module = {
                    342:     NGX_MODULE_V1,
                    343:     &ngx_http_scgi_module_ctx,             /* module context */
                    344:     ngx_http_scgi_commands,                /* module directives */
                    345:     NGX_HTTP_MODULE,                       /* module type */
                    346:     NULL,                                  /* init master */
                    347:     NULL,                                  /* init module */
                    348:     NULL,                                  /* init process */
                    349:     NULL,                                  /* init thread */
                    350:     NULL,                                  /* exit thread */
                    351:     NULL,                                  /* exit process */
                    352:     NULL,                                  /* exit master */
                    353:     NGX_MODULE_V1_PADDING
                    354: };
                    355: 
                    356: 
                    357: static ngx_str_t ngx_http_scgi_hide_headers[] = {
                    358:     ngx_string("Status"),
                    359:     ngx_string("X-Accel-Expires"),
                    360:     ngx_string("X-Accel-Redirect"),
                    361:     ngx_string("X-Accel-Limit-Rate"),
                    362:     ngx_string("X-Accel-Buffering"),
                    363:     ngx_string("X-Accel-Charset"),
                    364:     ngx_null_string
                    365: };
                    366: 
                    367: 
                    368: #if (NGX_HTTP_CACHE)
                    369: 
                    370: static ngx_keyval_t  ngx_http_scgi_cache_headers[] = {
                    371:     { ngx_string("HTTP_IF_MODIFIED_SINCE"), ngx_string("") },
                    372:     { ngx_string("HTTP_IF_UNMODIFIED_SINCE"), ngx_string("") },
                    373:     { ngx_string("HTTP_IF_NONE_MATCH"), ngx_string("") },
                    374:     { ngx_string("HTTP_IF_MATCH"), ngx_string("") },
                    375:     { ngx_string("HTTP_RANGE"), ngx_string("") },
                    376:     { ngx_string("HTTP_IF_RANGE"), ngx_string("") },
                    377:     { ngx_null_string, ngx_null_string }
                    378: };
                    379: 
                    380: #endif
                    381: 
                    382: 
                    383: static ngx_path_init_t ngx_http_scgi_temp_path = {
                    384:     ngx_string(NGX_HTTP_SCGI_TEMP_PATH), { 1, 2, 0 }
                    385: };
                    386: 
                    387: 
                    388: static ngx_int_t
                    389: ngx_http_scgi_handler(ngx_http_request_t *r)
                    390: {
                    391:     ngx_int_t                  rc;
                    392:     ngx_http_status_t         *status;
                    393:     ngx_http_upstream_t       *u;
                    394:     ngx_http_scgi_loc_conf_t  *scf;
                    395: 
                    396:     if (r->subrequest_in_memory) {
                    397:         ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                    398:                       "ngx_http_scgi_module does not support "
                    399:                       "subrequests in memory");
                    400:         return NGX_HTTP_INTERNAL_SERVER_ERROR;
                    401:     }
                    402: 
                    403:     if (ngx_http_upstream_create(r) != NGX_OK) {
                    404:         return NGX_HTTP_INTERNAL_SERVER_ERROR;
                    405:     }
                    406: 
                    407:     status = ngx_pcalloc(r->pool, sizeof(ngx_http_status_t));
                    408:     if (status == NULL) {
                    409:         return NGX_HTTP_INTERNAL_SERVER_ERROR;
                    410:     }
                    411: 
                    412:     ngx_http_set_ctx(r, status, ngx_http_scgi_module);
                    413: 
                    414:     scf = ngx_http_get_module_loc_conf(r, ngx_http_scgi_module);
                    415: 
                    416:     if (scf->scgi_lengths) {
                    417:         if (ngx_http_scgi_eval(r, scf) != NGX_OK) {
                    418:             return NGX_HTTP_INTERNAL_SERVER_ERROR;
                    419:         }
                    420:     }
                    421: 
                    422:     u = r->upstream;
                    423: 
                    424:     ngx_str_set(&u->schema, "scgi://");
                    425:     u->output.tag = (ngx_buf_tag_t) &ngx_http_scgi_module;
                    426: 
                    427:     u->conf = &scf->upstream;
                    428: 
                    429: #if (NGX_HTTP_CACHE)
                    430:     u->create_key = ngx_http_scgi_create_key;
                    431: #endif
                    432:     u->create_request = ngx_http_scgi_create_request;
                    433:     u->reinit_request = ngx_http_scgi_reinit_request;
                    434:     u->process_header = ngx_http_scgi_process_status_line;
                    435:     u->abort_request = ngx_http_scgi_abort_request;
                    436:     u->finalize_request = ngx_http_scgi_finalize_request;
                    437:     r->state = 0;
                    438: 
                    439:     u->buffering = scf->upstream.buffering;
                    440: 
                    441:     u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t));
                    442:     if (u->pipe == NULL) {
                    443:         return NGX_HTTP_INTERNAL_SERVER_ERROR;
                    444:     }
                    445: 
                    446:     u->pipe->input_filter = ngx_event_pipe_copy_input_filter;
                    447:     u->pipe->input_ctx = r;
                    448: 
                    449:     rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init);
                    450: 
                    451:     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
                    452:         return rc;
                    453:     }
                    454: 
                    455:     return NGX_DONE;
                    456: }
                    457: 
                    458: 
                    459: static ngx_int_t
                    460: ngx_http_scgi_eval(ngx_http_request_t *r, ngx_http_scgi_loc_conf_t * scf)
                    461: {
                    462:     ngx_url_t             url;
                    463:     ngx_http_upstream_t  *u;
                    464: 
                    465:     ngx_memzero(&url, sizeof(ngx_url_t));
                    466: 
                    467:     if (ngx_http_script_run(r, &url.url, scf->scgi_lengths->elts, 0,
                    468:                             scf->scgi_values->elts)
                    469:         == NULL)
                    470:     {
                    471:         return NGX_ERROR;
                    472:     }
                    473: 
                    474:     url.no_resolve = 1;
                    475: 
                    476:     if (ngx_parse_url(r->pool, &url) != NGX_OK) {
                    477:         if (url.err) {
                    478:             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                    479:                           "%s in upstream \"%V\"", url.err, &url.url);
                    480:         }
                    481: 
                    482:         return NGX_ERROR;
                    483:     }
                    484: 
                    485:     u = r->upstream;
                    486: 
                    487:     u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
                    488:     if (u->resolved == NULL) {
                    489:         return NGX_ERROR;
                    490:     }
                    491: 
                    492:     if (url.addrs && url.addrs[0].sockaddr) {
                    493:         u->resolved->sockaddr = url.addrs[0].sockaddr;
                    494:         u->resolved->socklen = url.addrs[0].socklen;
                    495:         u->resolved->naddrs = 1;
                    496:         u->resolved->host = url.addrs[0].name;
                    497: 
                    498:     } else {
                    499:         u->resolved->host = url.host;
                    500:         u->resolved->port = url.port;
                    501:         u->resolved->no_port = url.no_port;
                    502:     }
                    503: 
                    504:     return NGX_OK;
                    505: }
                    506: 
                    507: 
                    508: #if (NGX_HTTP_CACHE)
                    509: 
                    510: static ngx_int_t
                    511: ngx_http_scgi_create_key(ngx_http_request_t *r)
                    512: {
                    513:     ngx_str_t                 *key;
                    514:     ngx_http_scgi_loc_conf_t  *scf;
                    515: 
                    516:     key = ngx_array_push(&r->cache->keys);
                    517:     if (key == NULL) {
                    518:         return NGX_ERROR;
                    519:     }
                    520: 
                    521:     scf = ngx_http_get_module_loc_conf(r, ngx_http_scgi_module);
                    522: 
                    523:     if (ngx_http_complex_value(r, &scf->cache_key, key) != NGX_OK) {
                    524:         return NGX_ERROR;
                    525:     }
                    526: 
                    527:     return NGX_OK;
                    528: }
                    529: 
                    530: #endif
                    531: 
                    532: 
                    533: static ngx_int_t
                    534: ngx_http_scgi_create_request(ngx_http_request_t *r)
                    535: {
                    536:     off_t                         content_length_n;
                    537:     u_char                        ch, *key, *val, *lowcase_key;
                    538:     size_t                        len, key_len, val_len, allocated;
                    539:     ngx_buf_t                    *b;
                    540:     ngx_str_t                     content_length;
                    541:     ngx_uint_t                    i, n, hash, skip_empty, header_params;
                    542:     ngx_chain_t                  *cl, *body;
                    543:     ngx_list_part_t              *part;
                    544:     ngx_table_elt_t              *header, **ignored;
                    545:     ngx_http_script_code_pt       code;
                    546:     ngx_http_script_engine_t      e, le;
                    547:     ngx_http_scgi_loc_conf_t     *scf;
                    548:     ngx_http_script_len_code_pt   lcode;
                    549:     u_char                        buffer[NGX_OFF_T_LEN];
                    550: 
                    551:     content_length_n = 0;
                    552:     body = r->upstream->request_bufs;
                    553: 
                    554:     while (body) {
                    555:         content_length_n += ngx_buf_size(body->buf);
                    556:         body = body->next;
                    557:     }
                    558: 
                    559:     content_length.data = buffer;
                    560:     content_length.len = ngx_sprintf(buffer, "%O", content_length_n) - buffer;
                    561: 
                    562:     len = sizeof("CONTENT_LENGTH") + content_length.len + 1;
                    563: 
                    564:     header_params = 0;
                    565:     ignored = NULL;
                    566: 
                    567:     scf = ngx_http_get_module_loc_conf(r, ngx_http_scgi_module);
                    568: 
                    569:     if (scf->params_len) {
                    570:         ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
                    571: 
                    572:         ngx_http_script_flush_no_cacheable_variables(r, scf->flushes);
                    573:         le.flushed = 1;
                    574: 
                    575:         le.ip = scf->params_len->elts;
                    576:         le.request = r;
                    577: 
                    578:         while (*(uintptr_t *) le.ip) {
                    579: 
                    580:             lcode = *(ngx_http_script_len_code_pt *) le.ip;
                    581:             key_len = lcode(&le);
                    582: 
                    583:             lcode = *(ngx_http_script_len_code_pt *) le.ip;
                    584:             skip_empty = lcode(&le);
                    585: 
                    586:             for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
                    587:                 lcode = *(ngx_http_script_len_code_pt *) le.ip;
                    588:             }
                    589:             le.ip += sizeof(uintptr_t);
                    590: 
                    591:             if (skip_empty && val_len == 0) {
                    592:                 continue;
                    593:             }
                    594: 
                    595:             len += key_len + val_len + 1;
                    596:         }
                    597:     }
                    598: 
                    599:     if (scf->upstream.pass_request_headers) {
                    600: 
                    601:         allocated = 0;
                    602:         lowcase_key = NULL;
                    603: 
                    604:         if (scf->header_params) {
                    605:             n = 0;
                    606:             part = &r->headers_in.headers.part;
                    607: 
                    608:             while (part) {
                    609:                 n += part->nelts;
                    610:                 part = part->next;
                    611:             }
                    612: 
                    613:             ignored = ngx_palloc(r->pool, n * sizeof(void *));
                    614:             if (ignored == NULL) {
                    615:                 return NGX_ERROR;
                    616:             }
                    617:         }
                    618: 
                    619:         part = &r->headers_in.headers.part;
                    620:         header = part->elts;
                    621: 
                    622:         for (i = 0; /* void */; i++) {
                    623: 
                    624:             if (i >= part->nelts) {
                    625:                 if (part->next == NULL) {
                    626:                     break;
                    627:                 }
                    628: 
                    629:                 part = part->next;
                    630:                 header = part->elts;
                    631:                 i = 0;
                    632:             }
                    633: 
                    634:             if (scf->header_params) {
                    635:                 if (allocated < header[i].key.len) {
                    636:                     allocated = header[i].key.len + 16;
                    637:                     lowcase_key = ngx_pnalloc(r->pool, allocated);
                    638:                     if (lowcase_key == NULL) {
                    639:                         return NGX_ERROR;
                    640:                     }
                    641:                 }
                    642: 
                    643:                 hash = 0;
                    644: 
                    645:                 for (n = 0; n < header[i].key.len; n++) {
                    646:                     ch = header[i].key.data[n];
                    647: 
                    648:                     if (ch >= 'A' && ch <= 'Z') {
                    649:                         ch |= 0x20;
                    650: 
                    651:                     } else if (ch == '-') {
                    652:                         ch = '_';
                    653:                     }
                    654: 
                    655:                     hash = ngx_hash(hash, ch);
                    656:                     lowcase_key[n] = ch;
                    657:                 }
                    658: 
                    659:                 if (ngx_hash_find(&scf->headers_hash, hash, lowcase_key, n)) {
                    660:                     ignored[header_params++] = &header[i];
                    661:                     continue;
                    662:                 }
                    663:             }
                    664: 
                    665:             len += sizeof("HTTP_") - 1 + header[i].key.len + 1
                    666:                 + header[i].value.len + 1;
                    667:         }
                    668:     }
                    669: 
                    670:     /* netstring: "length:" + packet + "," */
                    671: 
                    672:     b = ngx_create_temp_buf(r->pool, NGX_SIZE_T_LEN + 1 + len + 1);
                    673:     if (b == NULL) {
                    674:         return NGX_ERROR;
                    675:     }
                    676: 
                    677:     cl = ngx_alloc_chain_link(r->pool);
                    678:     if (cl == NULL) {
                    679:         return NGX_ERROR;
                    680:     }
                    681: 
                    682:     cl->buf = b;
                    683: 
                    684:     b->last = ngx_sprintf(b->last, "%ui:CONTENT_LENGTH%Z%V%Z",
                    685:                           len, &content_length);
                    686: 
                    687:     if (scf->params_len) {
                    688:         ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
                    689: 
                    690:         e.ip = scf->params->elts;
                    691:         e.pos = b->last;
                    692:         e.request = r;
                    693:         e.flushed = 1;
                    694: 
                    695:         le.ip = scf->params_len->elts;
                    696: 
                    697:         while (*(uintptr_t *) le.ip) {
                    698: 
                    699:             lcode = *(ngx_http_script_len_code_pt *) le.ip;
                    700:             lcode(&le); /* key length */
                    701: 
                    702:             lcode = *(ngx_http_script_len_code_pt *) le.ip;
                    703:             skip_empty = lcode(&le);
                    704: 
                    705:             for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) {
                    706:                 lcode = *(ngx_http_script_len_code_pt *) le.ip;
                    707:             }
                    708:             le.ip += sizeof(uintptr_t);
                    709: 
                    710:             if (skip_empty && val_len == 0) {
                    711:                 e.skip = 1;
                    712: 
                    713:                 while (*(uintptr_t *) e.ip) {
                    714:                     code = *(ngx_http_script_code_pt *) e.ip;
                    715:                     code((ngx_http_script_engine_t *) &e);
                    716:                 }
                    717:                 e.ip += sizeof(uintptr_t);
                    718: 
                    719:                 e.skip = 0;
                    720: 
                    721:                 continue;
                    722:             }
                    723: 
                    724: #if (NGX_DEBUG)
                    725:             key = e.pos;
                    726: #endif
                    727:             code = *(ngx_http_script_code_pt *) e.ip;
                    728:             code((ngx_http_script_engine_t *) & e);
                    729: 
                    730: #if (NGX_DEBUG)
                    731:             val = e.pos;
                    732: #endif
                    733:             while (*(uintptr_t *) e.ip) {
                    734:                 code = *(ngx_http_script_code_pt *) e.ip;
                    735:                 code((ngx_http_script_engine_t *) &e);
                    736:             }
                    737:             *e.pos++ = '\0';
                    738:             e.ip += sizeof(uintptr_t);
                    739: 
                    740:             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    741:                            "scgi param: \"%s: %s\"", key, val);
                    742:         }
                    743: 
                    744:         b->last = e.pos;
                    745:     }
                    746: 
                    747:     if (scf->upstream.pass_request_headers) {
                    748: 
                    749:         part = &r->headers_in.headers.part;
                    750:         header = part->elts;
                    751: 
                    752:         for (i = 0; /* void */; i++) {
                    753: 
                    754:             if (i >= part->nelts) {
                    755:                 if (part->next == NULL) {
                    756:                     break;
                    757:                 }
                    758: 
                    759:                 part = part->next;
                    760:                 header = part->elts;
                    761:                 i = 0;
                    762:             }
                    763: 
                    764:             for (n = 0; n < header_params; n++) {
                    765:                 if (&header[i] == ignored[n]) {
                    766:                     goto next;
                    767:                 }
                    768:             }
                    769: 
                    770:             key = b->last;
                    771:             b->last = ngx_cpymem(key, "HTTP_", sizeof("HTTP_") - 1);
                    772: 
                    773:             for (n = 0; n < header[i].key.len; n++) {
                    774:                 ch = header[i].key.data[n];
                    775: 
                    776:                 if (ch >= 'a' && ch <= 'z') {
                    777:                     ch &= ~0x20;
                    778: 
                    779:                 } else if (ch == '-') {
                    780:                     ch = '_';
                    781:                 }
                    782: 
                    783:                 *b->last++ = ch;
                    784:             }
                    785: 
                    786:             *b->last++ = (u_char) 0;
                    787: 
                    788:             val = b->last;
                    789:             b->last = ngx_copy(val, header[i].value.data, header[i].value.len);
                    790:             *b->last++ = (u_char) 0;
                    791: 
                    792:             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    793:                            "scgi param: \"%s: %s\"", key, val);
                    794: 
                    795:         next:
                    796: 
                    797:             continue;
                    798:          }
                    799:     }
                    800: 
                    801:     *b->last++ = (u_char) ',';
                    802: 
                    803:     if (scf->upstream.pass_request_body) {
                    804:         body = r->upstream->request_bufs;
                    805:         r->upstream->request_bufs = cl;
                    806: 
                    807:         while (body) {
                    808:             b = ngx_alloc_buf(r->pool);
                    809:             if (b == NULL) {
                    810:                 return NGX_ERROR;
                    811:             }
                    812: 
                    813:             ngx_memcpy(b, body->buf, sizeof(ngx_buf_t));
                    814: 
                    815:             cl->next = ngx_alloc_chain_link(r->pool);
                    816:             if (cl->next == NULL) {
                    817:                 return NGX_ERROR;
                    818:             }
                    819: 
                    820:             cl = cl->next;
                    821:             cl->buf = b;
                    822: 
                    823:             body = body->next;
                    824:         }
                    825: 
                    826:     } else {
                    827:         r->upstream->request_bufs = cl;
                    828:     }
                    829: 
                    830:     cl->next = NULL;
                    831: 
                    832:     return NGX_OK;
                    833: }
                    834: 
                    835: 
                    836: static ngx_int_t
                    837: ngx_http_scgi_reinit_request(ngx_http_request_t *r)
                    838: {
                    839:     ngx_http_status_t  *status;
                    840: 
                    841:     status = ngx_http_get_module_ctx(r, ngx_http_scgi_module);
                    842: 
                    843:     if (status == NULL) {
                    844:         return NGX_OK;
                    845:     }
                    846: 
                    847:     status->code = 0;
                    848:     status->count = 0;
                    849:     status->start = NULL;
                    850:     status->end = NULL;
                    851: 
                    852:     r->upstream->process_header = ngx_http_scgi_process_status_line;
                    853:     r->state = 0;
                    854: 
                    855:     return NGX_OK;
                    856: }
                    857: 
                    858: 
                    859: static ngx_int_t
                    860: ngx_http_scgi_process_status_line(ngx_http_request_t *r)
                    861: {
                    862:     size_t                len;
                    863:     ngx_int_t             rc;
                    864:     ngx_http_status_t    *status;
                    865:     ngx_http_upstream_t  *u;
                    866: 
                    867:     status = ngx_http_get_module_ctx(r, ngx_http_scgi_module);
                    868: 
                    869:     if (status == NULL) {
                    870:         return NGX_ERROR;
                    871:     }
                    872: 
                    873:     u = r->upstream;
                    874: 
                    875:     rc = ngx_http_parse_status_line(r, &u->buffer, status);
                    876: 
                    877:     if (rc == NGX_AGAIN) {
                    878:         return rc;
                    879:     }
                    880: 
                    881:     if (rc == NGX_ERROR) {
                    882:         u->process_header = ngx_http_scgi_process_header;
                    883:         return ngx_http_scgi_process_header(r);
                    884:     }
                    885: 
                    886:     if (u->state) {
                    887:         u->state->status = status->code;
                    888:     }
                    889: 
                    890:     u->headers_in.status_n = status->code;
                    891: 
                    892:     len = status->end - status->start;
                    893:     u->headers_in.status_line.len = len;
                    894: 
                    895:     u->headers_in.status_line.data = ngx_pnalloc(r->pool, len);
                    896:     if (u->headers_in.status_line.data == NULL) {
                    897:         return NGX_ERROR;
                    898:     }
                    899: 
                    900:     ngx_memcpy(u->headers_in.status_line.data, status->start, len);
                    901: 
                    902:     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    903:                    "http scgi status %ui \"%V\"",
                    904:                    u->headers_in.status_n, &u->headers_in.status_line);
                    905: 
                    906:     u->process_header = ngx_http_scgi_process_header;
                    907: 
                    908:     return ngx_http_scgi_process_header(r);
                    909: }
                    910: 
                    911: 
                    912: static ngx_int_t
                    913: ngx_http_scgi_process_header(ngx_http_request_t *r)
                    914: {
                    915:     ngx_str_t                      *status_line;
                    916:     ngx_int_t                       rc, status;
                    917:     ngx_table_elt_t                *h;
                    918:     ngx_http_upstream_t            *u;
                    919:     ngx_http_upstream_header_t     *hh;
                    920:     ngx_http_upstream_main_conf_t  *umcf;
                    921: 
                    922:     umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
                    923: 
                    924:     for ( ;; ) {
                    925: 
                    926:         rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);
                    927: 
                    928:         if (rc == NGX_OK) {
                    929: 
                    930:             /* a header line has been parsed successfully */
                    931: 
                    932:             h = ngx_list_push(&r->upstream->headers_in.headers);
                    933:             if (h == NULL) {
                    934:                 return NGX_ERROR;
                    935:             }
                    936: 
                    937:             h->hash = r->header_hash;
                    938: 
                    939:             h->key.len = r->header_name_end - r->header_name_start;
                    940:             h->value.len = r->header_end - r->header_start;
                    941: 
                    942:             h->key.data = ngx_pnalloc(r->pool,
                    943:                                       h->key.len + 1 + h->value.len + 1
                    944:                                       + h->key.len);
                    945:             if (h->key.data == NULL) {
                    946:                 return NGX_ERROR;
                    947:             }
                    948: 
                    949:             h->value.data = h->key.data + h->key.len + 1;
                    950:             h->lowcase_key = h->key.data + h->key.len + 1 + h->value.len + 1;
                    951: 
                    952:             ngx_memcpy(h->key.data, r->header_name_start, h->key.len);
                    953:             h->key.data[h->key.len] = '\0';
                    954:             ngx_memcpy(h->value.data, r->header_start, h->value.len);
                    955:             h->value.data[h->value.len] = '\0';
                    956: 
                    957:             if (h->key.len == r->lowcase_index) {
                    958:                 ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
                    959: 
                    960:             } else {
                    961:                 ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
                    962:             }
                    963: 
                    964:             hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
                    965:                                h->lowcase_key, h->key.len);
                    966: 
                    967:             if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
                    968:                 return NGX_ERROR;
                    969:             }
                    970: 
                    971:             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    972:                            "http scgi header: \"%V: %V\"", &h->key, &h->value);
                    973: 
                    974:             continue;
                    975:         }
                    976: 
                    977:         if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
                    978: 
                    979:             /* a whole header has been parsed successfully */
                    980: 
                    981:             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    982:                            "http scgi header done");
                    983: 
                    984:             u = r->upstream;
                    985: 
                    986:             if (u->headers_in.status_n) {
                    987:                 goto done;
                    988:             }
                    989: 
                    990:             if (u->headers_in.status) {
                    991:                 status_line = &u->headers_in.status->value;
                    992: 
                    993:                 status = ngx_atoi(status_line->data, 3);
                    994:                 if (status == NGX_ERROR) {
                    995:                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                    996:                                   "upstream sent invalid status \"%V\"",
                    997:                                   status_line);
                    998:                     return NGX_HTTP_UPSTREAM_INVALID_HEADER;
                    999:                 }
                   1000: 
                   1001:                 u->headers_in.status_n = status;
                   1002:                 u->headers_in.status_line = *status_line;
                   1003: 
                   1004:             } else if (u->headers_in.location) {
                   1005:                 u->headers_in.status_n = 302;
                   1006:                 ngx_str_set(&u->headers_in.status_line,
                   1007:                             "302 Moved Temporarily");
                   1008: 
                   1009:             } else {
                   1010:                 u->headers_in.status_n = 200;
                   1011:                 ngx_str_set(&u->headers_in.status_line, "200 OK");
                   1012:             }
                   1013: 
                   1014:             if (u->state) {
                   1015:                 u->state->status = u->headers_in.status_n;
                   1016:             }
                   1017: 
                   1018:         done:
                   1019: 
                   1020:             if (u->headers_in.status_n == NGX_HTTP_SWITCHING_PROTOCOLS
                   1021:                 && r->headers_in.upgrade)
                   1022:             {
                   1023:                 u->upgrade = 1;
                   1024:             }
                   1025: 
                   1026:             return NGX_OK;
                   1027:         }
                   1028: 
                   1029:         if (rc == NGX_AGAIN) {
                   1030:             return NGX_AGAIN;
                   1031:         }
                   1032: 
                   1033:         /* there was error while a header line parsing */
                   1034: 
                   1035:         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                   1036:                       "upstream sent invalid header");
                   1037: 
                   1038:         return NGX_HTTP_UPSTREAM_INVALID_HEADER;
                   1039:     }
                   1040: }
                   1041: 
                   1042: 
                   1043: static void
                   1044: ngx_http_scgi_abort_request(ngx_http_request_t *r)
                   1045: {
                   1046:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   1047:                    "abort http scgi request");
                   1048: 
                   1049:     return;
                   1050: }
                   1051: 
                   1052: 
                   1053: static void
                   1054: ngx_http_scgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
                   1055: {
                   1056:     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   1057:                    "finalize http scgi request");
                   1058: 
                   1059:     return;
                   1060: }
                   1061: 
                   1062: 
                   1063: static void *
                   1064: ngx_http_scgi_create_loc_conf(ngx_conf_t *cf)
                   1065: {
                   1066:     ngx_http_scgi_loc_conf_t  *conf;
                   1067: 
                   1068:     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_scgi_loc_conf_t));
                   1069:     if (conf == NULL) {
                   1070:         return NULL;
                   1071:     }
                   1072: 
                   1073:     conf->upstream.store = NGX_CONF_UNSET;
                   1074:     conf->upstream.store_access = NGX_CONF_UNSET_UINT;
                   1075:     conf->upstream.buffering = NGX_CONF_UNSET;
                   1076:     conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
                   1077: 
                   1078:     conf->upstream.local = NGX_CONF_UNSET_PTR;
                   1079: 
                   1080:     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
                   1081:     conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC;
                   1082:     conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC;
                   1083: 
                   1084:     conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE;
                   1085:     conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE;
                   1086: 
                   1087:     conf->upstream.busy_buffers_size_conf = NGX_CONF_UNSET_SIZE;
                   1088:     conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE;
                   1089:     conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE;
                   1090: 
                   1091:     conf->upstream.pass_request_headers = NGX_CONF_UNSET;
                   1092:     conf->upstream.pass_request_body = NGX_CONF_UNSET;
                   1093: 
                   1094: #if (NGX_HTTP_CACHE)
                   1095:     conf->upstream.cache = NGX_CONF_UNSET_PTR;
                   1096:     conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
                   1097:     conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR;
                   1098:     conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
                   1099:     conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
                   1100:     conf->upstream.cache_lock = NGX_CONF_UNSET;
                   1101:     conf->upstream.cache_lock_timeout = NGX_CONF_UNSET_MSEC;
                   1102: #endif
                   1103: 
                   1104:     conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
                   1105:     conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
                   1106: 
                   1107:     conf->upstream.intercept_errors = NGX_CONF_UNSET;
                   1108: 
                   1109:     /* "scgi_cyclic_temp_file" is disabled */
                   1110:     conf->upstream.cyclic_temp_file = 0;
                   1111: 
                   1112:     conf->upstream.change_buffering = 1;
                   1113: 
                   1114:     ngx_str_set(&conf->upstream.module, "scgi");
                   1115: 
                   1116:     return conf;
                   1117: }
                   1118: 
                   1119: 
                   1120: static char *
                   1121: ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
                   1122: {
                   1123:     ngx_http_scgi_loc_conf_t *prev = parent;
                   1124:     ngx_http_scgi_loc_conf_t *conf = child;
                   1125: 
                   1126:     size_t                        size;
                   1127:     ngx_hash_init_t               hash;
                   1128:     ngx_http_core_loc_conf_t     *clcf;
                   1129: 
                   1130:     if (conf->upstream.store != 0) {
                   1131:         ngx_conf_merge_value(conf->upstream.store, prev->upstream.store, 0);
                   1132: 
                   1133:         if (conf->upstream.store_lengths == NULL) {
                   1134:             conf->upstream.store_lengths = prev->upstream.store_lengths;
                   1135:             conf->upstream.store_values = prev->upstream.store_values;
                   1136:         }
                   1137:     }
                   1138: 
                   1139:     ngx_conf_merge_uint_value(conf->upstream.store_access,
                   1140:                               prev->upstream.store_access, 0600);
                   1141: 
                   1142:     ngx_conf_merge_value(conf->upstream.buffering,
                   1143:                               prev->upstream.buffering, 1);
                   1144: 
                   1145:     ngx_conf_merge_value(conf->upstream.ignore_client_abort,
                   1146:                               prev->upstream.ignore_client_abort, 0);
                   1147: 
                   1148:     ngx_conf_merge_ptr_value(conf->upstream.local,
                   1149:                               prev->upstream.local, NULL);
                   1150: 
                   1151:     ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
                   1152:                               prev->upstream.connect_timeout, 60000);
                   1153: 
                   1154:     ngx_conf_merge_msec_value(conf->upstream.send_timeout,
                   1155:                               prev->upstream.send_timeout, 60000);
                   1156: 
                   1157:     ngx_conf_merge_msec_value(conf->upstream.read_timeout,
                   1158:                               prev->upstream.read_timeout, 60000);
                   1159: 
                   1160:     ngx_conf_merge_size_value(conf->upstream.send_lowat,
                   1161:                               prev->upstream.send_lowat, 0);
                   1162: 
                   1163:     ngx_conf_merge_size_value(conf->upstream.buffer_size,
                   1164:                               prev->upstream.buffer_size,
                   1165:                               (size_t) ngx_pagesize);
                   1166: 
                   1167: 
                   1168:     ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs,
                   1169:                               8, ngx_pagesize);
                   1170: 
                   1171:     if (conf->upstream.bufs.num < 2) {
                   1172:         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                   1173:                            "there must be at least 2 \"scgi_buffers\"");
                   1174:         return NGX_CONF_ERROR;
                   1175:     }
                   1176: 
                   1177: 
                   1178:     size = conf->upstream.buffer_size;
                   1179:     if (size < conf->upstream.bufs.size) {
                   1180:         size = conf->upstream.bufs.size;
                   1181:     }
                   1182: 
                   1183: 
                   1184:     ngx_conf_merge_size_value(conf->upstream.busy_buffers_size_conf,
                   1185:                               prev->upstream.busy_buffers_size_conf,
                   1186:                               NGX_CONF_UNSET_SIZE);
                   1187: 
                   1188:     if (conf->upstream.busy_buffers_size_conf == NGX_CONF_UNSET_SIZE) {
                   1189:         conf->upstream.busy_buffers_size = 2 * size;
                   1190:     } else {
                   1191:         conf->upstream.busy_buffers_size =
                   1192:             conf->upstream.busy_buffers_size_conf;
                   1193:     }
                   1194: 
                   1195:     if (conf->upstream.busy_buffers_size < size) {
                   1196:         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                   1197:             "\"scgi_busy_buffers_size\" must be equal to or greater "
                   1198:             "than the maximum of the value of \"scgi_buffer_size\" and "
                   1199:             "one of the \"scgi_buffers\"");
                   1200: 
                   1201:         return NGX_CONF_ERROR;
                   1202:     }
                   1203: 
                   1204:     if (conf->upstream.busy_buffers_size
                   1205:         > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size)
                   1206:     {
                   1207:         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                   1208:             "\"scgi_busy_buffers_size\" must be less than "
                   1209:             "the size of all \"scgi_buffers\" minus one buffer");
                   1210: 
                   1211:         return NGX_CONF_ERROR;
                   1212:     }
                   1213: 
                   1214: 
                   1215:     ngx_conf_merge_size_value(conf->upstream.temp_file_write_size_conf,
                   1216:                               prev->upstream.temp_file_write_size_conf,
                   1217:                               NGX_CONF_UNSET_SIZE);
                   1218: 
                   1219:     if (conf->upstream.temp_file_write_size_conf == NGX_CONF_UNSET_SIZE) {
                   1220:         conf->upstream.temp_file_write_size = 2 * size;
                   1221:     } else {
                   1222:         conf->upstream.temp_file_write_size =
                   1223:             conf->upstream.temp_file_write_size_conf;
                   1224:     }
                   1225: 
                   1226:     if (conf->upstream.temp_file_write_size < size) {
                   1227:         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                   1228:             "\"scgi_temp_file_write_size\" must be equal to or greater than "
                   1229:             "the maximum of the value of \"scgi_buffer_size\" and "
                   1230:             "one of the \"scgi_buffers\"");
                   1231: 
                   1232:         return NGX_CONF_ERROR;
                   1233:     }
                   1234: 
                   1235: 
                   1236:     ngx_conf_merge_size_value(conf->upstream.max_temp_file_size_conf,
                   1237:                               prev->upstream.max_temp_file_size_conf,
                   1238:                               NGX_CONF_UNSET_SIZE);
                   1239: 
                   1240:     if (conf->upstream.max_temp_file_size_conf == NGX_CONF_UNSET_SIZE) {
                   1241:         conf->upstream.max_temp_file_size = 1024 * 1024 * 1024;
                   1242:     } else {
                   1243:         conf->upstream.max_temp_file_size =
                   1244:             conf->upstream.max_temp_file_size_conf;
                   1245:     }
                   1246: 
                   1247:     if (conf->upstream.max_temp_file_size != 0
                   1248:         && conf->upstream.max_temp_file_size < size) {
                   1249:         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                   1250:             "\"scgi_max_temp_file_size\" must be equal to zero to disable "
                   1251:             "temporary files usage or must be equal to or greater than "
                   1252:             "the maximum of the value of \"scgi_buffer_size\" and "
                   1253:             "one of the \"scgi_buffers\"");
                   1254: 
                   1255:         return NGX_CONF_ERROR;
                   1256:     }
                   1257: 
                   1258: 
                   1259:     ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers,
                   1260:                                  prev->upstream.ignore_headers,
                   1261:                                  NGX_CONF_BITMASK_SET);
                   1262: 
                   1263: 
                   1264:     ngx_conf_merge_bitmask_value(conf->upstream.next_upstream,
                   1265:                                  prev->upstream.next_upstream,
                   1266:                                  (NGX_CONF_BITMASK_SET
                   1267:                                   |NGX_HTTP_UPSTREAM_FT_ERROR
                   1268:                                   |NGX_HTTP_UPSTREAM_FT_TIMEOUT));
                   1269: 
                   1270:     if (conf->upstream.next_upstream & NGX_HTTP_UPSTREAM_FT_OFF) {
                   1271:         conf->upstream.next_upstream = NGX_CONF_BITMASK_SET
                   1272:                                        |NGX_HTTP_UPSTREAM_FT_OFF;
                   1273:     }
                   1274: 
                   1275:     if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
                   1276:                                   prev->upstream.temp_path,
                   1277:                                   &ngx_http_scgi_temp_path)
                   1278:         != NGX_OK)
                   1279:     {
                   1280:         return NGX_CONF_ERROR;
                   1281:     }
                   1282: 
                   1283: #if (NGX_HTTP_CACHE)
                   1284: 
                   1285:     ngx_conf_merge_ptr_value(conf->upstream.cache,
                   1286:                               prev->upstream.cache, NULL);
                   1287: 
                   1288:     if (conf->upstream.cache && conf->upstream.cache->data == NULL) {
                   1289:         ngx_shm_zone_t  *shm_zone;
                   1290: 
                   1291:         shm_zone = conf->upstream.cache;
                   1292: 
                   1293:         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                   1294:                            "\"scgi_cache\" zone \"%V\" is unknown",
                   1295:                            &shm_zone->shm.name);
                   1296: 
                   1297:         return NGX_CONF_ERROR;
                   1298:     }
                   1299: 
                   1300:     ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
                   1301:                               prev->upstream.cache_min_uses, 1);
                   1302: 
                   1303:     ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
                   1304:                               prev->upstream.cache_use_stale,
                   1305:                               (NGX_CONF_BITMASK_SET
                   1306:                                |NGX_HTTP_UPSTREAM_FT_OFF));
                   1307: 
                   1308:     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
                   1309:         conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
                   1310:                                          |NGX_HTTP_UPSTREAM_FT_OFF;
                   1311:     }
                   1312: 
                   1313:     if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_ERROR) {
                   1314:         conf->upstream.cache_use_stale |= NGX_HTTP_UPSTREAM_FT_NOLIVE;
                   1315:     }
                   1316: 
                   1317:     if (conf->upstream.cache_methods == 0) {
                   1318:         conf->upstream.cache_methods = prev->upstream.cache_methods;
                   1319:     }
                   1320: 
                   1321:     conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD;
                   1322: 
                   1323:     ngx_conf_merge_ptr_value(conf->upstream.cache_bypass,
                   1324:                              prev->upstream.cache_bypass, NULL);
                   1325: 
                   1326:     ngx_conf_merge_ptr_value(conf->upstream.no_cache,
                   1327:                              prev->upstream.no_cache, NULL);
                   1328: 
                   1329:     ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
                   1330:                              prev->upstream.cache_valid, NULL);
                   1331: 
                   1332:     if (conf->cache_key.value.data == NULL) {
                   1333:         conf->cache_key = prev->cache_key;
                   1334:     }
                   1335: 
                   1336:     ngx_conf_merge_value(conf->upstream.cache_lock,
                   1337:                               prev->upstream.cache_lock, 0);
                   1338: 
                   1339:     ngx_conf_merge_msec_value(conf->upstream.cache_lock_timeout,
                   1340:                               prev->upstream.cache_lock_timeout, 5000);
                   1341: 
                   1342: #endif
                   1343: 
                   1344:     ngx_conf_merge_value(conf->upstream.pass_request_headers,
                   1345:                          prev->upstream.pass_request_headers, 1);
                   1346:     ngx_conf_merge_value(conf->upstream.pass_request_body,
                   1347:                          prev->upstream.pass_request_body, 1);
                   1348: 
                   1349:     ngx_conf_merge_value(conf->upstream.intercept_errors,
                   1350:                          prev->upstream.intercept_errors, 0);
                   1351: 
                   1352:     hash.max_size = 512;
                   1353:     hash.bucket_size = ngx_align(64, ngx_cacheline_size);
                   1354:     hash.name = "scgi_hide_headers_hash";
                   1355: 
                   1356:     if (ngx_http_upstream_hide_headers_hash(cf, &conf->upstream,
                   1357:             &prev->upstream, ngx_http_scgi_hide_headers, &hash)
                   1358:         != NGX_OK)
                   1359:     {
                   1360:         return NGX_CONF_ERROR;
                   1361:     }
                   1362: 
                   1363:     if (conf->upstream.upstream == NULL) {
                   1364:         conf->upstream.upstream = prev->upstream.upstream;
                   1365:     }
                   1366: 
                   1367:     if (conf->scgi_lengths == NULL) {
                   1368:         conf->scgi_lengths = prev->scgi_lengths;
                   1369:         conf->scgi_values = prev->scgi_values;
                   1370:     }
                   1371: 
                   1372:     if (conf->upstream.upstream || conf->scgi_lengths) {
                   1373:         clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
                   1374:         if (clcf->handler == NULL && clcf->lmt_excpt) {
                   1375:             clcf->handler = ngx_http_scgi_handler;
                   1376:         }
                   1377:     }
                   1378: 
                   1379:     if (ngx_http_scgi_merge_params(cf, conf, prev) != NGX_OK) {
                   1380:         return NGX_CONF_ERROR;
                   1381:     }
                   1382: 
                   1383:     return NGX_CONF_OK;
                   1384: }
                   1385: 
                   1386: 
                   1387: static ngx_int_t
                   1388: ngx_http_scgi_merge_params(ngx_conf_t *cf, ngx_http_scgi_loc_conf_t *conf,
                   1389:     ngx_http_scgi_loc_conf_t *prev)
                   1390: {
                   1391:     u_char                       *p;
                   1392:     size_t                        size;
                   1393:     uintptr_t                    *code;
                   1394:     ngx_uint_t                    i, nsrc;
                   1395:     ngx_array_t                   headers_names;
                   1396: #if (NGX_HTTP_CACHE)
                   1397:     ngx_array_t                   params_merged;
                   1398: #endif
                   1399:     ngx_hash_key_t               *hk;
                   1400:     ngx_hash_init_t               hash;
                   1401:     ngx_http_upstream_param_t    *src;
                   1402:     ngx_http_script_compile_t     sc;
                   1403:     ngx_http_script_copy_code_t  *copy;
                   1404: 
                   1405:     if (conf->params_source == NULL) {
                   1406:         conf->params_source = prev->params_source;
                   1407: 
                   1408:         if (prev->headers_hash.buckets
                   1409: #if (NGX_HTTP_CACHE)
                   1410:             && ((conf->upstream.cache == NULL)
                   1411:                 == (prev->upstream.cache == NULL))
                   1412: #endif
                   1413:            )
                   1414:         {
                   1415:             conf->flushes = prev->flushes;
                   1416:             conf->params_len = prev->params_len;
                   1417:             conf->params = prev->params;
                   1418:             conf->headers_hash = prev->headers_hash;
                   1419:             conf->header_params = prev->header_params;
                   1420: 
                   1421:             return NGX_OK;
                   1422:         }
                   1423:     }
                   1424: 
                   1425:     if (conf->params_source == NULL
                   1426: #if (NGX_HTTP_CACHE)
                   1427:         && (conf->upstream.cache == NULL)
                   1428: #endif
                   1429:        )
                   1430:     {
                   1431:         conf->headers_hash.buckets = (void *) 1;
                   1432:         return NGX_OK;
                   1433:     }
                   1434: 
                   1435:     conf->params_len = ngx_array_create(cf->pool, 64, 1);
                   1436:     if (conf->params_len == NULL) {
                   1437:         return NGX_ERROR;
                   1438:     }
                   1439: 
                   1440:     conf->params = ngx_array_create(cf->pool, 512, 1);
                   1441:     if (conf->params == NULL) {
                   1442:         return NGX_ERROR;
                   1443:     }
                   1444: 
                   1445:     if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t))
                   1446:         != NGX_OK)
                   1447:     {
                   1448:         return NGX_ERROR;
                   1449:     }
                   1450: 
                   1451:     if (conf->params_source) {
                   1452:         src = conf->params_source->elts;
                   1453:         nsrc = conf->params_source->nelts;
                   1454: 
                   1455:     } else {
                   1456:         src = NULL;
                   1457:         nsrc = 0;
                   1458:     }
                   1459: 
                   1460: #if (NGX_HTTP_CACHE)
                   1461: 
                   1462:     if (conf->upstream.cache) {
                   1463:         ngx_keyval_t               *h;
                   1464:         ngx_http_upstream_param_t  *s;
                   1465: 
                   1466:         if (ngx_array_init(&params_merged, cf->temp_pool, 4,
                   1467:                            sizeof(ngx_http_upstream_param_t))
                   1468:             != NGX_OK)
                   1469:         {
                   1470:             return NGX_ERROR;
                   1471:         }
                   1472: 
                   1473:         for (i = 0; i < nsrc; i++) {
                   1474: 
                   1475:             s = ngx_array_push(&params_merged);
                   1476:             if (s == NULL) {
                   1477:                 return NGX_ERROR;
                   1478:             }
                   1479: 
                   1480:             *s = src[i];
                   1481:         }
                   1482: 
                   1483:         h = ngx_http_scgi_cache_headers;
                   1484: 
                   1485:         while (h->key.len) {
                   1486: 
                   1487:             src = params_merged.elts;
                   1488:             nsrc = params_merged.nelts;
                   1489: 
                   1490:             for (i = 0; i < nsrc; i++) {
                   1491:                 if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) {
                   1492:                     goto next;
                   1493:                 }
                   1494:             }
                   1495: 
                   1496:             s = ngx_array_push(&params_merged);
                   1497:             if (s == NULL) {
                   1498:                 return NGX_ERROR;
                   1499:             }
                   1500: 
                   1501:             s->key = h->key;
                   1502:             s->value = h->value;
                   1503:             s->skip_empty = 0;
                   1504: 
                   1505:         next:
                   1506: 
                   1507:             h++;
                   1508:         }
                   1509: 
                   1510:         src = params_merged.elts;
                   1511:         nsrc = params_merged.nelts;
                   1512:     }
                   1513: 
                   1514: #endif
                   1515: 
                   1516:     for (i = 0; i < nsrc; i++) {
                   1517: 
                   1518:         if (src[i].key.len > sizeof("HTTP_") - 1
                   1519:             && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0)
                   1520:         {
                   1521:             hk = ngx_array_push(&headers_names);
                   1522:             if (hk == NULL) {
                   1523:                 return NGX_ERROR;
                   1524:             }
                   1525: 
                   1526:             hk->key.len = src[i].key.len - 5;
                   1527:             hk->key.data = src[i].key.data + 5;
                   1528:             hk->key_hash = ngx_hash_key_lc(hk->key.data, hk->key.len);
                   1529:             hk->value = (void *) 1;
                   1530: 
                   1531:             if (src[i].value.len == 0) {
                   1532:                 continue;
                   1533:             }
                   1534:         }
                   1535: 
                   1536:         copy = ngx_array_push_n(conf->params_len,
                   1537:                                 sizeof(ngx_http_script_copy_code_t));
                   1538:         if (copy == NULL) {
                   1539:             return NGX_ERROR;
                   1540:         }
                   1541: 
                   1542:         copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
                   1543:         copy->len = src[i].key.len + 1;
                   1544: 
                   1545:         copy = ngx_array_push_n(conf->params_len,
                   1546:                                 sizeof(ngx_http_script_copy_code_t));
                   1547:         if (copy == NULL) {
                   1548:             return NGX_ERROR;
                   1549:         }
                   1550: 
                   1551:         copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
                   1552:         copy->len = src[i].skip_empty;
                   1553: 
                   1554: 
                   1555:         size = (sizeof(ngx_http_script_copy_code_t)
                   1556:                 + src[i].key.len + 1 + sizeof(uintptr_t) - 1)
                   1557:                & ~(sizeof(uintptr_t) - 1);
                   1558: 
                   1559:         copy = ngx_array_push_n(conf->params, size);
                   1560:         if (copy == NULL) {
                   1561:             return NGX_ERROR;
                   1562:         }
                   1563: 
                   1564:         copy->code = ngx_http_script_copy_code;
                   1565:         copy->len = src[i].key.len + 1;
                   1566: 
                   1567:         p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t);
                   1568:         (void) ngx_cpystrn(p, src[i].key.data, src[i].key.len + 1);
                   1569: 
                   1570: 
                   1571:         ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
                   1572: 
                   1573:         sc.cf = cf;
                   1574:         sc.source = &src[i].value;
                   1575:         sc.flushes = &conf->flushes;
                   1576:         sc.lengths = &conf->params_len;
                   1577:         sc.values = &conf->params;
                   1578: 
                   1579:         if (ngx_http_script_compile(&sc) != NGX_OK) {
                   1580:             return NGX_ERROR;
                   1581:         }
                   1582: 
                   1583:         code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t));
                   1584:         if (code == NULL) {
                   1585:             return NGX_ERROR;
                   1586:         }
                   1587: 
                   1588:         *code = (uintptr_t) NULL;
                   1589: 
                   1590: 
                   1591:         code = ngx_array_push_n(conf->params, sizeof(uintptr_t));
                   1592:         if (code == NULL) {
                   1593:             return NGX_ERROR;
                   1594:         }
                   1595: 
                   1596:         *code = (uintptr_t) NULL;
                   1597:     }
                   1598: 
                   1599:     code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t));
                   1600:     if (code == NULL) {
                   1601:         return NGX_ERROR;
                   1602:     }
                   1603: 
                   1604:     *code = (uintptr_t) NULL;
                   1605: 
                   1606:     code = ngx_array_push_n(conf->params, sizeof(uintptr_t));
                   1607:     if (code == NULL) {
                   1608:         return NGX_ERROR;
                   1609:     }
                   1610: 
                   1611:     *code = (uintptr_t) NULL;
                   1612: 
                   1613:     conf->header_params = headers_names.nelts;
                   1614: 
                   1615:     hash.hash = &conf->headers_hash;
                   1616:     hash.key = ngx_hash_key_lc;
                   1617:     hash.max_size = 512;
                   1618:     hash.bucket_size = 64;
                   1619:     hash.name = "scgi_params_hash";
                   1620:     hash.pool = cf->pool;
                   1621:     hash.temp_pool = NULL;
                   1622: 
                   1623:     return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts);
                   1624: }
                   1625: 
                   1626: 
                   1627: static char *
                   1628: ngx_http_scgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
                   1629: {
                   1630:     ngx_http_scgi_loc_conf_t *scf = conf;
                   1631: 
                   1632:     ngx_url_t                   u;
                   1633:     ngx_str_t                  *value, *url;
                   1634:     ngx_uint_t                  n;
                   1635:     ngx_http_core_loc_conf_t   *clcf;
                   1636:     ngx_http_script_compile_t   sc;
                   1637: 
                   1638:     if (scf->upstream.upstream || scf->scgi_lengths) {
                   1639:         return "is duplicate";
                   1640:     }
                   1641: 
                   1642:     clcf = ngx_http_conf_get_module_loc_conf (cf, ngx_http_core_module);
                   1643:     clcf->handler = ngx_http_scgi_handler;
                   1644: 
                   1645:     value = cf->args->elts;
                   1646: 
                   1647:     url = &value[1];
                   1648: 
                   1649:     n = ngx_http_script_variables_count(url);
                   1650: 
                   1651:     if (n) {
                   1652: 
                   1653:         ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
                   1654: 
                   1655:         sc.cf = cf;
                   1656:         sc.source = url;
                   1657:         sc.lengths = &scf->scgi_lengths;
                   1658:         sc.values = &scf->scgi_values;
                   1659:         sc.variables = n;
                   1660:         sc.complete_lengths = 1;
                   1661:         sc.complete_values = 1;
                   1662: 
                   1663:         if (ngx_http_script_compile(&sc) != NGX_OK) {
                   1664:             return NGX_CONF_ERROR;
                   1665:         }
                   1666: 
                   1667:         return NGX_CONF_OK;
                   1668:     }
                   1669: 
                   1670:     ngx_memzero(&u, sizeof(ngx_url_t));
                   1671: 
                   1672:     u.url = value[1];
                   1673:     u.no_resolve = 1;
                   1674: 
                   1675:     scf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
                   1676:     if (scf->upstream.upstream == NULL) {
                   1677:         return NGX_CONF_ERROR;
                   1678:     }
                   1679: 
                   1680:     if (clcf->name.data[clcf->name.len - 1] == '/') {
                   1681:         clcf->auto_redirect = 1;
                   1682:     }
                   1683: 
                   1684:     return NGX_CONF_OK;
                   1685: }
                   1686: 
                   1687: 
                   1688: static char *
                   1689: ngx_http_scgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
                   1690: {
                   1691:     ngx_http_scgi_loc_conf_t *scf = conf;
                   1692: 
                   1693:     ngx_str_t                  *value;
                   1694:     ngx_http_script_compile_t   sc;
                   1695: 
                   1696:     if (scf->upstream.store != NGX_CONF_UNSET || scf->upstream.store_lengths) {
                   1697:         return "is duplicate";
                   1698:     }
                   1699: 
                   1700:     value = cf->args->elts;
                   1701: 
                   1702:     if (ngx_strcmp(value[1].data, "off") == 0) {
                   1703:         scf->upstream.store = 0;
                   1704:         return NGX_CONF_OK;
                   1705:     }
                   1706: 
                   1707: #if (NGX_HTTP_CACHE)
                   1708: 
                   1709:     if (scf->upstream.cache != NGX_CONF_UNSET_PTR
                   1710:         && scf->upstream.cache != NULL)
                   1711:     {
                   1712:         return "is incompatible with \"scgi_cache\"";
                   1713:     }
                   1714: 
                   1715: #endif
                   1716: 
                   1717:     if (ngx_strcmp(value[1].data, "on") == 0) {
                   1718:         scf->upstream.store = 1;
                   1719:         return NGX_CONF_OK;
                   1720:     }
                   1721: 
                   1722:     /* include the terminating '\0' into script */
                   1723:     value[1].len++;
                   1724: 
                   1725:     ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
                   1726: 
                   1727:     sc.cf = cf;
                   1728:     sc.source = &value[1];
                   1729:     sc.lengths = &scf->upstream.store_lengths;
                   1730:     sc.values = &scf->upstream.store_values;
                   1731:     sc.variables = ngx_http_script_variables_count(&value[1]);;
                   1732:     sc.complete_lengths = 1;
                   1733:     sc.complete_values = 1;
                   1734: 
                   1735:     if (ngx_http_script_compile(&sc) != NGX_OK) {
                   1736:         return NGX_CONF_ERROR;
                   1737:     }
                   1738: 
                   1739:     return NGX_CONF_OK;
                   1740: }
                   1741: 
                   1742: 
                   1743: #if (NGX_HTTP_CACHE)
                   1744: 
                   1745: static char *
                   1746: ngx_http_scgi_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
                   1747: {
                   1748:     ngx_http_scgi_loc_conf_t *scf = conf;
                   1749: 
                   1750:     ngx_str_t  *value;
                   1751: 
                   1752:     value = cf->args->elts;
                   1753: 
                   1754:     if (scf->upstream.cache != NGX_CONF_UNSET_PTR) {
                   1755:         return "is duplicate";
                   1756:     }
                   1757: 
                   1758:     if (ngx_strcmp(value[1].data, "off") == 0) {
                   1759:         scf->upstream.cache = NULL;
                   1760:         return NGX_CONF_OK;
                   1761:     }
                   1762: 
                   1763:     if (scf->upstream.store > 0 || scf->upstream.store_lengths) {
                   1764:         return "is incompatible with \"scgi_store\"";
                   1765:     }
                   1766: 
                   1767:     scf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0,
                   1768:                                                 &ngx_http_scgi_module);
                   1769:     if (scf->upstream.cache == NULL) {
                   1770:         return NGX_CONF_ERROR;
                   1771:     }
                   1772: 
                   1773:     return NGX_CONF_OK;
                   1774: }
                   1775: 
                   1776: 
                   1777: static char *
                   1778: ngx_http_scgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
                   1779: {
                   1780:     ngx_http_scgi_loc_conf_t *scf = conf;
                   1781: 
                   1782:     ngx_str_t                         *value;
                   1783:     ngx_http_compile_complex_value_t   ccv;
                   1784: 
                   1785:     value = cf->args->elts;
                   1786: 
                   1787:     if (scf->cache_key.value.data) {
                   1788:         return "is duplicate";
                   1789:     }
                   1790: 
                   1791:     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
                   1792: 
                   1793:     ccv.cf = cf;
                   1794:     ccv.value = &value[1];
                   1795:     ccv.complex_value = &scf->cache_key;
                   1796: 
                   1797:     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
                   1798:         return NGX_CONF_ERROR;
                   1799:     }
                   1800: 
                   1801:     return NGX_CONF_OK;
                   1802: }
                   1803: 
                   1804: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>