You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							182 lines
						
					
					
						
							5.0 KiB
						
					
					
				
			
		
		
	
	
							182 lines
						
					
					
						
							5.0 KiB
						
					
					
				var _ = require('lodash') | 
						|
var httpProxy = require('http-proxy') | 
						|
var configFactory = require('./config-factory') | 
						|
var handlers = require('./handlers') | 
						|
var contextMatcher = require('./context-matcher') | 
						|
var PathRewriter = require('./path-rewriter') | 
						|
var Router = require('./router') | 
						|
var logger = require('./logger').getInstance() | 
						|
var getArrow = require('./logger').getArrow | 
						|
 | 
						|
module.exports = HttpProxyMiddleware | 
						|
 | 
						|
function HttpProxyMiddleware(context, opts) { | 
						|
  // https://github.com/chimurai/http-proxy-middleware/issues/57 | 
						|
  var wsUpgradeDebounced = _.debounce(handleUpgrade) | 
						|
  var wsInitialized = false | 
						|
  var config = configFactory.createConfig(context, opts) | 
						|
  var proxyOptions = config.options | 
						|
 | 
						|
  // create proxy | 
						|
  var proxy = httpProxy.createProxyServer({}) | 
						|
  logger.info( | 
						|
    '[HPM] Proxy created:', | 
						|
    config.context, | 
						|
    ' -> ', | 
						|
    proxyOptions.target | 
						|
  ) | 
						|
 | 
						|
  var pathRewriter = PathRewriter.create(proxyOptions.pathRewrite) // returns undefined when "pathRewrite" is not provided | 
						|
 | 
						|
  // attach handler to http-proxy events | 
						|
  handlers.init(proxy, proxyOptions) | 
						|
 | 
						|
  // log errors for debug purpose | 
						|
  proxy.on('error', logError) | 
						|
 | 
						|
  // https://github.com/chimurai/http-proxy-middleware/issues/19 | 
						|
  // expose function to upgrade externally | 
						|
  middleware.upgrade = wsUpgradeDebounced | 
						|
 | 
						|
  return middleware | 
						|
 | 
						|
  function middleware(req, res, next) { | 
						|
    if (shouldProxy(config.context, req)) { | 
						|
      var activeProxyOptions = prepareProxyRequest(req) | 
						|
      proxy.web(req, res, activeProxyOptions) | 
						|
    } else { | 
						|
      next() | 
						|
    } | 
						|
 | 
						|
    if (proxyOptions.ws === true) { | 
						|
      // use initial request to access the server object to subscribe to http upgrade event | 
						|
      catchUpgradeRequest(req.connection.server) | 
						|
    } | 
						|
  } | 
						|
 | 
						|
  function catchUpgradeRequest(server) { | 
						|
    // subscribe once; don't subscribe on every request... | 
						|
    // https://github.com/chimurai/http-proxy-middleware/issues/113 | 
						|
    if (!wsInitialized) { | 
						|
      server.on('upgrade', wsUpgradeDebounced) | 
						|
      wsInitialized = true | 
						|
    } | 
						|
  } | 
						|
 | 
						|
  function handleUpgrade(req, socket, head) { | 
						|
    // set to initialized when used externally | 
						|
    wsInitialized = true | 
						|
 | 
						|
    if (shouldProxy(config.context, req)) { | 
						|
      var activeProxyOptions = prepareProxyRequest(req) | 
						|
      proxy.ws(req, socket, head, activeProxyOptions) | 
						|
      logger.info('[HPM] Upgrading to WebSocket') | 
						|
    } | 
						|
  } | 
						|
 | 
						|
  /** | 
						|
   * Determine whether request should be proxied. | 
						|
   * | 
						|
   * @private | 
						|
   * @param  {String} context [description] | 
						|
   * @param  {Object} req     [description] | 
						|
   * @return {Boolean} | 
						|
   */ | 
						|
  function shouldProxy(context, req) { | 
						|
    var path = req.originalUrl || req.url | 
						|
    return contextMatcher.match(context, path, req) | 
						|
  } | 
						|
 | 
						|
  /** | 
						|
   * Apply option.router and option.pathRewrite | 
						|
   * Order matters: | 
						|
   *    Router uses original path for routing; | 
						|
   *    NOT the modified path, after it has been rewritten by pathRewrite | 
						|
   * @param {Object} req | 
						|
   * @return {Object} proxy options | 
						|
   */ | 
						|
  function prepareProxyRequest(req) { | 
						|
    // https://github.com/chimurai/http-proxy-middleware/issues/17 | 
						|
    // https://github.com/chimurai/http-proxy-middleware/issues/94 | 
						|
    req.url = req.originalUrl || req.url | 
						|
 | 
						|
    // store uri before it gets rewritten for logging | 
						|
    var originalPath = req.url | 
						|
    var newProxyOptions = _.assign({}, proxyOptions) | 
						|
 | 
						|
    // Apply in order: | 
						|
    // 1. option.router | 
						|
    // 2. option.pathRewrite | 
						|
    __applyRouter(req, newProxyOptions) | 
						|
    __applyPathRewrite(req, pathRewriter) | 
						|
 | 
						|
    // debug logging for both http(s) and websockets | 
						|
    if (proxyOptions.logLevel === 'debug') { | 
						|
      var arrow = getArrow( | 
						|
        originalPath, | 
						|
        req.url, | 
						|
        proxyOptions.target, | 
						|
        newProxyOptions.target | 
						|
      ) | 
						|
      logger.debug( | 
						|
        '[HPM] %s %s %s %s', | 
						|
        req.method, | 
						|
        originalPath, | 
						|
        arrow, | 
						|
        newProxyOptions.target | 
						|
      ) | 
						|
    } | 
						|
 | 
						|
    return newProxyOptions | 
						|
  } | 
						|
 | 
						|
  // Modify option.target when router present. | 
						|
  function __applyRouter(req, options) { | 
						|
    var newTarget | 
						|
 | 
						|
    if (options.router) { | 
						|
      newTarget = Router.getTarget(req, options) | 
						|
 | 
						|
      if (newTarget) { | 
						|
        logger.debug( | 
						|
          '[HPM] Router new target: %s -> "%s"', | 
						|
          options.target, | 
						|
          newTarget | 
						|
        ) | 
						|
        options.target = newTarget | 
						|
      } | 
						|
    } | 
						|
  } | 
						|
 | 
						|
  // rewrite path | 
						|
  function __applyPathRewrite(req, pathRewriter) { | 
						|
    if (pathRewriter) { | 
						|
      var path = pathRewriter(req.url, req) | 
						|
 | 
						|
      if (typeof path === 'string') { | 
						|
        req.url = path | 
						|
      } else { | 
						|
        logger.info('[HPM] pathRewrite: No rewritten path found. (%s)', req.url) | 
						|
      } | 
						|
    } | 
						|
  } | 
						|
 | 
						|
  function logError(err, req, res) { | 
						|
    var hostname = | 
						|
      (req.headers && req.headers.host) || (req.hostname || req.host) // (websocket) || (node0.10 || node 4/5) | 
						|
    var target = proxyOptions.target.host || proxyOptions.target | 
						|
    var errorMessage = | 
						|
      '[HPM] Error occurred while trying to proxy request %s from %s to %s (%s) (%s)' | 
						|
    var errReference = | 
						|
      'https://nodejs.org/api/errors.html#errors_common_system_errors' // link to Node Common Systems Errors page | 
						|
 | 
						|
    logger.error( | 
						|
      errorMessage, | 
						|
      req.url, | 
						|
      hostname, | 
						|
      target, | 
						|
      err.code || err, | 
						|
      errReference | 
						|
    ) | 
						|
  } | 
						|
}
 | 
						|
 |