tor-browser

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

test_forwardingprefix.js (6508B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 /* Exercise prefix-based forwarding of packets to other transports. */
      7 
      8 const { RootActor } = require("resource://devtools/server/actors/root.js");
      9 
     10 var gMainConnection, gMainTransport;
     11 var gSubconnection1, gSubconnection2;
     12 var gClient;
     13 
     14 function run_test() {
     15  DevToolsServer.init();
     16 
     17  add_test(createMainConnection);
     18  add_test(TestNoForwardingYet);
     19  add_test(createSubconnection1);
     20  add_test(TestForwardPrefix1OnlyRoot);
     21  add_test(createSubconnection2);
     22  add_test(TestForwardPrefix12OnlyRoot);
     23  add_test(TestForwardPrefix12WithActor1);
     24  add_test(TestForwardPrefix12WithActor12);
     25  run_next_test();
     26 }
     27 
     28 /*
     29 * Create a pipe connection, and return an object |{ conn, transport }|,
     30 * where |conn| is the new DevToolsServerConnection instance, and
     31 * |transport| is the client side of the transport on which it communicates
     32 * (that is, packets sent on |transport| go to the new connection, and
     33 * |transport|'s hooks receive replies).
     34 *
     35 * |prefix| is optional; if present, it's the prefix (minus the '/') for
     36 * actors in the new connection.
     37 */
     38 function newConnection(prefix) {
     39  let conn;
     40  DevToolsServer.createRootActor = function (connection) {
     41    conn = connection;
     42    return new RootActor(connection, {});
     43  };
     44 
     45  const transport = DevToolsServer.connectPipe(prefix);
     46 
     47  return { conn, transport };
     48 }
     49 
     50 /* Create the main connection for these tests. */
     51 function createMainConnection() {
     52  ({ conn: gMainConnection, transport: gMainTransport } = newConnection());
     53  gClient = new DevToolsClient(gMainTransport);
     54  gClient.connect().then(() => run_next_test());
     55 }
     56 
     57 /*
     58 * Exchange 'echo' messages with five actors:
     59 * - root
     60 * - prefix1/root
     61 * - prefix1/actor
     62 * - prefix2/root
     63 * - prefix2/actor
     64 *
     65 * Expect proper echos from those named in |reachables|, and 'noSuchActor'
     66 * errors from the others. When we've gotten all our replies (errors or
     67 * otherwise), call |completed|.
     68 *
     69 * To avoid deep stacks, we call completed from the next tick.
     70 */
     71 async function tryActors(reachables, completed) {
     72  for (const actor of [
     73    "root",
     74    "prefix1/root",
     75    "prefix1/actor",
     76    "prefix2/root",
     77    "prefix2/actor",
     78  ]) {
     79    let response;
     80    try {
     81      if (actor.endsWith("root")) {
     82        // Root actor doesn't expose any echo method,
     83        // so fallback on getRoot which returns `{ from: "root" }`.
     84        // For the top level root actor, we have to use its front.
     85        if (actor == "root") {
     86          response = await gClient.mainRoot.getRoot();
     87        } else {
     88          response = await gClient.request({ to: actor, type: "getRoot" });
     89        }
     90      } else {
     91        response = await gClient.request({
     92          to: actor,
     93          type: "echo",
     94          value: "tango",
     95        });
     96      }
     97    } catch (e) {
     98      response = e;
     99    }
    100    if (reachables.has(actor)) {
    101      if (actor.endsWith("root")) {
    102        // RootActor's getRoot response is almost empty on xpcshell
    103        Assert.deepEqual({ from: actor }, response);
    104      } else {
    105        Assert.deepEqual(
    106          { from: actor, to: actor, type: "echo", value: "tango" },
    107          response
    108        );
    109      }
    110    } else {
    111      Assert.deepEqual(
    112        {
    113          from: actor,
    114          error: "noSuchActor",
    115          message: "No such actor for ID: " + actor,
    116        },
    117        response
    118      );
    119    }
    120  }
    121  executeSoon(completed, "tryActors callback " + completed.name);
    122 }
    123 
    124 /*
    125 * With no forwarding established, sending messages to root should work,
    126 * but sending messages to prefixed actor names, or anyone else, should get
    127 * an error.
    128 */
    129 function TestNoForwardingYet() {
    130  tryActors(new Set(["root"]), run_next_test);
    131 }
    132 
    133 /*
    134 * Create a new pipe connection which forwards its reply packets to
    135 * gMainConnection's client, and to which gMainConnection forwards packets
    136 * directed to actors whose names begin with |prefix + '/'|, and.
    137 *
    138 * Return an object { conn, transport }, as for newConnection.
    139 */
    140 function newSubconnection(prefix) {
    141  const { conn, transport } = newConnection(prefix);
    142  transport.hooks = {
    143    onPacket: packet => gMainConnection.send(packet),
    144  };
    145  gMainConnection.setForwarding(prefix, transport);
    146 
    147  return { conn, transport };
    148 }
    149 
    150 /* Create a second root actor, to which we can forward things. */
    151 function createSubconnection1() {
    152  const { conn, transport } = newSubconnection("prefix1");
    153  gSubconnection1 = conn;
    154  transport.ready();
    155  gClient.expectReply("prefix1/root", () => run_next_test());
    156 }
    157 
    158 // Establish forwarding, but don't put any actors in that server.
    159 function TestForwardPrefix1OnlyRoot() {
    160  tryActors(new Set(["root", "prefix1/root"]), run_next_test);
    161 }
    162 
    163 /* Create a third root actor, to which we can forward things. */
    164 function createSubconnection2() {
    165  const { conn, transport } = newSubconnection("prefix2");
    166  gSubconnection2 = conn;
    167  transport.ready();
    168  gClient.expectReply("prefix2/root", () => run_next_test());
    169 }
    170 
    171 function TestForwardPrefix12OnlyRoot() {
    172  tryActors(new Set(["root", "prefix1/root", "prefix2/root"]), run_next_test);
    173 }
    174 
    175 // A dumb actor that implements 'echo'.
    176 //
    177 // It's okay that both subconnections' actors behave identically, because
    178 // the reply-sending code attaches the replying actor's name to the packet,
    179 // so simply matching the 'from' field in the reply ensures that we heard
    180 // from the right actor.
    181 const { Actor } = require("resource://devtools/shared/protocol/Actor.js");
    182 class EchoActor extends Actor {
    183  constructor(conn) {
    184    super(conn, { typeName: "EchoActor", methods: [] });
    185 
    186    this.requestTypes = {
    187      echo: EchoActor.prototype.onEcho,
    188    };
    189  }
    190 
    191  onEcho(request) {
    192    /*
    193     * Request packets are frozen. Copy request, so that
    194     * DevToolsServerConnection.onPacket can attach a 'from' property.
    195     */
    196    return JSON.parse(JSON.stringify(request));
    197  }
    198 }
    199 
    200 function TestForwardPrefix12WithActor1() {
    201  const actor = new EchoActor(gSubconnection1);
    202  actor.actorID = "prefix1/actor";
    203  gSubconnection1.addActor(actor);
    204 
    205  tryActors(
    206    new Set(["root", "prefix1/root", "prefix1/actor", "prefix2/root"]),
    207    run_next_test
    208  );
    209 }
    210 
    211 function TestForwardPrefix12WithActor12() {
    212  const actor = new EchoActor(gSubconnection2);
    213  actor.actorID = "prefix2/actor";
    214  gSubconnection2.addActor(actor);
    215 
    216  tryActors(
    217    new Set([
    218      "root",
    219      "prefix1/root",
    220      "prefix1/actor",
    221      "prefix2/root",
    222      "prefix2/actor",
    223    ]),
    224    run_next_test
    225  );
    226 }