tor-browser

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

inspector-helpers.js (4557B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 /* exported assertOwnershipTrees, checkMissing, waitForMutation,
      7   isSrcChange, isUnretained, isChildList */
      8 
      9 function serverOwnershipTree(walkerArg) {
     10  return SpecialPowers.spawn(
     11    gBrowser.selectedBrowser,
     12    [[walkerArg.actorID]],
     13    function (actorID) {
     14      const { require } = ChromeUtils.importESModule(
     15        "resource://devtools/shared/loader/Loader.sys.mjs"
     16      );
     17      const {
     18        DevToolsServer,
     19      } = require("resource://devtools/server/devtools-server.js");
     20      const {
     21        DocumentWalker,
     22      } = require("resource://devtools/server/actors/inspector/document-walker.js");
     23 
     24      // Convert actorID to current compartment string otherwise
     25      // searchAllConnectionsForActor is confused and won't find the actor.
     26      actorID = String(actorID);
     27      const serverWalker = DevToolsServer.searchAllConnectionsForActor(actorID);
     28 
     29      function sortOwnershipChildrenContentScript(children) {
     30        return children.sort((a, b) => a.name.localeCompare(b.name));
     31      }
     32 
     33      function serverOwnershipSubtree(walker, node) {
     34        const actor = walker.getNode(node);
     35        if (!actor) {
     36          return undefined;
     37        }
     38 
     39        const children = [];
     40        const docwalker = new DocumentWalker(node, content);
     41        let child = docwalker.firstChild();
     42        while (child) {
     43          const item = serverOwnershipSubtree(walker, child);
     44          if (item) {
     45            children.push(item);
     46          }
     47          child = docwalker.nextSibling();
     48        }
     49        return {
     50          name: actor.actorID,
     51          children: sortOwnershipChildrenContentScript(children),
     52        };
     53      }
     54      return {
     55        root: serverOwnershipSubtree(serverWalker, serverWalker.rootDoc),
     56        orphaned: [...serverWalker._orphaned].map(o =>
     57          serverOwnershipSubtree(serverWalker, o.rawNode)
     58        ),
     59        retained: [...serverWalker._retainedOrphans].map(o =>
     60          serverOwnershipSubtree(serverWalker, o.rawNode)
     61        ),
     62      };
     63    }
     64  );
     65 }
     66 
     67 function sortOwnershipChildren(children) {
     68  return children.sort((a, b) => a.name.localeCompare(b.name));
     69 }
     70 
     71 function clientOwnershipSubtree(node) {
     72  return {
     73    name: node.actorID,
     74    children: sortOwnershipChildren(
     75      node.treeChildren().map(child => clientOwnershipSubtree(child))
     76    ),
     77  };
     78 }
     79 
     80 function clientOwnershipTree(walker) {
     81  return {
     82    root: clientOwnershipSubtree(walker.rootNode),
     83    orphaned: [...walker._orphaned].map(o => clientOwnershipSubtree(o)),
     84    retained: [...walker._retainedOrphans].map(o => clientOwnershipSubtree(o)),
     85  };
     86 }
     87 
     88 function ownershipTreeSize(tree) {
     89  let size = 1;
     90  for (const child of tree.children) {
     91    size += ownershipTreeSize(child);
     92  }
     93  return size;
     94 }
     95 
     96 async function assertOwnershipTrees(walker) {
     97  const serverTree = await serverOwnershipTree(walker);
     98  const clientTree = clientOwnershipTree(walker);
     99  is(
    100    JSON.stringify(clientTree, null, " "),
    101    JSON.stringify(serverTree, null, " "),
    102    "Server and client ownership trees should match."
    103  );
    104 
    105  return ownershipTreeSize(clientTree.root);
    106 }
    107 
    108 // Verify that an actorID is inaccessible both from the client library and the server.
    109 async function checkMissing({ client }, actorID) {
    110  const front = client.getFrontByID(actorID);
    111  ok(
    112    !front,
    113    "Front shouldn't be accessible from the client for actorID: " + actorID
    114  );
    115 
    116  try {
    117    await client.request({
    118      to: actorID,
    119      type: "request",
    120    });
    121    ok(false, "The actor wasn't missing as the request worked");
    122  } catch (e) {
    123    is(
    124      e.error,
    125      "noSuchActor",
    126      "node list actor should no longer be contactable."
    127    );
    128  }
    129 }
    130 
    131 // Load mutations aren't predictable, so keep accumulating mutations until
    132 // the one we're looking for shows up.
    133 function waitForMutation(walker, test, mutations = []) {
    134  return new Promise(resolve => {
    135    for (const change of mutations) {
    136      if (test(change)) {
    137        resolve(mutations);
    138      }
    139    }
    140 
    141    walker.once("mutations", newMutations => {
    142      waitForMutation(walker, test, mutations.concat(newMutations)).then(
    143        finalMutations => {
    144          resolve(finalMutations);
    145        }
    146      );
    147    });
    148  });
    149 }
    150 
    151 function isSrcChange(change) {
    152  return change.type === "attributes" && change.attributeName === "src";
    153 }
    154 
    155 function isUnretained(change) {
    156  return change.type === "unretained";
    157 }
    158 
    159 function isChildList(change) {
    160  return change.type === "childList";
    161 }