tor-browser

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

headers.https.html (6069B)


      1 <!DOCTYPE html>
      2 <title>Sec-Purpose header on prerendered page</title>
      3 <meta name="timeout" content="long">
      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="/common/utils.js"></script>
      8 <script src="/common/dispatcher/dispatcher.js"></script>
      9 <script src="/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js"></script>
     10 <script src="../resources/utils.js"></script>
     11 <script src="resources/utils.js"></script>
     12 
     13 <body>
     14 <script>
     15 setup(() => assertSpeculationRulesIsSupported());
     16 
     17 promise_test(async () => {
     18  const rcHelper = new PrerenderingRemoteContextHelper();
     19  const referrerRC = await rcHelper.addWindow(undefined, { features: 'noopener' });
     20  const prerenderedRC = await referrerRC.addPrerender();
     21 
     22  const prerenderedHeaders = await prerenderedRC.getRequestHeaders();
     23  assertHeaders(prerenderedHeaders, true, true, 'prerendered page');
     24 
     25  const iframeRC = await prerenderedRC.addIframe();
     26  const iframeHeaders = await iframeRC.getRequestHeaders();
     27  assertHeaders(iframeHeaders, true, false, 'iframe');
     28 
     29  // No test for cross-origin iframe, since those requests are delayed until
     30  // after activation. See below.
     31 
     32  const imageHeaders = await insertImageAndGetRequestHeaders(prerenderedRC);
     33  assertHeaders(imageHeaders, true, false, 'image');
     34 
     35  const crossOriginImageHeaders = await insertImageAndGetRequestHeaders(
     36    prerenderedRC,
     37    get_host_info().HTTPS_REMOTE_ORIGIN
     38  );
     39  assertHeaders(crossOriginImageHeaders, true, false, 'cross-origin image');
     40 
     41  const fetchHeaders = await doFetchAndGetRequestHeaders(prerenderedRC);
     42  assertHeaders(fetchHeaders, true, false, 'fetch');
     43 
     44  const crossOriginFetchHeaders = await doFetchAndGetRequestHeaders(
     45    prerenderedRC,
     46    get_host_info().HTTPS_REMOTE_ORIGIN
     47  );
     48  assertHeaders(crossOriginFetchHeaders, true, false, 'cross-origin fetch');
     49 
     50  const navigatedToRC = await prerenderedRC.navigateToNew();
     51  const navigatedToHeaders = await navigatedToRC.getRequestHeaders();
     52  assertHeaders(navigatedToHeaders, true, false, 'navigated-to page');
     53 }, 'Headers before activation, including prerendered page navigation');
     54 
     55 promise_test(async () => {
     56  const rcHelper = new PrerenderingRemoteContextHelper();
     57  const referrerRC = await rcHelper.addWindow(undefined, { features: 'noopener' });
     58  const prerenderedRC = await referrerRC.addPrerender();
     59 
     60  // Add the iframe now, but only check its headers after activation.
     61  const crossOriginIframeBeforeActivationRC = await prerenderedRC.addIframe({ origin: 'HTTPS_REMOTE_ORIGIN' });
     62 
     63  await referrerRC.navigateExpectingPrerenderingActivation(prerenderedRC);
     64 
     65  const crossOriginIframeBeforeActivationHeaders = await crossOriginIframeBeforeActivationRC.getRequestHeaders();
     66  assertHeaders(crossOriginIframeBeforeActivationHeaders, true, false, 'cross-origin iframe before activation');
     67 
     68  const iframeRC = await prerenderedRC.addIframe();
     69  const iframeHeaders = await iframeRC.getRequestHeaders();
     70  assertHeaders(iframeHeaders, false, false, 'post-activation iframe');
     71 
     72  const imageHeaders = await insertImageAndGetRequestHeaders(prerenderedRC);
     73  assertHeaders(imageHeaders, false, false, 'post-activation image');
     74 
     75  const crossOriginImageHeaders = await insertImageAndGetRequestHeaders(
     76    prerenderedRC,
     77    get_host_info().HTTPS_REMOTE_ORIGIN
     78  );
     79  assertHeaders(crossOriginImageHeaders, false, false, 'cross-origin image');
     80 
     81  const fetchHeaders = await doFetchAndGetRequestHeaders(prerenderedRC);
     82  assertHeaders(fetchHeaders, false, false, 'post-activation fetch');
     83 
     84  const crossOriginFetchHeaders = await doFetchAndGetRequestHeaders(
     85    prerenderedRC,
     86    get_host_info().HTTPS_REMOTE_ORIGIN
     87  );
     88  assertHeaders(crossOriginFetchHeaders, false, false, 'cross-origin fetch');
     89 }, 'Headers after activation (plus cross-origin iframe before activation)');
     90 
     91 async function insertImageAndGetRequestHeaders(rc, hostname) {
     92  const uuid = token();
     93  const url = (new URL(`resources/image-with-headers-stash.py?image=${uuid}`, location.href));
     94  const headersURL = (new URL(`resources/image-with-headers-stash.py?read=${uuid}`, location.href));
     95 
     96  if (hostname !== undefined) {
     97    url.hostname = hostname;
     98    headersURL.hostname = hostname;
     99  }
    100 
    101  await rc.executeScript(async (url) => {
    102    const img = new Image();
    103    img.src = url;
    104    const promise = new Promise(resolve => img.onload = resolve);
    105    document.body.append(img);
    106    return promise;
    107  }, [url]);
    108 
    109  const headersJSON = await (await fetch(headersURL)).json();
    110  assert_not_equals(headersJSON, null, 'image headers should not be null');
    111  return new Headers(headersJSON);
    112 }
    113 
    114 async function doFetchAndGetRequestHeaders(rc, hostname) {
    115  const uuid = token();
    116  const url = (new URL(`resources/image-with-headers-stash.py?image=${uuid}`, location.href));
    117  const headersURL = (new URL(`resources/image-with-headers-stash.py?read=${uuid}`, location.href));
    118 
    119  if (hostname !== undefined) {
    120    url.hostname = hostname;
    121    headersURL.hostname = hostname;
    122  }
    123 
    124  await rc.executeScript(async (url) => {
    125    return fetch(url, { mode: "cors" });
    126  }, [url]);
    127 
    128  const headersJSON = await (await fetch(headersURL)).json();
    129  assert_not_equals(headersJSON, null, 'fetch headers should not be null');
    130  return new Headers(headersJSON);
    131 }
    132 
    133 function assertHeaders(headers, secPurposeIsPrefetchPrerender, secSpeculationTagsIsPresent, label) {
    134  if (secPurposeIsPrefetchPrerender) {
    135    assert_equals(
    136      headers.get('Sec-Purpose'),
    137      'prefetch;prerender',
    138      `${label} Sec-Purpose`
    139    );
    140  } else {
    141    assert_false(
    142      headers.has('Sec-Purpose'),
    143      `${label} Sec-Purpose should not be present`
    144    );
    145  }
    146  if (secSpeculationTagsIsPresent) {
    147    assert_equals(
    148      headers.get('Sec-Speculation-Tags'),
    149      'null',
    150      `${label} Sec-Speculation-Tags`
    151    );
    152  } else {
    153    assert_false(
    154      headers.has('Sec-Speculation-Tags'),
    155      `${label} Sec-Speculation-Tags should not be present`
    156    );
    157  }
    158 }
    159 </script>