Skip to content

Commit 7f2f3ac

Browse files
committed
Add support for auto host rewriting and protocol rewriting
auto host rewriting allows rewriting to work as expected in most cases without extra cumbersome configuration protocol rewriting allows node-http-proxy to be able to listen over HTTPS and properly reverse-proxy to sites running over HTTP (to avoid doing SSL twice)
1 parent 9ece52f commit 7f2f3ac

File tree

3 files changed

+106
-33
lines changed

3 files changed

+106
-33
lines changed

lib/http-proxy.js

+2
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ module.exports.createProxyServer =
4242
* localAddress : <Local interface string to bind for outgoing connections>
4343
* changeOrigin: <true/false, Default: false - changes the origin of the host header to the target URL>
4444
* hostRewrite: rewrites the location hostname on (301/302/307/308) redirects, Default: null.
45+
* autoRewrite: rewrites the location host/port on (301/302/307/308) redirects based on requested host/port. Default: false.
46+
* protocolRewrite: rewrites the location protocol on (301/302/307/308) redirects to 'http' or 'https'. Default: null.
4547
* }
4648
*
4749
* NOTE: `options.ws` and `options.ssl` are optional.

lib/http-proxy/passes/web-outgoing.js

+10-2
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,19 @@ var redirectRegex = /^30(1|2|7|8)$/;
4747
},
4848

