tor-browser

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

commands-from-url.js (5333B)


      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 const {
      8  DevToolsServer,
      9 } = require("resource://devtools/server/devtools-server.js");
     10 const {
     11  DevToolsClient,
     12 } = require("resource://devtools/client/devtools-client.js");
     13 const {
     14  remoteClientManager,
     15 } = require("resource://devtools/client/shared/remote-debugging/remote-client-manager.js");
     16 const {
     17  CommandsFactory,
     18 } = require("resource://devtools/shared/commands/commands-factory.js");
     19 
     20 /**
     21 * Construct a commands object for a given URL with various query parameters:
     22 *
     23 * - host, port & ws: See the documentation for clientFromURL
     24 *
     25 * - type: "tab", "extension", "worker" or "process"
     26 *      {String} The type of target to connect to.
     27 *
     28 * If type == "tab":
     29 * - id:
     30 *      {Number} the tab browserId
     31 *
     32 * If type == "extension":
     33 * - id:
     34 *      {String} the addonID of the webextension to debug.
     35 *
     36 * If type == "worker":
     37 * - id:
     38 *      {String} the unique Worker id of the Worker to debug.
     39 *
     40 * If type == "process":
     41 * - id:
     42 *      {Number} the process id to debug. Default to 0, which is the parent process.
     43 *
     44 * @param {URL} url
     45 *        The url to fetch query params from.
     46 *
     47 * @return A commands object
     48 */
     49 exports.commandsFromURL = async function commandsFromURL(url) {
     50  const client = await clientFromURL(url);
     51  const params = url.searchParams;
     52 
     53  // Clients retrieved from the remote-client-manager are already connected.
     54  const isCachedClient = params.get("remoteId");
     55  if (!isCachedClient) {
     56    // Connect any other client.
     57    await client.connect();
     58  }
     59 
     60  const id = params.get("id");
     61  const type = params.get("type");
     62 
     63  let commands;
     64  try {
     65    commands = await _commandsFromURL(client, id, type);
     66  } catch (e) {
     67    if (!isCachedClient) {
     68      // If the client was not cached, then the client was created here. If the target
     69      // creation failed, we should close the client.
     70      await client.close();
     71    }
     72    throw e;
     73  }
     74 
     75  // When opening about:debugging's toolboxes for remote runtimes,
     76  // we create a new commands using a shared and cached client.
     77  // Prevent closing the DevToolsClient on toolbox close and Commands destruction
     78  // as this can be used by about:debugging and other toolboxes.
     79  if (isCachedClient) {
     80    commands.shouldCloseClient = false;
     81  }
     82 
     83  return commands;
     84 };
     85 
     86 async function _commandsFromURL(client, id, type) {
     87  if (!type) {
     88    throw new Error("commandsFromURL, missing type parameter");
     89  }
     90 
     91  let commands;
     92  if (type === "tab") {
     93    // Fetch target for a remote tab
     94    id = parseInt(id, 10);
     95    if (isNaN(id)) {
     96      throw new Error(
     97        `commandsFromURL, wrong tab id '${id}', should be a number`
     98      );
     99    }
    100    try {
    101      commands = await CommandsFactory.forRemoteTab(id, { client });
    102    } catch (ex) {
    103      if (ex.message.startsWith("Protocol error (noTab)")) {
    104        throw new Error(
    105          `commandsFromURL, tab with browserId '${id}' doesn't exist`
    106        );
    107      }
    108      throw ex;
    109    }
    110  } else if (type === "extension") {
    111    commands = await CommandsFactory.forAddon(id, { client });
    112 
    113    if (!commands) {
    114      throw new Error(
    115        `commandsFromURL, extension with id '${id}' doesn't exist`
    116      );
    117    }
    118  } else if (type === "worker") {
    119    commands = await CommandsFactory.forWorker(id, { client });
    120 
    121    if (!commands) {
    122      throw new Error(`commandsFromURL, worker with id '${id}' doesn't exist`);
    123    }
    124  } else if (type == "process") {
    125    // When debugging firefox itself, force the server to accept debugging processes.
    126    DevToolsServer.allowChromeProcess = true;
    127    commands = await CommandsFactory.forMainProcess({ client });
    128  } else {
    129    throw new Error(`commandsFromURL, unsupported type '${type}' parameter`);
    130  }
    131 
    132  return commands;
    133 }
    134 
    135 /**
    136 * Create a DevToolsClient for a given URL object having various query parameters:
    137 *
    138 * host:
    139 *    {String} The hostname or IP address to connect to.
    140 * port:
    141 *    {Number} The TCP port to connect to, to use with `host` argument.
    142 * remoteId:
    143 *    {String} Remote client id, for runtimes from the remote-client-manager
    144 * ws:
    145 *    {Boolean} If true, connect via websocket instead of regular TCP connection.
    146 *
    147 * @param {URL} url
    148 *        The url to fetch query params from.
    149 * @return a promise that resolves a DevToolsClient object
    150 */
    151 async function clientFromURL(url) {
    152  const params = url.searchParams;
    153 
    154  // If a remote id was provided we should already have a connected client available.
    155  const remoteId = params.get("remoteId");
    156  if (remoteId) {
    157    const client = remoteClientManager.getClientByRemoteId(remoteId);
    158    if (!client) {
    159      throw new Error(`Could not find client with remote id: ${remoteId}`);
    160    }
    161    return client;
    162  }
    163 
    164  const host = params.get("host");
    165  const port = params.get("port");
    166  const webSocket = !!params.get("ws");
    167 
    168  let transport;
    169  if (port) {
    170    transport = await DevToolsClient.socketConnect({ host, port, webSocket });
    171  } else {
    172    // Setup a server if we don't have one already running
    173    DevToolsServer.init();
    174    DevToolsServer.registerAllActors();
    175    transport = DevToolsServer.connectPipe();
    176  }
    177  return new DevToolsClient(transport);
    178 }