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