Skip to content

Commit 8b89110

Browse files
Jeremy JudeauxJeremy Judeaux
Jeremy Judeaux
authored and
Jeremy Judeaux
committed
cookieDomainRewrite option
1 parent 9d06ca9 commit 8b89110

File tree

4 files changed

+146
-30
lines changed

4 files changed

+146
-30
lines changed

Diff for: README.md

+12
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,18 @@ proxyServer.listen(8015);
337337
* **hostRewrite**: rewrites the location hostname on (201/301/302/307/308) redirects.
338338
* **autoRewrite**: rewrites the location host/port on (201/301/302/307/308) redirects based on requested host/port. Default: false.
339339
* **protocolRewrite**: rewrites the location protocol on (201/301/302/307/308) redirects to 'http' or 'https'. Default: null.
340+
* **cookieDomainRewrite**: rewrites domain of `set-cookie` headers. Possible values:
341+
* `false` (default): disable cookie rewriting
342+
* String: new domain, for example `cookieDomainRewrite: "new.domain"`. To remove the domain, use `cookieDomainRewrite: ""`.
343+
* Object: mapping of domains to new domains, use `"*"` to match all domains.
344+
For example keep one domain unchanged, rewrite one domain and remove other domains:
345+
```
346+
cookieDomainRewrite: {
347+
"unchanged.domain": "unchanged.domain",
348+
"old.domain": "new.domain",
349+
"*": ""
350+
}
351+
```
340352
* **headers**: object with extra headers to be added to target requests.
341353
342354
**NOTE:**

Diff for: lib/http-proxy/common.js

+37-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ var common = exports,
44
required = require('requires-port');
55

66
var upgradeHeader = /(^|,)\s*upgrade\s*($|,)/i,
7-
isSSL = /^https|wss/;
7+
isSSL = /^https|wss/,
8+
cookieDomainRegex = /(;\s*domain=)([^;]+)/i;
89

