commit 6fa68a53285b7f553114cda4030f51ffab3d1efb
parent 23626800f0305e47f1d3d67df93007d2653ea443
Author: Tim Huang <tihuang@mozilla.com>
Date: Mon, 24 Nov 2025 16:59:14 +0000
Bug 2000486 - Reset the IsThirdPartyContextToTopWindow flag for the redirect channel. r=bvandersloot,necko-reviewers,cookie-reviewers,valentin
Differential Revision: https://phabricator.services.mozilla.com/D273835
Diffstat:
7 files changed, 149 insertions(+), 0 deletions(-)
diff --git a/netwerk/cookie/test/browser/browser.toml b/netwerk/cookie/test/browser/browser.toml
@@ -46,6 +46,15 @@ support-files = ["oversize.sjs"]
["browser_partitionedConsole.js"]
support-files = ["partitioned.sjs"]
+["browser_redirect_ABA_chips.js"]
+support-files = [
+ "redirect_301.sjs",
+ "serviceWorker.js",
+ "set_cookie_cors.html",
+ "set_cookie_cors.html^headers^",
+ "sw_fetch.js"
+]
+
["browser_sameSiteConsole.js"]
support-files = ["sameSite.sjs"]
diff --git a/netwerk/cookie/test/browser/browser_redirect_ABA_chips.js b/netwerk/cookie/test/browser/browser_redirect_ABA_chips.js
@@ -0,0 +1,80 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const FIRST_PARTY_DOMAIN = "https://example.com/";
+const THIRD_PARTY_DOMAIN = "https://example.org/";
+
+const FIRST_PARTY_PAGE = FIRST_PARTY_DOMAIN + TEST_PATH + "file_empty.html";
+const THIRD_PARTY_PAGE = THIRD_PARTY_DOMAIN + TEST_PATH + "file_empty.html";
+const FIRST_PARTY_PAGE_CORS =
+ FIRST_PARTY_DOMAIN + TEST_PATH + "set_cookie_cors.html";
+
+add_setup(async () => {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ [
+ "network.cookie.cookieBehavior",
+ Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN,
+ ],
+ ["network.cookie.CHIPS.enabled", true],
+ ],
+ });
+
+ registerCleanupFunction(async () => {
+ await new Promise(resolve => {
+ Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, () =>
+ resolve()
+ );
+ });
+ });
+});
+
+add_task(async () => {
+ const tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ FIRST_PARTY_PAGE
+ );
+
+ const browser = tab.linkedBrowser;
+
+ // Load a third-party iframe.
+ let iframeBC = await SpecialPowers.spawn(
+ browser,
+ [THIRD_PARTY_PAGE],
+ async src => {
+ const iframe = content.document.createElement("iframe");
+
+ await new content.Promise(resolve => {
+ iframe.onload = resolve;
+
+ iframe.src = src;
+ content.document.body.appendChild(iframe);
+ });
+
+ return iframe.browsingContext;
+ }
+ );
+
+ // Register a service worker in the third-party iframe.
+ await SpecialPowers.spawn(iframeBC, [FIRST_PARTY_PAGE_CORS], async src => {
+ let reg = await content.navigator.serviceWorker.register("sw_fetch.js");
+
+ await ContentTaskUtils.waitForCondition(() => {
+ return reg.active && reg.active.state === "activated";
+ }, "The service worker is activated");
+
+ // Trigger a fetch which should be intercepted by the service worker. The
+ // fetch will be redirected to the first-party page to set a cookie.
+ await content.fetch("redirect_301.sjs?src=" + src);
+
+ ok(true, "The fetch is completed without a crash.");
+
+ // Clean up the service worker to avoid leaking control into later tests.
+ await reg.unregister();
+ });
+
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/netwerk/cookie/test/browser/redirect_301.sjs b/netwerk/cookie/test/browser/redirect_301.sjs
@@ -0,0 +1,25 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * A page that performs 301 redirection to the given 'src'.
+ */
+
+"use strict";
+
+function handleRequest(request, response) {
+ let query = new URLSearchParams(request.queryString);
+
+ // The 'src' must be included.
+ if (!query.has("src")) {
+ throw Error("No 'src' in the query string");
+ }
+
+ response.setStatusLine(request.httpVersion, 301, "Moved Permanently");
+ response.setHeader("Location", query.get("src"));
+ response.setHeader("Cache-Control", "no-cache", false);
+
+ // Optional body for 301 response
+ response.write("Redirecting...");
+}
diff --git a/netwerk/cookie/test/browser/set_cookie_cors.html b/netwerk/cookie/test/browser/set_cookie_cors.html
@@ -0,0 +1,2 @@
+<html><body>
+</body></html>
diff --git a/netwerk/cookie/test/browser/set_cookie_cors.html^headers^ b/netwerk/cookie/test/browser/set_cookie_cors.html^headers^
@@ -0,0 +1,3 @@
+Access-Control-Allow-Origin: https://example.org
+Access-Control-Allow-Credentials: true
+set-cookie: foo=bar; Secure; HttpOnly
diff --git a/netwerk/cookie/test/browser/sw_fetch.js b/netwerk/cookie/test/browser/sw_fetch.js
@@ -0,0 +1,15 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+self.oninstall = _ => {
+ self.skipWaiting();
+};
+
+self.onactivate = event => {
+ event.waitUntil(self.clients.claim());
+};
+
+self.onfetch = event => {
+ event.respondWith(fetch(event.request, { credentials: "include" }));
+};
diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -4569,6 +4569,21 @@ already_AddRefed<nsILoadInfo> HttpBaseChannel::CloneLoadInfoForRedirect(
}
}
+ // Clone a new cookieJarSettings from the old one for the new channel.
+ // Otherwise, updating the new cookieJarSettings will affect the old one.
+ nsCOMPtr<nsICookieJarSettings> oldCookieJarSettings;
+ mLoadInfo->GetCookieJarSettings(getter_AddRefs(oldCookieJarSettings));
+
+ RefPtr<CookieJarSettings> newCookieJarSettings;
+ newCookieJarSettings = CookieJarSettings::Cast(oldCookieJarSettings)->Clone();
+
+ newLoadInfo->SetCookieJarSettings(newCookieJarSettings);
+
+ // Clear the isThirdPartyContextToTopWindow flag for the new channel so that
+ // it will be computed again when the new channel is opened.
+ static_cast<net::LoadInfo*>(newLoadInfo.get())
+ ->ClearIsThirdPartyContextToTopWindow();
+
// Leave empty, we want a 'clean ground' when creating the new channel.
// This will be ensured to be either set by the protocol handler or set
// to the redirect target URI properly after the channel creation.