summaryrefslogtreecommitdiffstats
path: root/netwerk/cookie/test/browser
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /netwerk/cookie/test/browser
parentInitial commit. (diff)
downloadthunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz
thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'netwerk/cookie/test/browser')
-rw-r--r--netwerk/cookie/test/browser/browser.ini21
-rw-r--r--netwerk/cookie/test/browser/browser_broadcastChannel.js80
-rw-r--r--netwerk/cookie/test/browser/browser_cookie_insecure_overwrites_secure.js116
-rw-r--r--netwerk/cookie/test/browser/browser_cookies.js53
-rw-r--r--netwerk/cookie/test/browser/browser_cookies_ipv6.js55
-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_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/sameSite.sjs7
-rw-r--r--netwerk/cookie/test/browser/server.sjs9
19 files changed, 1127 insertions, 0 deletions
diff --git a/netwerk/cookie/test/browser/browser.ini b/netwerk/cookie/test/browser/browser.ini
new file mode 100644
index 0000000000..2f81a7f173
--- /dev/null
+++ b/netwerk/cookie/test/browser/browser.ini
@@ -0,0 +1,21 @@
+[DEFAULT]
+support-files =
+ file_empty.html
+ file_empty.js
+ head.js
+
+[browser_broadcastChannel.js]
+[browser_cookies.js]
+support-files = server.sjs
+[browser_domCache.js]
+[browser_indexedDB.js]
+[browser_originattributes.js]
+[browser_storage.js]
+[browser_serviceWorker.js]
+[browser_sharedWorker.js]
+[browser_sameSiteConsole.js]
+support-files = sameSite.sjs
+[browser_oversize.js]
+support-files = oversize.sjs
+[browser_cookie_insecure_overwrites_secure.js]
+[browser_cookies_ipv6.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..9d365d441a
--- /dev/null
+++ b/netwerk/cookie/test/browser/browser_cookie_insecure_overwrites_secure.js
@@ -0,0 +1,116 @@
+/* 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.import("resource://testing-common/httpd.js");
+
+const urlPath = "/browser/netwerk/cookie/test/browser/file_empty.html";
+const baseDomain = "example.com";
+
+// eslint doesn't like http
+/* eslint-disable */
+const URL_INSECURE_COM = "http://" + baseDomain + urlPath;
+/* eslint-enable */
+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(() => {
+ info("Cleaning up the test");
+});
+
+async function setup() {
+ 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_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..044c3ce577
--- /dev/null
+++ b/netwerk/cookie/test/browser/browser_cookies_ipv6.js
@@ -0,0 +1,55 @@
+"use strict";
+
+let { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js");
+
+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_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/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");
+ }
+}