tor-browser

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

history-length-fenced-navigations-replace-do-not-contribute-to-joint-inner.html (4773B)


      1 <!DOCTYPE html>
      2 <script src="/resources/testharness.js"></script>
      3 <script src="utils.js"></script>
      4 <title>Nested fenced frame named navigation helper</title>
      5 
      6 <body>
      7 <script>
      8 (async () => {
      9  // We need to wait for the window's `load` event to fire, because client-side
     10  // redirect navigations that take place before a document is "completely
     11  // loaded" [1] are carried out with replacement, as specified in [2]. Just
     12  // waiting for `load` is not enough though! After the `load` event is fired
     13  // (but before a document is marked "completely loaded"), a microtask
     14  // checkpoint is performed, which is where the below `Promise`'s `then`
     15  // handler is invoked (i.e., the rest of the script). So if we just resolve
     16  // the promise and continue, the whole script continues in the next immediate
     17  // microtask before the document is completely loaded. So we have to queue
     18  // another task so that we only continue executing once the document is
     19  // considered completely loaded, and then `location.href` assignments will not
     20  // be made with replacement history handling.
     21  //
     22  // [1]: https://html.spec.whatwg.org/C#the-end:completely-finish-loading
     23  // [2]: https://html.spec.whatwg.org/#the-location-interface:completely-loaded
     24  await new Promise(resolve => {
     25    window.onload = e => {
     26      setTimeout(resolve, 0);
     27    };
     28  });
     29 
     30  const kNavigationLimit = 5;
     31  // This is a helper file meant to be loaded inside a fenced frame. It performs
     32  // various navigations inside of the "fence" defined by this document, and
     33  // ensures that they are all done in a replace-only fashion [1].
     34  // Once we ensure that they are all done with replacement, we report back to
     35  // the outermost page via the server stash, and it ensures that there was no
     36  // impact on the joint session history as observed from beyond the fence.
     37  //
     38  // [1]: https://html.spec.whatwg.org/C/#hh-replace
     39 
     40  // See documentation in the outer page.
     41  const [fenced_navigation_complete_key,
     42         outer_page_ready_for_next_fenced_navigation_key,
     43         level] = parseKeylist();
     44 
     45  const url = new URL(location.href);
     46  const is_top_level_fenced_frame = (level == "top-level-fenced-frame");
     47 
     48  ////////////// Navigation code that may impact `history.length` should go here
     49  // The code in this block performs navigations that will run inside:
     50  //   - The top-level fenced frame
     51  //   - The nested fenced frame
     52  //   - The nested iframe
     53 
     54  // First, perform some real navigations to this same page. Normally this would
     55  // increase `history.length`.
     56  if (url.searchParams.get("navigationNumber") == null)
     57    url.searchParams.append("navigationNumber", 0);
     58 
     59  let navigationNumber = parseInt(url.searchParams.get("navigationNumber"));
     60 
     61  if (navigationNumber <= kNavigationLimit) {
     62    url.searchParams.set('navigationNumber', navigationNumber + 1);
     63    location.href = url;
     64    return;
     65  }
     66 
     67  // At this point we're done performing 5 subsequent navigations...
     68 
     69  // Next, perform `history.pushState()`s.
     70  history.pushState({} , "");
     71  history.pushState({} , "");
     72  history.pushState({} , "");
     73  ////////////// END
     74 
     75  // Finally observe `history.length` from within the fenced frame, and report
     76  // the results back to the outermost page.
     77  if (history.length == 1) {
     78    writeValueToServer(fenced_navigation_complete_key, "PASS > " +
     79        level);
     80  } else {
     81    writeValueToServer(fenced_navigation_complete_key,
     82        "FAIL > " + level + " history.length: " +
     83        history.length);
     84  }
     85 
     86  // We're only testing fenced frames, nested fenced frames, and iframes nested
     87  // within fenced frames. The below code adds a nested fenced frame and a
     88  // nested iframe, so it should only be reached by the top-level fenced frame.
     89  if (level != "top-level-fenced-frame")
     90    return;
     91 
     92  // Only top-level fenced frames will attach a nested fenced frame and run the
     93  // same tests there.
     94  await nextValueFromServer(outer_page_ready_for_next_fenced_navigation_key);
     95  const nested_fenced_frame_level = "nested-fenced-frame";
     96  attachFencedFrame(generateURL(
     97      "history-length-fenced-navigations-replace-do-not-" +
     98      "contribute-to-joint-inner.html",
     99      [fenced_navigation_complete_key,
    100      outer_page_ready_for_next_fenced_navigation_key,
    101      nested_fenced_frame_level]));
    102 
    103  await nextValueFromServer(outer_page_ready_for_next_fenced_navigation_key);
    104  const iframe = document.createElement('iframe');
    105  const nested_iframe_level = "nested-iframe";
    106  iframe.src = generateURL(
    107      "history-length-fenced-navigations-replace-do-not-contribute-to-joint-" +
    108      "inner.html",
    109      [fenced_navigation_complete_key,
    110      outer_page_ready_for_next_fenced_navigation_key,
    111      nested_iframe_level]);
    112  document.body.append(iframe);
    113 })();
    114 </script>
    115 </body>