tor-browser

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

browser_fetch_after_suspending_request.js (6913B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 add_task(async function () {
      7  info("Run test with network.http.rcwn.enabled set to true");
      8  await test_fetch_after_suspend(true);
      9  info("Run test with network.http.rcwn.enabled set to false");
     10  await test_fetch_after_suspend(false);
     11 });
     12 
     13 let wrappedChannel;
     14 
     15 async function test_fetch_after_suspend(rcwnEnabled) {
     16  info("Set network.http.rcwn.enabled to " + rcwnEnabled);
     17  await SpecialPowers.pushPrefEnv({
     18    set: [
     19      ["network.http.rcwn.enabled", rcwnEnabled],
     20      ["network.cache.suspended_writer_delay_ms", 300],
     21    ],
     22  });
     23 
     24  info("Add a new test tab");
     25  const tab = BrowserTestUtils.addTab(
     26    gBrowser,
     27    "https://example.com/document-builder.sjs?html=tab"
     28  );
     29  await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
     30 
     31  const testBlockedUrl = "https://example.com/?test-blocked";
     32 
     33  info(`Add an observer to suspend the next channel to ${testBlockedUrl}`);
     34  const { promise, resolve } = Promise.withResolvers();
     35  const onExamineResponse = subject => {
     36    if (!(subject instanceof Ci.nsIHttpChannel)) {
     37      return;
     38    }
     39 
     40    const channel = subject.QueryInterface(Ci.nsIHttpChannel);
     41    if (channel.URI.displaySpec !== testBlockedUrl) {
     42      return;
     43    }
     44 
     45    wrappedChannel = ChannelWrapper.get(channel);
     46    wrappedChannel.suspend("test-blocked-suspend");
     47    Services.obs.removeObserver(onExamineResponse, "http-on-examine-response");
     48    resolve();
     49  };
     50  Services.obs.addObserver(onExamineResponse, "http-on-examine-response");
     51 
     52  info(`Send fetch call for ${testBlockedUrl}`);
     53  let first = fetch(tab.linkedBrowser, testBlockedUrl);
     54 
     55  info(
     56    "Wait for the fetch request to be suspended in http-on-examine-response"
     57  );
     58  await promise;
     59 
     60  info("Fetch the same URL again");
     61  let secondCompleted = false;
     62  let second = fetch(tab.linkedBrowser, testBlockedUrl).then(() => {
     63    secondCompleted = true;
     64  });
     65 
     66  // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
     67  let timer = new Promise(resolve => setTimeout(resolve, 6000));
     68  await Promise.race([second, timer]);
     69 
     70  Assert.equal(
     71    secondCompleted,
     72    true,
     73    "The second fetch should resolve successfully"
     74  );
     75 
     76  // Resume the first channel and await its completion so we don't leak anything.
     77  wrappedChannel.resume();
     78  await first;
     79 
     80  info("Cleanup");
     81  gBrowser.removeTab(tab);
     82 }
     83 
     84 function fetch(browser, url) {
     85  return SpecialPowers.spawn(browser, [url], async _url => {
     86    const response = await content.fetch(_url);
     87    await response.text();
     88  });
     89 }
     90 
     91 add_task(async function test_fetch_after_suspended_timer_fires() {
     92  await SpecialPowers.pushPrefEnv({
     93    set: [
     94      ["network.http.rcwn.enabled", false],
     95      ["network.cache.suspended_writer_delay_ms", 300],
     96    ],
     97  });
     98 
     99  info("Add a new test tab");
    100  const tab = BrowserTestUtils.addTab(
    101    gBrowser,
    102    "https://example.com/document-builder.sjs?html=tab"
    103  );
    104  await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
    105 
    106  const testBlockedUrl = "https://example.com/?test-blocked";
    107 
    108  info(`Add an observer to suspend the next channel to ${testBlockedUrl}`);
    109  const { promise, resolve } = Promise.withResolvers();
    110  const onExamineResponse = subject => {
    111    if (!(subject instanceof Ci.nsIHttpChannel)) {
    112      return;
    113    }
    114 
    115    const channel = subject.QueryInterface(Ci.nsIHttpChannel);
    116    if (channel.URI.displaySpec !== testBlockedUrl) {
    117      return;
    118    }
    119 
    120    wrappedChannel = ChannelWrapper.get(channel);
    121    wrappedChannel.suspend("test-blocked-suspend");
    122    Services.obs.removeObserver(onExamineResponse, "http-on-examine-response");
    123    resolve();
    124  };
    125  Services.obs.addObserver(onExamineResponse, "http-on-examine-response");
    126 
    127  info(`Send fetch call for ${testBlockedUrl}`);
    128  let first = fetch(tab.linkedBrowser, testBlockedUrl);
    129 
    130  info(
    131    "Wait for the fetch request to be suspended in http-on-examine-response"
    132  );
    133  await promise;
    134 
    135  // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
    136  await new Promise(resolve => setTimeout(resolve, 500));
    137 
    138  info("Fetch the same URL again");
    139  let secondCompleted = false;
    140  let second = fetch(tab.linkedBrowser, testBlockedUrl).then(() => {
    141    secondCompleted = true;
    142  });
    143 
    144  // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
    145  let timer = new Promise(resolve => setTimeout(resolve, 2000));
    146  await Promise.race([second, timer]);
    147 
    148  Assert.equal(
    149    secondCompleted,
    150    true,
    151    "The second fetch should resolve successfully"
    152  );
    153 
    154  // Resume the first channel and await its completion so we don't leak anything.
    155  wrappedChannel.resume();
    156  await first;
    157 
    158  info("Cleanup");
    159  gBrowser.removeTab(tab);
    160 });
    161 
    162 add_task(async function test_fetch_after_suspended_and_resumed() {
    163  await SpecialPowers.pushPrefEnv({
    164    set: [
    165      ["network.http.rcwn.enabled", false],
    166      ["network.cache.suspended_writer_delay_ms", 1000],
    167    ],
    168  });
    169 
    170  info("Add a new test tab");
    171  const tab = BrowserTestUtils.addTab(
    172    gBrowser,
    173    "https://example.com/document-builder.sjs?html=tab"
    174  );
    175  await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
    176 
    177  const testBlockedUrl = "https://example.com/?test-blocked";
    178 
    179  info(`Add an observer to suspend the next channel to ${testBlockedUrl}`);
    180  const { promise, resolve } = Promise.withResolvers();
    181  const onExamineResponse = subject => {
    182    if (!(subject instanceof Ci.nsIHttpChannel)) {
    183      return;
    184    }
    185 
    186    const channel = subject.QueryInterface(Ci.nsIHttpChannel);
    187    if (channel.URI.displaySpec !== testBlockedUrl) {
    188      return;
    189    }
    190 
    191    wrappedChannel = ChannelWrapper.get(channel);
    192    wrappedChannel.suspend("test-blocked-suspend");
    193    Services.obs.removeObserver(onExamineResponse, "http-on-examine-response");
    194    resolve();
    195  };
    196  Services.obs.addObserver(onExamineResponse, "http-on-examine-response");
    197 
    198  info(`Send fetch call for ${testBlockedUrl}`);
    199  let first = fetch(tab.linkedBrowser, testBlockedUrl);
    200 
    201  info(
    202    "Wait for the fetch request to be suspended in http-on-examine-response"
    203  );
    204  await promise;
    205 
    206  // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
    207  await new Promise(resolve => setTimeout(resolve, 100));
    208 
    209  // Resume the channel to make sure we cancel timer
    210  wrappedChannel.resume();
    211 
    212  // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
    213  await new Promise(resolve => setTimeout(resolve, 1500));
    214 
    215  info("Fetch the same URL again");
    216  let secondCompleted = false;
    217  let second = fetch(tab.linkedBrowser, testBlockedUrl).then(() => {
    218    secondCompleted = true;
    219  });
    220 
    221  // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
    222  let timer = new Promise(resolve => setTimeout(resolve, 2000));
    223  await Promise.race([second, timer]);
    224 
    225  Assert.equal(
    226    secondCompleted,
    227    true,
    228    "The second fetch should resolve successfully"
    229  );
    230  await first;
    231 
    232  info("Cleanup");
    233  gBrowser.removeTab(tab);
    234 });