summaryrefslogtreecommitdiffstats
path: root/browser/components/sessionstore/test/browser_sessionStorage.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/sessionstore/test/browser_sessionStorage.js')
-rw-r--r--browser/components/sessionstore/test/browser_sessionStorage.js300
1 files changed, 300 insertions, 0 deletions
diff --git a/browser/components/sessionstore/test/browser_sessionStorage.js b/browser/components/sessionstore/test/browser_sessionStorage.js
new file mode 100644
index 0000000000..1f3ff8abff
--- /dev/null
+++ b/browser/components/sessionstore/test/browser_sessionStorage.js
@@ -0,0 +1,300 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const RAND = Math.random();
+const URL =
+ "http://mochi.test:8888/browser/" +
+ "browser/components/sessionstore/test/browser_sessionStorage.html" +
+ "?" +
+ RAND;
+
+const HAS_FIRST_PARTY_DOMAIN = [
+ Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN,
+].includes(Services.prefs.getIntPref("network.cookie.cookieBehavior"));
+const OUTER_ORIGIN = "http://mochi.test:8888";
+const FIRST_PARTY_DOMAIN = escape("(http,mochi.test)");
+const INNER_ORIGIN = HAS_FIRST_PARTY_DOMAIN
+ ? `http://example.com^partitionKey=${FIRST_PARTY_DOMAIN}`
+ : "http://example.com";
+const SECURE_INNER_ORIGIN = HAS_FIRST_PARTY_DOMAIN
+ ? `https://example.com^partitionKey=${FIRST_PARTY_DOMAIN}`
+ : "https://example.com";
+
+const OUTER_VALUE = "outer-value-" + RAND;
+const INNER_VALUE = "inner-value-" + RAND;
+
+/**
+ * This test ensures that setting, modifying and restoring sessionStorage data
+ * works as expected.
+ */
+add_task(async function session_storage() {
+ let tab = BrowserTestUtils.addTab(gBrowser, URL);
+ let browser = tab.linkedBrowser;
+ await promiseBrowserLoaded(browser);
+
+ // Flush to make sure chrome received all data.
+ await TabStateFlusher.flush(browser);
+
+ let { storage } = JSON.parse(ss.getTabState(tab));
+ is(
+ storage[INNER_ORIGIN].test,
+ INNER_VALUE,
+ "sessionStorage data for example.com has been serialized correctly"
+ );
+ is(
+ storage[OUTER_ORIGIN].test,
+ OUTER_VALUE,
+ "sessionStorage data for mochi.test has been serialized correctly"
+ );
+
+ // Ensure that modifying sessionStore values works for the inner frame only.
+ await modifySessionStorage(browser, { test: "modified1" }, { frameIndex: 0 });
+ await TabStateFlusher.flush(browser);
+
+ ({ storage } = JSON.parse(ss.getTabState(tab)));
+ is(
+ storage[INNER_ORIGIN].test,
+ "modified1",
+ "sessionStorage data for example.com has been serialized correctly"
+ );
+ is(
+ storage[OUTER_ORIGIN].test,
+ OUTER_VALUE,
+ "sessionStorage data for mochi.test has been serialized correctly"
+ );
+
+ // Ensure that modifying sessionStore values works for both frames.
+ await modifySessionStorage(browser, { test: "modified" });
+ await modifySessionStorage(browser, { test: "modified2" }, { frameIndex: 0 });
+ await TabStateFlusher.flush(browser);
+
+ ({ storage } = JSON.parse(ss.getTabState(tab)));
+ is(
+ storage[INNER_ORIGIN].test,
+ "modified2",
+ "sessionStorage data for example.com has been serialized correctly"
+ );
+ is(
+ storage[OUTER_ORIGIN].test,
+ "modified",
+ "sessionStorage data for mochi.test has been serialized correctly"
+ );
+
+ // Test that duplicating a tab works.
+ let tab2 = gBrowser.duplicateTab(tab);
+ let browser2 = tab2.linkedBrowser;
+ await promiseTabRestored(tab2);
+
+ // Flush to make sure chrome received all data.
+ await TabStateFlusher.flush(browser2);
+
+ ({ storage } = JSON.parse(ss.getTabState(tab2)));
+ is(
+ storage[INNER_ORIGIN].test,
+ "modified2",
+ "sessionStorage data for example.com has been duplicated correctly"
+ );
+ is(
+ storage[OUTER_ORIGIN].test,
+ "modified",
+ "sessionStorage data for mochi.test has been duplicated correctly"
+ );
+
+ // Ensure that the content script retains restored data
+ // (by e.g. duplicateTab) and sends it along with new data.
+ await modifySessionStorage(browser2, { test: "modified3" });
+ await TabStateFlusher.flush(browser2);
+
+ ({ storage } = JSON.parse(ss.getTabState(tab2)));
+ is(
+ storage[INNER_ORIGIN].test,
+ "modified2",
+ "sessionStorage data for example.com has been duplicated correctly"
+ );
+ is(
+ storage[OUTER_ORIGIN].test,
+ "modified3",
+ "sessionStorage data for mochi.test has been duplicated correctly"
+ );
+
+ // Check that loading a new URL discards data.
+ BrowserTestUtils.loadURI(browser2, "http://mochi.test:8888/");
+ await promiseBrowserLoaded(browser2);
+ await TabStateFlusher.flush(browser2);
+
+ ({ storage } = JSON.parse(ss.getTabState(tab2)));
+ is(
+ storage[OUTER_ORIGIN].test,
+ "modified3",
+ "navigating retains correct storage data"
+ );
+
+ is(
+ storage[INNER_ORIGIN].test,
+ "modified2",
+ "sessionStorage data for example.com wasn't discarded after top-level same-site navigation"
+ );
+
+ // Test that clearing the data in the first tab works properly within
+ // the subframe
+ await modifySessionStorage(browser, {}, { frameIndex: 0 });
+ await TabStateFlusher.flush(browser);
+ ({ storage } = JSON.parse(ss.getTabState(tab)));
+ is(
+ storage[INNER_ORIGIN],
+ undefined,
+ "sessionStorage data for example.com has been cleared correctly"
+ );
+
+ // Test that clearing the data in the first tab works properly within
+ // the top-level frame
+ await modifySessionStorage(browser, {});
+ await TabStateFlusher.flush(browser);
+ ({ storage } = JSON.parse(ss.getTabState(tab)));
+ ok(
+ storage === null || storage === undefined,
+ "sessionStorage data for the entire tab has been cleared correctly"
+ );
+
+ // Clean up.
+ BrowserTestUtils.removeTab(tab);
+ BrowserTestUtils.removeTab(tab2);
+});
+
+/**
+ * This test ensures that purging domain data also purges data from the
+ * sessionStorage data collected for tabs.
+ */
+add_task(async function purge_domain() {
+ let tab = BrowserTestUtils.addTab(gBrowser, URL);
+ let browser = tab.linkedBrowser;
+ await promiseBrowserLoaded(browser);
+
+ // Purge data for "mochi.test".
+ await purgeDomainData(browser, "mochi.test");
+
+ // Flush to make sure chrome received all data.
+ await TabStateFlusher.flush(browser);
+
+ let { storage } = JSON.parse(ss.getTabState(tab));
+ ok(
+ !storage[OUTER_ORIGIN],
+ "sessionStorage data for mochi.test has been purged"
+ );
+ is(
+ storage[INNER_ORIGIN].test,
+ INNER_VALUE,
+ "sessionStorage data for example.com has been preserved"
+ );
+
+ BrowserTestUtils.removeTab(tab);
+});
+
+/**
+ * This test ensures that collecting sessionStorage data respects the privacy
+ * levels as set by the user.
+ */
+add_task(async function respect_privacy_level() {
+ let tab = BrowserTestUtils.addTab(gBrowser, URL + "&secure");
+ await promiseBrowserLoaded(tab.linkedBrowser);
+ await TabStateFlusher.flush(tab.linkedBrowser);
+ await promiseRemoveTabAndSessionState(tab);
+
+ let [
+ {
+ state: { storage },
+ },
+ ] = ss.getClosedTabData(window);
+ is(
+ storage[OUTER_ORIGIN].test,
+ OUTER_VALUE,
+ "http sessionStorage data has been saved"
+ );
+ is(
+ storage[SECURE_INNER_ORIGIN].test,
+ INNER_VALUE,
+ "https sessionStorage data has been saved"
+ );
+
+ // Disable saving data for encrypted sites.
+ Services.prefs.setIntPref("browser.sessionstore.privacy_level", 1);
+
+ tab = BrowserTestUtils.addTab(gBrowser, URL + "&secure");
+ await promiseBrowserLoaded(tab.linkedBrowser);
+ await TabStateFlusher.flush(tab.linkedBrowser);
+ await promiseRemoveTabAndSessionState(tab);
+
+ [
+ {
+ state: { storage },
+ },
+ ] = ss.getClosedTabData(window);
+ is(
+ storage[OUTER_ORIGIN].test,
+ OUTER_VALUE,
+ "http sessionStorage data has been saved"
+ );
+ ok(
+ !storage[SECURE_INNER_ORIGIN],
+ "https sessionStorage data has *not* been saved"
+ );
+
+ // Disable saving data for any site.
+ Services.prefs.setIntPref("browser.sessionstore.privacy_level", 2);
+
+ // Check that duplicating a tab copies all private data.
+ tab = BrowserTestUtils.addTab(gBrowser, URL + "&secure");
+ await promiseBrowserLoaded(tab.linkedBrowser);
+ let tab2 = gBrowser.duplicateTab(tab);
+ await promiseTabRestored(tab2);
+ await promiseRemoveTabAndSessionState(tab);
+
+ // With privacy_level=2 the |tab| shouldn't have any sessionStorage data.
+ [
+ {
+ state: { storage },
+ },
+ ] = ss.getClosedTabData(window);
+ ok(!storage, "sessionStorage data has *not* been saved");
+
+ // Remove all closed tabs before continuing with the next test.
+ // As Date.now() isn't monotonic we might sometimes check
+ // the wrong closedTabData entry.
+ while (ss.getClosedTabCount(window) > 0) {
+ ss.forgetClosedTab(window, 0);
+ }
+
+ // Restore the default privacy level and close the duplicated tab.
+ Services.prefs.clearUserPref("browser.sessionstore.privacy_level");
+ await promiseRemoveTabAndSessionState(tab2);
+
+ // With privacy_level=0 the duplicated |tab2| should persist all data.
+ [
+ {
+ state: { storage },
+ },
+ ] = ss.getClosedTabData(window);
+ is(
+ storage[OUTER_ORIGIN].test,
+ OUTER_VALUE,
+ "http sessionStorage data has been saved"
+ );
+ is(
+ storage[SECURE_INNER_ORIGIN].test,
+ INNER_VALUE,
+ "https sessionStorage data has been saved"
+ );
+});
+
+function purgeDomainData(browser, domain) {
+ return new Promise(resolve => {
+ Services.clearData.deleteDataFromHost(
+ domain,
+ true,
+ Services.clearData.CLEAR_SESSION_HISTORY,
+ resolve
+ );
+ });
+}