tor-browser

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

browser_events_module.js (9598B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 const { RootMessageHandlerRegistry } = ChromeUtils.importESModule(
      7  "chrome://remote/content/shared/messagehandler/RootMessageHandlerRegistry.sys.mjs"
      8 );
      9 const { RootMessageHandler } = ChromeUtils.importESModule(
     10  "chrome://remote/content/shared/messagehandler/RootMessageHandler.sys.mjs"
     11 );
     12 
     13 /**
     14 * Emit an event from a WindowGlobal module triggered by a specific command.
     15 * Check that the event is emitted on the RootMessageHandler as well as on
     16 * the parent process MessageHandlerRegistry.
     17 */
     18 add_task(async function test_event() {
     19  const tab = BrowserTestUtils.addTab(
     20    gBrowser,
     21    "https://example.com/document-builder.sjs?html=tab"
     22  );
     23  await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
     24  const browsingContext = tab.linkedBrowser.browsingContext;
     25 
     26  const rootMessageHandler = createRootMessageHandler("session-id-event");
     27  let messageHandlerEvent;
     28  let registryEvent;
     29 
     30  // Events are emitted both as generic message-handler-event events as well
     31  // as under their own name. We expect to receive the event for both.
     32  const _onMessageHandlerEvent = (eventName, eventData) => {
     33    if (eventData.name === "event-from-window-global") {
     34      messageHandlerEvent = eventData;
     35    }
     36  };
     37  rootMessageHandler.on("message-handler-event", _onMessageHandlerEvent);
     38  const onNamedEvent = rootMessageHandler.once("event-from-window-global");
     39  // MessageHandlerRegistry should forward all the message-handler-events.
     40  const _onMessageHandlerRegistryEvent = (eventName, eventData) => {
     41    if (eventData.name === "event-from-window-global") {
     42      registryEvent = eventData;
     43    }
     44  };
     45  RootMessageHandlerRegistry.on(
     46    "message-handler-registry-event",
     47    _onMessageHandlerRegistryEvent
     48  );
     49 
     50  callTestEmitEvent(rootMessageHandler, browsingContext.id);
     51 
     52  const namedEvent = await onNamedEvent;
     53  is(
     54    namedEvent.text,
     55    `event from ${browsingContext.id}`,
     56    "Received the expected payload"
     57  );
     58 
     59  is(
     60    messageHandlerEvent.name,
     61    "event-from-window-global",
     62    "Received event on the ROOT MessageHandler"
     63  );
     64  is(
     65    messageHandlerEvent.data.text,
     66    `event from ${browsingContext.id}`,
     67    "Received the expected payload"
     68  );
     69 
     70  is(
     71    registryEvent,
     72    messageHandlerEvent,
     73    "The event forwarded by the MessageHandlerRegistry is identical to the MessageHandler event"
     74  );
     75  rootMessageHandler.off("message-handler-event", _onMessageHandlerEvent);
     76  RootMessageHandlerRegistry.off(
     77    "message-handler-registry-event",
     78    _onMessageHandlerRegistryEvent
     79  );
     80  rootMessageHandler.destroy();
     81  gBrowser.removeTab(tab);
     82 });
     83 
     84 /**
     85 * Emit an event from a Root module triggered by a specific command.
     86 * Check that the event is emitted on the RootMessageHandler.
     87 */
     88 add_task(async function test_root_event() {
     89  const rootMessageHandler = createRootMessageHandler("session-id-root_event");
     90 
     91  // events are emitted both as generic message-handler-event events as
     92  // well as under their own name. We expect to receive the event for both.
     93  const onHandlerEvent = rootMessageHandler.once("message-handler-event");
     94  const onNamedEvent = rootMessageHandler.once("event-from-root");
     95 
     96  rootMessageHandler.handleCommand({
     97    moduleName: "event",
     98    commandName: "testEmitRootEvent",
     99    destination: {
    100      type: RootMessageHandler.type,
    101    },
    102  });
    103 
    104  const { name, data } = await onHandlerEvent;
    105  is(name, "event-from-root", "Received event on the ROOT MessageHandler");
    106  is(data.text, "event from root", "Received the expected payload");
    107 
    108  const namedEvent = await onNamedEvent;
    109  is(namedEvent.text, "event from root", "Received the expected payload");
    110 
    111  rootMessageHandler.destroy();
    112 });
    113 
    114 /**
    115 * Emit an event from a windowglobal-in-root module triggered by a specific command.
    116 * Check that the event is emitted on the RootMessageHandler.
    117 */
    118 add_task(async function test_windowglobal_in_root_event() {
    119  const tab = BrowserTestUtils.addTab(
    120    gBrowser,
    121    "https://example.com/document-builder.sjs?html=tab"
    122  );
    123  await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
    124  const browsingContext = tab.linkedBrowser.browsingContext;
    125 
    126  const rootMessageHandler = createRootMessageHandler(
    127    "session-id-windowglobal_in_root_event"
    128  );
    129 
    130  // events are emitted both as generic message-handler-event events as
    131  // well as under their own name. We expect to receive the event for both.
    132  const onHandlerEvent = rootMessageHandler.once("message-handler-event");
    133  const onNamedEvent = rootMessageHandler.once(
    134    "event-from-window-global-in-root"
    135  );
    136  rootMessageHandler.handleCommand({
    137    moduleName: "event",
    138    commandName: "testEmitWindowGlobalInRootEvent",
    139    destination: {
    140      type: WindowGlobalMessageHandler.type,
    141      id: browsingContext.id,
    142    },
    143  });
    144 
    145  const { name, data } = await onHandlerEvent;
    146  is(
    147    name,
    148    "event-from-window-global-in-root",
    149    "Received event on the ROOT MessageHandler"
    150  );
    151  is(
    152    data.text,
    153    `windowglobal-in-root event for ${browsingContext.id}`,
    154    "Received the expected payload"
    155  );
    156 
    157  const namedEvent = await onNamedEvent;
    158  is(
    159    namedEvent.text,
    160    `windowglobal-in-root event for ${browsingContext.id}`,
    161    "Received the expected payload"
    162  );
    163 
    164  rootMessageHandler.destroy();
    165  gBrowser.removeTab(tab);
    166 });
    167 
    168 /**
    169 * Emit an event from a windowglobal module, but from 2 different sessions.
    170 * Check that the event is emitted by the corresponding RootMessageHandler as
    171 * well as by the parent process MessageHandlerRegistry.
    172 */
    173 add_task(async function test_event_multisession() {
    174  const tab = BrowserTestUtils.addTab(
    175    gBrowser,
    176    "https://example.com/document-builder.sjs?html=tab"
    177  );
    178  await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
    179  const browsingContextId = tab.linkedBrowser.browsingContext.id;
    180 
    181  const root1 = createRootMessageHandler("session-id-event_multisession-1");
    182  let root1Events = 0;
    183  const onRoot1Event = function (evtName, wrappedEvt) {
    184    if (wrappedEvt.name === "event-from-window-global") {
    185      root1Events++;
    186    }
    187  };
    188  root1.on("message-handler-event", onRoot1Event);
    189 
    190  const root2 = createRootMessageHandler("session-id-event_multisession-2");
    191  let root2Events = 0;
    192  const onRoot2Event = function (evtName, wrappedEvt) {
    193    if (wrappedEvt.name === "event-from-window-global") {
    194      root2Events++;
    195    }
    196  };
    197  root2.on("message-handler-event", onRoot2Event);
    198 
    199  let registryEvents = 0;
    200  const onRegistryEvent = function (evtName, wrappedEvt) {
    201    if (wrappedEvt.name === "event-from-window-global") {
    202      registryEvents++;
    203    }
    204  };
    205  RootMessageHandlerRegistry.on(
    206    "message-handler-registry-event",
    207    onRegistryEvent
    208  );
    209 
    210  callTestEmitEvent(root1, browsingContextId);
    211  callTestEmitEvent(root2, browsingContextId);
    212 
    213  info("Wait for root1 event to be received");
    214  await TestUtils.waitForCondition(() => root1Events === 1);
    215  info("Wait for root2 event to be received");
    216  await TestUtils.waitForCondition(() => root2Events === 1);
    217 
    218  await TestUtils.waitForTick();
    219  is(root1Events, 1, "Session 1 only received 1 event");
    220  is(root2Events, 1, "Session 2 only received 1 event");
    221  is(
    222    registryEvents,
    223    2,
    224    "MessageHandlerRegistry forwarded events from both sessions"
    225  );
    226 
    227  root1.off("message-handler-event", onRoot1Event);
    228  root2.off("message-handler-event", onRoot2Event);
    229  RootMessageHandlerRegistry.off(
    230    "message-handler-registry-event",
    231    onRegistryEvent
    232  );
    233  root1.destroy();
    234  root2.destroy();
    235  gBrowser.removeTab(tab);
    236 });
    237 
    238 /**
    239 * Test that events can be emitted from individual frame contexts and that
    240 * events going through a shared content process MessageHandlerRegistry are not
    241 * duplicated.
    242 */
    243 add_task(async function test_event_with_frames() {
    244  info("Navigate the initial tab to the test URL");
    245  const tab = gBrowser.selectedTab;
    246  await loadURL(tab.linkedBrowser, createTestMarkupWithFrames());
    247 
    248  const contexts =
    249    tab.linkedBrowser.browsingContext.getAllBrowsingContextsInSubtree();
    250  is(contexts.length, 4, "Test tab has 3 children contexts (4 in total)");
    251 
    252  const rootMessageHandler = createRootMessageHandler(
    253    "session-id-event_with_frames"
    254  );
    255 
    256  const rootEvents = [];
    257  const onRootEvent = function (evtName, wrappedEvt) {
    258    if (wrappedEvt.name === "event-from-window-global") {
    259      rootEvents.push(wrappedEvt.data.text);
    260    }
    261  };
    262  rootMessageHandler.on("message-handler-event", onRootEvent);
    263 
    264  const namedEvents = [];
    265  const onNamedEvent = (name, event) => namedEvents.push(event.text);
    266  rootMessageHandler.on("event-from-window-global", onNamedEvent);
    267 
    268  for (const context of contexts) {
    269    callTestEmitEvent(rootMessageHandler, context.id);
    270    info("Wait for root event to be received in both event arrays");
    271    await TestUtils.waitForCondition(() =>
    272      [namedEvents, rootEvents].every(events =>
    273        events.includes(`event from ${context.id}`)
    274      )
    275    );
    276  }
    277 
    278  info("Wait for a bit and check that we did not receive duplicated events");
    279  await TestUtils.waitForTick();
    280  is(rootEvents.length, 4, "Only received 4 events");
    281 
    282  rootMessageHandler.off("message-handler-event", onRootEvent);
    283  rootMessageHandler.off("event-from-window-global", onNamedEvent);
    284  rootMessageHandler.destroy();
    285 });
    286 
    287 function callTestEmitEvent(rootMessageHandler, browsingContextId) {
    288  rootMessageHandler.handleCommand({
    289    moduleName: "event",
    290    commandName: "testEmitEvent",
    291    destination: {
    292      type: WindowGlobalMessageHandler.type,
    293      id: browsingContextId,
    294    },
    295  });
    296 }