diff --git a/browser/components/sessionstore/src/SessionStore.jsm b/browser/components/sessionstore/src/SessionStore.jsm index c8d84ff1c60..096f8bd9666 100644 --- a/browser/components/sessionstore/src/SessionStore.jsm +++ b/browser/components/sessionstore/src/SessionStore.jsm @@ -49,19 +49,6 @@ const WINDOW_HIDEABLE_FEATURES = [ "menubar", "toolbar", "locationbar", "personalbar", "statusbar", "scrollbars" ]; -/* -docShell capabilities to (re)store -Restored in restoreHistory() -eg: browser.docShell["allow" + aCapability] = false; - -XXX keep these in sync with all the attributes starting - with "allow" in /docshell/base/nsIDocShell.idl -*/ -const CAPABILITIES = [ - "Subframes", "Plugins", "Javascript", "MetaRedirects", "Images", - "DNSPrefetch", "Auth", "WindowControl" -]; - const MESSAGES = [ // The content script tells us that its form data (or that of one of its // subframes) might have changed. This can be the contents or values of @@ -97,6 +84,23 @@ Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", this); XPCOMUtils.defineLazyServiceGetter(this, "gSessionStartup", "@mozilla.org/browser/sessionstartup;1", "nsISessionStartup"); +// List of docShell capabilities to (re)store. These are automatically +// retrieved from a given docShell if not already collected before. +// This is made so they're automatically in sync with all nsIDocShell.allow* +// properties. +let gDocShellCapabilities = (function () { + let caps; + + return docShell => { + if (!caps) { + let keys = Object.keys(docShell); + caps = keys.filter(k => k.startsWith("allow")).map(k => k.slice(5)); + } + + return caps; + }; +})(); + XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "ScratchpadManager", @@ -1983,9 +1987,9 @@ let SessionStoreInternal = { tabData.hidden = aTab.hidden; var disallow = []; - for (var i = 0; i < CAPABILITIES.length; i++) - if (!browser.docShell["allow" + CAPABILITIES[i]]) - disallow.push(CAPABILITIES[i]); + for (let cap of gDocShellCapabilities(browser.docShell)) + if (!browser.docShell["allow" + cap]) + disallow.push(cap); if (disallow.length > 0) tabData.disallow = disallow.join(","); else if (tabData.disallow) @@ -3106,10 +3110,10 @@ let SessionStoreInternal = { } // make sure to reset the capabilities and attributes, in case this tab gets reused - var disallow = (tabData.disallow)?tabData.disallow.split(","):[]; - CAPABILITIES.forEach(function(aCapability) { - browser.docShell["allow" + aCapability] = disallow.indexOf(aCapability) == -1; - }); + let disallow = new Set(tabData.disallow && tabData.disallow.split(",")); + for (let cap of gDocShellCapabilities(browser.docShell)) + browser.docShell["allow" + cap] = !disallow.has(cap); + for (let name in this.xulAttributes) tab.removeAttribute(name); for (let name in tabData.attributes) diff --git a/browser/components/sessionstore/test/Makefile.in b/browser/components/sessionstore/test/Makefile.in index 0e168487c1f..5189930841a 100644 --- a/browser/components/sessionstore/test/Makefile.in +++ b/browser/components/sessionstore/test/Makefile.in @@ -21,6 +21,7 @@ XPCSHELL_TESTS = \ MOCHITEST_BROWSER_FILES = \ head.js \ + browser_capabilities.js \ browser_form_restore_events.js \ browser_form_restore_events_sample.html \ browser_formdata_format.js \ @@ -76,7 +77,6 @@ MOCHITEST_BROWSER_FILES = \ browser_490040.js \ browser_491168.js \ browser_491577.js \ - browser_493467.js \ browser_495495.js \ browser_500328.js \ browser_514751.js \ diff --git a/browser/components/sessionstore/test/browser_493467.js b/browser/components/sessionstore/test/browser_493467.js deleted file mode 100644 index 9332664e2c6..00000000000 --- a/browser/components/sessionstore/test/browser_493467.js +++ /dev/null @@ -1,35 +0,0 @@ -/* 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/. */ - -function test() { - /** Test for Bug 493467 **/ - - let tab = gBrowser.addTab(); - tab.linkedBrowser.stop(); - let tabState = JSON.parse(ss.getTabState(tab)); - is(tabState.disallow || "", "", "Everything is allowed per default"); - - // collect all permissions that can be set on a docShell (i.e. all - // attributes starting with "allow" such as "allowJavascript") and - // disallow them all, as SessionStore only remembers disallowed ones - let permissions = []; - let docShell = tab.linkedBrowser.docShell; - for (let attribute in docShell) { - if (/^allow([A-Z].*)/.test(attribute)) { - permissions.push(RegExp.$1); - docShell[attribute] = false; - } - } - - // make sure that all available permissions have been remembered - tabState = JSON.parse(ss.getTabState(tab)); - let disallow = tabState.disallow.split(","); - permissions.forEach(function(aName) { - ok(disallow.indexOf(aName) > -1, "Saved state of allow" + aName); - }); - // IF A TEST FAILS, please add the missing permission's name (without the - // leading "allow") to nsSessionStore.js's CAPABILITIES array. Thanks. - - gBrowser.removeTab(tab); -} diff --git a/browser/components/sessionstore/test/browser_capabilities.js b/browser/components/sessionstore/test/browser_capabilities.js new file mode 100644 index 00000000000..0259fd42eff --- /dev/null +++ b/browser/components/sessionstore/test/browser_capabilities.js @@ -0,0 +1,73 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +function test() { + TestRunner.run(); +} + +/** + * This test ensures that disabling features by flipping nsIDocShell.allow* + * properties are (re)stored as disabled. Disallowed features must be + * re-enabled when the tab is re-used by another tab restoration. + */ + +function runTests() { + // Create a tab that we're going to use for our tests. + let tab = gBrowser.selectedTab = gBrowser.addTab("about:mozilla"); + let browser = tab.linkedBrowser; + let docShell = browser.docShell; + yield waitForLoad(browser); + + // Get the list of capabilities for docShells. + let flags = Object.keys(docShell).filter(k => k.startsWith("allow")); + + // Check that everything is allowed by default for new tabs. + let state = JSON.parse(ss.getTabState(tab)); + ok(!("disallow" in state), "everything allowed by default"); + ok(flags.every(f => docShell[f]), "all flags set to true"); + + // Flip a couple of allow* flags. + docShell.allowImages = false; + docShell.allowMetaRedirects = false; + + // Check that we correctly save disallowed features. + let disallowedState = JSON.parse(ss.getTabState(tab)); + let disallow = new Set(disallowedState.disallow.split(",")); + ok(disallow.has("Images"), "images not allowed"); + ok(disallow.has("MetaRedirects"), "meta redirects not allowed"); + is(disallow.size, 2, "two capabilities disallowed"); + + // Reuse the tab to restore a new, clean state into it. + ss.setTabState(tab, JSON.stringify({ entries: [{url: "about:home"}] })); + yield waitForLoad(browser); + + // After restoring disallowed features must be available again. + state = JSON.parse(ss.getTabState(tab)); + ok(!("disallow" in state), "everything allowed again"); + ok(flags.every(f => docShell[f]), "all flags set to true"); + + // Restore the state with disallowed features. + ss.setTabState(tab, JSON.stringify(disallowedState)); + yield waitForLoad(browser); + + // Check that docShell flags are set. + ok(!docShell.allowImages, "images not allowed"); + ok(!docShell.allowMetaRedirects, "meta redirects not allowed") + + // Check that we correctly restored features as disabled. + state = JSON.parse(ss.getTabState(tab)); + disallow = new Set(state.disallow.split(",")); + ok(disallow.has("Images"), "images not allowed anymore"); + ok(disallow.has("MetaRedirects"), "meta redirects not allowed anymore"); + is(disallow.size, 2, "two capabilities disallowed"); + + // Clean up after ourselves. + gBrowser.removeTab(tab); +} + +function waitForLoad(aElement) { + aElement.addEventListener("load", function onLoad() { + aElement.removeEventListener("load", onLoad, true); + executeSoon(next); + }, true); +}