Bug 1377734 - Avoid instantiating a lazy tab from sendMessage, r?mixedpuppy
MozReview-Commit-ID: KfYg6hG8KmC
--- a/browser/components/extensions/test/browser/browser-common.ini
+++ b/browser/components/extensions/test/browser/browser-common.ini
@@ -123,16 +123,17 @@ skip-if = debug || asan # Bug 1354681
[browser_ext_tabs_executeScript_good.js]
[browser_ext_tabs_executeScript_bad.js]
[browser_ext_tabs_executeScript_multiple.js]
[browser_ext_tabs_executeScript_no_create.js]
[browser_ext_tabs_executeScript_runAt.js]
[browser_ext_tabs_getCurrent.js]
[browser_ext_tabs_insertCSS.js]
[browser_ext_tabs_lastAccessed.js]
+[browser_ext_tabs_lazy.js]
[browser_ext_tabs_removeCSS.js]
[browser_ext_tabs_move_array.js]
[browser_ext_tabs_move_window.js]
[browser_ext_tabs_move_window_multiple.js]
[browser_ext_tabs_move_window_pinned.js]
[browser_ext_tabs_onHighlighted.js]
[browser_ext_tabs_onUpdated.js]
[browser_ext_tabs_printPreview.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_lazy.js
@@ -0,0 +1,40 @@
+"use strict";
+
+const SESSION = {
+ windows: [{
+ tabs: [
+ {entries: [{url: "about:blank"}]},
+ {entries: [{url: "https://example.com/"}]},
+ ],
+ }],
+};
+
+add_task(async function() {
+ SessionStore.setBrowserState(JSON.stringify(SESSION));
+ const tab = gBrowser.tabs[1];
+
+ is(tab.getAttribute("pending"), "true", "The tab is pending restore");
+ is(tab.linkedBrowser.isConnected, false, "The tab is lazy");
+
+ async function background() {
+ const [tab] = await browser.tabs.query({url: "https://example.com/"});
+ browser.test.assertRejects(
+ browser.tabs.sendMessage(tab.id, "void"),
+ /Could not establish connection. Receiving end does not exist/,
+ "No recievers in a tab pending restore."
+ );
+ browser.test.notifyPass("lazy");
+ }
+
+ const manifest = {permissions: ["tabs"]};
+ const extension = ExtensionTestUtils.loadExtension({manifest, background});
+
+ await extension.startup();
+ await extension.awaitFinish("lazy");
+ await extension.unload();
+
+ is(tab.getAttribute("pending"), "true", "The tab is still pending restore");
+ is(tab.linkedBrowser.isConnected, false, "The tab is still lazy");
+
+ await BrowserTestUtils.removeTab(tab);
+});
--- a/toolkit/components/extensions/ExtensionParent.jsm
+++ b/toolkit/components/extensions/ExtensionParent.jsm
@@ -273,25 +273,32 @@ ProxyMessenger = {
/**
* @param {object} recipient An object that was passed to
* `MessageChannel.sendMessage`.
* @param {Extension} extension
* @returns {object|null} The message manager matching the recipient if found.
*/
getMessageManagerForRecipient(recipient) {
- let {tabId} = recipient;
// tabs.sendMessage / tabs.connect
- if (tabId) {
+ if ("tabId" in recipient) {
// `tabId` being set implies that the tabs API is supported, so we don't
// need to check whether `tabTracker` exists.
- let tab = apiManager.global.tabTracker.getTab(tabId, null);
+ let tab = apiManager.global.tabTracker.getTab(recipient.tabId, null);
if (!tab) {
return null;
}
+
+ // There can be no recipients in a tab pending restore,
+ // So we bail early to avoid instantiating the lazy browser.
+ let node = tab.browser || tab;
+ if (node.getAttribute("pending") === "true") {
+ return null;
+ }
+
let browser = tab.linkedBrowser || tab.browser;
// Options panels in the add-on manager currently require
// special-casing, since their message managers aren't currently
// connected to the tab's top-level message manager. To deal with
// this, we find the options <browser> for the tab, and use that
// directly, insteead.
if (browser.currentURI.cloneIgnoringRef().spec === "about:addons") {