tor-browser

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

protocol-handler-unregister.https.html (5357B)


      1 <!DOCTYPE html>
      2 <meta name="timeout" content="long">
      3 <script src="/resources/testharness.js"></script>
      4 <script src="/resources/testharnessreport.js"></script>
      5 <script src="/resources/testdriver.js"></script>
      6 <script src="/resources/testdriver-vendor.js"></script>
      7 <script src="/common/utils.js"></script>
      8 <script src="/common/dispatcher/dispatcher.js"></script>
      9 <script src="../resources/utils.js"></script>
     10 <script src="resources/utils.js"></script>
     11 <script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script>
     12 
     13 <script>
     14 
     15 function getNextWindowMessageFromFrame(frame) {
     16  return new Promise(resolve => {
     17    window.addEventListener('message', event => {
     18      if (event.source === frame.contentWindow) {
     19        resolve(event.data);
     20      }
     21    });
     22  });
     23 }
     24 
     25 function getNextMessageFromServiceWorker(serviceWorker) {
     26  return new Promise(resolve => {
     27    serviceWorker.addEventListener('message', event => {
     28      resolve(event.data);
     29    }, {once: true});
     30  });
     31 }
     32 
     33 promise_setup(async () => {
     34  assertSpeculationRulesIsSupported()
     35  await test_driver.set_rph_registration_mode('autoAccept');
     36  await test_driver.bless('handler registration');
     37 });
     38 
     39 // The overall idea for this test is:
     40 // 1. Register a protocol handler for a custom URI scheme.
     41 // 2. Create a prerendered page that unregisters the protocol handler.
     42 // 3. Navigate an iframe to the custom URI scheme. It should navigate
     43 // successfully.
     44 // 4. Activate the prerendered page. This should run the deferred unregistration
     45 // work.
     46 // 5. Navigate the iframe to the custom URI scheme again. It should fail to
     47 // navigate.
     48 // To detect the navigation failure, we use a service worker to perform the
     49 // navigation via client.navigate and report the result back to
     50 // the test. This is because the service worker's client.navigate method
     51 // actually reports if the navigation failed, unlike other mechanisms which
     52 // tell us nothing in this case.
     53 promise_test(async t => {
     54  const customUrlScheme = 'web+wptrphtest';
     55  function getProtocolHandlerUrlTemplate(id) {
     56    return new URL(
     57        `resources/protocol-handler.html?id=${id}&s=%s`, location.href).href;
     58  }
     59 
     60  const urlTemplate = getProtocolHandlerUrlTemplate('unregister');
     61 
     62  t.add_cleanup(() => {
     63    navigator.unregisterProtocolHandler(
     64        customUrlScheme, urlTemplate);
     65  });
     66  navigator.registerProtocolHandler(customUrlScheme, urlTemplate);
     67 
     68  const {exec, activate} = await create_prerendered_page(t);
     69 
     70  const result = await exec(
     71      (customUrlScheme, urlTemplate) => {
     72        try {
     73          navigator.unregisterProtocolHandler(
     74              customUrlScheme, urlTemplate);
     75        } catch (registerProtocolHandlerException) {
     76          return 'registerProtocolHandler failed with \'' +
     77              registerProtocolHandlerException.name + '\'';
     78        }
     79        return 'success';
     80  }, [customUrlScheme, urlTemplate]);
     81  assert_equals(result, 'success', 'unregisterProtocolHandler should succeed.');
     82 
     83  const frame1 = await with_iframe('about:blank');
     84 
     85  const frame1MessagePromise = getNextWindowMessageFromFrame(frame1);
     86  frame1.src = `${customUrlScheme}:1`;
     87  assert_equals((await frame1MessagePromise).id, 'unregister',
     88    'Until activation, the initial handler should be registered.');
     89 
     90  frame1.remove();
     91 
     92  // Activate the prerendered page.
     93  await activate();
     94 
     95  // At this point the deferred unregistration work has run during activation
     96  // and the protocol handler is no longer registered.
     97  // We use Service Worker client.navigate to detect the failed navigation since
     98  // it is well supported and reliably reports error for unknown URL schemes.
     99  const serviceWorkerScope =
    100      'resources/protocol-handler.html?service_worker_client';
    101  const frame2Url = serviceWorkerScope + '&id=communication';
    102  const frame3Url = serviceWorkerScope + '&id=nav_target';
    103  const serviceWorkerUrl = 'resources/protocol-handler-service-worker.js';
    104  const serviceWorkerRegistration =
    105      await service_worker_unregister_and_register(
    106          t, serviceWorkerUrl, serviceWorkerScope);
    107 
    108  t.add_cleanup(async () => {
    109    await serviceWorkerRegistration.unregister();
    110  });
    111 
    112  await wait_for_state(t, serviceWorkerRegistration.installing, 'activated');
    113 
    114  // We use frame2 to communicate with the service worker.
    115  const frame2 = await with_iframe(frame2Url);
    116 
    117  // Frame3 is used by the service worker to attempt navigation.
    118  const frame3 = await with_iframe(frame3Url);
    119 
    120  const serviceWorkerMessagePromise = getNextMessageFromServiceWorker(
    121      frame2.contentWindow.navigator.serviceWorker);
    122 
    123  // Post message via frame2 to the service worker to tell it to navigate frame3
    124  // to the custom URI.
    125  frame2.contentWindow.navigator.serviceWorker.controller.postMessage(
    126      {clientUrlMatch: new URL(frame3Url, location.href).href,
    127       navigationUrl: `${customUrlScheme}:3`});
    128 
    129  // The service worker will post message back the result of the navigation.
    130  const navigationResult = await serviceWorkerMessagePromise;
    131 
    132  frame2.remove();
    133  frame3.remove();
    134 
    135  assert_false(navigationResult.success, 'Navigation to unregistered URI should fail');
    136  assert_equals(navigationResult.message, 'navigate failure: TypeError',
    137      'unregisterProtocolHandler should have completed.');
    138 }, 'prerendering page unregisterProtocolHandler call defers registration until activation.');
    139 
    140 </script>