tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

frame-connector.js (5266B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 "use strict";
      6 
      7 var DevToolsUtils = require("devtools/shared/DevToolsUtils");
      8 var { dumpn } = DevToolsUtils;
      9 
     10 loader.lazyRequireGetter(
     11  this,
     12  "DevToolsServer",
     13  "resource://devtools/server/devtools-server.js",
     14  true
     15 );
     16 loader.lazyRequireGetter(
     17  this,
     18  "ChildDebuggerTransport",
     19  "resource://devtools/shared/transport/child-transport.js",
     20  true
     21 );
     22 
     23 loader.lazyRequireGetter(
     24  this,
     25  "EventEmitter",
     26  "resource://devtools/shared/event-emitter.js"
     27 );
     28 
     29 /**
     30 * Start a DevTools server in a remote frame's process and add it as a child server for
     31 * an active connection.
     32 *
     33 * @param object connection
     34 *        The devtools server connection to use.
     35 * @param Element frame
     36 *        The frame element with remote content to connect to.
     37 * @param function [onDestroy]
     38 *        Optional function to invoke when the child process closes or the connection
     39 *        shuts down. (Need to forget about the related target actor.)
     40 * @return object
     41 *         A promise object that is resolved once the connection is established.
     42 */
     43 function connectToFrame(connection, frame, onDestroy) {
     44  return new Promise(resolve => {
     45    // Get messageManager from XUL browser (which might be a specialized tunnel for RDM)
     46    // or else fallback to asking the frameLoader itself.
     47    const mm = frame.messageManager || frame.frameLoader.messageManager;
     48    mm.loadFrameScript("resource://devtools/server/startup/frame.js", false);
     49 
     50    const trackMessageManager = () => {
     51      if (!actor) {
     52        mm.addMessageListener("debug:actor", onActorCreated);
     53      }
     54    };
     55 
     56    const untrackMessageManager = () => {
     57      if (!actor) {
     58        mm.removeMessageListener("debug:actor", onActorCreated);
     59      }
     60    };
     61 
     62    let actor, childTransport;
     63    const prefix = connection.allocID("child");
     64    // Compute the same prefix that's used by DevToolsServerConnection
     65    const connPrefix = prefix + "/";
     66 
     67    const onActorCreated = DevToolsUtils.makeInfallible(function (msg) {
     68      if (msg.json.prefix != prefix) {
     69        return;
     70      }
     71      mm.removeMessageListener("debug:actor", onActorCreated);
     72 
     73      // Pipe Debugger message from/to parent/child via the message manager
     74      childTransport = new ChildDebuggerTransport(mm, prefix);
     75      childTransport.hooks = {
     76        // Pipe all the messages from content process actors back to the client
     77        // through the parent process connection.
     78        onPacket: connection.send.bind(connection),
     79      };
     80      childTransport.ready();
     81 
     82      connection.setForwarding(prefix, childTransport);
     83 
     84      dumpn(`Start forwarding for frame with prefix ${prefix}`);
     85 
     86      actor = msg.json.actor;
     87      resolve(actor);
     88    });
     89 
     90    const destroy = DevToolsUtils.makeInfallible(function () {
     91      connection.off("closed", destroy);
     92      Services.obs.removeObserver(
     93        onMessageManagerClose,
     94        "message-manager-close"
     95      );
     96 
     97      // TODO: Remove this deprecated path once it's no longer needed by add-ons.
     98      DevToolsServer.emit("disconnected-from-child:" + connPrefix, {
     99        mm,
    100        prefix: connPrefix,
    101      });
    102 
    103      if (actor) {
    104        actor = null;
    105      }
    106 
    107      // Notify the tab descriptor about the destruction before the call to
    108      // `cancelForwarding`, so that we notify about the target destruction
    109      // *before* we purge all request for this prefix.
    110      // When we purge the requests, we also destroy all related fronts,
    111      // including the target front. This clears all event listeners
    112      // and ultimately prevent target-destroyed from firing.
    113      if (onDestroy) {
    114        onDestroy(mm);
    115      }
    116 
    117      if (childTransport) {
    118        // If we have a child transport, the actor has already
    119        // been created. We need to stop using this message manager.
    120        childTransport.close();
    121        childTransport = null;
    122        connection.cancelForwarding(prefix);
    123 
    124        // ... and notify the child process to clean the target-scoped actors.
    125        try {
    126          // Bug 1169643: Ignore any exception as the child process
    127          // may already be destroyed by now.
    128          mm.sendAsyncMessage("debug:disconnect", { prefix });
    129        } catch (e) {
    130          // Nothing to do
    131        }
    132      } else {
    133        // Otherwise, the frame has been closed before the actor
    134        // had a chance to be created, so we are not able to create
    135        // the actor.
    136        resolve(null);
    137      }
    138 
    139      // Cleanup all listeners
    140      untrackMessageManager();
    141    });
    142 
    143    // Listen for various messages and frame events
    144    trackMessageManager();
    145 
    146    // Listen for app process exit
    147    const onMessageManagerClose = function (subject) {
    148      if (subject == mm) {
    149        destroy();
    150      }
    151    };
    152    Services.obs.addObserver(onMessageManagerClose, "message-manager-close");
    153 
    154    // Listen for connection close to cleanup things
    155    // when user unplug the device or we lose the connection somehow.
    156    connection.on("closed", destroy);
    157 
    158    mm.sendAsyncMessage("debug:connect", {
    159      prefix,
    160    });
    161  });
    162 }
    163 
    164 exports.connectToFrame = connectToFrame;