diff --git a/cgi.js b/cgi.js index 411cd50..269c7ba 100644 --- a/cgi.js +++ b/cgi.js @@ -104,22 +104,26 @@ function cgi(cgiBin, options) { debug('env: %o', env); opts.env = env; + if (options.nph && options.dupfd) { + opts.stdio= [req.connection, req.connection, 'inherit']; + } + var cgiSpawn = spawn(cgiBin, opts.args, opts); debug('cgi spawn (pid: %o)', cgiSpawn.pid); - + // The request body is piped to 'stdin' of the CGI spawn - req.pipe(cgiSpawn.stdin); + if (!options.nph) { + req.pipe(cgiSpawn.stdin); - // If `options.stderr` is set to a Stream instance, then re-emit the - // 'data' events onto the stream. - if (options.stderr) { - cgiSpawn.stderr.pipe(options.stderr); - } + // If `options.stderr` is set to a Stream instance, then re-emit the + // 'data' events onto the stream. + if (options.stderr) { + cgiSpawn.stderr.pipe(options.stderr); + } - // A proper CGI script is supposed to print headers to 'stdout' - // followed by a blank line, then a response body. - var cgiResult; - if (!options.nph) { + // A proper CGI script is supposed to print headers to 'stdout' + // followed by a blank line, then a response body. + var cgiResult; cgiResult = new CGIParser(cgiSpawn.stdout); // When the blank line after the headers has been parsed, then @@ -138,28 +142,43 @@ function cgi(cgiBin, options) { // The response body is piped to the response body of the HTTP request cgiResult.pipe(res); }); + + cgiSpawn.stdout.on('end', function () { + // clean up event listeners upon the "end" event + debug('cgi spawn %o stdout "end" event', cgiSpawn.pid); + if (cgiResult) { + cgiResult.cleanup(); + } + //if (options.stderr) { + // cgiSpawn.stderr.unpipe(options.stderr); + //} + }); + } else { // If it's an NPH script, then responsibility of the HTTP response is // completely passed off to the child process. - cgiSpawn.stdout.pipe(res.connection); + + if (options.dupfd) { + // Close the connection because it is now handled by the child + req.connection.destroy(); + } else { + req.pipe(cgiSpawn.stdin); + // Setup pipes + cgiSpawn.stdout.pipe(res.connection); + + // If `options.stderr` is set to a Stream instance, then re-emit the + // 'data' events onto the stream. + if (options.stderr) { + cgiSpawn.stderr.pipe(options.stderr); + } + } } cgiSpawn.on('exit', function(code, signal) { debug('cgi spawn %o "exit" event (code %o) (signal %o)', cgiSpawn.pid, code, signal); // TODO: react on a failure status code (dump stderr to the response?) }); - - cgiSpawn.stdout.on('end', function () { - // clean up event listeners upon the "end" event - debug('cgi spawn %o stdout "end" event', cgiSpawn.pid); - if (cgiResult) { - cgiResult.cleanup(); - } - //if (options.stderr) { - // cgiSpawn.stderr.unpipe(options.stderr); - //} - }); - }; + } } // The default config options to use for each `cgi()` call. @@ -172,6 +191,8 @@ cgi.DEFAULTS = { nph: false, // Set to a `Stream` instance if you want to log stderr of the CGI script somewhere stderr: null, + // Pass file descriptors of connection to the child (no copy). Probably only work with http connections + dupfd: false, // A list of arguments for the cgi bin to be used by spawn args: [] };