From 636493b80e373c22d3df4c2e4bd8f7a1711059ad Mon Sep 17 00:00:00 2001
From: Carsten Rohrbach <carsten.rohrbach@codecentric.de>
Date: Wed, 3 Jul 2024 08:54:31 +0200
Subject: [PATCH] fix: agent cookie host assignment

---
 src/node/agent.js      |  4 ++--
 src/node/index.js      |  9 +++++++++
 test/agent-base.js     | 20 ++++++++++++++++++++
 test/support/server.js | 25 +++++++++++++++++++++++++
 4 files changed, 56 insertions(+), 2 deletions(-)

diff --git a/src/node/agent.js b/src/node/agent.js
index 88030d776..a794d13cb 100644
--- a/src/node/agent.js
+++ b/src/node/agent.js
@@ -54,7 +54,7 @@ class Agent extends AgentBase {
     const cookies = res.headers['set-cookie'];
     if (cookies) {
       const url = new URL(res.request?.url || '');
-      this.jar.setCookies(cookies, url.hostname, url.pathname);
+      this.jar.setCookies(cookies, url.hostname, null);
     }
   }
 
@@ -82,7 +82,7 @@ for (const name of methods) {
     const request_ = new request.Request(method, url);
 
     request_.on('response', this._saveCookies.bind(this));
-    request_.on('redirect', this._saveCookies.bind(this));
+    request_.on('pre-redirect', this._saveCookies.bind(this));
     request_.on('redirect', this._attachCookies.bind(this, request_));
     this._setDefaults(request_);
     this._attachCookies(request_);
diff --git a/src/node/index.js b/src/node/index.js
index 75217c8bd..7c7fa55bc 100644
--- a/src/node/index.js
+++ b/src/node/index.js
@@ -504,6 +504,8 @@ Request.prototype._redirect = function (res) {
   // this is required for Node v0.10+
   res.resume();
 
+  this._emitPreRedirect(res);
+
   let headers = this.req.getHeaders ? this.req.getHeaders() : this.req._headers;
 
   const changesOrigin = new URL(url).host !== new URL(this.url).host;
@@ -956,6 +958,13 @@ Request.prototype._emitRedirect = function () {
   this.emit('redirect', response);
 };
 
+Request.prototype._emitPreRedirect = function (res) {
+  this.res = res;
+  const response = new Response(this);
+  response.redirects = this._redirectList;
+  this.emit('pre-redirect', response);
+};
+
 Request.prototype.end = function (fn) {
   this.request();
   debug('%s %s', this.method, this.url);
diff --git a/test/agent-base.js b/test/agent-base.js
index 592f996e8..a3b3c0b69 100644
--- a/test/agent-base.js
+++ b/test/agent-base.js
@@ -49,4 +49,24 @@ describe('Agent', () => {
         assert.deepEqual({ hello: 'world' }, res.body);
       });
   });
+
+  it('should assign cookies without domains correctly when following redirects', () => {
+    const agent = request.agent();
+
+    const firstUrl = new URL(base)
+    firstUrl.hostname = 'first.local'
+    const first = firstUrl.toString().slice(0, -1)
+
+    const secondUrl = new URL(base)
+    secondUrl.hostname = "second.local"
+    const second = secondUrl.toString().slice(0, -1)
+
+    return agent
+      .get(`${first}/cookie-cross-domain-redirect`)
+      .query({ first, second })
+      .connect('127.0.0.1')
+      .then((res) => {
+        assert.equal(res.text, 'first.local=true')
+      })
+  })
 });
diff --git a/test/support/server.js b/test/support/server.js
index a219c0d15..4e676862e 100644
--- a/test/support/server.js
+++ b/test/support/server.js
@@ -441,6 +441,31 @@ app.put('/redirect-308', (request, res) => {
   res.redirect(308, '/reply-method');
 });
 
+app.get('/cookie-cross-domain-redirect', (request, res) => {
+  const { first, second } = request.query
+  const hostname = new URL(`http://${request.headers.host ?? request.headers[':authority']}`).hostname
+  res.cookie(hostname, 'true', {
+    path: '/',
+    sameSite: 'lax',
+    secure: false,
+    maxAge: 1000
+  });
+
+  res.redirect(303, `${second}/cookie-cross-domain-second-redirect?first=${encodeURIComponent(first)}`);
+});
+
+app.get('/cookie-cross-domain-second-redirect', (request, res) => {
+  const first = request.query.first
+  const hostname = new URL(`http://${request.headers.host ?? request.headers[':authority']}`).hostname
+  res.cookie(hostname, 'true', {
+    path: '/',
+    sameSite: 'lax',
+    secure: false,
+    maxAge: 1000
+  });
+  res.redirect(303, `${first}/show-cookies`);
+});
+
 app.all('/reply-method', (request, res) => {
   res.send(`method=${request.method.toLowerCase()}`);
 });