summaryrefslogtreecommitdiffstats
path: root/netwerk/cookie/test/browser
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/cookie/test/browser')
-rw-r--r--netwerk/cookie/test/browser/browser.toml42
-rw-r--r--netwerk/cookie/test/browser/browser_broadcastChannel.js80
-rw-r--r--netwerk/cookie/test/browser/browser_cookie_insecure_overwrites_secure.js128
-rw-r--r--netwerk/cookie/test/browser/browser_cookie_purge_sync.js141
-rw-r--r--netwerk/cookie/test/browser/browser_cookies.js53
-rw-r--r--netwerk/cookie/test/browser/browser_cookies_ipv6.js57
-rw-r--r--netwerk/cookie/test/browser/browser_domCache.js25
-rw-r--r--netwerk/cookie/test/browser/browser_indexedDB.js84
-rw-r--r--netwerk/cookie/test/browser/browser_originattributes.js121
-rw-r--r--netwerk/cookie/test/browser/browser_oversize.js96
-rw-r--r--netwerk/cookie/test/browser/browser_partitionedConsole.js201
-rw-r--r--netwerk/cookie/test/browser/browser_partitioned_telemetry.js134
-rw-r--r--netwerk/cookie/test/browser/browser_sameSiteConsole.js133
-rw-r--r--netwerk/cookie/test/browser/browser_serviceWorker.js45
-rw-r--r--netwerk/cookie/test/browser/browser_sharedWorker.js18
-rw-r--r--netwerk/cookie/test/browser/browser_storage.js43
-rw-r--r--netwerk/cookie/test/browser/file_empty.html2
-rw-r--r--netwerk/cookie/test/browser/file_empty.js1
-rw-r--r--netwerk/cookie/test/browser/head.js201
-rw-r--r--netwerk/cookie/test/browser/oversize.sjs17
-rw-r--r--netwerk/cookie/test/browser/partitioned.sjs32
-rw-r--r--netwerk/cookie/test/browser/sameSite.sjs7
-rw-r--r--netwerk/cookie/test/browser/server.sjs9
23 files changed, 1670 insertions, 0 deletions
diff --git a/netwerk/cookie/test/browser/browser.toml b/netwerk/cookie/test/browser/browser.toml
new file mode 100644
index 0000000000..05a302ddbd
--- /dev/null
+++ b/netwerk/cookie/test/browser/browser.toml
@@ -0,0 +1,42 @@
+[DEFAULT]
+
+support-files = [
+ "file_empty.html",
+ "file_empty.js",
+ "head.js"
+]
+
+["browser_broadcastChannel.js"]
+
+["browser_cookie_insecure_overwrites_secure.js"]
+
+["browser_cookie_purge_sync.js"]
+
+["browser_cookies.js"]
+support-files = ["server.sjs"]
+
+["browser_cookies_ipv6.js"]
+
+["browser_domCache.js"]
+
+["browser_indexedDB.js"]
+
+["browser_originattributes.js"]
+
+["browser_oversize.js"]
+support-files = ["oversize.sjs"]
+
+["browser_partitionedConsole.js"]
+support-files = ["partitioned.sjs"]
+
+["browser_partitioned_telemetry.js"]
+support-files = ["partitioned.sjs"]
+
+["browser_sameSiteConsole.js"]
+support-files = ["sameSite.sjs"]
+
+["browser_serviceWorker.js"]
+
+["browser_sharedWorker.js"]
+
+["browser_storage.js"]
diff --git a/netwerk/cookie/test/browser/browser_broadcastChannel.js b/netwerk/cookie/test/browser/browser_broadcastChannel.js
new file mode 100644
index 0000000000..ee561e6f0c
--- /dev/null
+++ b/netwerk/cookie/test/browser/browser_broadcastChannel.js
@@ -0,0 +1,80 @@
+// BroadcastChannel is not considered part of CookieJar. It's not allowed to
+// communicate with other windows with different cookie jar settings.
+"use strict";
+
+CookiePolicyHelper.runTest("BroadcastChannel", {
+ cookieJarAccessAllowed: async w => {
+ new w.BroadcastChannel("hello");
+ ok(true, "BroadcastChannel be used");
+ },
+
+ cookieJarAccessDenied: async w => {
+ try {
+ new w.BroadcastChannel("hello");
+ ok(false, "BroadcastChannel cannot be used!");
+ } catch (e) {
+ ok(true, "BroadcastChannel cannot be used!");
+ is(e.name, "SecurityError", "We want a security error message.");
+ }
+ },
+});
+
+CookiePolicyHelper.runTest("BroadcastChannel in workers", {
+ cookieJarAccessAllowed: async w => {
+ function nonBlockingCode() {
+ new BroadcastChannel("hello");
+ postMessage(true);
+ }
+
+ let blob = new w.Blob([
+ nonBlockingCode.toString() + "; nonBlockingCode();",
+ ]);
+ ok(blob, "Blob has been created");
+
+ let blobURL = w.URL.createObjectURL(blob);
+ ok(blobURL, "Blob URL has been created");
+
+ let worker = new w.Worker(blobURL);
+ ok(worker, "Worker has been created");
+
+ await new w.Promise((resolve, reject) => {
+ worker.onmessage = function (e) {
+ if (e) {
+ resolve();
+ } else {
+ reject();
+ }
+ };
+ });
+ },
+
+ cookieJarAccessDenied: async w => {
+ function blockingCode() {
+ try {
+ new BroadcastChannel("hello");
+ postMessage(false);
+ } catch (e) {
+ postMessage(e.name == "SecurityError");
+ }
+ }
+
+ let blob = new w.Blob([blockingCode.toString() + "; blockingCode();"]);
+ ok(blob, "Blob has been created");
+
+ let blobURL = w.URL.createObjectURL(blob);
+ ok(blobURL, "Blob URL has been created");
+
+ let worker = new w.Worker(blobURL);
+ ok(worker, "Worker has been created");
+
+ await new w.Promise((resolve, reject) => {
+ worker.onmessage = function (e) {
+ if (e) {
+ resolve();
+ } else {
+ reject();
+ }
+ };
+ });
+ },
+});
diff --git a/netwerk/cookie/test/browser/browser_cookie_insecure_overwrites_secure.js b/netwerk/cookie/test/browser/browser_cookie_insecure_overwrites_secure.js
new file mode 100644
index 0000000000..7461e5cc16
--- /dev/null
+++ b/netwerk/cookie/test/browser/browser_cookie_insecure_overwrites_secure.js
@@ -0,0 +1,128 @@
+/* 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/. */
+
+let { HttpServer } = ChromeUtils.importESModule(
+ "resource://testing-common/httpd.sys.mjs"
+);
+
+const urlPath = "/browser/netwerk/cookie/test/browser/file_empty.html";
+const baseDomain = "example.com";
+
+// eslint doesn't like http
+// eslint-disable-next-line @microsoft/sdl/no-insecure-url
+const URL_INSECURE_COM = "http://" + baseDomain + urlPath;
+const URL_SECURE_COM = "https://" + baseDomain + urlPath;
+
+// common cookie strings
+const COOKIE_BASIC = "foo=one";
+const COOKIE_OTHER = "foo=two";
+const COOKIE_THIRD = "foo=three";
+const COOKIE_FORTH = "foo=four";
+
+function securify(cookie) {
+ return cookie + "; Secure";
+}
+
+registerCleanupFunction(() => {
+ Services.prefs.clearUserPref("dom.security.https_first");
+ Services.prefs.clearUserPref("network.cookie.cookieBehavior");
+ Services.prefs.clearUserPref(
+ "network.cookieJarSettings.unblocked_for_testing"
+ );
+ Services.prefs.clearUserPref("network.cookie.sameSite.laxByDefault");
+ Services.prefs.clearUserPref("network.cookie.sameSite.noneRequiresSecure");
+ Services.prefs.clearUserPref("network.cookie.sameSite.schemeful");
+ info("Cleaning up the test");
+});
+
+async function setup() {
+ // HTTPS-First would interfere with this test.
+ Services.prefs.setBoolPref("dom.security.https_first", false);
+
+ Services.prefs.setIntPref("network.cookie.cookieBehavior", 0);
+
+ Services.prefs.setBoolPref(
+ "network.cookieJarSettings.unblocked_for_testing",
+ true
+ );
+
+ Services.prefs.setBoolPref("network.cookie.sameSite.laxByDefault", false);
+ Services.prefs.setBoolPref(
+ "network.cookie.sameSite.noneRequiresSecure",
+ false
+ );
+ Services.prefs.setBoolPref("network.cookie.sameSite.schemeful", true);
+ Services.cookies.removeAll();
+}
+add_task(setup);
+
+// note:
+// 1. The URL scheme will not matter for insecure cookies, since
+// cookies are not "schemeful" in this sense.
+// So an insecure cookie set anywhere will be visible on http and https sites
+// Secure cookies are different, they will only be visible from https sites
+// and will prevent cookie setting of the same name on insecure sites.
+//
+// 2. The different processes (tabs) shouldn't matter since
+// cookie adds/changes are distributed to other processes on a need-to-know
+// basis.
+
+add_task(async function test_insecure_cant_overwrite_secure_via_doc() {
+ // insecure
+ const tab1 = BrowserTestUtils.addTab(gBrowser, URL_INSECURE_COM);
+ const browser = gBrowser.getBrowserForTab(tab1);
+ await BrowserTestUtils.browserLoaded(browser);
+
+ // secure
+ const tab2 = BrowserTestUtils.addTab(gBrowser, URL_SECURE_COM);
+ const browser2 = gBrowser.getBrowserForTab(tab2);
+ await BrowserTestUtils.browserLoaded(browser2);
+
+ // init with insecure cookie on insecure origin child process
+ await SpecialPowers.spawn(
+ browser,
+ [COOKIE_BASIC, COOKIE_BASIC],
+ (cookie, expected) => {
+ content.document.cookie = cookie;
+ is(content.document.cookie, expected);
+ }
+ );
+
+ // insecure cookie visible on secure origin process (sanity check)
+ await SpecialPowers.spawn(browser2, [COOKIE_BASIC], expected => {
+ is(content.document.cookie, expected);
+ });
+
+ // overwrite insecure cookie on secure origin with secure cookie (sanity check)
+ await SpecialPowers.spawn(
+ browser2,
+ [securify(COOKIE_OTHER), COOKIE_OTHER],
+ (cookie, expected) => {
+ content.document.cookie = cookie;
+ is(content.document.cookie, expected);
+ }
+ );
+
+ // insecure cookie will NOT overwrite the secure one on insecure origin
+ // and cookie.document appears blank
+ await SpecialPowers.spawn(browser, [COOKIE_THIRD, ""], (cookie, expected) => {
+ content.document.cookie = cookie; // quiet failure here
+ is(content.document.cookie, expected);
+ });
+
+ // insecure cookie will overwrite secure cookie on secure origin
+ // a bit weird, but this is normal
+ await SpecialPowers.spawn(
+ browser2,
+ [COOKIE_FORTH, COOKIE_FORTH],
+ (cookie, expected) => {
+ content.document.cookie = cookie;
+ is(content.document.cookie, expected);
+ }
+ );
+
+ BrowserTestUtils.removeTab(tab1);
+ BrowserTestUtils.removeTab(tab2);
+ Services.cookies.removeAll();
+});
diff --git a/netwerk/cookie/test/browser/browser_cookie_purge_sync.js b/netwerk/cookie/test/browser/browser_cookie_purge_sync.js
new file mode 100644
index 0000000000..186797d058
--- /dev/null
+++ b/netwerk/cookie/test/browser/browser_cookie_purge_sync.js
@@ -0,0 +1,141 @@
+/* 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/. */
+
+// This test checks that cookie purge broadcast correctly
+// updates content process memory as triggered by:
+// 1. stale-cookie update from content process
+// 2. delete cookie by host from parent process
+// 3. clear all cookies from parent process
+
+const URL_EXAMPLE = "https://example.com";
+const COOKIE_NAMEVALUE = "name=value";
+const COOKIE_NAMEVALUE_2 = COOKIE_NAMEVALUE + "2";
+const COOKIE_STRING = COOKIE_NAMEVALUE + "; Secure; SameSite=None";
+const COOKIE_STRING_2 = COOKIE_NAMEVALUE_2 + "; Secure; SameSite=None";
+const MAX_AGE_OLD = 2; // seconds
+const MAX_AGE_NEW = 100; // 100 sec
+
+registerCleanupFunction(() => {
+ info("Cleaning up the test setup");
+ Services.prefs.clearUserPref("network.cookie.sameSite.laxByDefault");
+ Services.cookies.removeAll();
+});
+
+add_setup(async function () {
+ info("Setting up the test");
+ Services.prefs.setBoolPref("network.cookie.sameSite.laxByDefault", false);
+});
+
+function waitForNotificationPromise(notification, expected) {
+ return new Promise(resolve => {
+ function observer(subject, topic, data) {
+ is(content.document.cookie, expected);
+ Services.obs.removeObserver(observer, notification);
+ resolve();
+ }
+ Services.obs.addObserver(observer, notification);
+ });
+}
+
+add_task(async function test_purge_sync_batch_and_deleted() {
+ const tab1 = BrowserTestUtils.addTab(gBrowser, URL_EXAMPLE);
+ const browser = gBrowser.getBrowserForTab(tab1);
+ await BrowserTestUtils.browserLoaded(browser);
+
+ const tab2 = BrowserTestUtils.addTab(gBrowser, URL_EXAMPLE);
+ const browser2 = gBrowser.getBrowserForTab(tab2);
+ await BrowserTestUtils.browserLoaded(browser2);
+
+ let firstCookieAdded = SpecialPowers.spawn(
+ browser2,
+ ["content-added-cookie", COOKIE_NAMEVALUE],
+ waitForNotificationPromise
+ );
+ await TestUtils.waitForTick(); // waiting helps --verify
+
+ // set old cookie in tab 1 and check it in tab 2
+ await SpecialPowers.spawn(
+ browser,
+ [COOKIE_STRING, MAX_AGE_OLD],
+ (cookie, max_age) => {
+ content.document.cookie = cookie + ";Max-Age=" + max_age;
+ }
+ );
+ await firstCookieAdded;
+
+ // wait until the first cookie expires
+ await SpecialPowers.spawn(browser2, [], () => {
+ return ContentTaskUtils.waitForCondition(
+ () => content.document.cookie == "",
+ "cookie did not expire in time",
+ 200
+ ).catch(msg => {
+ is(false, "Cookie did not expire in time");
+ });
+ });
+
+ // BATCH_DELETED/BatchDeleted pathway
+ let batchDeletedPromise = SpecialPowers.spawn(
+ browser,
+ ["content-batch-deleted-cookies", COOKIE_NAMEVALUE_2],
+ waitForNotificationPromise
+ );
+ await TestUtils.waitForTick(); // waiting helps --verify
+ await SpecialPowers.spawn(
+ browser,
+ [COOKIE_STRING_2, MAX_AGE_NEW],
+ (cookie, max_age) => {
+ content.document.cookie = cookie + ";Max-Age=" + max_age;
+ }
+ );
+ await batchDeletedPromise;
+
+ // COOKIE_DELETED/RemoveCookie pathway
+ let cookieRemovedPromise = SpecialPowers.spawn(
+ browser,
+ ["content-removed-cookie", ""],
+ waitForNotificationPromise
+ );
+ let cookieRemovedPromise2 = SpecialPowers.spawn(
+ browser2,
+ ["content-removed-cookie", ""],
+ waitForNotificationPromise
+ );
+ await TestUtils.waitForTick();
+ Services.cookies.removeCookiesFromExactHost(
+ "example.com",
+ JSON.stringify({})
+ );
+ await cookieRemovedPromise;
+ await cookieRemovedPromise2;
+
+ // cleanup prep
+ let anotherCookieAdded = SpecialPowers.spawn(
+ browser2,
+ ["content-added-cookie", COOKIE_NAMEVALUE],
+ waitForNotificationPromise
+ );
+ await TestUtils.waitForTick(); // waiting helps --verify
+ await SpecialPowers.spawn(
+ browser,
+ [COOKIE_STRING, MAX_AGE_NEW],
+ (cookie, max_age) => {
+ content.document.cookie = cookie + ";Max-Age=" + max_age;
+ }
+ );
+ await anotherCookieAdded;
+
+ // ALL_COOKIES_CLEARED/RemoveAll pathway
+ let cleanup = SpecialPowers.spawn(
+ browser2,
+ ["content-removed-all-cookies", ""],
+ waitForNotificationPromise
+ );
+ await TestUtils.waitForTick();
+ Services.cookies.removeAll();
+ await cleanup;
+
+ BrowserTestUtils.removeTab(tab1);
+ BrowserTestUtils.removeTab(tab2);
+});
diff --git a/netwerk/cookie/test/browser/browser_cookies.js b/netwerk/cookie/test/browser/browser_cookies.js
new file mode 100644
index 0000000000..8a0d8332bf
--- /dev/null
+++ b/netwerk/cookie/test/browser/browser_cookies.js
@@ -0,0 +1,53 @@
+"use strict";
+
+CookiePolicyHelper.runTest("document.cookies", {
+ cookieJarAccessAllowed: async _ => {
+ let hasCookie = !!content.document.cookie.length;
+
+ await content
+ .fetch("server.sjs")
+ .then(r => r.text())
+ .then(text => {
+ is(
+ text,
+ hasCookie ? "cookie-present" : "cookie-not-present",
+ "document.cookie is consistent with fetch requests"
+ );
+ });
+
+ content.document.cookie = "name=value";
+ ok(content.document.cookie.includes("name=value"), "Some cookies for me");
+ ok(content.document.cookie.includes("foopy=1"), "Some cookies for me");
+
+ await content
+ .fetch("server.sjs")
+ .then(r => r.text())
+ .then(text => {
+ is(text, "cookie-present", "We should have cookies");
+ });
+
+ ok(!!content.document.cookie.length, "Some Cookies for me");
+ },
+
+ cookieJarAccessDenied: async _ => {
+ is(content.document.cookie, "", "No cookies for me");
+ content.document.cookie = "name=value";
+ is(content.document.cookie, "", "No cookies for me");
+
+ await content
+ .fetch("server.sjs")
+ .then(r => r.text())
+ .then(text => {
+ is(text, "cookie-not-present", "We should not have cookies");
+ });
+ // Let's do it twice.
+ await content
+ .fetch("server.sjs")
+ .then(r => r.text())
+ .then(text => {
+ is(text, "cookie-not-present", "We should not have cookies");
+ });
+
+ is(content.document.cookie, "", "Still no cookies for me");
+ },
+});
diff --git a/netwerk/cookie/test/browser/browser_cookies_ipv6.js b/netwerk/cookie/test/browser/browser_cookies_ipv6.js
new file mode 100644
index 0000000000..088a76f4e8
--- /dev/null
+++ b/netwerk/cookie/test/browser/browser_cookies_ipv6.js
@@ -0,0 +1,57 @@
+"use strict";
+
+let { HttpServer } = ChromeUtils.importESModule(
+ "resource://testing-common/httpd.sys.mjs"
+);
+
+let gHttpServer = null;
+let ip = "[::1]";
+
+function contentHandler(metadata, response) {
+ response.setStatusLine(metadata.httpVersion, 200, "Ok");
+ response.setHeader("Content-Type", "text/html", false);
+ let body = `
+ <!DOCTYPE HTML>
+ <html>
+ <head>
+ <meta charset='utf-8'>
+ <title>Cookie ipv6 Test</title>
+ </head>
+ <body>
+ </body>
+ </html>`;
+ response.bodyOutputStream.write(body, body.length);
+}
+
+add_task(async _ => {
+ if (!gHttpServer) {
+ gHttpServer = new HttpServer();
+ gHttpServer.registerPathHandler("/content", contentHandler);
+ gHttpServer._start(-1, ip);
+ }
+
+ registerCleanupFunction(() => {
+ gHttpServer.stop(() => {
+ gHttpServer = null;
+ });
+ });
+
+ let serverPort = gHttpServer.identity.primaryPort;
+ let testURL = `http://${ip}:${serverPort}/content`;
+
+ // Let's open our tab.
+ const tab = BrowserTestUtils.addTab(gBrowser, testURL);
+ gBrowser.selectedTab = tab;
+
+ const browser = gBrowser.getBrowserForTab(tab);
+ await BrowserTestUtils.browserLoaded(browser);
+
+ // Test if we can set and get document.cookie successfully.
+ await SpecialPowers.spawn(browser, [], () => {
+ content.document.cookie = "foo=bar";
+ is(content.document.cookie, "foo=bar");
+ });
+
+ // Let's close the tab.
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/netwerk/cookie/test/browser/browser_domCache.js b/netwerk/cookie/test/browser/browser_domCache.js
new file mode 100644
index 0000000000..5f1aa84d83
--- /dev/null
+++ b/netwerk/cookie/test/browser/browser_domCache.js
@@ -0,0 +1,25 @@
+"use strict";
+
+CookiePolicyHelper.runTest("DOM Cache", {
+ cookieJarAccessAllowed: async w => {
+ await w.caches.open("wow").then(
+ _ => {
+ ok(true, "DOM Cache can be used!");
+ },
+ _ => {
+ ok(false, "DOM Cache can be used!");
+ }
+ );
+ },
+
+ cookieJarAccessDenied: async w => {
+ await w.caches.open("wow").then(
+ _ => {
+ ok(false, "DOM Cache cannot be used!");
+ },
+ _ => {
+ ok(true, "DOM Cache cannot be used!");
+ }
+ );
+ },
+});
diff --git a/netwerk/cookie/test/browser/browser_indexedDB.js b/netwerk/cookie/test/browser/browser_indexedDB.js
new file mode 100644
index 0000000000..7f417077eb
--- /dev/null
+++ b/netwerk/cookie/test/browser/browser_indexedDB.js
@@ -0,0 +1,84 @@
+"use strict";
+
+CookiePolicyHelper.runTest("IndexedDB", {
+ cookieJarAccessAllowed: async w => {
+ w.indexedDB.open("test", "1");
+ ok(true, "IDB should be allowed");
+ },
+
+ cookieJarAccessDenied: async w => {
+ try {
+ w.indexedDB.open("test", "1");
+ ok(false, "IDB should be blocked");
+ } catch (e) {
+ ok(true, "IDB should be blocked");
+ is(e.name, "SecurityError", "We want a security error message.");
+ }
+ },
+});
+
+CookiePolicyHelper.runTest("IndexedDB in workers", {
+ cookieJarAccessAllowed: async w => {
+ function nonBlockCode() {
+ indexedDB.open("test", "1");
+ postMessage(true);
+ }
+
+ let blob = new w.Blob([nonBlockCode.toString() + "; nonBlockCode();"]);
+ ok(blob, "Blob has been created");
+
+ let blobURL = w.URL.createObjectURL(blob);
+ ok(blobURL, "Blob URL has been created");
+
+ let worker = new w.Worker(blobURL);
+ ok(worker, "Worker has been created");
+
+ await new w.Promise((resolve, reject) => {
+ worker.onmessage = function (e) {
+ if (e.data) {
+ resolve();
+ } else {
+ reject();
+ }
+ };
+
+ worker.onerror = function (e) {
+ reject();
+ };
+ });
+ },
+
+ cookieJarAccessDenied: async w => {
+ function blockCode() {
+ try {
+ indexedDB.open("test", "1");
+ postMessage(false);
+ } catch (e) {
+ postMessage(e.name == "SecurityError");
+ }
+ }
+
+ let blob = new w.Blob([blockCode.toString() + "; blockCode();"]);
+ ok(blob, "Blob has been created");
+
+ let blobURL = w.URL.createObjectURL(blob);
+ ok(blobURL, "Blob URL has been created");
+
+ let worker = new w.Worker(blobURL);
+ ok(worker, "Worker has been created");
+
+ await new w.Promise((resolve, reject) => {
+ worker.onmessage = function (e) {
+ if (e.data) {
+ resolve();
+ } else {
+ reject();
+ }
+ };
+
+ worker.onerror = function (e) {
+ reject();
+ };
+ });
+ },
+});
diff --git a/netwerk/cookie/test/browser/browser_originattributes.js b/netwerk/cookie/test/browser/browser_originattributes.js
new file mode 100644
index 0000000000..fab7e67b2e
--- /dev/null
+++ b/netwerk/cookie/test/browser/browser_originattributes.js
@@ -0,0 +1,121 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+const USER_CONTEXTS = ["default", "personal", "work"];
+
+const COOKIE_NAMES = ["cookie0", "cookie1", "cookie2"];
+
+const TEST_URL =
+ "http://example.com/browser/netwerk/cookie/test/browser/file_empty.html";
+
+// opens `uri' in a new tab with the provided userContextId and focuses it.
+// returns the newly opened tab
+async function openTabInUserContext(uri, userContextId) {
+ // open the tab in the correct userContextId
+ let tab = BrowserTestUtils.addTab(gBrowser, uri, { userContextId });
+
+ // select tab and make sure its browser is focused
+ gBrowser.selectedTab = tab;
+ tab.ownerGlobal.focus();
+
+ let browser = gBrowser.getBrowserForTab(tab);
+ // wait for tab load
+ await BrowserTestUtils.browserLoaded(browser);
+
+ return { tab, browser };
+}
+
+add_setup(async function () {
+ // make sure userContext is enabled.
+ await new Promise(resolve => {
+ SpecialPowers.pushPrefEnv(
+ { set: [["privacy.userContext.enabled", true]] },
+ resolve
+ );
+ });
+});
+
+add_task(async function test() {
+ // load the page in 3 different contexts and set a cookie
+ // which should only be visible in that context
+ for (let userContextId of Object.keys(USER_CONTEXTS)) {
+ // open our tab in the given user context
+ let { tab, browser } = await openTabInUserContext(TEST_URL, userContextId);
+
+ await SpecialPowers.spawn(
+ browser,
+ [{ names: COOKIE_NAMES, value: USER_CONTEXTS[userContextId] }],
+ function (opts) {
+ for (let name of opts.names) {
+ content.document.cookie = name + "=" + opts.value;
+ }
+ }
+ );
+
+ // remove the tab
+ gBrowser.removeTab(tab);
+ }
+
+ let expectedValues = USER_CONTEXTS.slice(0);
+ await checkCookies(expectedValues, "before removal");
+
+ // remove cookies that belongs to user context id #1
+ Services.cookies.removeCookiesWithOriginAttributes(
+ JSON.stringify({ userContextId: 1 })
+ );
+
+ expectedValues[1] = undefined;
+ await checkCookies(expectedValues, "after removal");
+});
+
+async function checkCookies(expectedValues, time) {
+ for (let userContextId of Object.keys(expectedValues)) {
+ let cookiesFromTitle = await getCookiesFromJS(userContextId);
+ let cookiesFromManager = getCookiesFromManager(userContextId);
+
+ let expectedValue = expectedValues[userContextId];
+ for (let name of COOKIE_NAMES) {
+ is(
+ cookiesFromTitle[name],
+ expectedValue,
+ `User context ${userContextId}: ${name} should be correct from title ${time}`
+ );
+ is(
+ cookiesFromManager[name],
+ expectedValue,
+ `User context ${userContextId}: ${name} should be correct from manager ${time}`
+ );
+ }
+ }
+}
+
+function getCookiesFromManager(userContextId) {
+ let cookies = {};
+ let allCookies = Services.cookies.getCookiesWithOriginAttributes(
+ JSON.stringify({ userContextId })
+ );
+ for (let cookie of allCookies) {
+ cookies[cookie.name] = cookie.value;
+ }
+ return cookies;
+}
+
+async function getCookiesFromJS(userContextId) {
+ let { tab, browser } = await openTabInUserContext(TEST_URL, userContextId);
+
+ // get the cookies
+ let cookieString = await SpecialPowers.spawn(browser, [], function () {
+ return content.document.cookie;
+ });
+
+ // check each item in the title and validate it meets expectatations
+ let cookies = {};
+ for (let cookie of cookieString.split(";")) {
+ let [name, value] = cookie.trim().split("=");
+ cookies[name] = value;
+ }
+
+ gBrowser.removeTab(tab);
+ return cookies;
+}
diff --git a/netwerk/cookie/test/browser/browser_oversize.js b/netwerk/cookie/test/browser/browser_oversize.js
new file mode 100644
index 0000000000..f6e1f8a70b
--- /dev/null
+++ b/netwerk/cookie/test/browser/browser_oversize.js
@@ -0,0 +1,96 @@
+"use strict";
+
+const OVERSIZE_DOMAIN = "http://example.com/";
+const OVERSIZE_PATH = "browser/netwerk/cookie/test/browser/";
+const OVERSIZE_TOP_PAGE = OVERSIZE_DOMAIN + OVERSIZE_PATH + "oversize.sjs";
+
+add_task(async _ => {
+ const expected = [];
+
+ const consoleListener = {
+ observe(what) {
+ if (!(what instanceof Ci.nsIConsoleMessage)) {
+ return;
+ }
+
+ info("Console Listener: " + what);
+ for (let i = expected.length - 1; i >= 0; --i) {
+ const e = expected[i];
+
+ if (what.message.includes(e.match)) {
+ ok(true, "Message received: " + e.match);
+ expected.splice(i, 1);
+ e.resolve();
+ }
+ }
+ },
+ };
+
+ Services.console.registerListener(consoleListener);
+
+ registerCleanupFunction(() =>
+ Services.console.unregisterListener(consoleListener)
+ );
+
+ const netPromises = [
+ new Promise(resolve => {
+ expected.push({
+ resolve,
+ match:
+ "Cookie “a” is invalid because its size is too big. Max size is 4096 B.",
+ });
+ }),
+
+ new Promise(resolve => {
+ expected.push({
+ resolve,
+ match:
+ "Cookie “b” is invalid because its path size is too big. Max size is 1024 B.",
+ });
+ }),
+ ];
+
+ // Let's open our tab.
+ const tab = BrowserTestUtils.addTab(gBrowser, OVERSIZE_TOP_PAGE);
+ gBrowser.selectedTab = tab;
+
+ const browser = gBrowser.getBrowserForTab(tab);
+ await BrowserTestUtils.browserLoaded(browser);
+
+ // Let's wait for the first set of console events.
+ await Promise.all(netPromises);
+
+ // the DOM list of events.
+ const domPromises = [
+ new Promise(resolve => {
+ expected.push({
+ resolve,
+ match:
+ "Cookie “d” is invalid because its size is too big. Max size is 4096 B.",
+ });
+ }),
+
+ new Promise(resolve => {
+ expected.push({
+ resolve,
+ match:
+ "Cookie “e” is invalid because its path size is too big. Max size is 1024 B.",
+ });
+ }),
+ ];
+
+ // Let's use document.cookie
+ SpecialPowers.spawn(browser, [], () => {
+ const maxBytesPerCookie = 4096;
+ const maxBytesPerCookiePath = 1024;
+ content.document.cookie = "d=" + Array(maxBytesPerCookie + 1).join("x");
+ content.document.cookie =
+ "e=f; path=/" + Array(maxBytesPerCookiePath + 1).join("x");
+ });
+
+ // Let's wait for the dom events.
+ await Promise.all(domPromises);
+
+ // Let's close the tab.
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/netwerk/cookie/test/browser/browser_partitionedConsole.js b/netwerk/cookie/test/browser/browser_partitionedConsole.js
new file mode 100644
index 0000000000..ec834bfbcf
--- /dev/null
+++ b/netwerk/cookie/test/browser/browser_partitionedConsole.js
@@ -0,0 +1,201 @@
+"use strict";
+
+const DOMAIN = "https://example.com/";
+const PATH = "browser/netwerk/cookie/test/browser/";
+const TOP_PAGE = DOMAIN + PATH + "file_empty.html";
+
+// Run the test with CHIPS disabled, expecting a warning message
+add_task(async _ => {
+ await SpecialPowers.pushPrefEnv({
+ set: [["network.cookie.cookieBehavior.optInPartitioning", false]],
+ });
+
+ const expected = [];
+
+ const consoleListener = {
+ observe(what) {
+ if (!(what instanceof Ci.nsIConsoleMessage)) {
+ return;
+ }
+
+ info("Console Listener: " + what);
+ for (let i = expected.length - 1; i >= 0; --i) {
+ const e = expected[i];
+
+ if (what.message.includes(e.match)) {
+ ok(true, "Message received: " + e.match);
+ expected.splice(i, 1);
+ e.resolve();
+ }
+ }
+ },
+ };
+
+ Services.console.registerListener(consoleListener);
+
+ registerCleanupFunction(() =>
+ Services.console.unregisterListener(consoleListener)
+ );
+
+ const netPromises = [
+ new Promise(resolve => {
+ expected.push({
+ resolve,
+ match:
+ "Cookie “a” will soon be rejected because it is foreign and does not have the “Partitioned“ attribute.",
+ });
+ }),
+ ];
+
+ // Let's open our tab.
+ const tab = BrowserTestUtils.addTab(gBrowser, TOP_PAGE);
+ gBrowser.selectedTab = tab;
+ const browser = gBrowser.getBrowserForTab(tab);
+ await BrowserTestUtils.browserLoaded(browser);
+
+ // Set cookies with cross-site HTTP
+ await SpecialPowers.spawn(browser, [], async function () {
+ await content.fetch(
+ "https://example.org/browser/netwerk/cookie/test/browser/partitioned.sjs",
+ { credentials: "include" }
+ );
+ });
+
+ // Let's wait for the first set of console events.
+ await Promise.all(netPromises);
+
+ // Let's close the tab.
+ BrowserTestUtils.removeTab(tab);
+});
+
+// Run the test with CHIPS enabled, expecting a different warning message
+add_task(async _ => {
+ await SpecialPowers.pushPrefEnv({
+ set: [["network.cookie.cookieBehavior.optInPartitioning", true]],
+ });
+
+ const expected = [];
+
+ const consoleListener = {
+ observe(what) {
+ if (!(what instanceof Ci.nsIConsoleMessage)) {
+ return;
+ }
+
+ info("Console Listener: " + what);
+ for (let i = expected.length - 1; i >= 0; --i) {
+ const e = expected[i];
+
+ if (what.message.includes(e.match)) {
+ ok(true, "Message received: " + e.match);
+ expected.splice(i, 1);
+ e.resolve();
+ }
+ }
+ },
+ };
+
+ Services.console.registerListener(consoleListener);
+
+ registerCleanupFunction(() =>
+ Services.console.unregisterListener(consoleListener)
+ );
+
+ const netPromises = [
+ new Promise(resolve => {
+ expected.push({
+ resolve,
+ match:
+ "Cookie “a” has been rejected because it is foreign and does not have the “Partitioned“ attribute.",
+ });
+ }),
+ ];
+
+ // Let's open our tab.
+ const tab = BrowserTestUtils.addTab(gBrowser, TOP_PAGE);
+ gBrowser.selectedTab = tab;
+ const browser = gBrowser.getBrowserForTab(tab);
+ await BrowserTestUtils.browserLoaded(browser);
+
+ // Set cookies with cross-site HTTP
+ await SpecialPowers.spawn(browser, [], async function () {
+ await content.fetch(
+ "https://example.org/browser/netwerk/cookie/test/browser/partitioned.sjs",
+ { credentials: "include" }
+ );
+ });
+
+ // Let's wait for the first set of console events.
+ await Promise.all(netPromises);
+
+ // Let's close the tab.
+ BrowserTestUtils.removeTab(tab);
+});
+
+// Run the test with CHIPS enabled, ensuring the partitioned cookies require
+// secure context.
+add_task(async function partitionedAttrRequiresSecure() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["network.cookie.cookieBehavior.optInPartitioning", true]],
+ });
+
+ // Clear all cookies before testing.
+ Services.cookies.removeAll();
+
+ const expected = [];
+
+ const consoleListener = {
+ observe(what) {
+ if (!(what instanceof Ci.nsIConsoleMessage)) {
+ return;
+ }
+
+ info("Console Listener: " + what);
+ for (let i = expected.length - 1; i >= 0; --i) {
+ const e = expected[i];
+
+ if (what.message.includes(e.match)) {
+ ok(true, "Message received: " + e.match);
+ expected.splice(i, 1);
+ e.resolve();
+ }
+ }
+ },
+ };
+
+ Services.console.registerListener(consoleListener);
+
+ registerCleanupFunction(() =>
+ Services.console.unregisterListener(consoleListener)
+ );
+
+ const netPromises = [
+ new Promise(resolve => {
+ expected.push({
+ resolve,
+ match:
+ "Cookie “c” has been rejected because it has the “Partitioned” attribute but is missing the “secure” attribute.",
+ });
+ }),
+ ];
+
+ // Let's open our tab.
+ const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TOP_PAGE);
+
+ // Set cookies with cross-site HTTP
+ await SpecialPowers.spawn(tab.linkedBrowser, [], async function () {
+ await content.fetch(
+ "https://example.org/browser/netwerk/cookie/test/browser/partitioned.sjs?nosecure",
+ { credentials: "include" }
+ );
+ });
+
+ // Let's wait for the first set of console events.
+ await Promise.all(netPromises);
+
+ // Ensure no cookie is set.
+ is(Services.cookies.cookies.length, 0, "No cookie is set.");
+
+ // Let's close the tab.
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/netwerk/cookie/test/browser/browser_partitioned_telemetry.js b/netwerk/cookie/test/browser/browser_partitioned_telemetry.js
new file mode 100644
index 0000000000..f89bcdd189
--- /dev/null
+++ b/netwerk/cookie/test/browser/browser_partitioned_telemetry.js
@@ -0,0 +1,134 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+const TEST_URL =
+ "https://example.com/browser/netwerk/cookie/test/browser/file_empty.html";
+
+async function validateTelemetryValues(
+ { setCookies, setForeigns, setPartitioneds, setForeignPartitioneds },
+ message
+) {
+ await Services.fog.testFlushAllChildren();
+ let setCookieTelemetry = Glean.networking.setCookie.testGetValue();
+ is(
+ setCookieTelemetry ?? undefined,
+ setCookies,
+ message + " - all set cookies"
+ );
+ let foreignTelemetry = Glean.networking.setCookieForeign.testGetValue();
+ is(
+ foreignTelemetry?.numerator,
+ setForeigns,
+ message + " - foreign set cookies"
+ );
+ is(
+ foreignTelemetry?.denominator,
+ setCookies,
+ message + " - foreign set cookies denominator"
+ );
+ let partitonedTelemetry =
+ Glean.networking.setCookiePartitioned.testGetValue();
+ is(
+ partitonedTelemetry?.numerator,
+ setPartitioneds,
+ message + " - partitioned set cookies"
+ );
+ is(
+ partitonedTelemetry?.denominator,
+ setCookies,
+ message + " - partitioned set cookies denominator"
+ );
+ let foreignPartitonedTelemetry =
+ Glean.networking.setCookieForeignPartitioned.testGetValue();
+ is(
+ foreignPartitonedTelemetry?.numerator,
+ setForeignPartitioneds,
+ message + " - foreign partitioned set cookies"
+ );
+ is(
+ foreignPartitonedTelemetry?.denominator,
+ setCookies,
+ message + " - foreign partitioned set cookies denominator"
+ );
+}
+
+add_task(async () => {
+ await Services.fog.testFlushAllChildren();
+ Services.fog.testResetFOG();
+ await validateTelemetryValues({}, "initially empty");
+
+ // open a browser window for the test
+ let tab = BrowserTestUtils.addTab(gBrowser, TEST_URL);
+ let browser = gBrowser.getBrowserForTab(tab);
+ await BrowserTestUtils.browserLoaded(browser);
+
+ // Set cookies with Javascript
+ await SpecialPowers.spawn(browser, [], function () {
+ content.document.cookie = "a=1; Partitioned; SameSite=None; Secure";
+ content.document.cookie = "b=2; SameSite=None; Secure";
+ });
+ await validateTelemetryValues(
+ {
+ setCookies: 2,
+ setForeigns: 0,
+ setPartitioneds: 1,
+ setForeignPartitioneds: 0,
+ },
+ "javascript cookie"
+ );
+
+ // Set cookies with HTTP
+ await SpecialPowers.spawn(browser, [], async function () {
+ await content.fetch("partitioned.sjs");
+ });
+ await validateTelemetryValues(
+ {
+ setCookies: 4,
+ setForeigns: 0,
+ setPartitioneds: 2,
+ setForeignPartitioneds: 0,
+ },
+ "same site fetch"
+ );
+
+ // Set cookies with cross-site HTTP
+ await SpecialPowers.spawn(browser, [], async function () {
+ await content.fetch(
+ "https://example.org/browser/netwerk/cookie/test/browser/partitioned.sjs",
+ { credentials: "include" }
+ );
+ });
+ await validateTelemetryValues(
+ {
+ setCookies: 6,
+ setForeigns: 2,
+ setPartitioneds: 3,
+ setForeignPartitioneds: 1,
+ },
+ "foreign fetch"
+ );
+
+ // Set cookies with cross-site HTTP redirect
+ await SpecialPowers.spawn(browser, [], async function () {
+ await content.fetch(
+ encodeURI(
+ "https://example.org/browser/netwerk/cookie/test/browser/partitioned.sjs?redirect=https://example.com/browser/netwerk/cookie/test/browser/partitioned.sjs?nocookie"
+ ),
+ { credentials: "include" }
+ );
+ });
+
+ await validateTelemetryValues(
+ {
+ setCookies: 8,
+ setForeigns: 4,
+ setPartitioneds: 4,
+ setForeignPartitioneds: 2,
+ },
+ "foreign fetch redirect"
+ );
+
+ // remove the tab
+ gBrowser.removeTab(tab);
+});
diff --git a/netwerk/cookie/test/browser/browser_sameSiteConsole.js b/netwerk/cookie/test/browser/browser_sameSiteConsole.js
new file mode 100644
index 0000000000..84527296b2
--- /dev/null
+++ b/netwerk/cookie/test/browser/browser_sameSiteConsole.js
@@ -0,0 +1,133 @@
+"use strict";
+
+const SAMESITE_DOMAIN = "http://example.com/";
+const SAMESITE_PATH = "browser/netwerk/cookie/test/browser/";
+const SAMESITE_TOP_PAGE = SAMESITE_DOMAIN + SAMESITE_PATH + "sameSite.sjs";
+
+add_task(async _ => {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["network.cookie.sameSite.laxByDefault", true],
+ ["network.cookie.sameSite.noneRequiresSecure", true],
+ ],
+ });
+
+ const expected = [];
+
+ const consoleListener = {
+ observe(what) {
+ if (!(what instanceof Ci.nsIConsoleMessage)) {
+ return;
+ }
+
+ info("Console Listener: " + what);
+ for (let i = expected.length - 1; i >= 0; --i) {
+ const e = expected[i];
+
+ if (what.message.includes(e.match)) {
+ ok(true, "Message received: " + e.match);
+ expected.splice(i, 1);
+ e.resolve();
+ }
+ }
+ },
+ };
+
+ Services.console.registerListener(consoleListener);
+
+ registerCleanupFunction(() =>
+ Services.console.unregisterListener(consoleListener)
+ );
+
+ const netPromises = [
+ new Promise(resolve => {
+ expected.push({
+ resolve,
+ match:
+ "Cookie “a” has “SameSite” policy set to “Lax” because it is missing a “SameSite” attribute, and “SameSite=Lax” is the default value for this attribute.",
+ });
+ }),
+
+ new Promise(resolve => {
+ expected.push({
+ resolve,
+ match:
+ "Cookie “b” rejected because it has the “SameSite=None” attribute but is missing the “secure” attribute.",
+ });
+ }),
+
+ new Promise(resolve => {
+ expected.push({
+ resolve,
+ match:
+ "Invalid “SameSite“ value for cookie “c”. The supported values are: “Lax“, “Strict“, “None“.",
+ });
+ }),
+
+ new Promise(resolve => {
+ expected.push({
+ resolve,
+ match:
+ "Cookie “c” has “SameSite” policy set to “Lax” because it is missing a “SameSite” attribute, and “SameSite=Lax” is the default value for this attribute.",
+ });
+ }),
+ ];
+
+ // Let's open our tab.
+ const tab = BrowserTestUtils.addTab(gBrowser, SAMESITE_TOP_PAGE);
+ gBrowser.selectedTab = tab;
+
+ const browser = gBrowser.getBrowserForTab(tab);
+ await BrowserTestUtils.browserLoaded(browser);
+
+ // Let's wait for the first set of console events.
+ await Promise.all(netPromises);
+
+ // the DOM list of events.
+ const domPromises = [
+ new Promise(resolve => {
+ expected.push({
+ resolve,
+ match:
+ "Cookie “d” has “SameSite” policy set to “Lax” because it is missing a “SameSite” attribute, and “SameSite=Lax” is the default value for this attribute.",
+ });
+ }),
+
+ new Promise(resolve => {
+ expected.push({
+ resolve,
+ match:
+ "Cookie “e” rejected because it has the “SameSite=None” attribute but is missing the “secure” attribute.",
+ });
+ }),
+
+ new Promise(resolve => {
+ expected.push({
+ resolve,
+ match:
+ "Invalid “SameSite“ value for cookie “f”. The supported values are: “Lax“, “Strict“, “None“.",
+ });
+ }),
+
+ new Promise(resolve => {
+ expected.push({
+ resolve,
+ match:
+ "Cookie “f” has “SameSite” policy set to “Lax” because it is missing a “SameSite” attribute, and “SameSite=Lax” is the default value for this attribute.",
+ });
+ }),
+ ];
+
+ // Let's use document.cookie
+ SpecialPowers.spawn(browser, [], () => {
+ content.document.cookie = "d=4";
+ content.document.cookie = "e=5; sameSite=none";
+ content.document.cookie = "f=6; sameSite=batmat";
+ });
+
+ // Let's wait for the dom events.
+ await Promise.all(domPromises);
+
+ // Let's close the tab.
+ BrowserTestUtils.removeTab(tab);
+});
diff --git a/netwerk/cookie/test/browser/browser_serviceWorker.js b/netwerk/cookie/test/browser/browser_serviceWorker.js
new file mode 100644
index 0000000000..2a5c963535
--- /dev/null
+++ b/netwerk/cookie/test/browser/browser_serviceWorker.js
@@ -0,0 +1,45 @@
+"use strict";
+
+CookiePolicyHelper.runTest("ServiceWorker", {
+ prefs: [
+ ["dom.serviceWorkers.exemptFromPerDomainMax", true],
+ ["dom.ipc.processCount", 1],
+ ["dom.serviceWorkers.enabled", true],
+ ["dom.serviceWorkers.testing.enabled", true],
+ ],
+
+ cookieJarAccessAllowed: async w => {
+ await w.navigator.serviceWorker
+ .register("file_empty.js")
+ .then(
+ reg => {
+ ok(true, "ServiceWorker can be used!");
+ return reg;
+ },
+ _ => {
+ ok(false, "ServiceWorker cannot be used! " + _);
+ }
+ )
+ .then(
+ reg => reg.unregister(),
+ _ => {
+ ok(false, "unregister failed");
+ }
+ )
+ .catch(e => ok(false, "Promise rejected: " + e));
+ },
+
+ cookieJarAccessDenied: async w => {
+ await w.navigator.serviceWorker
+ .register("file_empty.js")
+ .then(
+ _ => {
+ ok(false, "ServiceWorker cannot be used!");
+ },
+ _ => {
+ ok(true, "ServiceWorker cannot be used!");
+ }
+ )
+ .catch(e => ok(false, "Promise rejected: " + e));
+ },
+});
diff --git a/netwerk/cookie/test/browser/browser_sharedWorker.js b/netwerk/cookie/test/browser/browser_sharedWorker.js
new file mode 100644
index 0000000000..88a8b3f0e7
--- /dev/null
+++ b/netwerk/cookie/test/browser/browser_sharedWorker.js
@@ -0,0 +1,18 @@
+"use strict";
+
+CookiePolicyHelper.runTest("SharedWorker", {
+ cookieJarAccessAllowed: async w => {
+ new w.SharedWorker("a.js", "foo");
+ ok(true, "SharedWorker is allowed");
+ },
+
+ cookieJarAccessDenied: async w => {
+ try {
+ new w.SharedWorker("a.js", "foo");
+ ok(false, "SharedWorker cannot be used!");
+ } catch (e) {
+ ok(true, "SharedWorker cannot be used!");
+ is(e.name, "SecurityError", "We want a security error message.");
+ }
+ },
+});
diff --git a/netwerk/cookie/test/browser/browser_storage.js b/netwerk/cookie/test/browser/browser_storage.js
new file mode 100644
index 0000000000..1e37b1a367
--- /dev/null
+++ b/netwerk/cookie/test/browser/browser_storage.js
@@ -0,0 +1,43 @@
+"use strict";
+
+CookiePolicyHelper.runTest("SessionStorage", {
+ cookieJarAccessAllowed: async w => {
+ try {
+ w.sessionStorage.foo = 42;
+ ok(true, "SessionStorage works");
+ } catch (e) {
+ ok(false, "SessionStorage works");
+ }
+ },
+
+ cookieJarAccessDenied: async w => {
+ try {
+ w.sessionStorage.foo = 42;
+ ok(false, "SessionStorage doesn't work");
+ } catch (e) {
+ ok(true, "SessionStorage doesn't work");
+ is(e.name, "SecurityError", "We want a security error message.");
+ }
+ },
+});
+
+CookiePolicyHelper.runTest("LocalStorage", {
+ cookieJarAccessAllowed: async w => {
+ try {
+ w.localStorage.foo = 42;
+ ok(true, "LocalStorage works");
+ } catch (e) {
+ ok(false, "LocalStorage works");
+ }
+ },
+
+ cookieJarAccessDenied: async w => {
+ try {
+ w.localStorage.foo = 42;
+ ok(false, "LocalStorage doesn't work");
+ } catch (e) {
+ ok(true, "LocalStorage doesn't work");
+ is(e.name, "SecurityError", "We want a security error message.");
+ }
+ },
+});
diff --git a/netwerk/cookie/test/browser/file_empty.html b/netwerk/cookie/test/browser/file_empty.html
new file mode 100644
index 0000000000..78b64149c4
--- /dev/null
+++ b/netwerk/cookie/test/browser/file_empty.html
@@ -0,0 +1,2 @@
+<html><body>
+</body></html>
diff --git a/netwerk/cookie/test/browser/file_empty.js b/netwerk/cookie/test/browser/file_empty.js
new file mode 100644
index 0000000000..3053583c76
--- /dev/null
+++ b/netwerk/cookie/test/browser/file_empty.js
@@ -0,0 +1 @@
+/* nothing here */
diff --git a/netwerk/cookie/test/browser/head.js b/netwerk/cookie/test/browser/head.js
new file mode 100644
index 0000000000..609ad683db
--- /dev/null
+++ b/netwerk/cookie/test/browser/head.js
@@ -0,0 +1,201 @@
+const { PermissionTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/PermissionTestUtils.sys.mjs"
+);
+
+const BEHAVIOR_ACCEPT = Ci.nsICookieService.BEHAVIOR_ACCEPT;
+const BEHAVIOR_REJECT = Ci.nsICookieService.BEHAVIOR_REJECT;
+
+const PERM_DEFAULT = Ci.nsICookiePermission.ACCESS_DEFAULT;
+const PERM_ALLOW = Ci.nsICookiePermission.ACCESS_ALLOW;
+const PERM_DENY = Ci.nsICookiePermission.ACCESS_DENY;
+
+const TEST_DOMAIN = "https://example.com/";
+const TEST_PATH = "browser/netwerk/cookie/test/browser/";
+const TEST_TOP_PAGE = TEST_DOMAIN + TEST_PATH + "file_empty.html";
+
+// Helper to eval() provided cookieJarAccessAllowed and cookieJarAccessDenied
+// toString()ed optionally async function in freshly created tabs with
+// BEHAVIOR_ACCEPT and BEHAVIOR_REJECT configured, respectively, in a number of
+// permutations. This includes verifying that changing the permission while the
+// page is open still results in the state of the permission when the
+// document/global was created still applying. Code will execute in the
+// ContentTask.spawn frame-script context, use content to access the underlying
+// page.
+this.CookiePolicyHelper = {
+ runTest(testName, config) {
+ // Testing allowed to blocked by cookie behavior
+ this._createTest(
+ testName,
+ config.cookieJarAccessAllowed,
+ config.cookieJarAccessDenied,
+ config.prefs,
+ {
+ fromBehavior: BEHAVIOR_ACCEPT,
+ toBehavior: BEHAVIOR_REJECT,
+ fromPermission: PERM_DEFAULT,
+ toPermission: PERM_DEFAULT,
+ }
+ );
+
+ // Testing blocked to allowed by cookie behavior
+ this._createTest(
+ testName,
+ config.cookieJarAccessDenied,
+ config.cookieJarAccessAllowed,
+ config.prefs,
+ {
+ fromBehavior: BEHAVIOR_REJECT,
+ toBehavior: BEHAVIOR_ACCEPT,
+ fromPermission: PERM_DEFAULT,
+ toPermission: PERM_DEFAULT,
+ }
+ );
+
+ // Testing allowed to blocked by cookie permission
+ this._createTest(
+ testName,
+ config.cookieJarAccessAllowed,
+ config.cookieJarAccessDenied,
+ config.prefs,
+ {
+ fromBehavior: BEHAVIOR_REJECT,
+ toBehavior: BEHAVIOR_REJECT,
+ fromPermission: PERM_ALLOW,
+ toPermission: PERM_DEFAULT,
+ }
+ );
+
+ // Testing blocked to allowed by cookie permission
+ this._createTest(
+ testName,
+ config.cookieJarAccessDenied,
+ config.cookieJarAccessAllowed,
+ config.prefs,
+ {
+ fromBehavior: BEHAVIOR_ACCEPT,
+ toBehavior: BEHAVIOR_ACCEPT,
+ fromPermission: PERM_DENY,
+ toPermission: PERM_DEFAULT,
+ }
+ );
+ },
+
+ _createTest(testName, goodCb, badCb, prefs, config) {
+ add_task(async _ => {
+ info("Starting " + testName + ": " + config.toSource());
+
+ await SpecialPowers.flushPrefEnv();
+
+ if (prefs) {
+ await SpecialPowers.pushPrefEnv({ set: prefs });
+ }
+
+ // Let's set the first cookie pref.
+ PermissionTestUtils.add(TEST_DOMAIN, "cookie", config.fromPermission);
+ await SpecialPowers.pushPrefEnv({
+ set: [["network.cookie.cookieBehavior", config.fromBehavior]],
+ });
+
+ // Let's open a tab and load content.
+ let tab = BrowserTestUtils.addTab(gBrowser, TEST_TOP_PAGE);
+ gBrowser.selectedTab = tab;
+
+ let browser = gBrowser.getBrowserForTab(tab);
+ await BrowserTestUtils.browserLoaded(browser);
+
+ // Let's create an iframe.
+ await SpecialPowers.spawn(
+ browser,
+ [{ url: TEST_TOP_PAGE }],
+ async obj => {
+ return new content.Promise(resolve => {
+ let ifr = content.document.createElement("iframe");
+ ifr.setAttribute("id", "iframe");
+ ifr.src = obj.url;
+ ifr.onload = () => resolve();
+ content.document.body.appendChild(ifr);
+ });
+ }
+ );
+
+ // Let's exec the "good" callback.
+ info(
+ "Executing the test after setting the cookie behavior to " +
+ config.fromBehavior +
+ " and permission to " +
+ config.fromPermission
+ );
+ await SpecialPowers.spawn(
+ browser,
+ [{ callback: goodCb.toString() }],
+ async obj => {
+ let runnableStr = `(() => {return (${obj.callback});})();`;
+ let runnable = eval(runnableStr); // eslint-disable-line no-eval
+ await runnable(content);
+
+ let ifr = content.document.getElementById("iframe");
+ await runnable(ifr.contentWindow);
+ }
+ );
+
+ // Now, let's change the cookie settings
+ PermissionTestUtils.add(TEST_DOMAIN, "cookie", config.toPermission);
+ await SpecialPowers.pushPrefEnv({
+ set: [["network.cookie.cookieBehavior", config.toBehavior]],
+ });
+
+ // We still want the good callback to succeed.
+ info(
+ "Executing the test after setting the cookie behavior to " +
+ config.toBehavior +
+ " and permission to " +
+ config.toPermission
+ );
+ await SpecialPowers.spawn(
+ browser,
+ [{ callback: goodCb.toString() }],
+ async obj => {
+ let runnableStr = `(() => {return (${obj.callback});})();`;
+ let runnable = eval(runnableStr); // eslint-disable-line no-eval
+ await runnable(content);
+
+ let ifr = content.document.getElementById("iframe");
+ await runnable(ifr.contentWindow);
+ }
+ );
+
+ // Let's close the tab.
+ BrowserTestUtils.removeTab(tab);
+
+ // Let's open a new tab and load content again.
+ tab = BrowserTestUtils.addTab(gBrowser, TEST_TOP_PAGE);
+ gBrowser.selectedTab = tab;
+
+ browser = gBrowser.getBrowserForTab(tab);
+ await BrowserTestUtils.browserLoaded(browser);
+
+ // Let's exec the "bad" callback.
+ info("Executing the test in a new tab");
+ await SpecialPowers.spawn(
+ browser,
+ [{ callback: badCb.toString() }],
+ async obj => {
+ let runnableStr = `(() => {return (${obj.callback});})();`;
+ let runnable = eval(runnableStr); // eslint-disable-line no-eval
+ await runnable(content);
+ }
+ );
+
+ // Let's close the tab.
+ BrowserTestUtils.removeTab(tab);
+
+ // Cleanup.
+ await new Promise(resolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_ALL,
+ resolve
+ );
+ });
+ });
+ },
+};
diff --git a/netwerk/cookie/test/browser/oversize.sjs b/netwerk/cookie/test/browser/oversize.sjs
new file mode 100644
index 0000000000..dfe2f31645
--- /dev/null
+++ b/netwerk/cookie/test/browser/oversize.sjs
@@ -0,0 +1,17 @@
+function handleRequest(aRequest, aResponse) {
+ aResponse.setStatusLine(aRequest.httpVersion, 200);
+
+ const maxBytesPerCookie = 4096;
+ const maxBytesPerCookiePath = 1024;
+
+ aResponse.setHeader(
+ "Set-Cookie",
+ "a=" + Array(maxBytesPerCookie + 1).join("x"),
+ true
+ );
+ aResponse.setHeader(
+ "Set-Cookie",
+ "b=c; path=/" + Array(maxBytesPerCookiePath + 1).join("x"),
+ true
+ );
+}
diff --git a/netwerk/cookie/test/browser/partitioned.sjs b/netwerk/cookie/test/browser/partitioned.sjs
new file mode 100644
index 0000000000..5649b88f2f
--- /dev/null
+++ b/netwerk/cookie/test/browser/partitioned.sjs
@@ -0,0 +1,32 @@
+function handleRequest(aRequest, aResponse) {
+ if (aRequest.hasHeader("Origin")) {
+ let origin = aRequest.getHeader("Origin");
+ aResponse.setHeader("Access-Control-Allow-Origin", origin);
+ aResponse.setHeader("Access-Control-Allow-Credentials", "true");
+ }
+
+ var params = new URLSearchParams(aRequest.queryString);
+ if (params.has("redirect")) {
+ aResponse.setHeader("Location", params.get("redirect"));
+ aResponse.setStatusLine(aRequest.httpVersion, 302);
+ } else {
+ aResponse.setStatusLine(aRequest.httpVersion, 200);
+ }
+
+ if (params.has("nocookie")) {
+ return;
+ }
+
+ if (params.has("nosecure")) {
+ aResponse.setHeader("Set-Cookie", "c=3; Partitioned;", true);
+
+ return;
+ }
+
+ aResponse.setHeader("Set-Cookie", "a=1; SameSite=None; Secure", true);
+ aResponse.setHeader(
+ "Set-Cookie",
+ "b=2; Partitioned; SameSite=None; Secure",
+ true
+ );
+}
diff --git a/netwerk/cookie/test/browser/sameSite.sjs b/netwerk/cookie/test/browser/sameSite.sjs
new file mode 100644
index 0000000000..a19624d2cb
--- /dev/null
+++ b/netwerk/cookie/test/browser/sameSite.sjs
@@ -0,0 +1,7 @@
+function handleRequest(aRequest, aResponse) {
+ aResponse.setStatusLine(aRequest.httpVersion, 200);
+
+ aResponse.setHeader("Set-Cookie", "a=1", true);
+ aResponse.setHeader("Set-Cookie", "b=2; sameSite=none", true);
+ aResponse.setHeader("Set-Cookie", "c=3; sameSite=batman", true);
+}
diff --git a/netwerk/cookie/test/browser/server.sjs b/netwerk/cookie/test/browser/server.sjs
new file mode 100644
index 0000000000..86835914bb
--- /dev/null
+++ b/netwerk/cookie/test/browser/server.sjs
@@ -0,0 +1,9 @@
+function handleRequest(aRequest, aResponse) {
+ aResponse.setStatusLine(aRequest.httpVersion, 200);
+ if (aRequest.hasHeader("Cookie")) {
+ aResponse.write("cookie-present");
+ } else {
+ aResponse.setHeader("Set-Cookie", "foopy=1");
+ aResponse.write("cookie-not-present");
+ }
+}