var net = require('net'), http = require('http'), Writable = require('stream').Writable, parsers = http.parsers, HTTPParser = process.binding('http_parser').HTTPParser, util = require('util'), EventEmitter = require('events').EventEmitter; function freeParser(parser, req) { if (parser) { parser._headers = []; parser.onIncoming = null; if (parser.socket) { parser.socket.onend = null; parser.socket.ondata = null; parser.socket.parser = null; } parser.socket = null; parser.incoming = null; parsers.free(parser); parser = null; } if (req) { req.parser = null; } } var HttpParsingStream = function (options) { Writable.call(this, {}); var socket = options.socket; var parser = parsers.alloc(); var streamChunks = []; var that = this; parser.reinitialize(options.parserMode); parser.socket = socket; socket.parser = parser; parser.onIncoming = function (request) { that.emit('headers', request); request.on('data', function () { //we either have to call resume or attach on data handler to get end event... // console.log(options.name + '.data', arguments); }); request.on('end', function () { that.emit('end'); freeParser(parser, request); }); }; socket.on('close', function () { that.emit('socket.close'); }); this._write = function (chunk, encoding, callback) { streamChunks.push({ chunk: chunk, encoding: encoding }); parser.execute(chunk, 0, chunk.length); callback && callback(); }; this.writeCurrentChunks = function (writableStream) { streamChunks.forEach(function (chunkObj) { console.log(chunkObj.chunk.toString('ascii')); writableStream.write(chunkObj.chunk, chunkObj.encoding); }); }; }; HttpParsingStream.createForRequest = function (socket) { return new HttpParsingStream({ socket: socket, parserMode: HTTPParser.REQUEST, name: 'request' }); }; HttpParsingStream.createForResponse = function (socket) { return new HttpParsingStream({ socket: socket, parserMode: HTTPParser.RESPONSE, name: 'response' }); }; util.inherits(HttpParsingStream, Writable); net.createServer(function (socketRequest) { var requestParser = HttpParsingStream.createForRequest(socketRequest); requestParser.on('headers', function (req) { console.log('request.headers'); //pause the request until we setup necessary plumbing req.pause(); var hostNameHeader = req.headers.host, hostAndPort = hostNameHeader.split(':'), host = hostAndPort[0], port = parseInt(hostAndPort[1]) || 80; var srvSocket = net.connect(port, host, function () { var responseParser = HttpParsingStream.createForResponse(srvSocket); responseParser.on('headers', function () { console.log('response.headers'); }); responseParser.on('end', function () { console.log('response.end'); }); srvSocket.pipe(responseParser); srvSocket.pipe(socketRequest); requestParser.writeCurrentChunks(srvSocket); socketRequest.pipe(srvSocket); req.resume(); }); }); requestParser.on('end', function () { console.log('request.end'); }); socketRequest.pipe(requestParser); }).listen(9000);