Skip to content

Instantly share code, notes, and snippets.

@hoshi-takanori
Last active December 2, 2021 10:25
Show Gist options
  • Save hoshi-takanori/ca54044b3daa3e369463 to your computer and use it in GitHub Desktop.
Save hoshi-takanori/ca54044b3daa3e369463 to your computer and use it in GitHub Desktop.
Invoke CGI from Express.js.
var express = require('express');
var cgi = require('./cgi');
app = express();
var script = __dirname + '/hello.cgi';
app.get('/', cgi(script, function (req, options) {
options.env.USERNAME = 'Mr. User';
}));
app.use(function (err, req, res, next) {
res.send(500, 'Error: ' + err.message);
});
app.listen(process.env.PORT || 3000);
var fs = require('fs');
var url = require('url');
var path = require('path');
var spawn = require('child_process').spawn;
var CGIParser = require('cgi/parser');
module.exports = function (cgiPath, callback) {
return function (req, res, next) {
try {
var stat = fs.statSync(cgiPath);
if (! stat.isFile() || (stat.mode & parseInt('111', 8)) == 0) {
return next(new Error('cgi file\'s mode = ' + stat.mode));
}
} catch (err) {
return next(err);
}
var parsedUrl = url.parse(req.url);
var env = {
REQUEST_METHOD: req.method,
QUERY_STRING: parsedUrl.query || ''
};
if ('content-length' in req.headers) {
env.CONTENT_LENGTH = req.headers['content-length'];
}
var options = { cwd: path.dirname(cgiPath), env: env };
if (callback) callback(req, options);
var proc = spawn(cgiPath, [], options);
req.pipe(proc.stdin);
var result = new CGIParser(proc.stdout);
result.on('headers', function (headers) {
headers.forEach(function (header) {
if (header.key === 'Status') return;
res.setHeader(header.key, header.value);
});
res.statusCode = parseInt(headers.status, 10) || 200;
result.pipe(res);
});
proc.on('exit', function (code, signal) {
if (code || signal) {
next(new Error('cgi proc died: code = ' + code + ', signal = ' + signal));
}
});
proc.stdout.on('end', function () {
if (result) result.cleanup();
});
};
};
#!/bin/sh
echo Status: 200
echo Content-Type: text/plain
echo
echo Hello, $USERNAME!
{
"name": "express-cgi",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node app"
},
"dependencies": {
"express": "*",
"cgi": "*"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment