UNPKG

4.26 kBJavaScriptView Raw
1var _ = require('lodash');
2var httpProxy = require('http-proxy');
3var configFactory = require('./config-factory');
4var handlers = require('./handlers');
5var contextMatcher = require('./context-matcher');
6var PathRewriter = require('./path-rewriter');
7var ProxyTable = require('./proxy-table');
8var logger = require('./logger').getInstance();
9var getArrow = require('./logger').getArrow;
10
11module.exports = HttpProxyMiddleware;
12
13function HttpProxyMiddleware(context, opts) {
14 // https://github.com/chimurai/http-proxy-middleware/issues/57
15 var wsUpgradeDebounced = _.debounce(handleUpgrade);
16 var config = configFactory.createConfig(context, opts);
17 var proxyOptions = config.options;
18
19 // create proxy
20 var proxy = httpProxy.createProxyServer(proxyOptions);
21 logger.info('[HPM] Proxy created:', config.context, ' -> ', proxyOptions.target);
22
23 var pathRewriter = PathRewriter.create(proxyOptions.pathRewrite); // returns undefined when "pathRewrite" is not provided
24
25 // attach handler to http-proxy events
26 handlers.init(proxy, proxyOptions);
27
28 // log errors for debug purpose
29 proxy.on('error', logError);
30
31 // https://github.com/chimurai/http-proxy-middleware/issues/19
32 // expose function to upgrade externally
33 middleware.upgrade = wsUpgradeDebounced;
34
35 return middleware;
36
37 function middleware(req, res, next) {
38 // https://github.com/chimurai/http-proxy-middleware/issues/17
39 req.url = req.originalUrl;
40
41 if (contextMatcher.match(config.context, req.url, req)) {
42 var activeProxyOptions = prepareProxyRequest(req);
43 proxy.web(req, res, activeProxyOptions);
44 } else {
45 next();
46 }
47
48 if (proxyOptions.ws === true) {
49 catchUpgradeRequest(req.connection.server);
50 }
51 }
52
53 function catchUpgradeRequest(server) {
54 server.on('upgrade', wsUpgradeDebounced);
55 }
56
57 function handleUpgrade(req, socket, head) {
58 if (contextMatcher.match(config.context, req.url, req)) {
59 var activeProxyOptions = prepareProxyRequest(req);
60 proxy.ws(req, socket, head, activeProxyOptions);
61 logger.info('[HPM] Upgrading to WebSocket');
62 }
63 }
64
65 /**
66 * Apply option.proxyTable and option.pathRewrite
67 * Order matters:
68 ProxyTable uses original path for routing;
69 NOT the modified path, after it has been rewritten by pathRewrite
70 */
71 function prepareProxyRequest(req) {
72 // store uri before it gets rewritten for logging
73 var originalPath = req.url;
74
75 // Apply in order:
76 // 1. option.proxyTable
77 // 2. option.pathRewrite
78 var alteredProxyOptions = __applyProxyTableOption(req, proxyOptions);
79 __applyPathRewrite(pathRewriter, req);
80
81 // debug logging for both http(s) and websockets
82 if (proxyOptions.logLevel === 'debug') {
83 var arrow = getArrow(originalPath, req.url, proxyOptions.target, alteredProxyOptions.target);
84 logger.debug('[HPM] %s %s %s %s', req.method, originalPath, arrow, alteredProxyOptions.target);
85 }
86
87 return alteredProxyOptions;
88 }
89
90 // Modify option.target when proxyTable present.
91 // return altered options
92 function __applyProxyTableOption(req) {
93 var result = proxyOptions;
94
95 if (proxyOptions.proxyTable) {
96 result = ProxyTable.createProxyOptions(req, proxyOptions);
97 }
98
99 return result;
100 }
101
102 // rewrite path
103 function __applyPathRewrite(pathRewriter, req) {
104 if (pathRewriter) {
105 var path = pathRewriter(req.url, req);
106
107 if (path) {
108 req.url = path;
109 } else {
110 logger.info('[HPM] pathRewrite: No rewritten path found. (%s)', req.url);
111 }
112 }
113 }
114
115 function logError(err, req, res) {
116 var hostname = (req.hostname || req.host) || (req.headers && req.headers.host); // (node0.10 || node 4/5) || (websocket)
117 var targetUri = (proxyOptions.target.host || proxyOptions.target) + req.url;
118
119 logger.error('[HPM] PROXY ERROR: %s. %s -> %s', err.code, hostname, targetUri);
120 }
121};