Skip to content

Commit 5a969d0

Browse files
committed
Merge pull request #787 from mokafive/master
Fixes / additions to URL rewriting
2 parents 21b30b7 + 26029ba commit 5a969d0

File tree

3 files changed

+142
-37
lines changed

3 files changed

+142
-37
lines changed

lib/http-proxy.js

+2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ module.exports.createProxyServer =
4343
* changeOrigin: <true/false, Default: false - changes the origin of the host header to the target URL>
4444
* auth : Basic authentication i.e. 'user:password' to compute an Authorization header.
4545
* hostRewrite: rewrites the location hostname on (301/302/307/308) redirects, Default: null.
46+
* autoRewrite: rewrites the location host/port on (301/302/307/308) redirects based on requested host/port. Default: false.
47+
* protocolRewrite: rewrites the location protocol on (301/302/307/308) redirects to 'http' or 'https'. Default: null.
4648
* }
4749
*
4850
* NOTE: `options.ws` and `options.ssl` are optional.

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

+17-2
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,26 @@ 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)) {
53+
var target = url.parse(options.target);
5354
var u = url.parse(proxyRes.headers['location']);
54-
u.host = options.hostRewrite;
55+
56+
// make sure the redirected host matches the target host before rewriting
57+
if (target.host != u.host) {
58+
return;
59+
}
60+
61+
if (options.hostRewrite) {
62+
u.host = options.hostRewrite;
63+
} else if (options.autoRewrite) {
64+
u.host = req.headers['host'];
65+
}
66+
if (options.protocolRewrite) {
67+
u.protocol = options.protocolRewrite;
68+
}
69+
5570
proxyRes.headers['location'] = u.format();
5671
}
5772
},

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

