Bug 1452666 - Simplify SessionHistory serialization code and test expanded principals are serialized and can restore tabs. r=bz, r=mikedeboer, a=RyanVM
authorJonathan Kingston <jkt@mozilla.com>
Sat, 19 May 2018 14:42:52 +0100
changeset 473530 c3359bea833fb3ac6ec2ff9fe1426ca1f5f1e8f1
parent 473529 8735fe57245edec03c7a99b82626e57f9a4997bd
child 473531 2449a216c49ff59d6a7f45a7ca33ee8739da2fff
push id1728
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:12:27 +0000
treeherdermozilla-release@c296fde26f5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, mikedeboer, RyanVM
bugs1452666
milestone61.0
Bug 1452666 - Simplify SessionHistory serialization code and test expanded principals are serialized and can restore tabs. r=bz, r=mikedeboer, a=RyanVM MozReview-Commit-ID: EV39wz2TFlj
browser/components/extensions/test/browser/browser-common.ini
browser/components/extensions/test/browser/browser_ext_sessions_restoreTab.js
toolkit/modules/sessionstore/SessionHistory.jsm
--- a/browser/components/extensions/test/browser/browser-common.ini
+++ b/browser/components/extensions/test/browser/browser-common.ini
@@ -132,16 +132,17 @@ skip-if = !e10s || !crashreporter # the 
 [browser_ext_runtime_openOptionsPage_uninstall.js]
 [browser_ext_runtime_setUninstallURL.js]
 [browser_ext_sessions_forgetClosedTab.js]
 [browser_ext_sessions_forgetClosedWindow.js]
 [browser_ext_sessions_getRecentlyClosed.js]
 [browser_ext_sessions_getRecentlyClosed_private.js]
 [browser_ext_sessions_getRecentlyClosed_tabs.js]
 [browser_ext_sessions_restore.js]
+[browser_ext_sessions_restoreTab.js]
 [browser_ext_sessions_window_tab_value.js]
 [browser_ext_settings_overrides_default_search.js]
 [browser_ext_sidebarAction.js]
 [browser_ext_sidebarAction_browser_style.js]
 [browser_ext_sidebarAction_context.js]
 [browser_ext_sidebarAction_contextMenu.js]
 [browser_ext_sidebarAction_runtime.js]
 [browser_ext_sidebarAction_tabs.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_sessions_restoreTab.js
@@ -0,0 +1,63 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+ChromeUtils.defineModuleGetter(this, "SessionStore",
+                               "resource:///modules/sessionstore/SessionStore.jsm");
+
+
+/**
+ This test checks that after closing an extension made tab it restores correctly.
+ The tab is given an expanded triggering principal and we didn't use to serialize
+ these correctly into session history.
+ */
+
+// Check that we can restore a tab modified by an extension.
+add_task(async function test_restoringModifiedTab() {
+  function background() {
+    browser.tabs.create({url: "http://example.com/"});
+    browser.test.onMessage.addListener((msg, filter) => {
+      if (msg == "change-tab") {
+        browser.tabs.executeScript({code: 'location.href += "?changedTab";'});
+      }
+    });
+  }
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      permissions: ["tabs", "<all_urls>"],
+    },
+    "browser_action": {
+      "default_title": "Navigate current tab via content script",
+    },
+    background,
+  });
+
+  const contentScriptTabURL = "http://example.com/?changedTab";
+
+  let win = await BrowserTestUtils.openNewBrowserWindow({});
+
+  // Open and close a tabs.
+  let tabPromise = BrowserTestUtils.waitForNewTab(win.gBrowser, "http://example.com/");
+  await extension.startup();
+  let firstTab = await tabPromise;
+  let locationChange = BrowserTestUtils.waitForLocationChange(win.gBrowser, contentScriptTabURL);
+  extension.sendMessage("change-tab");
+  await locationChange;
+  is(firstTab.linkedBrowser.currentURI.spec, contentScriptTabURL, "Got expected URL");
+
+  let sessionPromise = BrowserTestUtils.waitForSessionStoreUpdate(firstTab);
+  BrowserTestUtils.removeTab(firstTab);
+  await sessionPromise;
+
+  tabPromise = BrowserTestUtils.waitForNewTab(win.gBrowser, contentScriptTabURL, true);
+  SessionStore.undoCloseTab(win, 0);
+  let restoredTab = await tabPromise;
+  ok(restoredTab, "We returned a tab here");
+  is(restoredTab.linkedBrowser.currentURI.spec, contentScriptTabURL, "Got expected URL");
+
+  await extension.unload();
+  BrowserTestUtils.removeTab(restoredTab);
+
+  // Close the window.
+  await BrowserTestUtils.closeWindow(win);
+});
--- a/toolkit/modules/sessionstore/SessionHistory.jsm
+++ b/toolkit/modules/sessionstore/SessionHistory.jsm
@@ -209,35 +209,21 @@ var SessionHistoryInternal = {
         if (presStates.length > 0) {
           entry.presState = presStates;
         }
       }
     }
 
     // Collect triggeringPrincipal data for the current history entry.
     if (shEntry.principalToInherit) {
-      try {
-        let principalToInherit = Utils.serializePrincipal(shEntry.principalToInherit);
-        if (principalToInherit) {
-          entry.principalToInherit_base64 = principalToInherit;
-        }
-      } catch (e) {
-        debug(e);
-      }
+      entry.principalToInherit_base64 = Utils.serializePrincipal(shEntry.principalToInherit);
     }
 
     if (shEntry.triggeringPrincipal) {
-      try {
-        let triggeringPrincipal = Utils.serializePrincipal(shEntry.triggeringPrincipal);
-        if (triggeringPrincipal) {
-          entry.triggeringPrincipal_base64 = triggeringPrincipal;
-        }
-      } catch (e) {
-        debug(e);
-      }
+      entry.triggeringPrincipal_base64 = Utils.serializePrincipal(shEntry.triggeringPrincipal);
     }
 
     entry.docIdentifier = shEntry.BFCacheEntry.ID;
 
     if (shEntry.stateData != null) {
       entry.structuredCloneState = shEntry.stateData.getDataAsBase64();
       entry.structuredCloneVersion = shEntry.stateData.formatVersion;
     }
@@ -456,16 +442,22 @@ var SessionHistoryInternal = {
         shEntry.adoptBFCacheEntry(matchingEntry.shEntry);
         childDocIdents = matchingEntry.childDocIdents;
       }
     }
 
     if (entry.triggeringPrincipal_base64) {
       shEntry.triggeringPrincipal = Utils.deserializePrincipal(entry.triggeringPrincipal_base64);
     }
+    // Ensure that we have a null principal if we couldn't deserialize it.
+    // This won't always work however is safe to use.
+    if (!shEntry.triggeringPrincipal) {
+      debug("Couldn't deserialize the triggeringPrincipal, falling back to NullPrincipal");
+      shEntry.triggeringPrincipal = Services.scriptSecurityManager.createNullPrincipal({});
+    }
     if (entry.principalToInherit_base64) {
       shEntry.principalToInherit = Utils.deserializePrincipal(entry.principalToInherit_base64);
     }
 
     if (entry.children && shEntry instanceof Ci.nsISHContainer) {
       for (var i = 0; i < entry.children.length; i++) {
         // XXXzpao Wallpaper patch for bug 514751
         if (!entry.children[i].url)