Skip to content

Commit 5fa7a1c

Browse files
author
Anton Griadchenko
committed
Feature: Add 'megreCookies' options
1 parent d056241 commit 5fa7a1c

File tree

5 files changed

+78
-1
lines changed

5 files changed

+78
-1
lines changed

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,20 @@ proxyServer.listen(8015);
395395
396396
};
397397
```
398+
* **mergeCookies**: true/false, merges `set-cookie` header from a request passed to `httpProxy.web` and from response.
399+
E.g.:
400+
```
401+
const http = require("http");
402+
const httpProxy = require("http-proxy");
403+
const proxy = httpProxy.createProxyServer({});
404+
405+
const gateway = http.createServer((req, res) => {
406+
res.setHeader('set-cookie', ["gateway=true; Path=/"]);
407+
proxy.web(req, res, {target: "http://localhost:3002"});
408+
});
409+
410+
gateway.listen(3003);
411+
```
398412
399413
**NOTE:**
400414
`options.ws` and `options.ssl` are optional.

lib/http-proxy.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ function createProxyServer(options) {
4040
* hostRewrite: rewrites the location hostname on (201/301/302/307/308) redirects, Default: null.
4141
* autoRewrite: rewrites the location host/port on (201/301/302/307/308) redirects based on requested host/port. Default: false.
4242
* protocolRewrite: rewrites the location protocol on (201/301/302/307/308) redirects to 'http' or 'https'. Default: null.
43+
* mergeCookies: allows to merge `set-cookie` headers from passed response and response from target. Default: false.
4344
* }
4445
*
4546
* NOTE: `options.ws` and `options.ssl` are optional.

lib/http-proxy/common.js

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ common.setupOutgoing = function(outgoing, options, req, forward) {
4949
if (options.auth) {
5050
outgoing.auth = options.auth;
5151
}
52-
52+
5353
if (options.ca) {
5454
outgoing.ca = options.ca;
5555
}
@@ -236,6 +236,30 @@ common.rewriteCookieProperty = function rewriteCookieProperty(header, config, pr
236236
});
237237
};
238238

239+
/**
240+
* Merges `Set-Cookie` header
241+
*
242+
* @param {string|[string]} setCookie
243+
* @param {string|[string]} upstreamSetCookie
244+
* @returns {[string]}
245+
*
246+
* @api private
247+
*/
248+
common.mergeSetCookie = function mergeCookie(setCookie, upstreamSetCookie) {
249+
var existingCookieArray = setCookie || [],
250+
upstreamCookieArray = upstreamSetCookie || [];
251+
252+
if (!Array.isArray(existingCookieArray)) {
253+
existingCookieArray = [existingCookieArray]
254+
}
255+
256+
if (!Array.isArray(upstreamCookieArray)) {
257+
upstreamCookieArray = [upstreamCookieArray]
258+
}
259+
260+
return [].concat(existingCookieArray, upstreamCookieArray)
261+
};
262+
239263
/**
240264
* Check the host and see if it potentially has a port in it (keep it simple)
241265
*

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ module.exports = { // <--
8686
var rewriteCookieDomainConfig = options.cookieDomainRewrite,
8787
rewriteCookiePathConfig = options.cookiePathRewrite,
8888
preserveHeaderKeyCase = options.preserveHeaderKeyCase,
89+
mergeCookiesConfig = options.mergeCookies,
8990
rawHeaderKeyMap,
9091
setHeader = function(key, header) {
9192
if (header == undefined) return;
@@ -95,6 +96,9 @@ module.exports = { // <--
9596
if (rewriteCookiePathConfig && key.toLowerCase() === 'set-cookie') {
9697
header = common.rewriteCookieProperty(header, rewriteCookiePathConfig, 'path');
9798
}
99+
if (mergeCookiesConfig && key.toLowerCase() === 'set-cookie') {
100+
header = common.mergeSetCookie(res.getHeader("set-cookie"), header)
101+
}
98102
res.setHeader(String(key).trim(), header);
99103
};
100104

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,9 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () {
261261
// Header names are lower-cased
262262
this.headers[k.toLowerCase()] = v;
263263
},
264+
getHeader: function (k) {
265+
return this.headers[k.toLowerCase()]
266+
},
264267
headers: {}
265268
};
266269
});
@@ -404,6 +407,37 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () {
404407
expect(this.res.headers['set-cookie'])
405408
.to.contain('hello-on-my.special.domain; domain=my.special.domain; path=/');
406409
});
410+
411+
it('appends set-cookies header to an existing one', function () {
412+
var options = {
413+
mergeCookies: true,
414+
};
415+
416+
this.res.setHeader("set-cookie", ['hello; domain=my.domain; path=/']);
417+
418+
httpProxy.writeHeaders({}, this.res, this.proxyRes, options);
419+
420+
expect(this.res.headers['set-cookie']).to.be.an(Array);
421+
expect(this.res.headers['set-cookie']).to.have.length(3);
422+
});
423+
424+
it('appends set-cookies header to an existing one (set-cookie is not an array)', function () {
425+
var options = {
426+
mergeCookies: true,
427+
};
428+
429+
this.proxyRes.headers = {
430+
...this.proxyRes.headers,
431+
'set-cookie': 'hello1; domain=my.domain; path=/'
432+
};
433+
434+
this.res.setHeader("set-cookie", 'hello; domain=my.domain; path=/');
435+
436+
httpProxy.writeHeaders({}, this.res, this.proxyRes, options);
437+
438+
expect(this.res.headers['set-cookie']).to.be.an(Array);
439+
expect(this.res.headers['set-cookie']).to.have.length(2);
440+
});
407441
});
408442

409443

0 commit comments

Comments
 (0)