tor-browser

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

registration-updateviacache.https.html (8105B)


      1 <!DOCTYPE html>
      2 <title>Service Worker: Registration-updateViaCache</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="resources/test-helpers.sub.js"></script>
      8 <script>
      9  const UPDATE_VIA_CACHE_VALUES = [undefined, 'imports', 'all', 'none'];
     10  const SCRIPT_URL = 'resources/update-max-aged-worker.py';
     11  const SCOPE = 'resources/blank.html';
     12 
     13  async function cleanup() {
     14    const reg = await navigator.serviceWorker.getRegistration(SCOPE);
     15    if (!reg) return;
     16    if (reg.scope == new URL(SCOPE, location).href) {
     17      return reg.unregister();
     18    };
     19  }
     20 
     21  function getScriptTimes(sw, testName) {
     22    return new Promise(resolve => {
     23      navigator.serviceWorker.addEventListener('message', function listener(event) {
     24        if (event.data.test !== testName) return;
     25        navigator.serviceWorker.removeEventListener('message', listener);
     26        resolve({
     27          mainTime: event.data.mainTime,
     28          importTime: event.data.importTime
     29        });
     30      });
     31 
     32      sw.postMessage('');
     33    });
     34  }
     35 
     36  // Test creating registrations & triggering an update.
     37  for (const updateViaCache of UPDATE_VIA_CACHE_VALUES) {
     38    const testName = `register-with-updateViaCache-${updateViaCache}`;
     39 
     40    promise_test(async t => {
     41      await cleanup();
     42 
     43      const opts = {scope: SCOPE};
     44 
     45      if (updateViaCache) opts.updateViaCache = updateViaCache;
     46 
     47      const reg = await navigator.serviceWorker.register(
     48        `${SCRIPT_URL}?test=${testName}`,
     49        opts
     50      );
     51 
     52      assert_equals(reg.updateViaCache, updateViaCache || 'imports', "reg.updateViaCache");
     53 
     54      const sw = reg.installing || reg.waiting || reg.active;
     55      await wait_for_state(t, sw, 'activated');
     56      const values = await getScriptTimes(sw, testName);
     57      await reg.update();
     58 
     59      if (updateViaCache == 'all') {
     60        assert_equals(reg.installing, null, "No new service worker");
     61      }
     62      else {
     63        const newWorker = reg.installing;
     64        assert_true(!!newWorker, "New worker installing");
     65        const newValues = await getScriptTimes(newWorker, testName);
     66 
     67        if (!updateViaCache || updateViaCache == 'imports') {
     68          assert_not_equals(values.mainTime, newValues.mainTime, "Main script should have updated");
     69          assert_equals(values.importTime, newValues.importTime, "Imported script should be the same");
     70        }
     71        else if (updateViaCache == 'none') {
     72          assert_not_equals(values.mainTime, newValues.mainTime, "Main script should have updated");
     73          assert_not_equals(values.importTime, newValues.importTime, "Imported script should have updated");
     74        }
     75        else {
     76          // We should have handled all of the possible values for updateViaCache.
     77          // If this runs, something's gone very wrong.
     78          throw Error(`Unexpected updateViaCache value: ${updateViaCache}`);
     79        }
     80      }
     81 
     82      await cleanup();
     83    }, testName);
     84  }
     85 
     86  // Test changing the updateViaCache value of an existing registration.
     87  for (const updateViaCache1 of UPDATE_VIA_CACHE_VALUES) {
     88    for (const updateViaCache2 of UPDATE_VIA_CACHE_VALUES) {
     89      const testName = `register-with-updateViaCache-${updateViaCache1}-then-${updateViaCache2}`;
     90 
     91      promise_test(async t => {
     92        await cleanup();
     93 
     94        const fullScriptUrl = `${SCRIPT_URL}?test=${testName}`;
     95        let opts = {scope: SCOPE};
     96        if (updateViaCache1) opts.updateViaCache = updateViaCache1;
     97 
     98        const reg = await navigator.serviceWorker.register(fullScriptUrl, opts);
     99 
    100        const sw = reg.installing;
    101        await wait_for_state(t, sw, 'activated');
    102        const values = await getScriptTimes(sw, testName);
    103 
    104        const frame = await with_iframe(SCOPE);
    105        const reg_in_frame = await frame.contentWindow.navigator.serviceWorker.getRegistration(normalizeURL(SCOPE));
    106        assert_equals(reg_in_frame.updateViaCache, updateViaCache1 || 'imports', "reg_in_frame.updateViaCache");
    107 
    108        opts = {scope: SCOPE};
    109        if (updateViaCache2) opts.updateViaCache = updateViaCache2;
    110 
    111        await navigator.serviceWorker.register(fullScriptUrl, opts);
    112 
    113        const expected_updateViaCache = updateViaCache2 || 'imports';
    114 
    115        assert_equals(reg.updateViaCache, expected_updateViaCache, "reg.updateViaCache updated");
    116        // If the update happens via the cache, the scripts will come back byte-identical.
    117        // We bypass the byte-identical check if the script URL has changed, but not if
    118        // only the updateViaCache value has changed.
    119        if (updateViaCache2 == 'all') {
    120          assert_equals(reg.installing, null, "No new service worker");
    121        }
    122        // If there's no change to the updateViaCache value, register should be a no-op.
    123        // The default value should behave as 'imports'.
    124        else if ((updateViaCache1 || 'imports') == (updateViaCache2 || 'imports')) {
    125          assert_equals(reg.installing, null, "No new service worker");
    126        }
    127        else {
    128          const newWorker = reg.installing;
    129          assert_true(!!newWorker, "New worker installing");
    130          const newValues = await getScriptTimes(newWorker, testName);
    131 
    132          if (!updateViaCache2 || updateViaCache2 == 'imports') {
    133            assert_not_equals(values.mainTime, newValues.mainTime, "Main script should have updated");
    134            assert_equals(values.importTime, newValues.importTime, "Imported script should be the same");
    135          }
    136          else if (updateViaCache2 == 'none') {
    137            assert_not_equals(values.mainTime, newValues.mainTime, "Main script should have updated");
    138            assert_not_equals(values.importTime, newValues.importTime, "Imported script should have updated");
    139          }
    140          else {
    141            // We should have handled all of the possible values for updateViaCache2.
    142            // If this runs, something's gone very wrong.
    143            throw Error(`Unexpected updateViaCache value: ${updateViaCache}`);
    144          }
    145        }
    146 
    147        // Wait for all registration related tasks on |frame| to complete.
    148        await wait_for_activation_on_sample_scope(t, frame.contentWindow);
    149        // The updateViaCache change should have been propagated to all
    150        // corresponding JS registration objects.
    151        assert_equals(reg_in_frame.updateViaCache, expected_updateViaCache, "reg_in_frame.updateViaCache updated");
    152        frame.remove();
    153 
    154        await cleanup();
    155      }, testName);
    156    }
    157  }
    158 
    159  // Test accessing updateViaCache of an unregistered registration.
    160  for (const updateViaCache of UPDATE_VIA_CACHE_VALUES) {
    161    const testName = `access-updateViaCache-after-unregister-${updateViaCache}`;
    162 
    163    promise_test(async t => {
    164      await cleanup();
    165 
    166      const opts = {scope: SCOPE};
    167 
    168      if (updateViaCache) opts.updateViaCache = updateViaCache;
    169 
    170      const reg = await navigator.serviceWorker.register(
    171        `${SCRIPT_URL}?test=${testName}`,
    172        opts
    173      );
    174 
    175      const expected_updateViaCache = updateViaCache || 'imports';
    176      assert_equals(reg.updateViaCache, expected_updateViaCache, "reg.updateViaCache");
    177 
    178      await reg.unregister();
    179 
    180      // Keep the original value.
    181      assert_equals(reg.updateViaCache, expected_updateViaCache, "reg.updateViaCache");
    182 
    183      await cleanup();
    184    }, testName);
    185  }
    186 
    187  promise_test(async t => {
    188    await cleanup();
    189    t.add_cleanup(cleanup);
    190 
    191    const registration = await navigator.serviceWorker.register(
    192        'resources/empty.js',
    193        {scope: SCOPE});
    194    assert_equals(registration.updateViaCache, 'imports',
    195                  'before update attempt');
    196 
    197    const fail = navigator.serviceWorker.register(
    198        'resources/malformed-worker.py?parse-error',
    199        {scope: SCOPE, updateViaCache: 'none'});
    200    await promise_rejects_js(t, TypeError, fail);
    201    assert_equals(registration.updateViaCache, 'imports',
    202                  'after update attempt');
    203  }, 'updateViaCache is not updated if register() rejects');
    204 </script>