Bug 1724205 - Fix issue on restoring private tabs discarded while being created. r=Gijs,mixedpuppy

When an extension does call tabs.discard earlier in the tab creation (e.g. when the extension calls
tabs.discard from inside a tabs.onUpdated listener), when the tab is activated (e.g. by selecting
the non-currently active lazified tab) Firefox is expected to restore it to the webpage url that
was being loaded.

This was already working as expected on non-private tabs, where the expected tab url was stored
in the TabStateCache as the userTypedValue (which seems to be part of a fix also related to
tabs.discard and landed in Firefox 62 from Bug 1422588).

It didn't work yet for private tabs, because for a private tab we are storing `{isPrivate: true}`
into the TabStateCache as soon as we are creating the tab, and so the change to SessionStore
resetBrowserToLazyState applied from Bug 1422588 had no effect for the private tabs
(due to the check for an existing cached entry for the same tab).

This patch applies a small change to ensure we are caching the userTypedValue set on the browser
element if one is not already stored in the TabStateCache, and adds an additional test case
to browser_ext_tabs_discarded.js which cover the expected behavior (and fails as expected
without a fix for the underlying issue).

Differential Revision: https://phabricator.services.mozilla.com/D122370
This commit is contained in:
Luca Greco 2021-08-13 17:27:32 +00:00
parent 0eb305efaf
commit 87647faa54
2 changed files with 68 additions and 2 deletions

View File

@ -180,3 +180,59 @@ add_task(async function test_create_discarded() {
await extension.awaitFinish("test-finished");
await extension.unload();
});
add_task(async function test_discarded_private_tab_restored() {
let extension = ExtensionTestUtils.loadExtension({
incognitoOverride: "spanning",
background: async function() {
browser.tabs.onUpdated.addListener(
async (tabId, changeInfo, tab) => {
const { active, discarded, incognito } = tab;
if (!incognito || active || discarded) {
return;
}
await browser.tabs.discard(tabId);
browser.test.sendMessage("tab-discarded");
},
{ properties: ["status"] }
);
},
});
// Open a private browsing window.
const privateWin = await BrowserTestUtils.openNewBrowserWindow({
private: true,
});
await extension.startup();
const newTab = await BrowserTestUtils.addTab(
privateWin.gBrowser,
"https://example.com/"
);
await extension.awaitMessage("tab-discarded");
is(newTab.getAttribute("pending"), "true", "private tab should be discarded");
const promiseTabLoaded = BrowserTestUtils.browserLoaded(newTab.linkedBrowser);
info("Switching to the discarded background tab");
await BrowserTestUtils.switchTab(privateWin.gBrowser, newTab);
info("Wait for the restored tab to complete loading");
await promiseTabLoaded;
is(
newTab.hasAttribute("pending"),
false,
"discarded private tab should have been restored"
);
is(
newTab.linkedBrowser.currentURI.spec,
"https://example.com/",
"Got the expected url on the restored tab"
);
await extension.unload();
await BrowserTestUtils.closeWindow(privateWin);
});

View File

@ -2516,10 +2516,20 @@ var SessionStoreInternal = {
this._crashedBrowsers.delete(browser.permanentKey);
aTab.removeAttribute("crashed");
let { userTypedValue = "", userTypedClear = 0 } = browser;
let { userTypedValue = null, userTypedClear = 0 } = browser;
let cacheState = TabStateCache.get(browser.permanentKey);
if (cacheState === undefined && userTypedValue) {
// cache the userTypedValue either if the there is no cache state at all
// (e.g. if it was already discarded before we got to cache its state) or
// or it may have been created but not including a userTypedValue (e.g.
// for a private tab we will cache `isPrivate: true` as soon as the tab
// is opened).
//
// In both cases we want to be sure that we are caching the userTypedValue
// if the browser element has one, otherwise the lazy tab will not be
// restored with the expected url once activated again (e.g. See Bug 1724205).
if (userTypedValue && !cacheState?.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