diff options
Diffstat (limited to 'netwerk/cookie/test/browser')
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"); + } +} |