Skip to content

Instantly share code, notes, and snippets.

@ivershuo
Last active March 9, 2016 05:52
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ivershuo/10010608 to your computer and use it in GitHub Desktop.
Save ivershuo/10010608 to your computer and use it in GitHub Desktop.
FastCGI server for Node.js
var net = require('net'),
querystring = require('querystring');
var TYPES = {
FCGI_BEGIN_REQUEST : 1,
FCGI_ABORT_REQUEST : 2,
FCGI_END_REQUEST : 3,
FCGI_PARAMS : 4,
FCGI_STDIN : 5,
FCGI_STDOUT : 6,
FCGI_STDERR : 7,
FCGI_DATA : 8,
FCGI_GET_VALUES : 9,
FCGI_GET_VALUES_RESULT : 10,
FCGI_UNKNOWN_TYPE : 11
}
var mix = function(des, src, map){
map = map || function(d, s, i){
if(!(des[i] || (i in des))){
return s;
}
return d;
}
if(map === true){
map = function(d,s){
return s;
}
}
for (i in src) {
des[i] = map(des[i], src[i], i, des, src);
if(des[i] === undefined) delete des[i];
}
return des;
};
function getRcds(data, cb){
var rcds = [],
start = 0,
length = data.length;
return function (){
if(start >= length){
cb && cb(rcds);
rcds = null;
return;
}
var end = start + 8,
header = data.slice(start, end),
version = header[0],
type = header[1],
requestId = (header[2] << 8) + header[3],
contentLength = (header[4] << 8) + header[5],
paddingLength = header[6];
start = end + contentLength + paddingLength;
var body = contentLength ? data.slice(end, contentLength) : null;
rcds.push([type, body, requestId]);
return arguments.callee();
}
}
function parseParams(body){
var j = 0,
params = {},
length = body.length;
while(j < length){
var name,
value,
nameLength,
valueLength;
if(body[j] >> 7 == 1){
nameLength = ((body[j++] & 0x7f) << 24) + (body[j++] << 16) + (body[j++] << 8) + body[j++];
} else {
nameLength = body[j++];
}
if(body[j] >> 7 == 1){
valueLength = ((body[j++] & 0x7f) << 24) + (body[j++] << 16) + (body[j++] << 8) + body[j++];
} else {
valueLength = body[j++];
}
var ret = body.asciiSlice(j, j + nameLength + valueLength);
name = ret.substring(0, nameLength);
value = ret.substring(nameLength);
params[name] = value;
j += (nameLength + valueLength);
}
return params;
}
var res = (function(){
var MaxLength = Math.pow(2, 16);
function buffer0(len){
return new Buffer((new Array(len + 1)).join('\u0000'));
};
function writeStdout(data){
var rcdStdoutHd = new Buffer(8),
contendLength = data.length,
paddingLength = 8 - contendLength % 8;
rcdStdoutHd[0] = 1;
rcdStdoutHd[1] = TYPES.FCGI_STDOUT;
rcdStdoutHd[2] = 0;
rcdStdoutHd[3] = 1;
rcdStdoutHd[4] = contendLength >> 8;
rcdStdoutHd[5] = contendLength;
rcdStdoutHd[6] = paddingLength;
rcdStdoutHd[7] = 0;
return Buffer.concat([rcdStdoutHd, data, buffer0(paddingLength)]);
};
function writeHttpHead(){
return writeStdout(new Buffer("HTTP/1.1 200 OK\r\nContent-Type:text/html; charset=utf-8\r\nConnection: close\r\n\r\n"));
}
function writeHttpBody(bodyStr){
var bodyBuffer = [],
body = new Buffer(bodyStr);
for(var i = 0, l = body.length; i < l; i += MaxLength + 1){
bodyBuffer.push(writeStdout(body.slice(i, i + MaxLength)));
}
return Buffer.concat(bodyBuffer);
}
function writeEnd(){
var rcdEndHd = new Buffer(8);
rcdEndHd[0] = 1;
rcdEndHd[1] = TYPES.FCGI_END_REQUEST;
rcdEndHd[2] = 0;
rcdEndHd[3] = 1;
rcdEndHd[4] = 0;
rcdEndHd[5] = 8;
rcdEndHd[6] = 0;
rcdEndHd[7] = 0;
return Buffer.concat([rcdEndHd, buffer0(8)]);
}
return function(data){
return Buffer.concat([writeHttpHead(), writeHttpBody(data), writeEnd()]);
};
})();
var visitors = 0;
var server = net.createServer();
server.listen('/tmp/node_fcgi.sock');
server.on('connection', function(sock){
visitors++;
sock.on('data', function(data){
var params = {};
getRcds(data, function(rcds){
for(var i = 0, l = rcds.length; i < l; i++){
var bodyData = rcds[i],
type = bodyData[0],
body = bodyData[1];
if(body && (type === TYPES.FCGI_PARAMS || type === TYPES.FCGI_GET_VALUES || type === TYPES.FCGI_GET_VALUES_RESULT)){
mix(params, parseParams(body));
}
}
var querys = querystring.parse(params.QUERY_STRING);
var ret = res('欢迎你,' + (querys.name || '亲爱的朋友') + '!你是本站第' + visitors + '位用户哦~');
sock.write(ret);
ret = null;
sock.end();
})();
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment