CodeCharmLtd/http-master

View on GitHub
modules/middleware/proxy.js

Summary

Maintainability
B
6 hrs
Test Coverage
'use strict';

var http = require('http');
var https = require('https');
var httpProxy = require('http-proxy');
var url = require('url');
var regexpHelper = require('../../src/regexpHelper');
var assert = require('assert');

function parseEntry(entry) {
  var m;
  if(typeof entry == 'number')
    entry = entry.toString();

  assert(typeof entry === 'string');

  var withPath = false;
  withPath = !!entry.replace(/https?:\/\//, '').match(/.*\//);

  if((m = entry.match(/^\d+(?:|\/.*)$/))) {
    entry = '127.0.0.1:' + entry;
  }
  if(!entry.match(/https?:\/\//)) {
    entry = 'http://' + entry;
  }
  entry = url.parse(entry, true, true);
  entry.withPath = withPath;
  return entry;
}

function getAgent(config, portConfig) {
  let httpAgent = false, httpsAgent = false;
  var agentSettings = portConfig.agentSettings || config.agentSettings;
  if (agentSettings) {
    httpAgent = new http.Agent(agentSettings);
    httpsAgent = new https.Agent(agentSettings);
  }
  return {httpAgent, httpsAgent};
}

module.exports = function ProxyMiddleware(config, portConfig, di) {
  var {httpAgent, httpsAgent} = getAgent(config, portConfig);
  var proxyHttp = httpProxy.createProxyServer({xfwd: true, agent: httpAgent});
  var proxyHttps = httpProxy.createProxyServer({xfwd: true, agent: httpsAgent, secure: false});
  proxyHttp.on('error', function(err, req, res) {
    req.err = err;
    req.next(err);
  });
  proxyHttps.on('error', function(err, req, res) {
    req.err = err;
    req.next(err);
  });

  var rewriteTargetAndPathIfNeeded = function(req, target) {
    if(!req.match) {
      return target;
    }

    var processed = regexpHelper(target.href, req.match);

    if (req.parsedUrl.search) {
      processed += req.parsedUrl.search;
    }

    var newTarget = url.parse(processed);
    if(target.withPath) {
      req.url = newTarget.path;
    }
    return newTarget;
  };

  return {
    requestHandler: function(req, res, next, dispatchTarget) {
      req.next = next;
      // workaround for node-http-proxy/#591
      if(!req.headers.host) {
        req.headers.host = '';
      }
            
      var proxyTarget = rewriteTargetAndPathIfNeeded(req, dispatchTarget);
      var m = req.headers.host.match(/^(.+):(\d+)$/);
      if(m) {
        req.headers.host = m[1] + ':' + m[2];
      }

      // work around weirdness of new http-proxy url handling
      // for the purpose of passing the tests
      if(proxyTarget.pathname !== '/') {
        req.url = '';
      }
      else {
        proxyTarget.path = '';
      }
      let proxy = proxyTarget.protocol === 'https:' ? proxyHttps : proxyHttp;
      let agent = proxyTarget.protocol === 'https:' ? httpsAgent : httpAgent;
      req.__proxy = proxy;
      req.__agent = agent;

      var options = {
        target: proxyTarget,
        proxyTimeout: portConfig.proxyTargetTimeout,
        timeout: portConfig.proxyTimeout,
        toProxy: true
      };

      if(req.upgrade) {
        return proxy.ws(req, req.upgrade.socket, req.upgrade.head, options);
      }
      proxy.web(req, res, options);
    },
    entryParser: function(entry) {
      return parseEntry(entry.target || entry);
    }
  };
};