summaryrefslogtreecommitdiffstats
path: root/toolkit/components/cleardata/tests/browser/browser_sessionStorage.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/cleardata/tests/browser/browser_sessionStorage.js')
-rw-r--r--toolkit/components/cleardata/tests/browser/browser_sessionStorage.js235
1 files changed, 235 insertions, 0 deletions
diff --git a/toolkit/components/cleardata/tests/browser/browser_sessionStorage.js b/toolkit/components/cleardata/tests/browser/browser_sessionStorage.js
new file mode 100644
index 0000000000..013ae0fa92
--- /dev/null
+++ b/toolkit/components/cleardata/tests/browser/browser_sessionStorage.js
@@ -0,0 +1,235 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const BASE_DOMAIN_A = "example.com";
+const ORIGIN_A = `https://${BASE_DOMAIN_A}`;
+const ORIGIN_A_HTTP = `http://${BASE_DOMAIN_A}`;
+const ORIGIN_A_SUB = `https://test1.${BASE_DOMAIN_A}`;
+
+const BASE_DOMAIN_B = "example.org";
+const ORIGIN_B = `https://${BASE_DOMAIN_B}`;
+const ORIGIN_B_HTTP = `http://${BASE_DOMAIN_B}`;
+const ORIGIN_B_SUB = `https://test1.${BASE_DOMAIN_B}`;
+
+const TEST_ROOT_DIR = getRootDirectory(gTestPath);
+
+// Session storage is only valid for the lifetime of a tab, so we need to keep
+// tabs open for the duration of a test.
+let originToTabs = {};
+
+function getTestURLForOrigin(origin) {
+ return TEST_ROOT_DIR.replace("chrome://mochitests/content", origin);
+}
+
+function getTestEntryName(origin, partitioned) {
+ return `${origin}${partitioned ? "_partitioned" : ""}`;
+}
+
+async function testHasEntry(originFirstParty, isSet, originThirdParty) {
+ let tabs = originToTabs[originFirstParty];
+
+ for (let tab of tabs) {
+ // For the partition test we inspect the sessionStorage of the iframe.
+ let browsingContext = originThirdParty
+ ? tab.linkedBrowser.browsingContext.children[0]
+ : tab.linkedBrowser.browsingContext;
+ let actualSet = await SpecialPowers.spawn(
+ browsingContext,
+ [
+ getTestEntryName(
+ originThirdParty || originFirstParty,
+ !!originThirdParty
+ ),
+ ],
+ key => {
+ return !!content.sessionStorage.getItem(key);
+ }
+ );
+
+ let msg = `${originFirstParty}${isSet ? " " : " not "}set`;
+ if (originThirdParty) {
+ msg = "Partitioned under " + msg;
+ }
+
+ is(actualSet, isSet, msg);
+ }
+}
+
+/**
+ * Creates tabs and sets sessionStorage entries in first party and third party
+ * context.
+ * @returns {Promise} - Promise which resolves once all tabs are initialized,
+ * {@link originToTabs} is populated and (sub-)resources have loaded.
+ */
+function addTestTabs() {
+ let promises = [
+ [ORIGIN_A, ORIGIN_B],
+ [ORIGIN_A_SUB, ORIGIN_B_SUB],
+ [ORIGIN_A_HTTP, ORIGIN_B_HTTP],
+ [ORIGIN_B, ORIGIN_A],
+ [ORIGIN_B_SUB, ORIGIN_A_SUB],
+ [ORIGIN_B_HTTP, ORIGIN_A_HTTP],
+ ].map(async ([firstParty, thirdParty]) => {
+ info("Creating new tab for " + firstParty);
+ let tab = BrowserTestUtils.addTab(gBrowser, firstParty);
+ await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
+
+ info("Creating iframe for " + thirdParty);
+ await SpecialPowers.spawn(
+ tab.linkedBrowser,
+ [getTestEntryName(firstParty, false), thirdParty],
+ async (storageKey, url) => {
+ // Set unpartitioned sessionStorage for firstParty.
+ content.sessionStorage.setItem(storageKey, "foo");
+
+ let iframe = content.document.createElement("iframe");
+ iframe.src = url;
+
+ let loadPromise = ContentTaskUtils.waitForEvent(iframe, "load", false);
+ content.document.body.appendChild(iframe);
+ await loadPromise;
+ }
+ );
+
+ await SpecialPowers.spawn(
+ tab.linkedBrowser.browsingContext.children[0],
+ [getTestEntryName(thirdParty, true)],
+ async storageKey => {
+ // Set sessionStorage in partitioned third-party iframe.
+ content.sessionStorage.setItem(storageKey, "foo");
+ }
+ );
+
+ let tabs = originToTabs[firstParty];
+ if (!tabs) {
+ tabs = [];
+ originToTabs[firstParty] = tabs;
+ }
+ tabs.push(tab);
+ });
+
+ return Promise.all(promises);
+}
+
+function cleanup() {
+ Object.values(originToTabs).flat().forEach(BrowserTestUtils.removeTab);
+ originToTabs = {};
+ Services.obs.notifyObservers(null, "browser:purge-sessionStorage");
+}
+
+add_setup(async function () {
+ await SpecialPowers.pushPrefEnv({
+ set: [["network.cookie.cookieBehavior", 5]],
+ });
+ cleanup();
+});
+
+add_task(async function test_deleteByBaseDomain() {
+ await addTestTabs();
+
+ info("Clearing sessionStorage for base domain A " + BASE_DOMAIN_A);
+ await new Promise(resolve => {
+ Services.clearData.deleteDataFromBaseDomain(
+ BASE_DOMAIN_A,
+ false,
+ Ci.nsIClearDataService.CLEAR_DOM_QUOTA,
+ resolve
+ );
+ });
+
+ info("All entries for A should have been cleared.");
+ await testHasEntry(ORIGIN_A, false);
+ await testHasEntry(ORIGIN_A_SUB, false);
+ await testHasEntry(ORIGIN_A_HTTP, false);
+
+ info("Entries for B should still exist.");
+ await testHasEntry(ORIGIN_B, true);
+ await testHasEntry(ORIGIN_B_SUB, true);
+ await testHasEntry(ORIGIN_B_HTTP, true);
+
+ info("All partitioned entries for B under A should have been cleared.");
+ await testHasEntry(ORIGIN_A, false, ORIGIN_B);
+ await testHasEntry(ORIGIN_A_SUB, false, ORIGIN_B_SUB);
+ await testHasEntry(ORIGIN_A_HTTP, false, ORIGIN_B_HTTP);
+
+ info("All partitioned entries of A under B should have been cleared.");
+ await testHasEntry(ORIGIN_B, false, ORIGIN_A);
+ await testHasEntry(ORIGIN_B_SUB, false, ORIGIN_A_SUB);
+ await testHasEntry(ORIGIN_B_HTTP, false, ORIGIN_A_HTTP);
+
+ cleanup();
+});
+
+add_task(async function test_deleteAll() {
+ await addTestTabs();
+
+ info("Clearing sessionStorage for base domain A " + BASE_DOMAIN_A);
+ await new Promise(resolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_DOM_QUOTA,
+ resolve
+ );
+ });
+
+ info("All entries should have been cleared.");
+ await testHasEntry(ORIGIN_A, false);
+ await testHasEntry(ORIGIN_A_SUB, false);
+ await testHasEntry(ORIGIN_A_HTTP, false);
+ await testHasEntry(ORIGIN_B, false);
+ await testHasEntry(ORIGIN_B_SUB, false);
+ await testHasEntry(ORIGIN_B_HTTP, false);
+
+ info("All partitioned entries should have been cleared.");
+ await testHasEntry(ORIGIN_A, false, ORIGIN_B);
+ await testHasEntry(ORIGIN_A_SUB, false, ORIGIN_B_SUB);
+ await testHasEntry(ORIGIN_A_HTTP, false, ORIGIN_B_HTTP);
+ await testHasEntry(ORIGIN_B, false, ORIGIN_A);
+ await testHasEntry(ORIGIN_B_SUB, false, ORIGIN_A_SUB);
+ await testHasEntry(ORIGIN_B_HTTP, false, ORIGIN_A_HTTP);
+
+ cleanup();
+});
+
+add_task(async function test_deleteFromPrincipal() {
+ await addTestTabs();
+
+ info("Clearing sessionStorage for partitioned principal A " + BASE_DOMAIN_A);
+
+ let principalA = Services.scriptSecurityManager.createContentPrincipal(
+ Services.io.newURI(ORIGIN_A),
+ { partitionKey: `(https,${BASE_DOMAIN_B})` }
+ );
+
+ info("principal: " + principalA.origin);
+ info("principal partitionKey " + principalA.originAttributes.partitionKey);
+ await new Promise(resolve => {
+ Services.clearData.deleteDataFromPrincipal(
+ principalA,
+ false,
+ Ci.nsIClearDataService.CLEAR_DOM_QUOTA,
+ resolve
+ );
+ });
+
+ info("Unpartitioned entries should still exist.");
+ await testHasEntry(ORIGIN_A, true);
+ await testHasEntry(ORIGIN_A_SUB, true);
+ await testHasEntry(ORIGIN_A_HTTP, true);
+ await testHasEntry(ORIGIN_B, true);
+ await testHasEntry(ORIGIN_B_SUB, true);
+ await testHasEntry(ORIGIN_B_HTTP, true);
+
+ info("Only entries of principal should have been cleared.");
+ await testHasEntry(ORIGIN_A, true, ORIGIN_B);
+ await testHasEntry(ORIGIN_A_SUB, true, ORIGIN_B_SUB);
+ await testHasEntry(ORIGIN_A_HTTP, true, ORIGIN_B_HTTP);
+
+ await testHasEntry(ORIGIN_B, false, ORIGIN_A);
+
+ await testHasEntry(ORIGIN_B_SUB, true, ORIGIN_A_SUB);
+ await testHasEntry(ORIGIN_B_HTTP, true, ORIGIN_A_HTTP);
+
+ cleanup();
+});