910
/**
1011
* Simple Regex for testing if protocol is https
@@ -201,6 +202,41 @@ common.urlJoin = function() {
201202
return retSegs.join('?')
202203
};
203204

205+
/**
206+
* Rewrites or removes the domain of a cookie header
207+
*
208+
* @param {String|Array} Header
209+
* @param {Object} Config, mapping of domain to rewritten domain.
210+
* '*' key to match any domain, null value to remove the domain.
211+
*
212+
* @api private
213+
*/
214+
common.rewriteCookieDomain = function rewriteCookieDomain(header, config) {
215+
if (Array.isArray(header)) {
216+
return header.map(function (headerElement) {
217+
return rewriteCookieDomain(headerElement, config);
218+
});
219+
}
220+
return header.replace(cookieDomainRegex, function(match, prefix, previousDomain) {
221+
var newDomain;
222+
if (previousDomain in config) {
223+
newDomain = config[previousDomain];
224+
} else if ('*' in config) {
225+
newDomain = config['*'];
226+
} else {
227+
//no match, return previous domain
228+
return match;
229+
}
230+
if (newDomain) {
231+
//replace domain
232+
return prefix + newDomain;
233+
} else {
234+
//remove domain
235+
return '';
236+
}
237+
});
238+
};
239+
204240
/**
205241
* Check the host and see if it potentially has a port in it (keep it simple)
206242
*

Diff for: lib/http-proxy/passes/web-outgoing.js

+13-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
var url = require('url'),
2+
common = require('../common'),
23
passes = exports;
34

45
var redirectRegex = /^201|30(1|2|7|8)$/;
@@ -77,13 +78,22 @@ var redirectRegex = /^201|30(1|2|7|8)$/;
7778
* @param {ClientRequest} Req Request object
7879
* @param {IncomingMessage} Res Response object
7980
* @param {proxyResponse} Res Response object from the proxy request
81+
* @param {Object} Options options.cookieDomainRewrite: Config to rewrite cookie domain
8082
*
8183
* @api private
8284
*/
83-
function writeHeaders(req, res, proxyRes) {
85+
function writeHeaders(req, res, proxyRes, options) {
86+
var rewriteCookieDomainConfig = options.cookieDomainRewrite;
87+
if (typeof rewriteCookieDomainConfig === 'string') { //also test for ''
88+
rewriteCookieDomainConfig = { '*': rewriteCookieDomainConfig };
89+
}
8490
Object.keys(proxyRes.headers).forEach(function(key) {
85-
if(proxyRes.headers[key] != undefined){
86-
res.setHeader(String(key).trim(), proxyRes.headers[key]);
91+
var header = proxyRes.headers[key];
92+
if (header != undefined) {
93+
if (rewriteCookieDomainConfig && key.toLowerCase() === 'set-cookie') {
94+
header = common.rewriteCookieDomain(header, rewriteCookieDomainConfig);
95+
}
96+
res.setHeader(String(key).trim(), header);
8797
}
8898
});
8999
},

Diff for: test/lib-http-proxy-passes-web-outgoing-test.js

+84-26
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,23 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () {
66
beforeEach(function() {
77
this.req = {
88
headers: {
9-
host: "ext-auto.com"
9+
host: 'ext-auto.com'
1010
}
1111
};
1212
this.proxyRes = {
1313
statusCode: 301,
1414
headers: {
15-
location: "http://backend.com/"
15+
location: 'http://backend.com/'
1616
}
1717
};
1818
this.options = {
19-
target: "http://backend.com"
19+
target: 'http://backend.com'
2020
};
2121
});
2222

2323
context('rewrites location host with hostRewrite', function() {
2424
beforeEach(function() {
25-
this.options.hostRewrite = "ext-manual.com";
25+
this.options.hostRewrite = 'ext-manual.com';
2626
});
2727
[201, 301, 302, 307, 308].forEach(function(code) {
2828
it('on ' + code, function() {
@@ -52,14 +52,14 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () {
5252

5353
it('not when the redirected location does not match target host', function() {
5454
this.proxyRes.statusCode = 302;
55-
this.proxyRes.headers.location = "http://some-other/";
55+
this.proxyRes.headers.location = 'http://some-other/';
5656
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
5757
expect(this.proxyRes.headers.location).to.eql('http://some-other/');
5858
});
5959

6060
it('not when the redirected location does not match target port', function() {
6161
this.proxyRes.statusCode = 302;
62-
this.proxyRes.headers.location = "http://backend.com:8080/";
62+
this.proxyRes.headers.location = 'http://backend.com:8080/';
6363
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
6464
expect(this.proxyRes.headers.location).to.eql('http://backend.com:8080/');
6565
});
@@ -91,14 +91,14 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () {
9191

9292
it('not when the redirected location does not match target host', function() {
9393
this.proxyRes.statusCode = 302;
94-
this.proxyRes.headers.location = "http://some-other/";
94+
this.proxyRes.headers.location = 'http://some-other/';
9595
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
9696
expect(this.proxyRes.headers.location).to.eql('http://some-other/');
9797
});
9898

9999
it('not when the redirected location does not match target port', function() {
100100
this.proxyRes.statusCode = 302;
101-
this.proxyRes.headers.location = "http://backend.com:8080/";
101+
this.proxyRes.headers.location = 'http://backend.com:8080/';
102102
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
103103
expect(this.proxyRes.headers.location).to.eql('http://backend.com:8080/');
104104
});
@@ -129,13 +129,13 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () {
129129
});
130130

131131
it('works together with hostRewrite', function() {
132-
this.options.hostRewrite = 'ext-manual.com'
132+
this.options.hostRewrite = 'ext-manual.com';
133133
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
134134
expect(this.proxyRes.headers.location).to.eql('https://ext-manual.com/');
135135
});
136136

137137
it('works together with autoRewrite', function() {
138-
this.options.autoRewrite = true
138+
this.options.autoRewrite = true;
139139
httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options);
140140
expect(this.proxyRes.headers.location).to.eql('https://ext-auto.com/');
141141
});
@@ -199,31 +199,89 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () {
199199
writeHead: function(n) {
200200
expect(n).to.eql(200);
201201
}
202-
}
202+
};
203203

204204
httpProxy.writeStatusCode({}, res, { statusCode: 200 });
205205
});
206206
});
207207

208208
describe('#writeHeaders', function() {
209-
var proxyRes = {
210-
headers: {
211-
hey: 'hello',
212-
how: 'are you?'
213-
}
214-
};
209+
beforeEach(function() {
210+
this.proxyRes = {
211+
headers: {
212+
hey: 'hello',
213+
how: 'are you?',
214+
'set-cookie': 'hello; domain=my.domain; path=/'
215+
}
216+
};
217+
this.res = {
218+
setHeader: function(k, v) {
219+
this.headers[k] = v;
220+
},
221+
headers: {}
222+
};
223+
});
215224

216-
var res = {
217-
setHeader: function(k, v) {
218-
this.headers[k] = v;
219-
},
220-
headers: {}
221-
};
225+
it('writes headers', function() {
226+
var options = {};
222227

223-
httpProxy.writeHeaders({}, res, proxyRes);
228+
httpProxy.writeHeaders({}, this.res, this.proxyRes, options);
229+
230+
expect(this.res.headers.hey).to.eql('hello');
231+
expect(this.res.headers.how).to.eql('are you?');
232+
});
224233

225-
expect(res.headers.hey).to.eql('hello');
226-
expect(res.headers.how).to.eql('are you?');
234+
it('does not rewrite domain', function() {
235+
var options = {};
236+
237+
httpProxy.writeHeaders({}, this.res, this.proxyRes, options);
238+
239+
expect(this.res.headers['set-cookie']).to.eql('hello; domain=my.domain; path=/');
240+
});
241+
242+
it('rewrites domain', function() {
243+
var options = {
244+
cookieDomainRewrite: 'my.new.domain'
245+
};
246+
247+
httpProxy.writeHeaders({}, this.res, this.proxyRes, options);
248+
249+
expect(this.res.headers['set-cookie']).to.eql('hello; domain=my.new.domain; path=/');
250+
});
251+
252+
it('removes domain', function() {
253+
var options = {
254+
cookieDomainRewrite: ''
255+
};
256+
257+
httpProxy.writeHeaders({}, this.res, this.proxyRes, options);
258+
259+
expect(this.res.headers['set-cookie']).to.eql('hello; path=/');
260+
});
261+
262+
it('rewrites headers with advanced configuration', function() {
263+
var options = {
264+
cookieDomainRewrite: {
265+
'*': '',
266+
'my.old.domain': 'my.new.domain',
267+
'my.special.domain': 'my.special.domain'
268+
}
269+
};
270+
this.proxyRes.headers['set-cookie'] = [
271+
'hello-on-my.domain; domain=my.domain; path=/',
272+
'hello-on-my.old.domain; domain=my.old.domain; path=/',
273+
'hello-on-my.special.domain; domain=my.special.domain; path=/'
274+
];
275+
276+
httpProxy.writeHeaders({}, this.res, this.proxyRes, options);
277+
278+
expect(this.res.headers['set-cookie'])
279+
.to.contain('hello-on-my.domain; path=/');
280+
expect(this.res.headers['set-cookie'])
281+
.to.contain('hello-on-my.old.domain; domain=my.new.domain; path=/');
282+
expect(this.res.headers['set-cookie'])
283+
.to.contain('hello-on-my.special.domain; domain=my.special.domain; path=/');
284+
});
227285
});
228286

229287

0 commit comments

Comments
 (0)