Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 45 additions & 24 deletions cgi.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand All @@ -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: []
};