diff --git a/remote/shared/messagehandler/ModuleCache.jsm b/remote/shared/messagehandler/ModuleCache.jsm index 4a1636ccfb66b..350b37c5534a2 100644 --- a/remote/shared/messagehandler/ModuleCache.jsm +++ b/remote/shared/messagehandler/ModuleCache.jsm @@ -168,6 +168,21 @@ class ModuleCache { return module; } + /** + * Check if the given module exists for the destination. + * + * @param {String} moduleName + * The name of the module. + * @param {Destination} destination + * The destination. + * @returns {Boolean} + * True if the module exists. + */ + hasModule(moduleName, destination) { + const classes = this.getAllModuleClasses(moduleName, destination); + return classes.length != 0; + } + toString() { return `[object ${this.constructor.name} ${this.messageHandler.name}]`; } diff --git a/remote/shared/messagehandler/RootMessageHandler.jsm b/remote/shared/messagehandler/RootMessageHandler.jsm index 60f6d25cbbb46..bb7d8ef55ed6a 100644 --- a/remote/shared/messagehandler/RootMessageHandler.jsm +++ b/remote/shared/messagehandler/RootMessageHandler.jsm @@ -146,6 +146,19 @@ class RootMessageHandler extends MessageHandler { return []; } + const destination = { + type: WindowGlobalMessageHandler.type, + contextDescriptor: { + type: CONTEXT_DESCRIPTOR_TYPES.ALL, + }, + }; + + // Don't apply session data if the module is not present + // for the destination. + if (!this._moduleCache.hasModule(moduleName, destination)) { + return Promise.resolve(); + } + return this.handleCommand({ moduleName, commandName: "_applySessionData", @@ -153,12 +166,7 @@ class RootMessageHandler extends MessageHandler { [isAdding ? "added" : "removed"]: updatedValues, category, }, - destination: { - type: WindowGlobalMessageHandler.type, - contextDescriptor: { - type: CONTEXT_DESCRIPTOR_TYPES.ALL, - }, - }, + destination, }); } } diff --git a/remote/shared/messagehandler/WindowGlobalMessageHandler.jsm b/remote/shared/messagehandler/WindowGlobalMessageHandler.jsm index a14dda76671fa..49a0ed3a49282 100644 --- a/remote/shared/messagehandler/WindowGlobalMessageHandler.jsm +++ b/remote/shared/messagehandler/WindowGlobalMessageHandler.jsm @@ -72,6 +72,10 @@ class WindowGlobalMessageHandler extends MessageHandler { return; } + const destination = { + type: WindowGlobalMessageHandler.type, + }; + for (const sessionDataItem of sessionDataItems) { const { moduleName, @@ -80,6 +84,12 @@ class WindowGlobalMessageHandler extends MessageHandler { value, } = sessionDataItem; if (this._isRelevantContext(contextDescriptor)) { + // Don't apply session data if the module is not present + // for the destination. + if (!this._moduleCache.hasModule(moduleName, destination)) { + continue; + } + await this.handleCommand({ moduleName, commandName: "_applySessionData", @@ -91,9 +101,7 @@ class WindowGlobalMessageHandler extends MessageHandler { // though it will make the implementation more complex. added: [value], }, - destination: { - type: WindowGlobalMessageHandler.type, - }, + destination, }); } } diff --git a/remote/shared/messagehandler/test/browser/browser_session_data.js b/remote/shared/messagehandler/test/browser/browser_session_data.js index 18c6ff110f055..ab36aeecd21da 100644 --- a/remote/shared/messagehandler/test/browser/browser_session_data.js +++ b/remote/shared/messagehandler/test/browser/browser_session_data.js @@ -158,6 +158,36 @@ add_task(async function test_sessionData() { is(sessionDataSnapshot.size, 0, "session data should be empty again"); }); +add_task(async function test_sessionDataRootOnlyModule() { + const sessionId = "sessionData-test-rootOnly"; + + const rootMessageHandler = createRootMessageHandler(sessionId); + ok(rootMessageHandler, "Valid ROOT MessageHandler created"); + + await BrowserTestUtils.loadURI( + gBrowser, + "https://example.com/document-builder.sjs?html=tab" + ); + + const windowGlobalCreated = rootMessageHandler.once("message-handler-event"); + + // Updating the session data on the root message handler should not cause + // failures for other message handlers if the module only exists for root. + await rootMessageHandler.addSessionData({ + moduleName: "rootOnly", + category: "session_data_root_only", + contextDescriptor: { + type: CONTEXT_DESCRIPTOR_TYPES.ALL, + }, + values: [true], + }); + + await windowGlobalCreated; + ok(true, "Window global has been initialized"); + + rootMessageHandler.destroy(); +}); + function checkSessionDataItem(item, moduleName, category, contextType, value) { is(item.moduleName, moduleName, "Data item has the expected module name"); is(item.category, category, "Data item has the expected category"); diff --git a/remote/shared/messagehandler/test/browser/resources/modules/root/rootOnly.jsm b/remote/shared/messagehandler/test/browser/resources/modules/root/rootOnly.jsm new file mode 100644 index 0000000000000..3b7d678a89f8a --- /dev/null +++ b/remote/shared/messagehandler/test/browser/resources/modules/root/rootOnly.jsm @@ -0,0 +1,25 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const EXPORTED_SYMBOLS = ["rootOnly"]; + +const { Module } = ChromeUtils.import( + "chrome://remote/content/shared/messagehandler/Module.jsm" +); + +class RootOnly extends Module { + destroy() {} + + /** + * Commands + */ + + testCommand(params = {}) { + return params; + } +} + +const rootOnly = RootOnly;