+123-35
Original file line numberDiff line numberDiff line change
@@ -3,53 +3,141 @@ 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() {
6+
beforeEach(function() {
7+
this.req = {
8+
headers: {
9+
host: "ext-auto.com"
10+
}
11+
};
12+
this.proxyRes = {
13+
statusCode: 301,
14+
headers: {
15+
location: "http://backend.com/"
16+
}
17+
};
18+
this.options = {
19+
target: "http://backend.com"
20+
};
21+
});
22+
23+
context('rewrites location host with hostRewrite', function() {
724
beforeEach(function() {
8-
this.proxyRes = {
9-
statusCode: 301,
10-
headers: {
11-
location: "http://f.com/"
12-
}
13-
};
25+
this.options.hostRewrite = "ext-manual.com";
26+
});
27+
[301, 302, 307, 308].forEach(function(code) {
28+
it('on ' + code, function() {
29+
this.proxyRes.statusCode = code;
30+
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
31+
expect(this.proxyRes.headers.location).to.eql('http://ext-manual.com/');
32+
});
33+
});
34+
35+
it('not on 200', function() {
36+
this.proxyRes.statusCode = 200;
37+
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
38+
expect(this.proxyRes.headers.location).to.eql('http://backend.com/');
39+
});
1440

15-
this.options = {
16-
hostRewrite: "x.com"
17-
};
41+
it('not when hostRewrite is unset', function() {
42+
delete this.options.hostRewrite;
43+
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
44+
expect(this.proxyRes.headers.location).to.eql('http://backend.com/');
1845
});
1946

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+'/');
47+
it('takes precedence over autoRewrite', function() {
48+
this.options.autoRewrite = true;
49+
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
50+
expect(this.proxyRes.headers.location).to.eql('http://ext-manual.com/');
2451
});
2552

26-
it('on 302', function() {
53+
it('not when the redirected location does not match target host', function() {
2754
this.proxyRes.statusCode = 302;
28-
httpProxy.setRedirectHostRewrite({}, {}, this.proxyRes, this.options);
29-
expect(this.proxyRes.headers.location).to.eql('http://'+this.options.hostRewrite+'/');
55+
this.proxyRes.headers.location = "http://some-other/";
56+
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
57+
expect(this.proxyRes.headers.location).to.eql('http://some-other/');
3058
});
3159

32-
it('on 307', function() {
33-
this.proxyRes.statusCode = 307;
34-
httpProxy.setRedirectHostRewrite({}, {}, this.proxyRes, this.options);
35-
expect(this.proxyRes.headers.location).to.eql('http://'+this.options.hostRewrite+'/');
60+
it('not when the redirected location does not match target port', function() {
61+
this.proxyRes.statusCode = 302;
62+
this.proxyRes.headers.location = "http://backend.com:8080/";
63+
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
64+
expect(this.proxyRes.headers.location).to.eql('http://backend.com:8080/');
3665
});
66+
});
3767

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+'/');
68+
context('rewrites location host with autoRewrite', function() {
69+
beforeEach(function() {
70+
this.options.autoRewrite = true;
71+
});
72+
[301, 302, 307, 308].forEach(function(code) {
73+
it('on ' + code, function() {
74+
this.proxyRes.statusCode = code;
75+
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
76+
expect(this.proxyRes.headers.location).to.eql('http://ext-auto.com/');
77+
});
4278
});
4379

4480
it('not on 200', function() {
4581
this.proxyRes.statusCode = 200;
46-
httpProxy.setRedirectHostRewrite({}, {}, this.proxyRes, this.options);
47-
expect(this.proxyRes.headers.location).to.eql('http://f.com/');
82+
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
83+
expect(this.proxyRes.headers.location).to.eql('http://backend.com/');
4884
});
4985

50-
it('not when hostRewrite is unset', function() {
51-
httpProxy.setRedirectHostRewrite({}, {}, this.proxyRes, {});
52-
expect(this.proxyRes.headers.location).to.eql('http://f.com/');
86+
it('not when autoRewrite is unset', function() {
87+
delete this.options.autoRewrite;
88+
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
89+
expect(this.proxyRes.headers.location).to.eql('http://backend.com/');
90+
});
91+
92+
it('not when the redirected location does not match target host', function() {
93+
this.proxyRes.statusCode = 302;
94+
this.proxyRes.headers.location = "http://some-other/";
95+
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
96+
expect(this.proxyRes.headers.location).to.eql('http://some-other/');
97+
});
98+
99+
it('not when the redirected location does not match target port', function() {
100+
this.proxyRes.statusCode = 302;
101+
this.proxyRes.headers.location = "http://backend.com:8080/";
102+
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
103+
expect(this.proxyRes.headers.location).to.eql('http://backend.com:8080/');
104+
});
105+
});
106+
107+
context('rewrites location protocol with protocolRewrite', function() {
108+
beforeEach(function() {
109+
this.options.protocolRewrite = 'https';
110+
});
111+
[301, 302, 307, 308].forEach(function(code) {
112+
it('on ' + code, function() {
113+
this.proxyRes.statusCode = code;
114+
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
115+
expect(this.proxyRes.headers.location).to.eql('https://backend.com/');
116+
});
117+
});
118+
119+
it('not on 200', function() {
120+
this.proxyRes.statusCode = 200;
121+
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
122+
expect(this.proxyRes.headers.location).to.eql('http://backend.com/');
123+
});
124+
125+
it('not when protocolRewrite is unset', function() {
126+
delete this.options.protocolRewrite;
127+
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
128+
expect(this.proxyRes.headers.location).to.eql('http://backend.com/');
129+
});
130+
131+
it('works together with hostRewrite', function() {
132+
this.options.hostRewrite = 'ext-manual.com'
133+
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
134+
expect(this.proxyRes.headers.location).to.eql('https://ext-manual.com/');
135+
});
136+
137+
it('works together with autoRewrite', function() {
138+
this.options.autoRewrite = true
139+
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
140+
expect(this.proxyRes.headers.location).to.eql('https://ext-auto.com/');
53141
});
54142
});
55143
});
@@ -64,7 +152,7 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () {
64152
}
65153
}, {}, proxyRes);
66154

67-
expect(proxyRes.headers.connection).to.eql('close');
155+
expect(proxyRes.headers.connection).to.eql('close');
68156
});
69157

70158
it('set the right connection with 1.0 - req.connection', function() {
@@ -76,7 +164,7 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () {
76164
}
77165
}, {}, proxyRes);
78166

79-
expect(proxyRes.headers.connection).to.eql('hey');
167+
expect(proxyRes.headers.connection).to.eql('hey');
80168
});
81169

82170
it('set the right connection - req.connection', function() {
@@ -88,7 +176,7 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () {
88176
}
89177
}, {}, proxyRes);
90178

91-
expect(proxyRes.headers.connection).to.eql('hola');
179+
expect(proxyRes.headers.connection).to.eql('hola');
92180
});
93181

94182
it('set the right connection - `keep-alive`', function() {
@@ -100,7 +188,7 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () {
100188
}
101189
}, {}, proxyRes);
102190

103-
expect(proxyRes.headers.connection).to.eql('keep-alive');
191+
expect(proxyRes.headers.connection).to.eql('keep-alive');
104192
});
105193

106194
});
@@ -153,4 +241,4 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () {
153241
});
154242

155243
});
156-
244+

0 commit comments

Comments
 (0)