tor-browser

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

helper_service_workers_navigation.js (3804B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 /* import-globals-from head.js */
      7 
      8 /* exported setupServiceWorkerNavigationTest */
      9 async function setupServiceWorkerNavigationTest() {
     10  // Disable the preloaded process as it creates processes intermittently
     11  // which forces the emission of RDP requests we aren't correctly waiting for.
     12  await pushPref("dom.ipc.processPrelaunch.enabled", false);
     13 }
     14 
     15 /* exported watchServiceWorkerTargets */
     16 async function watchServiceWorkerTargets(tab) {
     17  info("Create a target list for a tab target");
     18  const commands = await CommandsFactory.forTab(tab);
     19  const targetCommand = commands.targetCommand;
     20 
     21  // Enable Service Worker listening.
     22  targetCommand.listenForServiceWorkers = true;
     23  await targetCommand.startListening();
     24 
     25  // Setup onAvailable & onDestroyed callbacks so that we can check how many
     26  // times they are called and with which targetFront.
     27  const hooks = {
     28    availableCount: 0,
     29    destroyedCount: 0,
     30    targets: [],
     31  };
     32 
     33  const onAvailable = async ({ targetFront }) => {
     34    info(` + Service worker target available for ${targetFront.url}\n`);
     35    hooks.availableCount++;
     36    hooks.targets.push(targetFront);
     37  };
     38 
     39  const onDestroyed = ({ targetFront }) => {
     40    info(` - Service worker target destroy for ${targetFront.url}\n`);
     41    hooks.destroyedCount++;
     42    hooks.targets.splice(hooks.targets.indexOf(targetFront), 1);
     43  };
     44 
     45  await targetCommand.watchTargets({
     46    types: [targetCommand.TYPES.SERVICE_WORKER],
     47    onAvailable,
     48    onDestroyed,
     49  });
     50 
     51  return { hooks, commands, targetCommand };
     52 }
     53 
     54 /**
     55 * Wait until the expected URL is loaded and win.registration has resolved.
     56 */
     57 /* exported waitForRegistrationReady */
     58 async function waitForRegistrationReady(tab, expectedPageUrl, workerUrl) {
     59  await asyncWaitUntil(() =>
     60    SpecialPowers.spawn(
     61      tab.linkedBrowser,
     62      [expectedPageUrl],
     63      async function (_url) {
     64        try {
     65          const win = content.wrappedJSObject;
     66          const isExpectedUrl = win.location.href === _url;
     67          const hasRegistration = !!(await win.registrationPromise);
     68          return isExpectedUrl && hasRegistration;
     69        } catch (e) {
     70          return false;
     71        }
     72      }
     73    )
     74  );
     75  // On debug builds, the registration may not be yet ready in the parent process
     76  // so we also need to ensure it is ready.
     77  const swm = Cc["@mozilla.org/serviceworkers/manager;1"].getService(
     78    Ci.nsIServiceWorkerManager
     79  );
     80  await waitFor(() => {
     81    // Unfortunately we can't use swm.getRegistrationByPrincipal, as it requires a "scope", which doesn't seem to be the worker URL.
     82    const registrations = swm.getAllRegistrations();
     83    for (let i = 0; i < registrations.length; i++) {
     84      const info = registrations.queryElementAt(
     85        i,
     86        Ci.nsIServiceWorkerRegistrationInfo
     87      );
     88      // Lookup for an exact URL match.
     89      if (info.scriptSpec === workerUrl) {
     90        return true;
     91      }
     92    }
     93    return false;
     94  });
     95 }
     96 
     97 /**
     98 * Assert helper for the `hooks` object, updated by the onAvailable and
     99 * onDestroyed callbacks. Assert that the callbacks have been called the
    100 * expected number of times, with the expected targets.
    101 */
    102 /* exported checkHooks */
    103 async function checkHooks(hooks, { available, destroyed, targets }) {
    104  await waitUntil(
    105    () => hooks.availableCount == available && hooks.destroyedCount == destroyed
    106  );
    107  is(hooks.availableCount, available, "onAvailable was called as expected");
    108  is(hooks.destroyedCount, destroyed, "onDestroyed was called as expected");
    109 
    110  is(hooks.targets.length, targets.length, "Expected number of targets");
    111  targets.forEach((url, i) => {
    112    is(hooks.targets[i].url, url, `SW target ${i} has the expected url`);
    113  });
    114 }