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