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(¶ms_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(¶ms_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(¶ms_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>