tor-browser

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

test_stale-while-revalidate_positive.js (4250B)


      1 /*
      2 
      3 Tests the Cache-control: stale-while-revalidate response directive.
      4 
      5 Purpose is to check we perform the background revalidation when the window is set
      6 and we hit it.
      7 
      8 * Make request #1.
      9  - response is from the server and version=1
     10  - max-age=1, stale-while-revalidate=9999
     11 * Switch version of the data on the server and prolong the max-age to not let req #3
     12  do a bck reval at the end of the test (prevent leaks/shutdown races.)
     13 * Make request #2 in 2 seconds (entry should be expired by that time, but fall into
     14  the reval window.)
     15  - response is from the cache, version=1
     16  - a new background request should be made for the data
     17 * Wait for "http-on-background-revalidation" notifying finish of the background reval.
     18 * Make request #3.
     19  - response is from the cache, version=2
     20 * Done.
     21 
     22 */
     23 
     24 "use strict";
     25 
     26 const { HttpServer } = ChromeUtils.importESModule(
     27  "resource://testing-common/httpd.sys.mjs"
     28 );
     29 
     30 let max_age;
     31 let version;
     32 let expectCookies = false;
     33 let generate_response = ver => `response version=${ver}`;
     34 
     35 function test_handler(metadata, response) {
     36  // ensures initial network request and background revalidation request sends custom headers
     37  // See Bug 1893842
     38  if (
     39    !metadata.hasHeader("X-Custom-header") ||
     40    metadata.getHeader("X-Custom-header") != "custom-value"
     41  ) {
     42    response.setStatusLine(metadata.httpVersion, 400, "OK");
     43    return;
     44  }
     45 
     46  // Check if the request has a cookie
     47  if (expectCookies) {
     48    let cookies = metadata.getHeader("Cookie");
     49    if (cookies !== "Custom=CustomValue") {
     50      response.setStatusLine(metadata.httpVersion, 400, "Cookies dont match");
     51      return;
     52    }
     53  }
     54 
     55  // Set the cookie in the response
     56  response.setHeader(
     57    "Set-Cookie",
     58    "Custom=CustomValue; HttpOnly; Path=/",
     59    true
     60  );
     61 
     62  const originalBody = generate_response(version);
     63  response.setHeader("Content-Type", "text/html", false);
     64  response.setHeader(
     65    "Cache-control",
     66    `max-age=${max_age}, stale-while-revalidate=9999`,
     67    false
     68  );
     69 
     70  response.setStatusLine(metadata.httpVersion, 200, "OK");
     71  response.bodyOutputStream.write(originalBody, originalBody.length);
     72 }
     73 
     74 function make_channel(url) {
     75  var chan = NetUtil.newChannel({
     76    uri: url,
     77    loadUsingSystemPrincipal: true,
     78  }).QueryInterface(Ci.nsIHttpChannel);
     79  chan.setRequestHeader("X-Custom-header", "custom-value", false);
     80  return chan;
     81 }
     82 
     83 async function get_response(channel, fromCache) {
     84  return new Promise(resolve => {
     85    channel.asyncOpen(
     86      new ChannelListener((request, buffer, ctx, isFromCache) => {
     87        Assert.equal(
     88          fromCache,
     89          isFromCache,
     90          `got response from cache = ${fromCache}`
     91        );
     92        resolve(buffer);
     93      })
     94    );
     95  });
     96 }
     97 
     98 async function sleep(time) {
     99  return new Promise(resolve => {
    100    do_timeout(time * 1000, resolve);
    101  });
    102 }
    103 
    104 async function stop_server(httpserver) {
    105  return new Promise(resolve => {
    106    httpserver.stop(resolve);
    107  });
    108 }
    109 
    110 async function background_reval_promise() {
    111  return new Promise(resolve => {
    112    Services.obs.addObserver(resolve, "http-on-background-revalidation");
    113  });
    114 }
    115 
    116 add_task(async function () {
    117  Services.prefs.setIntPref("network.cookie.cookieBehavior", 0);
    118  Services.prefs.setBoolPref(
    119    "network.cookieJarSettings.unblocked_for_testing",
    120    true
    121  );
    122  let httpserver = new HttpServer();
    123  httpserver.registerPathHandler("/testdir", test_handler);
    124  httpserver.start(-1);
    125  const PORT = httpserver.identity.primaryPort;
    126  const URI = `http://localhost:${PORT}/testdir`;
    127 
    128  let response;
    129 
    130  version = 1;
    131  max_age = 1;
    132  response = await get_response(make_channel(URI), false);
    133  Assert.equal(response, generate_response(1), "got response ver 1");
    134  expectCookies = true;
    135  await sleep(max_age + 1);
    136 
    137  // must specifically wait for the internal channel to finish the reval to make
    138  // the test race-free.
    139  let reval_done = background_reval_promise();
    140 
    141  version = 2;
    142  max_age = 100;
    143  response = await get_response(make_channel(URI), true);
    144  Assert.equal(response, generate_response(1), "got response ver 1");
    145 
    146  await reval_done;
    147 
    148  response = await get_response(make_channel(URI), true);
    149  Assert.equal(response, generate_response(2), "got response ver 2");
    150 
    151  await stop_server(httpserver);
    152 });