~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Nginx/http/modules/ngx_http_scgi_module.c

Version: ~ [ nginx-1.4.1 ] ~ [ nginx-1.5.0 ] ~

  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
1805 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.