tor-browser

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

messaging-helpers.js (6840B)


      1 'use strict';
      2 
      3 // This script depends on the following script:
      4 //    /fs/resources/test-helpers.js
      5 //    /service-workers/service-worker/resources/test-helpers.sub.js
      6 
      7 // Define the URL constants used for each type of message target, including
      8 // iframes and workers.
      9 const kDocumentMessageTarget = '../fs/resources/message-target.html';
     10 const kSharedWorkerMessageTarget =
     11    '../fs/resources/message-target-shared-worker.js';
     12 const kServiceWorkerMessageTarget =
     13    '../fs/resources/message-target-service-worker.js';
     14 const kDedicatedWorkerMessageTarget =
     15    '../fs/resources/message-target-dedicated-worker.js';
     16 
     17 function create_dedicated_worker(test, url) {
     18  const dedicated_worker = new Worker(url);
     19  test.add_cleanup(() => {
     20    dedicated_worker.terminate();
     21  });
     22  return dedicated_worker;
     23 }
     24 
     25 async function create_service_worker(test, script_url, scope) {
     26  const registration = await service_worker_unregister_and_register(
     27    test, script_url, scope);
     28  test.add_cleanup(() => {
     29    return registration.unregister();
     30  });
     31  return registration;
     32 }
     33 
     34 // Creates an iframe and waits to receive a message from the iframe.
     35 // Valid |options| include src, srcdoc and sandbox, which mirror the
     36 // corresponding iframe element properties.
     37 async function add_iframe(test, options) {
     38  const iframe = document.createElement('iframe');
     39 
     40  if (options.sandbox !== undefined) {
     41    iframe.sandbox = options.sandbox;
     42  }
     43 
     44  if (options.src !== undefined) {
     45    iframe.src = options.src;
     46  }
     47 
     48  if (options.srcdoc !== undefined) {
     49    iframe.srcdoc = options.srcdoc;
     50  }
     51 
     52  document.body.appendChild(iframe);
     53  test.add_cleanup(() => {
     54    iframe.remove();
     55  });
     56 
     57  await wait_for_loaded_message(self);
     58  return iframe;
     59 }
     60 
     61 // Creates a child window using window.open() and waits to receive a message
     62 // from the child window.
     63 async function open_window(test, url) {
     64  const child_window = window.open(url);
     65  test.add_cleanup(() => {
     66    child_window.close();
     67  });
     68  await wait_for_loaded_message(self);
     69  return child_window;
     70 }
     71 
     72 // Wait until |receiver| gets a message event with the data set to 'LOADED'.
     73 // The postMessage() tests use messaging instead of the loaded event because
     74 // cross-origin child windows from window.open() do not dispatch the loaded
     75 // event to the parent window.
     76 async function wait_for_loaded_message(receiver) {
     77  const message_promise = new Promise((resolve, reject) => {
     78    receiver.addEventListener('message', message_event => {
     79      if (message_event.data === 'LOADED') {
     80        resolve();
     81      } else {
     82        reject('The message target must receive a "LOADED" message response.');
     83      }
     84    });
     85  });
     86  await message_promise;
     87 }
     88 
     89 // Sets up a new message channel. Sends one port to |target| and then returns
     90 // the other port.
     91 function create_message_channel(target, target_origin) {
     92  const message_channel = new MessageChannel();
     93 
     94  const message_data =
     95    { type: 'receive-message-port', message_port: message_channel.port2 };
     96  target.postMessage(
     97    message_data,
     98    {
     99      transfer: [message_channel.port2],
    100      targetOrigin: target_origin
    101    });
    102  message_channel.port1.start();
    103  return message_channel.port1;
    104 }
    105 
    106 // Creates a variety of different FileSystemFileHandles for testing.
    107 async function create_file_system_handles(root) {
    108  // Create some files to use with postMessage().
    109  const empty_file = await createEmptyFile('empty-file', root);
    110  const first_file = await createFileWithContents(
    111      'first-file-with-contents', 'first-text-content', root);
    112  const second_file = await createFileWithContents(
    113      'second-file-with-contents', 'second-text-content', root);
    114 
    115  // Create an empty directory to use with postMessage().
    116  const empty_directory = await createDirectory('empty-directory', root);
    117 
    118  // Create a directory containing both files and subdirectories to use
    119  // with postMessage().
    120  const directory_with_files =
    121      await createDirectory('directory-with-files', root);
    122  await createFileWithContents(
    123      'first-file-in-directory', 'first-directory-text-content',
    124      directory_with_files);
    125  await createFileWithContents(
    126      'second-file-in-directory', 'second-directory-text-content',
    127      directory_with_files);
    128  const subdirectory =
    129      await createDirectory('subdirectory', directory_with_files);
    130  await createFileWithContents(
    131      'first-file-in-subdirectory', 'first-subdirectory-text-content',
    132      subdirectory);
    133 
    134  return [
    135    empty_file,
    136    first_file,
    137    second_file,
    138    // Include the same FileSystemFileHandle twice.
    139    second_file,
    140    empty_directory,
    141    // Include the Same FileSystemDirectoryHandle object twice.
    142    empty_directory,
    143    directory_with_files
    144  ];
    145 }
    146 
    147 // Tests sending an array of FileSystemHandles to |target| with postMessage().
    148 // The array includes both FileSystemFileHandles and FileSystemDirectoryHandles.
    149 // After receiving the message, |target| accesses all cloned handles by
    150 // serializing the properties of each handle to a JavaScript object.
    151 //
    152 // |target| then responds with the resulting array of serialized handles. The
    153 // response also includes the array of cloned handles, which creates more
    154 // clones. After receiving the response, this test runner verifies that both
    155 // the serialized handles and the cloned handles contain the expected properties.
    156 async function do_post_message_test(
    157  test, root_dir, receiver, target, target_origin) {
    158  // Create and send the handles to |target|.
    159  const handles = await create_file_system_handles(root_dir);
    160  target.postMessage(
    161    { type: 'receive-file-system-handles', cloned_handles: handles },
    162    { targetOrigin: target_origin });
    163 
    164  // Wait for |target| to respond with results.
    165  const event_watcher = new EventWatcher(test, receiver, 'message');
    166  const message_event = await event_watcher.wait_for('message');
    167  const response = message_event.data;
    168 
    169  assert_equals(response.type, 'receive-serialized-file-system-handles',
    170    'The test runner must receive a "serialized-file-system-handles" ' +
    171    `message response. Actual response: ${response}`);
    172 
    173  // Verify the results.
    174  const expected_serialized_handles = await serialize_handles(handles);
    175 
    176  assert_equals_serialized_handles(
    177    response.serialized_handles, expected_serialized_handles);
    178 
    179  await assert_equals_cloned_handles(response.cloned_handles, handles);
    180 }
    181 
    182 // Runs the same test as do_post_message_test(), but uses a MessagePort.
    183 // This test starts by establishing a message channel between the test runner
    184 // and |target|. Afterwards, the test sends FileSystemHandles through the
    185 // message port channel.
    186 async function do_message_port_test(test, root_dir, target, target_origin) {
    187  const message_port = create_message_channel(target, target_origin);
    188  await do_post_message_test(
    189      test, root_dir, /*receiver=*/ message_port, /*target=*/ message_port);
    190 }