diff --git a/lib/http-proxy.js b/lib/http-proxy.js index b1ad646f4..78522b63b 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -42,6 +42,8 @@ module.exports.createProxyServer = * localAddress : * changeOrigin: * hostRewrite: rewrites the location hostname on (301/302/307/308) redirects, Default: null. + * autoRewrite: rewrites the location host/port on (301/302/307/308) redirects based on requested host/port. Default: false. + * protocolRewrite: rewrites the location protocol on (301/302/307/308) redirects to 'http' or 'https'. Default: null. * } * * NOTE: `options.ws` and `options.ssl` are optional. diff --git a/lib/http-proxy/passes/web-outgoing.js b/lib/http-proxy/passes/web-outgoing.js index 67a1a6d98..99f886477 100644 --- a/lib/http-proxy/passes/web-outgoing.js +++ b/lib/http-proxy/passes/web-outgoing.js @@ -47,11 +47,19 @@ var redirectRegex = /^30(1|2|7|8)$/; }, function setRedirectHostRewrite(req, res, proxyRes, options) { - if (options.hostRewrite + if ((options.hostRewrite || options.autoRewrite || options.protocolRewrite) && proxyRes.headers['location'] && redirectRegex.test(proxyRes.statusCode)) { var u = url.parse(proxyRes.headers['location']); - u.host = options.hostRewrite; + if (options.hostRewrite) { + u.host = options.hostRewrite; + } else if (options.autoRewrite) { + u.host = req.headers['host']; + } + if (options.protocolRewrite) { + u.protocol = options.protocolRewrite; + } + proxyRes.headers['location'] = u.format(); } }, diff --git a/test/lib-http-proxy-passes-web-outgoing-test.js b/test/lib-http-proxy-passes-web-outgoing-test.js index ee1077e03..342f024ea 100644 --- a/test/lib-http-proxy-passes-web-outgoing-test.js +++ b/test/lib-http-proxy-passes-web-outgoing-test.js @@ -3,55 +3,118 @@ var httpProxy = require('../lib/http-proxy/passes/web-outgoing'), describe('lib/http-proxy/passes/web-outgoing.js', function () { describe('#setRedirectHostRewrite', function () { - context('rewrites location host to option', function() { - beforeEach(function() { - this.proxyRes = { - statusCode: 301, - headers: { - location: "http://f.com/" - } - }; + beforeEach(function() { + this.req = { + headers: { + host: "x2.com" + } + }; + this.proxyRes = { + statusCode: 301, + headers: { + location: "http://f.com/" + } + }; + }); + context('rewrites location host with hostRewrite', function() { + beforeEach(function() { this.options = { hostRewrite: "x.com" }; }); + [301, 302, 307, 308].forEach(function(code) { + it('on ' + code, function() { + this.proxyRes.statusCode = code; + httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); + expect(this.proxyRes.headers.location).to.eql('http://'+this.options.hostRewrite+'/'); + }); + }); - it('on 301', function() { - this.proxyRes.statusCode = 301; - httpProxy.setRedirectHostRewrite({}, {}, this.proxyRes, this.options); - expect(this.proxyRes.headers.location).to.eql('http://'+this.options.hostRewrite+'/'); + it('not on 200', function() { + this.proxyRes.statusCode = 200; + httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); + expect(this.proxyRes.headers.location).to.eql('http://f.com/'); }); - it('on 302', function() { - this.proxyRes.statusCode = 302; - httpProxy.setRedirectHostRewrite({}, {}, this.proxyRes, this.options); - expect(this.proxyRes.headers.location).to.eql('http://'+this.options.hostRewrite+'/'); + it('not when hostRewrite is unset', function() { + delete this.options.hostRewrite; + httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); + expect(this.proxyRes.headers.location).to.eql('http://f.com/'); }); - it('on 307', function() { - this.proxyRes.statusCode = 307; - httpProxy.setRedirectHostRewrite({}, {}, this.proxyRes, this.options); + it('takes precedence over autoRewrite', function() { + this.options.autoRewrite = true; + httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); expect(this.proxyRes.headers.location).to.eql('http://'+this.options.hostRewrite+'/'); }); + }); - it('on 308', function() { - this.proxyRes.statusCode = 308; - httpProxy.setRedirectHostRewrite({}, {}, this.proxyRes, this.options); - expect(this.proxyRes.headers.location).to.eql('http://'+this.options.hostRewrite+'/'); + context('rewrites location host with autoRewrite', function() { + beforeEach(function() { + this.options = { + autoRewrite: true, + }; + }); + [301, 302, 307, 308].forEach(function(code) { + it('on ' + code, function() { + this.proxyRes.statusCode = code; + httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); + expect(this.proxyRes.headers.location).to.eql('http://'+this.req.headers.host+'/'); + }); }); it('not on 200', function() { this.proxyRes.statusCode = 200; - httpProxy.setRedirectHostRewrite({}, {}, this.proxyRes, this.options); + httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); expect(this.proxyRes.headers.location).to.eql('http://f.com/'); }); - it('not when hostRewrite is unset', function() { - httpProxy.setRedirectHostRewrite({}, {}, this.proxyRes, {}); + it('not when autoRewrite is unset', function() { + delete this.options.autoRewrite; + httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); expect(this.proxyRes.headers.location).to.eql('http://f.com/'); }); }); + + context('rewrites location protocol with protocolRewrite', function() { + beforeEach(function() { + this.options = { + protocolRewrite: 'https', + }; + }); + [301, 302, 307, 308].forEach(function(code) { + it('on ' + code, function() { + this.proxyRes.statusCode = code; + httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); + expect(this.proxyRes.headers.location).to.eql('https://f.com/'); + }); + }); + + it('not on 200', function() { + this.proxyRes.statusCode = 200; + httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); + expect(this.proxyRes.headers.location).to.eql('http://f.com/'); + }); + + it('not when protocolRewrite is unset', function() { + delete this.options.protocolRewrite; + httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); + expect(this.proxyRes.headers.location).to.eql('http://f.com/'); + }); + + it('works together with hostRewrite', function() { + this.options.hostRewrite = 'x.com' + httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); + expect(this.proxyRes.headers.location).to.eql('https://x.com/'); + }); + + it('works together with autoRewrite', function() { + this.options.autoRewrite = true + httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); + expect(this.proxyRes.headers.location).to.eql('https://x2.com/'); + }); + }); }); describe('#setConnection', function () { @@ -64,7 +127,7 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { } }, {}, proxyRes); - expect(proxyRes.headers.connection).to.eql('close'); + expect(proxyRes.headers.connection).to.eql('close'); }); it('set the right connection with 1.0 - req.connection', function() { @@ -76,7 +139,7 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { } }, {}, proxyRes); - expect(proxyRes.headers.connection).to.eql('hey'); + expect(proxyRes.headers.connection).to.eql('hey'); }); it('set the right connection - req.connection', function() { @@ -88,7 +151,7 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { } }, {}, proxyRes); - expect(proxyRes.headers.connection).to.eql('hola'); + expect(proxyRes.headers.connection).to.eql('hola'); }); it('set the right connection - `keep-alive`', function() { @@ -100,7 +163,7 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { } }, {}, proxyRes); - expect(proxyRes.headers.connection).to.eql('keep-alive'); + expect(proxyRes.headers.connection).to.eql('keep-alive'); }); }); @@ -153,4 +216,4 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { }); }); - +