| 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 | 
|     ) | 
|   } | 
| } |