Bug 1163745 - Properly support shistory purging for pending tabs r=Yoric
authorTim Taubert <ttaubert@mozilla.com>
Wed, 10 Jun 2015 14:53:07 +0200
changeset 250107 5e6f90f35f9bde7cedf3a003773faeba644440ac
parent 250106 f109e82854fea3801d2e8728be55f17a9ebfafa7
child 250108 8d99fb177495bb0224002941d30db435031f3ec9
push id13700
push userttaubert@mozilla.com
push dateWed, 24 Jun 2015 20:37:33 +0000
treeherderfx-team@832cef974560 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersYoric
bugs1163745
milestone41.0a1
Bug 1163745 - Properly support shistory purging for pending tabs r=Yoric
browser/components/sessionstore/ContentRestore.jsm
browser/components/sessionstore/SessionStore.jsm
browser/components/sessionstore/test/browser.ini
browser/components/sessionstore/test/browser_purge_shistory.js
--- a/browser/components/sessionstore/ContentRestore.jsm
+++ b/browser/components/sessionstore/ContentRestore.jsm
@@ -339,16 +339,25 @@ HistoryListener.prototype = {
   OnHistoryGoForward: function(forwardURI) { return true; },
   OnHistoryGotoIndex: function(index, gotoURI) { return true; },
   OnHistoryPurge: function(numEntries) { return true; },
   OnHistoryReplaceEntry: function(index) {},
 
   // This will be called for a pending tab when loadURI(uri) is called where
   // the given |uri| only differs in the fragment.
   OnHistoryNewEntry(newURI) {
+    let currentURI = this.webNavigation.currentURI;
+
+    // Ignore new SHistory entries with the same URI as those do not indicate
+    // a navigation inside a document by changing the #hash part of the URL.
+    // We usually hit this when purging session history for browsers.
+    if (currentURI && (currentURI.spec == newURI.spec)) {
+      return;
+    }
+
     // Reset the tab's URL to what it's actually showing. Without this loadURI()
     // would use the current document and change the displayed URL only.
     this.webNavigation.setCurrentURI(Utils.makeURI("about:blank"));
 
     // Kick off a new load so that we navigate away from about:blank to the
     // new URL that was passed to loadURI(). The new load will cause a
     // STATE_START notification to be sent and the ProgressListener will then
     // notify the parent and do the rest.
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -1276,25 +1276,21 @@ let SessionStoreInternal = {
   onPurgeSessionHistory: function ssi_onPurgeSessionHistory() {
     SessionFile.wipe();
     // If the browser is shutting down, simply return after clearing the
     // session data on disk as this notification fires after the
     // quit-application notification so the browser is about to exit.
     if (RunState.isQuitting)
       return;
     LastSession.clear();
+
     let openWindows = {};
-    this._forEachBrowserWindow(function(aWindow) {
-      Array.forEach(aWindow.gBrowser.tabs, function(aTab) {
-        delete aTab.linkedBrowser.__SS_data;
-        if (aTab.linkedBrowser.__SS_restoreState)
-          this._resetTabRestoringState(aTab);
-      }, this);
-      openWindows[aWindow.__SSi] = true;
-    });
+    // Collect open windows.
+    this._forEachBrowserWindow(({__SSi: id}) => openWindows[id] = true);
+
     // also clear all data about closed tabs and windows
     for (let ix in this._windows) {
       if (ix in openWindows) {
         this._windows[ix]._closedTabs = [];
       } else {
         delete this._windows[ix];
       }
     }
--- a/browser/components/sessionstore/test/browser.ini
+++ b/browser/components/sessionstore/test/browser.ini
@@ -91,16 +91,18 @@ skip-if = buildapp == 'mulet'
 [browser_global_store.js]
 [browser_history_persist.js]
 [browser_label_and_icon.js]
 [browser_merge_closed_tabs.js]
 [browser_page_title.js]
 [browser_pageStyle.js]
 [browser_pending_tabs.js]
 [browser_privatetabs.js]
+[browser_purge_shistory.js]
+skip-if = e10s
 [browser_replace_load.js]
 [browser_restore_redirect.js]
 [browser_scrollPositions.js]
 [browser_sessionHistory.js]
 [browser_sessionStorage.js]
 [browser_swapDocShells.js]
 skip-if = e10s # See bug 918634
 [browser_switch_remoteness.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/browser_purge_shistory.js
@@ -0,0 +1,58 @@
+"use strict";
+
+/**
+ * This test checks that pending tabs are treated like fully loaded tabs when
+ * purging session history. Just like for fully loaded tabs we want to remove
+ * every but the current shistory entry.
+ */
+
+const TAB_STATE = {
+  entries: [{url: "about:mozilla"}, {url: "about:robots"}],
+  index: 1,
+};
+
+function checkTabContents(browser) {
+  return ContentTask.spawn(browser, null, function* () {
+    let Ci = Components.interfaces;
+    let webNavigation = docShell.QueryInterface(Ci.nsIWebNavigation);
+    let history = webNavigation.sessionHistory.QueryInterface(Ci.nsISHistoryInternal);
+    return history && history.count == 1 && content.document.documentURI == "about:mozilla";
+  });
+}
+
+add_task(function* () {
+  // Create a new tab.
+  let tab = gBrowser.addTab("about:blank");
+  let browser = tab.linkedBrowser;
+  yield promiseBrowserLoaded(browser);
+  yield promiseTabState(tab, TAB_STATE);
+
+  // Create another new tab.
+  let tab2 = gBrowser.addTab("about:blank");
+  let browser2 = tab2.linkedBrowser;
+  yield promiseBrowserLoaded(browser2);
+
+  // The tab shouldn't be restored right away.
+  Services.prefs.setBoolPref("browser.sessionstore.restore_on_demand", true);
+
+  // Prepare the tab state.
+  let promise = promiseTabRestoring(tab2);
+  ss.setTabState(tab2, JSON.stringify(TAB_STATE));
+  ok(tab2.hasAttribute("pending"), "tab is pending");
+  yield promise;
+
+  // Purge session history.
+  Services.obs.notifyObservers(null, "browser:purge-session-history", "");
+  ok((yield checkTabContents(browser)), "expected tab contents found");
+  ok(tab2.hasAttribute("pending"), "tab is still pending");
+
+  // Kick off tab restoration.
+  gBrowser.selectedTab = tab2;
+  yield promiseTabRestored(tab2);
+  ok((yield checkTabContents(browser2)), "expected tab contents found");
+  ok(!tab2.hasAttribute("pending"), "tab is not pending anymore");
+
+  // Cleanup.
+  gBrowser.removeTab(tab2);
+  gBrowser.removeTab(tab);
+});