Skip to content

Enable proxy response to have multiple Set-Cookie raw headers #1101 #1102

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/http/proxy-https-to-http.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ var https = require('https'),
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('hello http over https\n');
res.end();
res.end();
}).listen(9009);

//
Expand Down
2 changes: 1 addition & 1 deletion examples/http/proxy-https-to-https.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ var https = require('https'),
https.createServer(httpsOpts, function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('hello https\n');
res.end();
res.end();
}).listen(9010);

//
Expand Down
20 changes: 15 additions & 5 deletions lib/http-proxy/passes/web-outgoing.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,19 @@ module.exports = { // <--
*/
writeHeaders: function writeHeaders(req, res, proxyRes, options) {
var rewriteCookieDomainConfig = options.cookieDomainRewrite,
// In proxyRes.rawHeaders Set-Cookie headers are sparse.
// so, we'll collect Set-Cookie headers, and set them in the response as an array.
set_cookies = [],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

camelCase

setHeader = function(key, header) {
if (header != undefined) {
if (rewriteCookieDomainConfig && key.toLowerCase() === 'set-cookie') {
header = common.rewriteCookieDomain(header, rewriteCookieDomainConfig);
if (key === 'Set-Cookie' || key === 'set-cookie') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can still do key.toLowerCase() === 'set-cookie'

if (rewriteCookieDomainConfig) {
header = common.rewriteCookieDomain(header, rewriteCookieDomainConfig);
}
set_cookies.push(header); // defer
} else {
res.setHeader(String(key).trim(), header);
}
res.setHeader(String(key).trim(), header);
}
};

Expand All @@ -99,18 +106,21 @@ module.exports = { // <--

// message.rawHeaders is added in: v0.11.6
// https://nodejs.org/api/http.html#http_message_rawheaders
if (proxyRes.rawHeaders != undefined) {
if (proxyRes.rawHeaders !== undefined) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current code here supports if it is undefined or null, we should be sure that it is strictly undefined.

for (var i = 0; i < proxyRes.rawHeaders.length; i += 2) {
var key = proxyRes.rawHeaders[i];
var header = proxyRes.rawHeaders[i + 1];
setHeader(key, header);
};
}
} else {
Object.keys(proxyRes.headers).forEach(function(key) {
var header = proxyRes.headers[key];
setHeader(key, header);
});
}
if (set_cookies.length) {
res.setHeader('Set-Cookie', set_cookies.length === 1 ? set_cookies[0] : set_cookies);
}
},

/**
Expand Down
67 changes: 55 additions & 12 deletions test/lib-http-proxy-passes-web-outgoing-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -233,12 +233,18 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () {
headers: {
hey: 'hello',
how: 'are you?',
'set-cookie': 'hello; domain=my.domain; path=/'
},
'set-cookie': [
'hello; domain=my.domain; path=/',
'there; domain=my.domain; path=/'
]
}
};
this.rawProxyRes = {
rawHeaders: [
'Hey', 'hello',
'How', 'are you?',
'Set-Cookie', 'hello; domain=my.domain; path=/'
'Set-Cookie', 'hello; domain=my.domain; path=/',
'Set-Cookie', 'there; domain=my.domain; path=/'
]
};
this.res = {
Expand All @@ -253,19 +259,35 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () {

it('writes headers', function() {
var options = {};

httpProxy.writeHeaders({}, this.res, this.proxyRes, options);

expect(this.res.headers.hey).to.eql('hello');
expect(this.res.headers.how).to.eql('are you?');

expect(this.res.headers).to.have.key('set-cookie');
expect(this.res.headers['set-cookie']).to.be.an(Array);
expect(this.res.headers['set-cookie']).to.have.length(2);
});

it('writes raw headers', function() {
var options = {};
httpProxy.writeHeaders({}, this.res, this.rawProxyRes, options);

expect(this.res.headers.hey).to.eql('hello');
expect(this.res.headers.how).to.eql('are you?');

expect(this.res.headers).to.have.key('set-cookie');
expect(this.res.headers['set-cookie']).to.be.an(Array);
expect(this.res.headers['set-cookie']).to.have.length(2);
});

it('does not rewrite domain', function() {
var options = {};

httpProxy.writeHeaders({}, this.res, this.proxyRes, options);

expect(this.res.headers['set-cookie']).to.eql('hello; domain=my.domain; path=/');
expect(this.res.headers['set-cookie'])
.to.contain('hello; domain=my.domain; path=/');
});

it('rewrites domain', function() {
Expand All @@ -275,7 +297,8 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () {

httpProxy.writeHeaders({}, this.res, this.proxyRes, options);

expect(this.res.headers['set-cookie']).to.eql('hello; domain=my.new.domain; path=/');
expect(this.res.headers['set-cookie'])
.to.contain('hello; domain=my.new.domain; path=/');
});

it('removes domain', function() {
Expand All @@ -285,7 +308,8 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () {

httpProxy.writeHeaders({}, this.res, this.proxyRes, options);

expect(this.res.headers['set-cookie']).to.eql('hello; path=/');
expect(this.res.headers['set-cookie'])
.to.contain('hello; path=/');
});

it('rewrites headers with advanced configuration', function() {
Expand All @@ -301,14 +325,33 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () {
'hello-on-my.old.domain; domain=my.old.domain; path=/',
'hello-on-my.special.domain; domain=my.special.domain; path=/'
];
var setCookieValueIndex = this.proxyRes.rawHeaders.indexOf('Set-Cookie') + 1;
this.proxyRes.rawHeaders[setCookieValueIndex] = [
httpProxy.writeHeaders({}, this.res, this.proxyRes, options);

expect(this.res.headers['set-cookie'])
.to.contain('hello-on-my.domain; path=/');
expect(this.res.headers['set-cookie'])
.to.contain('hello-on-my.old.domain; domain=my.new.domain; path=/');
expect(this.res.headers['set-cookie'])
.to.contain('hello-on-my.special.domain; domain=my.special.domain; path=/');
});

it('rewrites raw headers with advanced configuration', function() {
var options = {
cookieDomainRewrite: {
'*': '',
'my.old.domain': 'my.new.domain',
'my.special.domain': 'my.special.domain'
}
};
this.rawProxyRes.rawHeaders = this.rawProxyRes.rawHeaders.concat([
'Set-Cookie',
'hello-on-my.domain; domain=my.domain; path=/',
'Set-Cookie',
'hello-on-my.old.domain; domain=my.old.domain; path=/',
'Set-Cookie',
'hello-on-my.special.domain; domain=my.special.domain; path=/'
];

httpProxy.writeHeaders({}, this.res, this.proxyRes, options);
]);
httpProxy.writeHeaders({}, this.res, this.rawProxyRes, options);

expect(this.res.headers['set-cookie'])
.to.contain('hello-on-my.domain; path=/');
Expand Down
2 changes: 1 addition & 1 deletion test/lib-https-proxy-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Object.defineProperty(gen, 'port', {

describe('lib/http-proxy.js', function() {
describe('HTTPS #createProxyServer', function() {
describe('HTTPS to HTTP', function () {
describe('HTTPS to HTTP', function () {
it('should proxy the request en send back the response', function (done) {
var ports = { source: gen.port, proxy: gen.port };
var source = http.createServer(function(req, res) {
Expand Down