| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- 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, errReference)
- }
- }
|