diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /devtools/server/connectors/frame-connector.js | |
parent | Initial commit. (diff) | |
download | thunderbird-59f4b6b6d49b15c5a468f3fe34f3cfa4dd956ce2.tar.xz thunderbird-59f4b6b6d49b15c5a468f3fe34f3cfa4dd956ce2.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'devtools/server/connectors/frame-connector.js')
-rw-r--r-- | devtools/server/connectors/frame-connector.js | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/devtools/server/connectors/frame-connector.js b/devtools/server/connectors/frame-connector.js new file mode 100644 index 0000000000..789d405d90 --- /dev/null +++ b/devtools/server/connectors/frame-connector.js @@ -0,0 +1,171 @@ +/* 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"; + +var DevToolsUtils = require("devtools/shared/DevToolsUtils"); +var { dumpn } = DevToolsUtils; + +loader.lazyRequireGetter( + this, + "DevToolsServer", + "resource://devtools/server/devtools-server.js", + true +); +loader.lazyRequireGetter( + this, + "ChildDebuggerTransport", + "resource://devtools/shared/transport/child-transport.js", + true +); + +loader.lazyRequireGetter( + this, + "EventEmitter", + "resource://devtools/shared/event-emitter.js" +); + +/** + * Start a DevTools server in a remote frame's process and add it as a child server for + * an active connection. + * + * @param object connection + * The devtools server connection to use. + * @param Element frame + * The frame element with remote content to connect to. + * @param function [onDestroy] + * Optional function to invoke when the child process closes or the connection + * shuts down. (Need to forget about the related target actor.) + * @return object + * A promise object that is resolved once the connection is established. + */ +function connectToFrame( + connection, + frame, + onDestroy, + { addonId, addonBrowsingContextGroupId } = {} +) { + return new Promise(resolve => { + // Get messageManager from XUL browser (which might be a specialized tunnel for RDM) + // or else fallback to asking the frameLoader itself. + const mm = frame.messageManager || frame.frameLoader.messageManager; + mm.loadFrameScript("resource://devtools/server/startup/frame.js", false); + + const trackMessageManager = () => { + if (!actor) { + mm.addMessageListener("debug:actor", onActorCreated); + } + }; + + const untrackMessageManager = () => { + if (!actor) { + mm.removeMessageListener("debug:actor", onActorCreated); + } + }; + + let actor, childTransport; + const prefix = connection.allocID("child"); + // Compute the same prefix that's used by DevToolsServerConnection + const connPrefix = prefix + "/"; + + const onActorCreated = DevToolsUtils.makeInfallible(function (msg) { + if (msg.json.prefix != prefix) { + return; + } + mm.removeMessageListener("debug:actor", onActorCreated); + + // Pipe Debugger message from/to parent/child via the message manager + childTransport = new ChildDebuggerTransport(mm, prefix); + childTransport.hooks = { + // Pipe all the messages from content process actors back to the client + // through the parent process connection. + onPacket: connection.send.bind(connection), + }; + childTransport.ready(); + + connection.setForwarding(prefix, childTransport); + + dumpn(`Start forwarding for frame with prefix ${prefix}`); + + actor = msg.json.actor; + resolve(actor); + }); + + const destroy = DevToolsUtils.makeInfallible(function () { + EventEmitter.off(connection, "closed", destroy); + Services.obs.removeObserver( + onMessageManagerClose, + "message-manager-close" + ); + + // TODO: Remove this deprecated path once it's no longer needed by add-ons. + DevToolsServer.emit("disconnected-from-child:" + connPrefix, { + mm, + prefix: connPrefix, + }); + + if (actor) { + actor = null; + } + + // Notify the tab descriptor about the destruction before the call to + // `cancelForwarding`, so that we notify about the target destruction + // *before* we purge all request for this prefix. + // When we purge the requests, we also destroy all related fronts, + // including the target front. This clears all event listeners + // and ultimately prevent target-destroyed from firing. + if (onDestroy) { + onDestroy(mm); + } + + if (childTransport) { + // If we have a child transport, the actor has already + // been created. We need to stop using this message manager. + childTransport.close(); + childTransport = null; + connection.cancelForwarding(prefix); + + // ... and notify the child process to clean the target-scoped actors. + try { + // Bug 1169643: Ignore any exception as the child process + // may already be destroyed by now. + mm.sendAsyncMessage("debug:disconnect", { prefix }); + } catch (e) { + // Nothing to do + } + } else { + // Otherwise, the frame has been closed before the actor + // had a chance to be created, so we are not able to create + // the actor. + resolve(null); + } + + // Cleanup all listeners + untrackMessageManager(); + }); + + // Listen for various messages and frame events + trackMessageManager(); + + // Listen for app process exit + const onMessageManagerClose = function (subject, topic, data) { + if (subject == mm) { + destroy(); + } + }; + Services.obs.addObserver(onMessageManagerClose, "message-manager-close"); + + // Listen for connection close to cleanup things + // when user unplug the device or we lose the connection somehow. + EventEmitter.on(connection, "closed", destroy); + + mm.sendAsyncMessage("debug:connect", { + prefix, + addonId, + addonBrowsingContextGroupId, + }); + }); +} + +exports.connectToFrame = connectToFrame; |