123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- 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
- * @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
- */
- 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 errReference = 'https://nodejs.org/api/errors.html#errors_common_system_errors'; // link to Node Common Systems Errors page
- logger.error('[HPM] Error occurred while trying to proxy request %s from %s to %s (%s) (%s)', req.url, hostname, target, err.code, errReference);
- }
- };
|