4949
function setRedirectHostRewrite(req, res, proxyRes, options) {
50-
if (options.hostRewrite
50+
if ((options.hostRewrite || options.autoRewrite || options.protocolRewrite)
5151
&& proxyRes.headers['location']
5252
&& redirectRegex.test(proxyRes.statusCode)) {
5353
var u = url.parse(proxyRes.headers['location']);
54-
u.host = options.hostRewrite;
54+
if (options.hostRewrite) {
55+
u.host = options.hostRewrite;
56+
} else if (options.autoRewrite) {
57+
u.host = req.headers['host'];
58+
}
59+
if (options.protocolRewrite) {
60+
u.protocol = options.protocolRewrite;
61+
}
62+
5563
proxyRes.headers['location'] = u.format();
5664
}
5765
},

test/lib-http-proxy-passes-web-outgoing-test.js

+94-31
Original file line numberDiff line numberDiff line change
@@ -3,55 +3,118 @@ var httpProxy = require('../lib/http-proxy/passes/web-outgoing'),
33

44
describe('lib/http-proxy/passes/web-outgoing.js', function () {
55
describe('#setRedirectHostRewrite', function () {
6-
context('rewrites location host to option', function() {
7-
beforeEach(function() {
8-
this.proxyRes = {
9-
statusCode: 301,
10-
headers: {
11-
location: "http://f.com/"
12-
}
13-
};
6+
beforeEach(function() {
7+
this.req = {
8+
headers: {
9+
host: "x2.com"
10+
}
11+
};
12+
this.proxyRes = {
13+
statusCode: 301,
14+
headers: {
15+
location: "http://f.com/"
16+
}
17+
};
18+
});
1419

20+
context('rewrites location host with hostRewrite', function() {
21+
beforeEach(function() {
1522
this.options = {
1623
hostRewrite: "x.com"
1724
};
1825
});
26+
[301, 302, 307, 308].forEach(function(code) {
27+
it('on ' + code, function() {
28+
this.proxyRes.statusCode = code;
29+
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
30+
expect(this.proxyRes.headers.location).to.eql('http://'+this.options.hostRewrite+'/');
31+
});
32+
});
1933

20-
it('on 301', function() {
21-
this.proxyRes.statusCode = 301;
22-
httpProxy.setRedirectHostRewrite({}, {}, this.proxyRes, this.options);
23-
expect(this.proxyRes.headers.location).to.eql('http://'+this.options.hostRewrite+'/');
34+
it('not on 200', function() {
35+
this.proxyRes.statusCode = 200;
36+
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
37+
expect(this.proxyRes.headers.location).to.eql('http://f.com/');
2438
});
2539

26-
it('on 302', function() {
27-
this.proxyRes.statusCode = 302;
28-
httpProxy.setRedirectHostRewrite({}, {}, this.proxyRes, this.options);
29-
expect(this.proxyRes.headers.location).to.eql('http://'+this.options.hostRewrite+'/');
40+
it('not when hostRewrite is unset', function() {
41+
delete this.options.hostRewrite;
42+
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
43+
expect(this.proxyRes.headers.location).to.eql('http://f.com/');
3044
});
3145

32-
it('on 307', function() {
33-
this.proxyRes.statusCode = 307;
34-
httpProxy.setRedirectHostRewrite({}, {}, this.proxyRes, this.options);
46+
it('takes precedence over autoRewrite', function() {
47+
this.options.autoRewrite = true;
48+
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
3549
expect(this.proxyRes.headers.location).to.eql('http://'+this.options.hostRewrite+'/');
3650
});
51+
});
3752

38-
it('on 308', function() {
39-
this.proxyRes.statusCode = 308;
40-
httpProxy.setRedirectHostRewrite({}, {}, this.proxyRes, this.options);
41-
expect(this.proxyRes.headers.location).to.eql('http://'+this.options.hostRewrite+'/');
53+
context('rewrites location host with autoRewrite', function() {
54+
beforeEach(function() {
55+
this.options = {
56+
autoRewrite: true,
57+
};
58+
});
59+
[301, 302, 307, 308].forEach(function(code) {
60+
it('on ' + code, function() {
61+
this.proxyRes.statusCode = code;
62+
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
63+
expect(this.proxyRes.headers.location).to.eql('http://'+this.req.headers.host+'/');
64+
});
4265
});
4366

4467
it('not on 200', function() {
4568
this.proxyRes.statusCode = 200;
46-
httpProxy.setRedirectHostRewrite({}, {}, this.proxyRes, this.options);
69+
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
4770
expect(this.proxyRes.headers.location).to.eql('http://f.com/');
4871
});
4972

50-
it('not when hostRewrite is unset', function() {
51-
httpProxy.setRedirectHostRewrite({}, {}, this.proxyRes, {});
73+
it('not when autoRewrite is unset', function() {
74+
delete this.options.autoRewrite;
75+
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
5276
expect(this.proxyRes.headers.location).to.eql('http://f.com/');
5377
});
5478
});
79+
80+
context('rewrites location protocol with protocolRewrite', function() {
81+
beforeEach(function() {
82+
this.options = {
83+
protocolRewrite: 'https',
84+
};
85+
});
86+
[301, 302, 307, 308].forEach(function(code) {
87+
it('on ' + code, function() {
88+
this.proxyRes.statusCode = code;
89+
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
90+
expect(this.proxyRes.headers.location).to.eql('https://f.com/');
91+
});
92+
});
93+
94+
it('not on 200', function() {
95+
this.proxyRes.statusCode = 200;
96+
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
97+
expect(this.proxyRes.headers.location).to.eql('http://f.com/');
98+
});
99+
100+
it('not when protocolRewrite is unset', function() {
101+
delete this.options.protocolRewrite;
102+
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
103+
expect(this.proxyRes.headers.location).to.eql('http://f.com/');
104+
});
105+
106+
it('works together with hostRewrite', function() {
107+
this.options.hostRewrite = 'x.com'
108+
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
109+
expect(this.proxyRes.headers.location).to.eql('https://x.com/');
110+
});
111+
112+
it('works together with autoRewrite', function() {
113+
this.options.autoRewrite = true
114+
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
115+
expect(this.proxyRes.headers.location).to.eql('https://x2.com/');
116+
});
117+
});
55118
});
56119

57120
describe('#setConnection', function () {
@@ -64,7 +127,7 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () {
64127
}
65128
}, {}, proxyRes);
66129

67-
expect(proxyRes.headers.connection).to.eql('close');
130+
expect(proxyRes.headers.connection).to.eql('close');
68131
});
69132

70133
it('set the right connection with 1.0 - req.connection', function() {
@@ -76,7 +139,7 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () {
76139
}
77140
}, {}, proxyRes);
78141

79-
expect(proxyRes.headers.connection).to.eql('hey');
142+
expect(proxyRes.headers.connection).to.eql('hey');
80143
});
81144

82145
it('set the right connection - req.connection', function() {
@@ -88,7 +151,7 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () {
88151
}
89152
}, {}, proxyRes);
90153

91-
expect(proxyRes.headers.connection).to.eql('hola');
154+
expect(proxyRes.headers.connection).to.eql('hola');
92155
});
93156

94157
it('set the right connection - `keep-alive`', function() {
@@ -100,7 +163,7 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () {
100163
}
101164
}, {}, proxyRes);
102165

103-
expect(proxyRes.headers.connection).to.eql('keep-alive');
166+
expect(proxyRes.headers.connection).to.eql('keep-alive');
104167
});
105168

106169
});
@@ -153,4 +216,4 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () {
153216
});
154217

155218
});
156-
219+

0 commit comments

Comments
 (0)