var TCP = process.binding("tcp_wrap").TCP; var Buffer = process.binding("buffer").SlowBuffer; var HTTPParser = process.binding("http_parser").HTTPParser; function setupSocket(peer) { function shutdownHandler(status, handle, req) { // TODO: ensure we only shutdown once if(status != 0) { if(peer.onerror) { var err = new Error("shutdown"); err.errno = errno; peer.onerror(err); } } handle.close(); if(peer.onclose) peer.onclose(); } function kill() { if(!peer.closed) { peer.readStop(); peer.onread = function() {}; var r = peer.shutdown(); peer.closed = true; r.oncomplete = shutdownHandler; } } function send(buff, cb) { var wr = peer.write(buff); if (!wr) { if(peer.onerror) { var err = new Error("write"); err.errno = errno; peer.onerror(err); } peer.kill(); return false; } wr.oncomplete = cb; return true; } peer.closed = false; peer.kill = kill; peer.send = send; } var responses = { keepalive: "HTTP/1.1 200 OK\r\nServer: node-/0.6.10\r\nDate: Thu, 09 Feb 2012 00:46:42 GMT\r\nContent-Type: text/html\r\nContent-Length: 0\r\nLast-Modified: Tue, 06 Dec 2011 17:29:28 GMT\r\nConnection: keep-alive\r\nAccept-Ranges: bytes\r\n\r\n", close: "HTTP/1.1 200 OK\r\nServer: nginx/0.7.67\r\nDate: Thu, 09 Feb 2012 00:46:42 GMT\r\nContent-Type: text/html\r\nContent-Length: 0\r\nLast-Modified: Tue, 06 Dec 2011 17:29:28 GMT\r\nConnection: close\r\nAccept-Ranges: bytes\r\n\r\n" } for (name in responses) { var b = new Buffer(responses[name].length); b.asciiWrite(responses[name]); responses[name] = b; } var FreeList = function(name, max, constructor) { this.name = name; this.constructor = constructor; this.max = max; this.list = []; }; FreeList.prototype.alloc = function() { return this.list.length ? this.list.shift() : this.constructor.apply(this, arguments); }; FreeList.prototype.free = function(obj) { if (this.list.length < this.max) this.list.push(obj); }; var HTTPParsers = new FreeList("HTTPParsers", 1024, function() { var parser = new HTTPParser(HTTPParser.REQUEST); parser.onHeadersComplete = function(info) { var peer = this.peer; peer.info = info }; parser.onMessageComplete = function() { var peer = this.peer; peer.send(peer.info.shouldKeepAlive?responses.keepalive:responses.close, function(status, handle, req) { if(status != 0) { var err = new Error("write"); err.errno = errno; console.error(err); peer.kill(); return; } if(!peer.info.shouldKeepAlive) peer.kill(); }); }; return parser; }); function onConnection(peer) { if(!peer) { var err = new Error("accept"); err.errno = errno; console.error(err); return; } setupSocket(peer); var parser = HTTPParsers.alloc(); parser.peer = peer; peer.onread = function(buf, start, len) { if(!buf) { var err = new Error("EOF"); err.errno = errno; console.error(err); peer.kill(); return; } var r = parser.execute(buf, start, len); if(r < 0) { var err = new Error("parse"); console.error(err); peer.kill(); return; } } peer.onerror = function(err) { console.error(err); } peer.onclose = function() { HTTPParsers.free(parser); } peer.readStart(); } var sock = new TCP(); sock.bind("0.0.0.0", 80); sock.onconnection = onConnection; sock.listen();