diff --git a/README.md b/README.md index ae8ed8110..49c49a396 100644 --- a/README.md +++ b/README.md @@ -333,6 +333,7 @@ proxyServer.listen(8015); * **ignorePath**: true/false, Default: false - specify whether you want to ignore the proxy path of the incoming request (note: you will have to append / manually if required). * **localAddress**: Local interface string to bind for outgoing connections * **changeOrigin**: true/false, Default: false - changes the origin of the host header to the target URL +* **preserveHeaderKeyCase**: true/false, Default: false - specify whether you want to keep letter case of response header key * **auth**: Basic authentication i.e. 'user:password' to compute an Authorization header. * **hostRewrite**: rewrites the location hostname on (201/301/302/307/308) redirects. * **autoRewrite**: rewrites the location host/port on (201/301/302/307/308) redirects based on requested host/port. Default: false. diff --git a/lib/http-proxy.js b/lib/http-proxy.js index 40f2e4b91..7dab7a48d 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -35,6 +35,7 @@ function createProxyServer(options) { * ignorePath: * localAddress : * changeOrigin: + * preserveHeaderKeyCase: * auth : Basic authentication i.e. 'user:password' to compute an Authorization header. * hostRewrite: rewrites the location hostname on (301/302/307/308) redirects, Default: null. * autoRewrite: rewrites the location host/port on (301/302/307/308) redirects based on requested host/port. Default: false. diff --git a/lib/http-proxy/passes/web-outgoing.js b/lib/http-proxy/passes/web-outgoing.js index e7dc479f8..cff86a700 100644 --- a/lib/http-proxy/passes/web-outgoing.js +++ b/lib/http-proxy/passes/web-outgoing.js @@ -84,18 +84,14 @@ 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. - setCookies = [], + preserveHeaderKeyCase = options.preserveHeaderKeyCase, + rawHeaderKeyMap, setHeader = function(key, header) { if (header == undefined) return; - if (key.toLowerCase() !== 'set-cookie') { - return res.setHeader(String(key).trim(), header); - } - if (rewriteCookieDomainConfig) { + if (rewriteCookieDomainConfig && key.toLowerCase() === 'set-cookie') { header = common.rewriteCookieDomain(header, rewriteCookieDomainConfig); } - setCookies.push(header); // defer to the end when we have all of them + res.setHeader(String(key).trim(), header); }; if (typeof rewriteCookieDomainConfig === 'string') { //also test for '' @@ -104,21 +100,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 (preserveHeaderKeyCase && proxyRes.rawHeaders != undefined) { + rawHeaderKeyMap = {}; for (var i = 0; i < proxyRes.rawHeaders.length; i += 2) { var key = proxyRes.rawHeaders[i]; - var header = proxyRes.rawHeaders[i + 1]; - setHeader(key, header); + rawHeaderKeyMap[key.toLowerCase()] = key; } - } else { - Object.keys(proxyRes.headers).forEach(function(key) { - var header = proxyRes.headers[key]; - setHeader(key, header); - }); - } - if (setCookies.length) { - res.setHeader('Set-Cookie', setCookies.length === 1 ? setCookies[0] : setCookies); } + + Object.keys(proxyRes.headers).forEach(function(key) { + var header = proxyRes.headers[key]; + if (preserveHeaderKeyCase && rawHeaderKeyMap) { + key = rawHeaderKeyMap[key] || key; + } + setHeader(key, header); + }); }, /** diff --git a/test/lib-http-proxy-passes-web-outgoing-test.js b/test/lib-http-proxy-passes-web-outgoing-test.js index 451f61419..ae86904da 100644 --- a/test/lib-http-proxy-passes-web-outgoing-test.js +++ b/test/lib-http-proxy-passes-web-outgoing-test.js @@ -240,6 +240,14 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { } }; this.rawProxyRes = { + headers: { + hey: 'hello', + how: 'are you?', + 'set-cookie': [ + 'hello; domain=my.domain; path=/', + 'there; domain=my.domain; path=/' + ] + }, rawHeaders: [ 'Hey', 'hello', 'How', 'are you?', @@ -343,6 +351,11 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { 'my.special.domain': 'my.special.domain' } }; + this.rawProxyRes.headers['set-cookie'] = [ + 'hello-on-my.domain; domain=my.domain; path=/', + 'hello-on-my.old.domain; domain=my.old.domain; path=/', + 'hello-on-my.special.domain; domain=my.special.domain; path=/' + ]; this.rawProxyRes.rawHeaders = this.rawProxyRes.rawHeaders.concat([ 'Set-Cookie', 'hello-on-my.domain; domain=my.domain; path=/', diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index 8b024c9f1..06702be05 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -130,7 +130,8 @@ describe('lib/http-proxy.js', function() { it('should make the request, handle response and finish it', function(done) { var ports = { source: gen.port, proxy: gen.port }; var proxy = httpProxy.createProxyServer({ - target: 'http://127.0.0.1:' + ports.source + target: 'http://127.0.0.1:' + ports.source, + preserveHeaderKeyCase: true }).listen(ports.proxy); var source = http.createServer(function(req, res) {