Skip to content

Instantly share code, notes, and snippets.

@miensol
Created March 23, 2014 17:37
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save miensol/9726643 to your computer and use it in GitHub Desktop.
Save miensol/9726643 to your computer and use it in GitHub Desktop.
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);
@asyncer
Copy link

asyncer commented May 21, 2015

I've tested your code but it shows error below on line 31
TypeError: Cannot read property 'alloc' of undefined

Would you please let me know how to fix it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment