tor-browser

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

test_blockBFCache.html (9250B)


      1 <!DOCTYPE HTML>
      2 <html>
      3 <head>
      4  <meta charset="utf-8">
      5  <title>Blocking pages from entering BFCache</title>
      6  <script src="/tests/SimpleTest/SimpleTest.js"></script>
      7  <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
      8 </head>
      9 <body onload="">
     10 <script>
     11 
     12 const getUserMediaPrefs = {
     13  set: [
     14    ["media.devices.insecure.enabled", true],
     15    ["media.getusermedia.insecure.enabled", true],
     16    ["media.navigator.permission.disabled", true],
     17  ],
     18 };
     19 const msePrefs = {
     20  set: [
     21    ["media.mediasource.enabled", true],
     22    ["media.audio-max-decode-error", 0],
     23    ["media.video-max-decode-error", 0],
     24  ]
     25 };
     26 
     27 const blockBFCacheTests = [
     28  {
     29    name: "Request",
     30    test: () => {
     31      return new Promise((resolve) => {
     32        const xhr = new XMLHttpRequest();
     33        xhr.open("GET", "slow.sjs");
     34        xhr.addEventListener("progress", () => { resolve(xhr); }, { once: true });
     35        xhr.send();
     36      });
     37    },
     38  },
     39  {
     40    name: "Background request",
     41    test: () => {
     42      return new Promise((resolve) => {
     43        const xhr = new XMLHttpRequest();
     44        xhr.open("GET", "slow.sjs");
     45        xhr.addEventListener("readystatechange", () => { if (xhr.readyState == xhr.HEADERS_RECEIVED) resolve(xhr); });
     46        xhr.send();
     47      });
     48    },
     49  },
     50  {
     51    name: "getUserMedia",
     52    prefs: getUserMediaPrefs,
     53    test: () => {
     54      return navigator.mediaDevices.getUserMedia({ audio: true, fake: true });
     55    },
     56  },
     57  {
     58    name: "RTCPeerConnection",
     59    test: () => {
     60      let pc = new RTCPeerConnection();
     61      return pc.createOffer();
     62    },
     63  },
     64  {
     65    name: "MSE",
     66    prefs: msePrefs,
     67    test: () => {
     68      const ms = new MediaSource();
     69      const el = document.createElement("video");
     70      el.src = URL.createObjectURL(ms);
     71      el.preload = "auto";
     72      return el;
     73    },
     74  },
     75  {
     76    name: "WebSpeech",
     77    test: () => {
     78      return new Promise((resolve) => {
     79        const utterance = new SpeechSynthesisUtterance('bfcache');
     80        utterance.lang = 'it-IT-noend';
     81        utterance.addEventListener('start', () => { resolve(utterance); })
     82        speechSynthesis.speak(utterance);
     83      });
     84    },
     85  },
     86  {
     87    name: "WebVR",
     88    prefs: {
     89      set: [
     90        ["dom.vr.test.enabled", true],
     91        ["dom.vr.puppet.enabled", true],
     92        ["dom.vr.require-gesture", false],
     93      ],
     94    },
     95    test: () => {
     96      return navigator.requestVRServiceTest();
     97    }
     98  },
     99 ];
    100 
    101 if (SpecialPowers.effectiveIsolationStrategy() == SpecialPowers.ISOLATION_STRATEGY.IsolateEverything) {
    102  blockBFCacheTests.push({
    103    name: "Loading OOP iframe",
    104    test: () => {
    105      return new Promise((resolve) => {
    106        const el = document.createElement("iframe");
    107        el.id = "frame";
    108        addEventListener("message", ({ data }) => {
    109          if (data == "onload") {
    110            resolve();
    111          }
    112        });
    113        el.src = "https://example.com/tests/docshell/test/navigation/iframe_slow_onload.html";
    114        document.body.appendChild(el);
    115      });
    116    },
    117    waitForDone: () => {
    118      SimpleTest.requestFlakyTimeout("Test has a loop in an onload handler that runs for 5000ms, we need to make sure the loop is done before moving to the next test.");
    119      return new Promise(resolve => {
    120        setTimeout(resolve, 5000);
    121      });
    122    },
    123  });
    124 }
    125 
    126 const dontBlockBFCacheTests = [
    127  {
    128    name: "getUserMedia",
    129    prefs: getUserMediaPrefs,
    130    test: () => {
    131      return navigator.mediaDevices.getUserMedia({ video: true, fake: true }).then(stream => {
    132        stream.getTracks().forEach(track => track.stop());
    133        return stream;
    134      });
    135    },
    136  },
    137 /*
    138  Disabled because MediaKeys rely on being destroyed by the CC before they
    139  notify their window, so the test would intermittently fail depending on
    140  when the CC runs.
    141 
    142  {
    143    name: "MSE",
    144    prefs: msePrefs,
    145    test: () => {
    146      return new Promise((resolve) => {
    147        const ms = new MediaSource();
    148        const el = document.createElement("video");
    149        ms.addEventListener("sourceopen", () => { resolve(el) }, { once: true });
    150        el.src = URL.createObjectURL(ms);
    151        el.preload = "auto";
    152      }).then(el => {
    153        el.src = "";
    154        return el;
    155      });
    156    },
    157  },
    158 */
    159 ];
    160 
    161 
    162 
    163 function executeTest() {
    164 
    165  let bc = new BroadcastChannel("bfcache_blocking");
    166 
    167  function promiseMessage(type) {
    168    return new Promise((resolve) => {
    169      bc.addEventListener("message", (e) => {
    170        if (e.data.type == type) {
    171          resolve(e.data);
    172        }
    173      }, { once: true });
    174    });
    175  }
    176 
    177  function promisePageShow(shouldBePersisted) {
    178    return promiseMessage("pageshow").then(data => data.persisted == shouldBePersisted);
    179  }
    180 
    181  function promisePageShowFromBFCache() {
    182    return promisePageShow(true);
    183  }
    184 
    185  function promisePageShowNotFromBFCache() {
    186    return promisePageShow(false);
    187  }
    188 
    189  function runTests(testArray, shouldBlockBFCache) {
    190    for (const { name, prefs = {}, test, waitForDone } of testArray) {
    191      add_task(async function() {
    192        await SpecialPowers.pushPrefEnv(prefs, async function() {
    193          // Load a mostly blank page that we can communicate with over
    194          // BroadcastChannel (though it will close the BroadcastChannel after
    195          // receiving the next "load" message, to avoid blocking BFCache).
    196          let loaded = promisePageShowNotFromBFCache();
    197          window.open("file_blockBFCache.html", "", "noopener");
    198          await loaded;
    199 
    200          // Load the same page with a different URL.
    201          loaded = promisePageShowNotFromBFCache();
    202          bc.postMessage({ message: "load", url: `file_blockBFCache.html?${name}_${shouldBlockBFCache}` });
    203          await loaded;
    204 
    205          // Run test script in the second page.
    206          bc.postMessage({ message: "runScript", fun: test.toString() });
    207          await promiseMessage("runScriptDone");
    208 
    209          // Go back to the first page (this should just come from the BFCache).
    210          let goneBack = promisePageShowFromBFCache();
    211          bc.postMessage({ message: "back" });
    212          await goneBack;
    213 
    214          // Go forward again to the second page and check that it does/doesn't come
    215          // from the BFCache.
    216          let goneForward = promisePageShow(!shouldBlockBFCache);
    217          bc.postMessage({ message: "forward" });
    218          let result = await goneForward;
    219          ok(result, `Page ${shouldBlockBFCache ? "should" : "should not"} have been blocked from going into the BFCache (${name})`);
    220 
    221          // If the test will keep running after navigation, then we need to make
    222          // sure it's completely done before moving to the next test, to avoid
    223          // interfering with any following tests. If waitForDone is defined then
    224          // it'll return a Promise that we can use to wait for the end of the
    225          // test.
    226          if (waitForDone) {
    227            await waitForDone();
    228          }
    229 
    230          // Do a similar test, but replace the bfcache test page with a new page,
    231          // not a page coming from the session history.
    232 
    233          // Load the same page with a different URL.
    234          loaded = promisePageShowNotFromBFCache();
    235          bc.postMessage({ message: "load", url: `file_blockBFCache.html?p2_${name}_${shouldBlockBFCache}` });
    236          await loaded;
    237 
    238          // Run the test script.
    239          bc.postMessage({ message: "runScript", fun: test.toString() });
    240          await promiseMessage("runScriptDone");
    241 
    242          // Load a new page.
    243          loaded = promisePageShowNotFromBFCache();
    244          bc.postMessage({ message: "load", url: "file_blockBFCache.html" });
    245          await loaded;
    246 
    247          // Go back to the previous page and check that it does/doesn't come
    248          // from the BFCache.
    249          goneBack = promisePageShow(!shouldBlockBFCache);
    250          bc.postMessage({ message: "back" });
    251          result = await goneBack;
    252          ok(result, `Page ${shouldBlockBFCache ? "should" : "should not"} have been blocked from going into the BFCache (${name})`);
    253 
    254          if (waitForDone) {
    255            await waitForDone();
    256          }
    257 
    258          bc.postMessage({ message: "close" });
    259 
    260          SpecialPowers.popPrefEnv();
    261        });
    262      });
    263    }
    264  }
    265 
    266  // If Fission is disabled, the pref is no-op.
    267  SpecialPowers.pushPrefEnv({set: [["fission.bfcacheInParent", true]]}, () => {
    268    runTests(blockBFCacheTests, true);
    269    runTests(dontBlockBFCacheTests, false);
    270  });
    271 }
    272 
    273 if (isXOrigin) {
    274  // Bug 1746646: Make mochitests work with TCP enabled (cookieBehavior = 5)
    275  // Acquire storage access permission here so that the BroadcastChannel used to
    276  // communicate with the opened windows works in xorigin tests. Otherwise,
    277  // the iframe containing this page is isolated from first-party storage access,
    278  // which isolates BroadcastChannel communication.
    279  SpecialPowers.wrap(document).notifyUserGestureActivation();
    280  SpecialPowers.addPermission("storageAccessAPI", true, window.location.href).then(() => {
    281    SpecialPowers.wrap(document).requestStorageAccess().then(() => {
    282      SpecialPowers.pushPrefEnv({
    283        set: [["privacy.partition.always_partition_third_party_non_cookie_storage", false]]
    284      }).then(() => {
    285        executeTest();
    286      });
    287    });
    288  });
    289 } else {
    290  executeTest();
    291 }
    292 
    293 </script>
    294 </body>
    295 </html>