tor-browser

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

fetch-waits-for-activate.https.html (4692B)


      1 <!DOCTYPE html>
      2 <title>Service Worker: Fetch Event Waits for Activate Event</title>
      3 <meta name=timeout content=long>
      4 <script src="/resources/testharness.js"></script>
      5 <script src="resources/testharness-helpers.js"></script>
      6 <script src="/resources/testharnessreport.js"></script>
      7 <script src="/common/get-host-info.sub.js"></script>
      8 <script src="resources/test-helpers.sub.js"></script>
      9 <body>
     10 <script>
     11 
     12 const worker_url = 'resources/fetch-waits-for-activate-worker.js';
     13 const normalized_worker_url = normalizeURL(worker_url);
     14 const worker_scope = 'resources/fetch-waits-for-activate/';
     15 
     16 // Resolves with the Service Worker's registration once it's reached the
     17 // "activating" state. (The Service Worker should remain "activating" until
     18 // explicitly told advance to the "activated" state).
     19 async function registerAndWaitForActivating(t) {
     20  const registration = await service_worker_unregister_and_register(
     21      t, worker_url, worker_scope);
     22  t.add_cleanup(() => service_worker_unregister(t, worker_scope));
     23 
     24  await wait_for_state(t, registration.installing, 'activating');
     25 
     26  return registration;
     27 }
     28 
     29 // Attempts to ensure that the "Handle Fetch" algorithm has reached the step
     30 //
     31 //   "If activeWorker’s state is "activating", wait for activeWorker’s state to
     32 //    become "activated"."
     33 //
     34 // by waiting for some time to pass.
     35 //
     36 // WARNING: whether the algorithm has reached that step isn't directly
     37 // observable, so this is best effort and can race. Note that this can only
     38 // result in false positives (where the algorithm hasn't reached that step yet
     39 // and any functional events haven't actually been handled by the Service
     40 // Worker).
     41 async function ensureFunctionalEventsAreWaiting(registration) {
     42  await (new Promise(resolve => { setTimeout(resolve, 1000); }));
     43 
     44  assert_equals(registration.active.scriptURL, normalized_worker_url,
     45                'active worker should be present');
     46  assert_equals(registration.active.state, 'activating',
     47                'active worker should be in activating state');
     48 }
     49 
     50 promise_test(async t => {
     51  const registration = await registerAndWaitForActivating(t);
     52 
     53  let frame = null;
     54  t.add_cleanup(() => {
     55    if (frame) {
     56      frame.remove();
     57    }
     58  });
     59 
     60  // This should block until we message the worker to tell it to complete
     61  // the activate event.
     62  const frameLoadPromise = with_iframe(worker_scope).then(function(f) {
     63    frame = f;
     64  });
     65 
     66  await ensureFunctionalEventsAreWaiting(registration);
     67  assert_equals(frame, null, 'frame should not be loaded');
     68 
     69  registration.active.postMessage('ACTIVATE');
     70 
     71  await frameLoadPromise;
     72  assert_equals(frame.contentWindow.navigator.serviceWorker.controller.scriptURL,
     73                normalized_worker_url,
     74                'frame should now be loaded and controlled');
     75  assert_equals(registration.active.state, 'activated',
     76                'active worker should be in activated state');
     77 }, 'Navigation fetch events should wait for the activate event to complete.');
     78 
     79 promise_test(async t => {
     80  const frame = await with_iframe(worker_scope);
     81  t.add_cleanup(() => { frame.remove(); });
     82 
     83  const registration = await registerAndWaitForActivating(t);
     84 
     85  // Make the Service Worker control the frame so the frame can perform an
     86  // intercepted fetch.
     87  await (new Promise(resolve => {
     88    navigator.serviceWorker.onmessage = e => {
     89      assert_equals(
     90        frame.contentWindow.navigator.serviceWorker.controller.scriptURL,
     91        normalized_worker_url, 'frame should be controlled');
     92      resolve();
     93    };
     94 
     95    registration.active.postMessage('CLAIM');
     96  }));
     97 
     98  const fetch_url = `${worker_scope}non/existent/path`;
     99  const expected_fetch_result = 'Hello world';
    100  let fetch_promise_settled = false;
    101 
    102  // This should block until we message the worker to tell it to complete
    103  // the activate event.
    104  const fetchPromise = frame.contentWindow.fetch(fetch_url, {
    105    method: 'POST',
    106    body: expected_fetch_result,
    107  }).then(response => {
    108    fetch_promise_settled = true;
    109    return response;
    110  });
    111 
    112  await ensureFunctionalEventsAreWaiting(registration);
    113  assert_false(fetch_promise_settled,
    114               "fetch()-ing a Service Worker-controlled scope shouldn't have " +
    115               "settled yet");
    116 
    117  registration.active.postMessage('ACTIVATE');
    118 
    119  const response = await fetchPromise;
    120  assert_equals(await response.text(), expected_fetch_result,
    121                "Service Worker should have responded to request to" +
    122                fetch_url)
    123  assert_equals(registration.active.state, 'activated',
    124                'active worker should be in activated state');
    125 }, 'Subresource fetch events should wait for the activate event to complete.');
    126 
    127 </script>
    128 </body>