Skip to content

Instantly share code, notes, and snippets.

@AlexF4Dev
Forked from miensol/net-proxy.js
Created January 12, 2025 23:19
Show Gist options
  • Save AlexF4Dev/651a61119dcece73a79ddfa04fbdfdff to your computer and use it in GitHub Desktop.
Save AlexF4Dev/651a61119dcece73a79ddfa04fbdfdff to your computer and use it in GitHub Desktop.

Revisions

  1. @miensol miensol created this gist Mar 23, 2014.
    118 changes: 118 additions & 0 deletions net-proxy.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,118 @@
    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);