tor-browser

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

browser_toolbox_tool_remote_reopen.js (3282B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 const {
      7  DevToolsServer,
      8 } = require("resource://devtools/server/devtools-server.js");
      9 
     10 // Bug 1277805: Too slow for debug runs
     11 requestLongerTimeout(2);
     12 
     13 /**
     14 * Bug 979536: Ensure fronts are destroyed after toolbox close.
     15 *
     16 * The fronts need to be destroyed manually to unbind their onPacket handlers.
     17 *
     18 * When you initialize a front and call |this.manage|, it adds a client actor
     19 * pool that the DevToolsClient uses to route packet replies to that actor.
     20 *
     21 * Most (all?) tools create a new front when they are opened.  When the destroy
     22 * step is skipped and the tool is reopened, a second front is created and also
     23 * added to the client actor pool.  When a packet reply is received, is ends up
     24 * being routed to the first (now unwanted) front that is still in the client
     25 * actor pool.  Since this is not the same front that was used to make the
     26 * request, an error occurs.
     27 *
     28 * This problem does not occur with the toolbox for a local tab because the
     29 * toolbox target creates its own DevToolsClient for the local tab, and the
     30 * client is destroyed when the toolbox is closed, which removes the client
     31 * actor pools, and avoids this issue.
     32 *
     33 * In remote debugging, we do not destroy the DevToolsClient on toolbox close
     34 * because it can still used for other targets.
     35 * Thus, the same client gets reused across multiple toolboxes,
     36 * which leads to the tools failing if they don't destroy their fronts.
     37 */
     38 
     39 function runTools(tab) {
     40  return (async function () {
     41    let toolbox;
     42    const toolIds = await getSupportedToolIds(tab);
     43    for (const toolId of toolIds) {
     44      info("About to open " + toolId);
     45      toolbox = await gDevTools.showToolboxForTab(tab, {
     46        toolId,
     47        hostType: "window",
     48      });
     49      ok(toolbox, "toolbox exists for " + toolId);
     50      is(toolbox.currentToolId, toolId, "currentToolId should be " + toolId);
     51 
     52      const panel = toolbox.getCurrentPanel();
     53      ok(panel, toolId + " panel has been registered in the toolbox");
     54    }
     55 
     56    const client = toolbox.commands.client;
     57    await toolbox.destroy();
     58 
     59    // We need to check the client after the toolbox destruction.
     60    return client;
     61  })();
     62 }
     63 
     64 function test() {
     65  (async function () {
     66    toggleAllTools(true);
     67    const tab = await addTab("about:blank");
     68 
     69    const client = await runTools(tab);
     70 
     71    const rootFronts = [...client.mainRoot.fronts.values()];
     72 
     73    // Actor fronts should be destroyed now that the toolbox has closed, but
     74    // look for any that remain.
     75    for (const pool of client.__pools) {
     76      if (!pool.__poolMap) {
     77        continue;
     78      }
     79 
     80      // Ignore the root fronts, which are top-level pools and aren't released
     81      // on toolbox destroy, but on client close.
     82      if (rootFronts.includes(pool)) {
     83        continue;
     84      }
     85 
     86      for (const actor of pool.__poolMap.keys()) {
     87        // Ignore the root front as it is only release on client close
     88        if (actor == "root") {
     89          continue;
     90        }
     91        ok(false, "Front for " + actor + " still held in pool!");
     92      }
     93    }
     94 
     95    gBrowser.removeCurrentTab();
     96    DevToolsServer.destroy();
     97    toggleAllTools(false);
     98    finish();
     99  })();
    100 }