From 11480ab4c22b96aed2f31c0f33d763191cde378c Mon Sep 17 00:00:00 2001
From: Anton Griadchenko <anton_griadchenko@epam.com>
Date: Wed, 28 Aug 2019 11:16:17 +0300
Subject: [PATCH 1/2] Feature: Add 'megreCookies' options

---
 README.md                                     | 14 +++++++++
 lib/http-proxy.js                             |  1 +
 lib/http-proxy/common.js                      | 26 +++++++++++++++-
 lib/http-proxy/passes/web-outgoing.js         |  4 +++
 ...lib-http-proxy-passes-web-outgoing-test.js | 31 +++++++++++++++++++
 5 files changed, 75 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 5b2d0b3..011feb5 100644
--- a/README.md
+++ b/README.md
@@ -395,6 +395,20 @@ proxyServer.listen(8015);
 
     };
     ```
+* **mergeCookies**: true/false, merges `set-cookie` header from a request passed to `httpProxy.web` and from response.
+  E.g.:
+  ```
+  const http = require("http");
+  const httpProxy = require("http-proxy");
+  const proxy = httpProxy.createProxyServer({});
+  
+  const gateway = http.createServer((req, res) => {
+    res.setHeader('set-cookie', ["gateway=true; Path=/"]);
+    proxy.web(req, res, {target: "http://localhost:3002"});
+  });
+  
+  gateway.listen(3003);
+  ```
 
 **NOTE:**
 `options.ws` and `options.ssl` are optional.
diff --git a/lib/http-proxy.js b/lib/http-proxy.js
index 8ea2789..0a24789 100644
--- a/lib/http-proxy.js
+++ b/lib/http-proxy.js
@@ -40,6 +40,7 @@ function createProxyServer(options) {
    *    hostRewrite: rewrites the location hostname on (201/301/302/307/308) redirects, Default: null.
    *    autoRewrite: rewrites the location host/port on (201/301/302/307/308) redirects based on requested host/port. Default: false.
    *    protocolRewrite: rewrites the location protocol on (201/301/302/307/308) redirects to 'http' or 'https'. Default: null.
+   *    mergeCookies: allows to merge `set-cookie` headers from passed response and response from target. Default: false.
    *  }
    *
    *  NOTE: `options.ws` and `options.ssl` are optional.
diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js
index 6513e81..10feca2 100644
--- a/lib/http-proxy/common.js
+++ b/lib/http-proxy/common.js
@@ -49,7 +49,7 @@ common.setupOutgoing = function(outgoing, options, req, forward) {
   if (options.auth) {
     outgoing.auth = options.auth;
   }
-  
+
   if (options.ca) {
       outgoing.ca = options.ca;
   }
@@ -236,6 +236,30 @@ common.rewriteCookieProperty = function rewriteCookieProperty(header, config, pr
   });
 };
 
+/**
+ * Merges `Set-Cookie` header
+ *
+ * @param {string|[string]} setCookie
+ * @param {string|[string]} upstreamSetCookie
+ * @returns {[string]}
+ *
+ * @api private
+ */
+common.mergeSetCookie = function mergeCookie(setCookie, upstreamSetCookie) {
+  var existingCookieArray = setCookie || [],
+    upstreamCookieArray = upstreamSetCookie || [];
+
+  if (!Array.isArray(existingCookieArray)) {
+    existingCookieArray = [existingCookieArray]
+  }
+
+  if (!Array.isArray(upstreamCookieArray)) {
+    upstreamCookieArray = [upstreamCookieArray]
+  }
+
+  return [].concat(existingCookieArray, upstreamCookieArray)
+};
+
 /**
  * Check the host and see if it potentially has a port in it (keep it simple)
  *
diff --git a/lib/http-proxy/passes/web-outgoing.js b/lib/http-proxy/passes/web-outgoing.js
index 46352f6..6b6278e 100644
--- a/lib/http-proxy/passes/web-outgoing.js
+++ b/lib/http-proxy/passes/web-outgoing.js
@@ -86,6 +86,7 @@ module.exports = { // <--
     var rewriteCookieDomainConfig = options.cookieDomainRewrite,
         rewriteCookiePathConfig = options.cookiePathRewrite,
         preserveHeaderKeyCase = options.preserveHeaderKeyCase,
+        mergeCookiesConfig = options.mergeCookies,
         rawHeaderKeyMap,
         setHeader = function(key, header) {
           if (header == undefined) return;
@@ -95,6 +96,9 @@ module.exports = { // <--
           if (rewriteCookiePathConfig && key.toLowerCase() === 'set-cookie') {
             header = common.rewriteCookieProperty(header, rewriteCookiePathConfig, 'path');
           }
+          if (mergeCookiesConfig && key.toLowerCase() === 'set-cookie') {
+            header = common.mergeSetCookie(res.getHeader("set-cookie"), header)
+          }
           res.setHeader(String(key).trim(), header);
         };
 
diff --git a/test/lib-http-proxy-passes-web-outgoing-test.js b/test/lib-http-proxy-passes-web-outgoing-test.js
index a509cf1..c3b8ded 100644
--- a/test/lib-http-proxy-passes-web-outgoing-test.js
+++ b/test/lib-http-proxy-passes-web-outgoing-test.js
@@ -261,6 +261,9 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () {
           // Header names are lower-cased
           this.headers[k.toLowerCase()] = v;
         },
+        getHeader: function (k) {
+          return this.headers[k.toLowerCase()]
+        },
         headers: {}
       };
     });
@@ -404,6 +407,34 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () {
       expect(this.res.headers['set-cookie'])
         .to.contain('hello-on-my.special.domain; domain=my.special.domain; path=/');
     });
+
+    it('appends set-cookies header to an existing one', function () {
+      var options = {
+        mergeCookies: true,
+      };
+
+      this.res.setHeader("set-cookie", ['hello; domain=my.domain; path=/']);
+
+      httpProxy.writeHeaders({}, this.res, this.proxyRes, options);
+
+      expect(this.res.headers['set-cookie']).to.be.an(Array);
+      expect(this.res.headers['set-cookie']).to.have.length(3);
+    });
+
+    it('appends set-cookies header to an existing one (set-cookie is not an array)', function () {
+      var options = {
+        mergeCookies: true,
+      };
+
+      this.proxyRes.headers = Object.assign({}, this.proxyRes.headers, {'set-cookie': 'hello1; domain=my.domain; path=/'});
+
+      this.res.setHeader("set-cookie", 'hello; domain=my.domain; path=/');
+
+      httpProxy.writeHeaders({}, this.res, this.proxyRes, options);
+
+      expect(this.res.headers['set-cookie']).to.be.an(Array);
+      expect(this.res.headers['set-cookie']).to.have.length(2);
+    });
   });
 
 
-- 
GitLab


From 3fcde39df6e0dcb603aff70a8f4c0d8e90e580de Mon Sep 17 00:00:00 2001
From: Anton Griadchenko <anton_griadchenko@epam.com>
Date: Wed, 28 Aug 2019 16:59:06 +0300
Subject: [PATCH 2/2] Replace quotations

---
 lib/http-proxy/passes/web-outgoing.js           | 2 +-
 test/lib-http-proxy-passes-web-outgoing-test.js | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/http-proxy/passes/web-outgoing.js b/lib/http-proxy/passes/web-outgoing.js
index 6b6278e..e1d5224 100644
--- a/lib/http-proxy/passes/web-outgoing.js
+++ b/lib/http-proxy/passes/web-outgoing.js
@@ -97,7 +97,7 @@ module.exports = { // <--
             header = common.rewriteCookieProperty(header, rewriteCookiePathConfig, 'path');
           }
           if (mergeCookiesConfig && key.toLowerCase() === 'set-cookie') {
-            header = common.mergeSetCookie(res.getHeader("set-cookie"), header)
+            header = common.mergeSetCookie(res.getHeader('set-cookie'), header)
           }
           res.setHeader(String(key).trim(), header);
         };
diff --git a/test/lib-http-proxy-passes-web-outgoing-test.js b/test/lib-http-proxy-passes-web-outgoing-test.js
index c3b8ded..524ad69 100644
--- a/test/lib-http-proxy-passes-web-outgoing-test.js
+++ b/test/lib-http-proxy-passes-web-outgoing-test.js
@@ -413,7 +413,7 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () {
         mergeCookies: true,
       };
 
-      this.res.setHeader("set-cookie", ['hello; domain=my.domain; path=/']);
+      this.res.setHeader('set-cookie', ['hello; domain=my.domain; path=/']);
 
       httpProxy.writeHeaders({}, this.res, this.proxyRes, options);
 
@@ -428,7 +428,7 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () {
 
       this.proxyRes.headers = Object.assign({}, this.proxyRes.headers, {'set-cookie': 'hello1; domain=my.domain; path=/'});
 
-      this.res.setHeader("set-cookie", 'hello; domain=my.domain; path=/');
+      this.res.setHeader('set-cookie', 'hello; domain=my.domain; path=/');
 
       httpProxy.writeHeaders({}, this.res, this.proxyRes, options);
 
-- 
GitLab