1 var url = require('url')
2 var httpProxy = require('http-proxy')
4 var log = require('../logger').create('proxy')
6 var parseProxyConfig = function (proxies, config) {
8 var endsWithSlash = function (str) {
9 return str.substr(-1) === '/'
16 Object.keys(proxies).forEach(function (proxyPath) {
17 var proxyUrl = proxies[proxyPath]
18 var proxyDetails = url.parse(proxyUrl)
19 var pathname = proxyDetails.pathname
21 // normalize the proxies config
22 // should we move this to lib/config.js ?
23 if (endsWithSlash(proxyPath) && !endsWithSlash(proxyUrl)) {
24 log.warn('proxy "%s" normalized to "%s"', proxyUrl, proxyUrl + '/')
29 if (!endsWithSlash(proxyPath) && endsWithSlash(proxyUrl)) {
30 log.warn('proxy "%s" normalized to "%s"', proxyPath, proxyPath + '/')
34 if (pathname === '/' && !endsWithSlash(proxyUrl)) {
38 proxyConfig[proxyPath] = {
39 host: proxyDetails.hostname,
40 port: proxyDetails.port,
41 baseProxyUrl: pathname,
42 https: proxyDetails.protocol === 'https:'
45 if (!proxyConfig[proxyPath].port) {
46 if (!proxyConfig[proxyPath].host) {
47 proxyConfig[proxyPath].host = config.hostname
48 proxyConfig[proxyPath].port = config.port
50 proxyConfig[proxyPath].port = proxyConfig[proxyPath].https ? '443' : '80'
59 * Returns a handler which understands the proxies and its redirects, along with the proxy to use
60 * @param proxy A http-proxy.RoutingProxy object with the proxyRequest method
61 * @param proxies a map of routes to proxy url
62 * @return {Function} handler function
64 var createProxyHandler = function (proxy, proxyConfig, proxyValidateSSL, urlRoot, config) {
65 var proxies = parseProxyConfig(proxyConfig, config)
66 var proxiesList = Object.keys(proxies).sort().reverse()
68 if (!proxiesList.length) {
69 var nullProxy = function createNullProxy (request, response, next) {
72 nullProxy.upgrade = function upgradeNullProxy () {}
76 proxy.on('proxyError', function (err, req) {
77 if (err.code === 'ECONNRESET' && req.socket.destroyed) {
78 log.debug('failed to proxy %s (browser hung up the socket)', req.url)
80 log.warn('failed to proxy %s (%s)', req.url, err.message)
84 var middleware = function createProxy (request, response, next) {
85 for (var i = 0; i < proxiesList.length; i++) {
86 if (request.url.indexOf(proxiesList[i]) === 0) {
87 var proxiedUrl = proxies[proxiesList[i]]
89 log.debug('proxying request - %s to %s:%s', request.url, proxiedUrl.host, proxiedUrl.port)
90 request.url = request.url.replace(proxiesList[i], proxiedUrl.baseProxyUrl)
91 proxy.proxyRequest(request, response, {
92 host: proxiedUrl.host,
93 port: proxiedUrl.port,
94 target: {https: proxiedUrl.https, rejectUnauthorized: proxyValidateSSL}
103 middleware.upgrade = function upgradeProxy (request, socket, head) {
104 // special-case karma's route to avoid upgrading it
105 if (request.url.indexOf(urlRoot) === 0) {
106 log.debug('NOT upgrading proxyWebSocketRequest %s', request.url)
109 for (var i = 0; i < proxiesList.length; i++) {
110 if (request.url.indexOf(proxiesList[i]) === 0) {
111 var proxiedUrl = proxies[proxiesList[i]]
112 log.debug('upgrade proxyWebSocketRequest %s to %s:%s',
113 request.url, proxiedUrl.host, proxiedUrl.port)
114 proxy.proxyWebSocketRequest(request, socket, head,
115 {host: proxiedUrl.host, port: proxiedUrl.port})
123 var createProxyHandlerFactory = function (/* config */ config, /* config.proxies */ proxies,
124 /* config.proxyValidateSSL */ validateSSL) {
125 return createProxyHandler(new httpProxy.RoutingProxy({changeOrigin: true}),
126 proxies, validateSSL, config.urlRoot, config)
128 createProxyHandlerFactory.$inject = ['config', 'config.proxies', 'config.proxyValidateSSL']
130 exports.create = createProxyHandlerFactory