FastCGI server for Node.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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