tor-browser

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

clients-get-resultingClientId.https.html (6999B)


      1 <!DOCTYPE html>
      2 <meta charset="utf-8">
      3 <title>Test clients.get(resultingClientId)</title>
      4 <script src="/resources/testharness.js"></script>
      5 <script src="/resources/testharnessreport.js"></script>
      6 <script src="/common/get-host-info.sub.js"></script>
      7 <script src="resources/test-helpers.sub.js"></script>
      8 <script>
      9 const scope = "resources/";
     10 let worker;
     11 
     12 // Setup. Keep this as the first promise_test.
     13 promise_test(async (t) => {
     14  const registration = await service_worker_unregister_and_register(
     15      t, 'resources/get-resultingClientId-worker.js',
     16      scope);
     17  worker = registration.installing;
     18  await wait_for_state(t, worker, 'activated');
     19 }, 'global setup');
     20 
     21 // Sends |command| to the worker and returns a promise that resolves to its
     22 // response. There should only be one inflight command at a time.
     23 async function sendCommand(command) {
     24  const saw_message = new Promise((resolve) => {
     25    navigator.serviceWorker.onmessage = (event) => {
     26      resolve(event.data);
     27    };
     28  });
     29  worker.postMessage(command);
     30  return saw_message;
     31 }
     32 
     33 // Wrapper for 'startTest' command. Tells the worker a test is starting,
     34 // so it resets state and keeps itself alive until 'finishTest'.
     35 async function startTest(t) {
     36  const result = await sendCommand({command: 'startTest'});
     37  assert_equals(result, 'ok', 'startTest');
     38 
     39  t.add_cleanup(async () => {
     40    return finishTest();
     41  });
     42 }
     43 
     44 // Wrapper for 'finishTest' command.
     45 async function finishTest() {
     46  const result = await sendCommand({command: 'finishTest'});
     47  assert_equals(result, 'ok', 'finishTest');
     48 }
     49 
     50 // Wrapper for 'getResultingClient' command. Tells the worker to return
     51 // clients.get(event.resultingClientId) for the navigation that occurs
     52 // during this test.
     53 //
     54 // The return value describes how clients.get() settled. It also includes
     55 // |queriedId| which is the id passed to clients.get() (the resultingClientId
     56 // in this case).
     57 //
     58 // Example value:
     59 // {
     60 //   queriedId: 'abc',
     61 //   promiseState: fulfilled,
     62 //   promiseValue: client,
     63 //   client: {
     64 //     id: 'abc',
     65 //     url: '//example.com/client'
     66 //   }
     67 // }
     68 async function getResultingClient() {
     69  return sendCommand({command: 'getResultingClient'});
     70 }
     71 
     72 // Wrapper for 'getClient' command. Tells the worker to return
     73 // clients.get(|id|). The return value is as in the getResultingClient()
     74 // documentation.
     75 async function getClient(id) {
     76  return sendCommand({command: 'getClient', id: id});
     77 }
     78 
     79 // Navigates to |url|. Returns the result of clients.get() on the
     80 // resultingClientId.
     81 async function navigateAndGetResultingClient(t, url) {
     82  const resultPromise = getResultingClient();
     83  const frame = await with_iframe(url);
     84  t.add_cleanup(() => {
     85    frame.remove();
     86  });
     87  const result = await resultPromise;
     88  const resultingClientId = result.queriedId;
     89 
     90  // First test clients.get(event.resultingClientId) inside the fetch event. The
     91  // behavior of this is subtle due to the use of iframes and about:blank
     92  // replacement. The spec probably requires that it resolve to the original
     93  // about:blank client, and that later that client should be discarded after
     94  // load if the load was to another origin. Implementations might differ. For
     95  // now, this test just asserts that the promise resolves. See
     96  // https://github.com/w3c/ServiceWorker/issues/1385.
     97  assert_equals(result.promiseState, 'fulfilled',
     98                'get(event.resultingClientId) in the fetch event should fulfill');
     99 
    100  // Test clients.get() on the previous resultingClientId again. By this
    101  // time the load finished, so it's more straightforward how this promise
    102  // should settle. Return the result of this promise.
    103  return await getClient(resultingClientId);
    104 }
    105 
    106 // Test get(resultingClientId) in the basic same-origin case.
    107 promise_test(async (t) => {
    108  await startTest(t);
    109 
    110  const url = new URL('resources/empty.html', window.location);
    111  const result = await navigateAndGetResultingClient(t, url);
    112  assert_equals(result.promiseState, 'fulfilled', 'promiseState');
    113  assert_equals(result.promiseValue, 'client', 'promiseValue');
    114  assert_equals(result.client.url, url.href, 'client.url',);
    115  assert_equals(result.client.id, result.queriedId, 'client.id');
    116 }, 'get(resultingClientId) for same-origin document');
    117 
    118 // Test get(resultingClientId) when the response redirects to another origin.
    119 promise_test(async (t) => {
    120  await startTest(t);
    121 
    122  // Navigate to a URL that redirects to another origin.
    123  const base_url = new URL('.', window.location);
    124  const host_info = get_host_info();
    125  const other_origin_url = new URL(base_url.pathname + 'resources/empty.html',
    126                                   host_info['HTTPS_REMOTE_ORIGIN']);
    127  const url = new URL('resources/empty.html', window.location);
    128  const pipe = `status(302)|header(Location, ${other_origin_url})`;
    129  url.searchParams.set('pipe', pipe);
    130 
    131  // The original reserved client should have been discarded on cross-origin
    132  // redirect.
    133  const result = await navigateAndGetResultingClient(t, url);
    134  assert_equals(result.promiseState, 'fulfilled', 'promiseState');
    135  assert_equals(result.promiseValue, 'undefinedValue', 'promiseValue');
    136 }, 'get(resultingClientId) on cross-origin redirect');
    137 
    138 // Test get(resultingClientId) when the document is sandboxed to a unique
    139 // origin using a CSP HTTP response header.
    140 promise_test(async (t) => {
    141  await startTest(t);
    142 
    143  // Navigate to a URL that has CSP sandboxing set in the HTTP response header.
    144  const url = new URL('resources/empty.html', window.location);
    145  const pipe = 'header(Content-Security-Policy, sandbox)';
    146  url.searchParams.set('pipe', pipe);
    147 
    148  // The original reserved client should have been discarded upon loading
    149  // the sandboxed document.
    150  const result = await navigateAndGetResultingClient(t, url);
    151  assert_equals(result.promiseState, 'fulfilled', 'promiseState');
    152  assert_equals(result.promiseValue, 'undefinedValue', 'promiseValue');
    153 }, 'get(resultingClientId) for document sandboxed by CSP header');
    154 
    155 // Test get(resultingClientId) when the document is sandboxed with
    156 // allow-same-origin.
    157 promise_test(async (t) => {
    158  await startTest(t);
    159 
    160  // Navigate to a URL that has CSP sandboxing set in the HTTP response header.
    161  const url = new URL('resources/empty.html', window.location);
    162  const pipe = 'header(Content-Security-Policy, sandbox allow-same-origin)';
    163  url.searchParams.set('pipe', pipe);
    164 
    165  // The client should be the original reserved client, as it's same-origin.
    166  const result = await navigateAndGetResultingClient(t, url);
    167  assert_equals(result.promiseState, 'fulfilled', 'promiseState');
    168  assert_equals(result.promiseValue, 'client', 'promiseValue');
    169  assert_equals(result.client.url, url.href, 'client.url',);
    170  assert_equals(result.client.id, result.queriedId, 'client.id');
    171 }, 'get(resultingClientId) for document sandboxed by CSP header with allow-same-origin');
    172 
    173 // Cleanup. Keep this as the last promise_test.
    174 promise_test(async (t) => {
    175  return service_worker_unregister(t, scope);
    176 }, 'global cleanup');
    177 </script>