Bug 1422588 fix discard if tab sessionstate is not ready, r=mikedeboer
If discard is used immediately after creating a tab, restoring the tab
resulted in an unusable tab. This was due to the sessionstate not being
ready. This adds enough sessionstate to restore when this occurs.
MozReview-Commit-ID: 6PIc71BS8VU
--- a/browser/components/extensions/test/browser/browser_ext_tabs_discarded.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_discarded.js
@@ -62,8 +62,46 @@ add_task(async function test_discarded()
await extension.awaitFinish("test-finished");
await extension.unload();
BrowserTestUtils.removeTab(tab1);
BrowserTestUtils.removeTab(tab2);
});
+// If discard is called immediately after creating a new tab, the new tab may not have loaded,
+// and the sessionstore for that tab is not ready for discarding. The result was a corrupted
+// sessionstore for the tab, which when the tab was activated, resulted in a tab with partial
+// state.
+add_task(async function test_create_then_discard() {
+ let extension = ExtensionTestUtils.loadExtension({
+ manifest: {
+ "permissions": ["tabs", "webNavigation"],
+ },
+
+ background: async function() {
+ let createdTab;
+
+ browser.tabs.onUpdated.addListener((tabId, updatedInfo) => {
+ if (!updatedInfo.discarded) {
+ return;
+ }
+
+ browser.webNavigation.onCompleted.addListener(async (details) => {
+ browser.test.assertEq(createdTab.id, details.tabId, "created tab navigation is completed");
+ let activeTab = await browser.tabs.get(details.tabId);
+ browser.test.assertEq("http://example.com/", details.url, "created tab url is correct");
+ browser.test.assertEq("http://example.com/", activeTab.url, "created tab url is correct");
+ browser.tabs.remove(details.tabId);
+ browser.test.notifyPass("test-finished");
+ }, {url: [{hostContains: "example.com"}]});
+
+ browser.tabs.update(tabId, {active: true});
+ });
+
+ createdTab = await browser.tabs.create({url: "http://example.com/", active: false});
+ browser.tabs.discard(createdTab.id);
+ },
+ });
+ await extension.startup();
+ await extension.awaitFinish("test-finished");
+ await extension.unload();
+});
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -2025,21 +2025,35 @@ var SessionStoreInternal = {
this.cleanUpRemovedBrowser(aTab);
aTab.setAttribute("pending", "true");
this._lastKnownFrameLoader.delete(browser.permanentKey);
this._crashedBrowsers.delete(browser.permanentKey);
aTab.removeAttribute("crashed");
+ let {userTypedValue = "", userTypedClear = 0} = browser;
+
+ let cacheState = TabStateCache.get(browser);
+ if (cacheState === undefined && userTypedValue) {
+ // Discard was likely called before state can be cached. Update
+ // the persistent tab state cache with browser information so a
+ // restore will be successful. This information is necessary for
+ // restoreTabContent in ContentRestore.jsm to work properly.
+ TabStateCache.update(browser, {
+ userTypedValue,
+ userTypedClear: 1,
+ });
+ }
+
TAB_LAZY_STATES.set(aTab, {
url: browser.currentURI.spec,
title: aTab.label,
- userTypedValue: browser.userTypedValue || "",
- userTypedClear: browser.userTypedClear || 0
+ userTypedValue,
+ userTypedClear,
});
},
/**
* When a tab is removed or suspended, remove listeners and reset restoring state.
* @param aBrowser
* Browser reference
*/