tor-browser

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

browser_document_rdp_basics.js (5774B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 /**
      5 * Document the basics of RDP packets via a test.
      6 */
      7 
      8 "use strict";
      9 
     10 const TEST_URL = "data:text/html,new-tab";
     11 
     12 add_task(async () => {
     13  // Allow logging all RDP packets
     14  await pushPref("devtools.debugger.log", true);
     15  // Really all of them
     16  await pushPref("devtools.debugger.log.verbose", true);
     17 
     18  // Instantiate a DevTools server
     19  DevToolsServer.init();
     20  DevToolsServer.registerAllActors();
     21 
     22  // Instantiate a client connected to this server
     23  const transport = DevToolsServer.connectPipe();
     24  const client = new DevToolsClient(transport);
     25 
     26  // This will trigger some handshake with the server
     27  await client.connect();
     28 
     29  // Ignore this gross hack, this is to be able to emit raw RDP packet via client.request
     30  // (a Front is instantiated by DevToolsClient which would be confused with us sending
     31  //  RDP packets for the Root actor)
     32  client.mainRoot.destroy();
     33 
     34  // You need to call listTabs once to retrieve the existing list of Tab Descriptor actors...
     35  const { tabs } = await client.request({ to: "root", type: "listTabs" });
     36 
     37  // ... which will let you receive the 'tabListChanged' event.
     38  // This is an empty RDP packet, you need to re-call listTabs to get the full new updated list of actors.
     39  const onTabListUpdated = client.once("tabListChanged");
     40 
     41  // Open a new tab.
     42  await BrowserTestUtils.openNewForegroundTab({
     43    gBrowser,
     44    url: TEST_URL,
     45  });
     46 
     47  await onTabListUpdated;
     48 
     49  // The new list of Tab descriptors should contain the newly opened tab
     50  const { tabs: newTabs } = await client.request({
     51    to: "root",
     52    type: "listTabs",
     53  });
     54  is(newTabs.length, tabs.length + 1);
     55 
     56  const tabDescriptorActor = newTabs.pop();
     57  is(tabDescriptorActor.url, TEST_URL);
     58 
     59  // Query the Tab Descriptor actor to retrieve its related Watcher actor.
     60  // Each Descriptor actor has a dedicated watcher which will be scoped to the context of the descriptor.
     61  // Here the watcher will focus on the related tab.
     62  //
     63  // You want to pass isServerTargetSwitchingEnabled set to true in order to be notified about the top level document,
     64  // as well as navigations to subsequent documents.
     65  const watcherActor = await client.request({
     66    to: tabDescriptorActor.actor,
     67    type: "getWatcher",
     68    isServerTargetSwitchingEnabled: true,
     69  });
     70 
     71  // The call to Watcher Actor's watchTargets will emit target-available-form RDP events.
     72  // One per available target. It will emit one for each immediatly available target,
     73  // but also for any available later. That, until you call unwatchTarget method.
     74  const onTopTargetAvailable = client.once("target-available-form");
     75 
     76  // watchTargets accepts "frame", "process" and "worker"
     77  // When debugging a web page you want to listen to frame and worker targets.
     78  // "frame" would better be named "WindowGlobal" as it will notify you about all the WindowGlobal of the page.
     79  // Each top level documents and any iframe documents will have a related WindowGlobal,
     80  // if any of these documents navigate, a new WindowGlobal will be instantiated.
     81  // If you care about workers, listen to worker targets as well.
     82  await client.request({
     83    to: watcherActor.actor,
     84    type: "watchTargets",
     85    targetType: "frame",
     86  });
     87 
     88  // This is a trivial example so we have a unique WindowGlobal target for the top level document
     89  const { target: topTarget } = await onTopTargetAvailable;
     90  is(topTarget.url, TEST_URL);
     91 
     92  // Similarly to watchTarget, the next call to watchResources will emit new resources right away as well as later.
     93  const onConsoleMessages = client.once("resources-available-array");
     94 
     95  // If you want to observe anything, you have to use Watcher Actor's watchrResources API.
     96  // The list of all available resources is here:
     97  // https://searchfox.org/mozilla-central/source/devtools/server/actors/resources/index.js#9
     98  // And you might have a look at each ResourceWatcher subclass to learn more about the fields exposed by each resource type:
     99  // https://searchfox.org/mozilla-central/source/devtools/server/actors/resources
    100  await client.request({
    101    to: watcherActor.actor,
    102    type: "watchResources",
    103    resourceTypes: ["console-message"],
    104  });
    105 
    106  // You may use many useful actors on each target actor, like console, thread, ...
    107  // You can get the full list of available actors in:
    108  // https://searchfox.org/mozilla-central/source/devtools/server/actors/utils/actor-registry.js#176
    109  // And then look into the mentioned path for implementation.
    110  //
    111  // The "target form" contains the list of all these actor IDs
    112  const webConsoleActorID = topTarget.consoleActor;
    113 
    114  // Call the Console API in order to force emitting a console-message resource
    115  await client.request({
    116    to: webConsoleActorID,
    117    type: "evaluateJSAsync",
    118    text: "console.log('42')",
    119  });
    120 
    121  // Wait for the related console-message resource
    122  const { type, array } = await onConsoleMessages;
    123 
    124  // The resources are encapsulated into a RDP event packet, with an "array" attribute
    125  is(type, "resources-available-array");
    126  is(
    127    array.length,
    128    1,
    129    "The top array has only one array, as only one resourceType is notified"
    130  );
    131  // This array attribute is an array of arrays with two elements each.
    132  // These two elements are a resourceType string and a resources array.
    133  is(array[0].length, 2);
    134  const [resourceType, resources] = array[0];
    135  is(resourceType, "console-message");
    136  is(resources.length, 1, "Received only one console-message resource");
    137  // Note that resources-available-array comes with a "array" attribute which is an array of resources
    138  // which may contain various resource types.
    139  is(resources[0].arguments[0], "42");
    140 
    141  await client.close();
    142 });