forked from coolaj86/goldilocks.js
		
	reduced code duplication for proxying
This commit is contained in:
		
							parent
							
								
									d25ceadf4a
								
							
						
					
					
						commit
						df3a818914
					
				@ -80,40 +80,16 @@ module.exports.create = function (deps, config) {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function createTcpForwarder(mod) {
 | 
			
		||||
    var destination = mod.address.split(':');
 | 
			
		||||
    var connected = false;
 | 
			
		||||
 | 
			
		||||
    return function (conn) {
 | 
			
		||||
      var newConn = deps.net.createConnection({
 | 
			
		||||
        port: destination[1]
 | 
			
		||||
      , host: destination[0] || '127.0.0.1'
 | 
			
		||||
      var newConnOpts = require('./domain-utils').separatePort(mod.address);
 | 
			
		||||
 | 
			
		||||
      , remoteFamily:  conn.remoteFamily
 | 
			
		||||
      , remoteAddress: conn.remoteAddress
 | 
			
		||||
      , remotePort:    conn.remotePort
 | 
			
		||||
      }, function () {
 | 
			
		||||
        connected = true;
 | 
			
		||||
 | 
			
		||||
        newConn.pipe(conn);
 | 
			
		||||
        conn.pipe(newConn);
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      // Not sure how to effectively report this to the user or client, but we need to listen
 | 
			
		||||
      // for the event to prevent it from crashing us.
 | 
			
		||||
      newConn.on('error', function (err) {
 | 
			
		||||
        if (connected) {
 | 
			
		||||
          console.error('TCP forward remote error', err);
 | 
			
		||||
          conn.end();
 | 
			
		||||
        } else {
 | 
			
		||||
          console.log('TCP forward connection error', err);
 | 
			
		||||
          require('./proxy-err-resp').sendBadGateway(conn, err, config.debug);
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
      conn.on('error', function (err) {
 | 
			
		||||
        console.error('TCP forward client error', err);
 | 
			
		||||
        newConn.end();
 | 
			
		||||
      ['remote', 'local'].forEach(function (end) {
 | 
			
		||||
        ['Family', 'Address', 'Port'].forEach(function (name) {
 | 
			
		||||
          newConnOpts[end+name] = conn[end+name];
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      deps.proxy(conn, newConnOpts);
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -275,7 +275,6 @@ module.exports.create = function (deps, conf, greenlockMiddleware) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    var connected = false;
 | 
			
		||||
    var newConnOpts = separatePort(mod.address);
 | 
			
		||||
    newConnOpts.servername = separatePort(headers.host).host;
 | 
			
		||||
    newConnOpts.data = opts.firstChunk;
 | 
			
		||||
@ -284,28 +283,7 @@ module.exports.create = function (deps, conf, greenlockMiddleware) {
 | 
			
		||||
    newConnOpts.remoteAddress = opts.address || conn.remoteAddress;
 | 
			
		||||
    newConnOpts.remotePort    = opts.port    || conn.remotePort;
 | 
			
		||||
 | 
			
		||||
    var newConn = deps.net.createConnection(newConnOpts, function () {
 | 
			
		||||
      connected = true;
 | 
			
		||||
      newConn.write(opts.firstChunk);
 | 
			
		||||
      newConn.pipe(conn);
 | 
			
		||||
      conn.pipe(newConn);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Not sure how to effectively report this to the user or client, but we need to listen
 | 
			
		||||
    // for the event to prevent it from crashing us.
 | 
			
		||||
    newConn.on('error', function (err) {
 | 
			
		||||
      if (connected) {
 | 
			
		||||
        console.error('HTTP proxy remote error', err);
 | 
			
		||||
        conn.end();
 | 
			
		||||
      } else {
 | 
			
		||||
        require('../proxy-err-resp').sendBadGateway(conn, err, conf.debug);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    conn.on('error', function (err) {
 | 
			
		||||
      console.error('HTTP proxy client error', err);
 | 
			
		||||
      newConn.end();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    deps.proxy(conn, newConnOpts, opts.firstChunk);
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -186,49 +186,24 @@ module.exports.create = function (deps, config, netHandler) {
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  function proxy(socket, opts, mod) {
 | 
			
		||||
    var destination = mod.address.split(':');
 | 
			
		||||
    var connected = false;
 | 
			
		||||
    var newConnOpts = require('../domain-utils').separatePort(mod.address);
 | 
			
		||||
    newConnOpts.servername = opts.servername;
 | 
			
		||||
    newConnOpts.data = opts.firstChunk;
 | 
			
		||||
 | 
			
		||||
    var newConn = deps.net.createConnection({
 | 
			
		||||
        port: destination[1]
 | 
			
		||||
      , host: destination[0] || '127.0.0.1'
 | 
			
		||||
    newConnOpts.remoteFamily  = opts.family  || extractSocketProp(socket, 'remoteFamily');
 | 
			
		||||
    newConnOpts.remoteAddress = opts.address || extractSocketProp(socket, 'remoteAddress');
 | 
			
		||||
    newConnOpts.remotePort    = opts.port    || extractSocketProp(socket, 'remotePort');
 | 
			
		||||
 | 
			
		||||
      , servername: opts.servername
 | 
			
		||||
      , data: opts.firstChunk
 | 
			
		||||
      , remoteFamily:  opts.family  || extractSocketProp(socket, 'remoteFamily')
 | 
			
		||||
      , remoteAddress: opts.address || extractSocketProp(socket, 'remoteAddress')
 | 
			
		||||
      , remotePort:    opts.port    || extractSocketProp(socket, 'remotePort')
 | 
			
		||||
    }, function () {
 | 
			
		||||
      connected = true;
 | 
			
		||||
      if (!opts.hyperPeek) {
 | 
			
		||||
        newConn.write(opts.firstChunk);
 | 
			
		||||
      }
 | 
			
		||||
      newConn.pipe(socket);
 | 
			
		||||
      socket.pipe(newConn);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Not sure how to effectively report this to the user or client, but we need to listen
 | 
			
		||||
    // for the event to prevent it from crashing us.
 | 
			
		||||
    newConn.on('error', function (err) {
 | 
			
		||||
      if (connected) {
 | 
			
		||||
        console.error('TLS proxy remote error', err);
 | 
			
		||||
        socket.end();
 | 
			
		||||
    deps.proxy(socket, newConnOpts, opts.firstChunk, function () {
 | 
			
		||||
      // This function is called in the event of a connection error and should decrypt
 | 
			
		||||
      // the socket so the proxy module can send a 502 HTTP response.
 | 
			
		||||
      var tlsOpts = localhostCerts.mergeTlsOptions('localhost.daplie.me', {isServer: true});
 | 
			
		||||
      if (opts.hyperPeek) {
 | 
			
		||||
        return new tls.TLSSocket(socket, tlsOpts);
 | 
			
		||||
      } else {
 | 
			
		||||
        console.log('TLS proxy connection error', err);
 | 
			
		||||
        var tlsOpts = localhostCerts.mergeTlsOptions('localhost.daplie.me', {isServer: true});
 | 
			
		||||
        var decrypted;
 | 
			
		||||
        if (opts.hyperPeek) {
 | 
			
		||||
          decrypted = new tls.TLSSocket(socket, tlsOpts);
 | 
			
		||||
        } else {
 | 
			
		||||
          decrypted = new tls.TLSSocket(wrapSocket(socket, opts), tlsOpts);
 | 
			
		||||
        }
 | 
			
		||||
        require('../proxy-err-resp').sendBadGateway(decrypted, err, config.debug);
 | 
			
		||||
        return new tls.TLSSocket(wrapSocket(socket, opts), tlsOpts);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    socket.on('error', function (err) {
 | 
			
		||||
      console.error('TLS proxy client error', err);
 | 
			
		||||
      newConn.end();
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function terminate(socket, opts) {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										71
									
								
								lib/proxy-conn.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								lib/proxy-conn.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,71 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
function getRespBody(err, debug) {
 | 
			
		||||
  if (debug) {
 | 
			
		||||
    return err.toString();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (err.code === 'ECONNREFUSED') {
 | 
			
		||||
    return 'The connection was refused. Most likely the service being connected to '
 | 
			
		||||
      + 'has stopped running or the configuration is wrong.';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return 'Bad Gateway: ' + err.code;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function sendBadGateway(conn, err, debug) {
 | 
			
		||||
  var body = getRespBody(err, debug);
 | 
			
		||||
 | 
			
		||||
  conn.write([
 | 
			
		||||
    'HTTP/1.1 502 Bad Gateway'
 | 
			
		||||
  , 'Date: ' + (new Date()).toUTCString()
 | 
			
		||||
  , 'Connection: close'
 | 
			
		||||
  , 'Content-Type: text/html'
 | 
			
		||||
  , 'Content-Length: ' + body.length
 | 
			
		||||
  , ''
 | 
			
		||||
  , body
 | 
			
		||||
  ].join('\r\n'));
 | 
			
		||||
  conn.end();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports.getRespBody = getRespBody;
 | 
			
		||||
module.exports.sendBadGateway = sendBadGateway;
 | 
			
		||||
 | 
			
		||||
module.exports.create = function (deps, config) {
 | 
			
		||||
  return function proxy(conn, newConnOpts, firstChunk, decrypt) {
 | 
			
		||||
    var connected = false;
 | 
			
		||||
    var newConn = deps.net.createConnection(newConnOpts, function () {
 | 
			
		||||
      connected = true;
 | 
			
		||||
 | 
			
		||||
      if (firstChunk) {
 | 
			
		||||
        newConn.write(firstChunk);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      newConn.pipe(conn);
 | 
			
		||||
      conn.pipe(newConn);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    newConn.on('error', function (err) {
 | 
			
		||||
      if (connected) {
 | 
			
		||||
        // Not sure how to report this to a user or a client. We can assume that some data
 | 
			
		||||
        // has already been exchanged, so we can't really be sure what we can send in addition
 | 
			
		||||
        // that wouldn't result in a parse error.
 | 
			
		||||
        console.log('proxy remote error', err);
 | 
			
		||||
        conn.end();
 | 
			
		||||
      } else {
 | 
			
		||||
        console.log('proxy connection error', err);
 | 
			
		||||
        if (decrypt) {
 | 
			
		||||
          sendBadGateway(decrypt(conn), err, config.debug);
 | 
			
		||||
        } else {
 | 
			
		||||
          sendBadGateway(conn, err, config.debug);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Listening for this largely to prevent uncaught exceptions.
 | 
			
		||||
    conn.on('error', function (err) {
 | 
			
		||||
      console.log('proxy client error', err);
 | 
			
		||||
      newConn.end();
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
@ -1,32 +0,0 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
function getRespBody(err, debug) {
 | 
			
		||||
  if (debug) {
 | 
			
		||||
    return err.toString();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (err.code === 'ECONNREFUSED') {
 | 
			
		||||
    return 'The connection was refused. Most likely the service being connected to '
 | 
			
		||||
      + 'has stopped running or the configuration is wrong.';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return 'Bad Gateway: ' + err.code;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function sendBadGateway(conn, err, debug) {
 | 
			
		||||
  var body = getRespBody(err, debug);
 | 
			
		||||
 | 
			
		||||
  conn.write([
 | 
			
		||||
    'HTTP/1.1 502 Bad Gateway'
 | 
			
		||||
  , 'Date: ' + (new Date()).toUTCString()
 | 
			
		||||
  , 'Connection: close'
 | 
			
		||||
  , 'Content-Type: text/html'
 | 
			
		||||
  , 'Content-Length: ' + body.length
 | 
			
		||||
  , ''
 | 
			
		||||
  , body
 | 
			
		||||
  ].join('\r\n'));
 | 
			
		||||
  conn.end();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports.getRespBody = getRespBody;
 | 
			
		||||
module.exports.sendBadGateway = sendBadGateway;
 | 
			
		||||
@ -9,5 +9,7 @@ process.on('message', function (conf) {
 | 
			
		||||
    // HTTP proxying connection creation is not something we currently control.
 | 
			
		||||
  , net: require('net')
 | 
			
		||||
  };
 | 
			
		||||
  deps.proxy = require('./proxy-conn').create(deps, conf);
 | 
			
		||||
 | 
			
		||||
  require('./goldilocks.js').create(deps, conf);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user