tor-browser

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

link-load-error-events.sub.js (5969B)


      1 /**
      2 * This is the guts of the load/error event tests for <link rel="stylesheet">.
      3 *
      4 * We have a list of tests each of which is an object containing: href value,
      5 * expected load success boolean, test description.  Href values are set up in
      6 * such a way that we guarantee that all stylesheet URLs are unique.  This
      7 * avoids issues around caching of sheets based on URL.
      8 */
      9 
     10 // Our URLs are random, so we don't use them in error messages by
     11 // default, but enable doing it if someone wants to debug things.
     12 const DEBUG_URLS = false;
     13 
     14 var isHttps = location.protocol == "https:";
     15 
     16 var tests = [
     17  // Basic tests
     18  {
     19    href: existingSheet(),
     20    success: true,
     21    description: "Basic load of stylesheet",
     22  },
     23  {
     24    href: nonexistentSheet(),
     25    success: false,
     26    description: "Attempted load of nonexistent stylesheet",
     27  },
     28  {
     29    href: `data:text/css,@import url("${existingSheet()}")`,
     30    success: true,
     31    description: "Import of stylesheet",
     32  },
     33  {
     34    href: `data:text/css,@import url("${nonexistentSheet()}")`,
     35    success: false,
     36    description: "Import of nonexistent stylesheet",
     37  },
     38  {
     39    href: `data:text/css,@import url("data:text/css,@import url('${existingSheet()}')")`,
     40    success: true,
     41    description: "Import of import of stylesheet",
     42  },
     43  {
     44    href: `data:text/css,@import url("data:text/css,@import url('${nonexistentSheet()}')")`,
     45    success: false,
     46    description: "Import of import of nonexistent stylesheet",
     47  },
     48 
     49  // Non-CSS-response tests.
     50  {
     51    href: makeUnique(""),
     52    success: false,
     53    description: "Load of non-CSS stylesheet",
     54  },
     55  {
     56    href: `data:text/css,@import url("${makeUnique("")}")`,
     57    success: false,
     58    description: "Import of non-CSS stylesheet",
     59  },
     60  {
     61    href: `data:text/css,@import url("data:text/css,@import url('${makeUnique("")}')")`,
     62    success: false,
     63    description: "Import of import of non-CSS stylesheet",
     64  },
     65 
     66  // http:// tests, to test what happens with mixed content blocking.
     67  {
     68    href: httpSheet(),
     69    success: !isHttps,
     70    description: "Load of http:// stylesheet",
     71  },
     72  {
     73    href: `data:text/css,@import url("${httpSheet()}")`,
     74    success: !isHttps,
     75    description: "Import of http:// stylesheet",
     76  },
     77  {
     78    href: `data:text/css,@import url("data:text/css,@import url('${httpSheet()}')")`,
     79    success: !isHttps,
     80    description: "Import of import of http:// stylesheet",
     81  },
     82 
     83  // https:// tests just as a control
     84  {
     85    href: httpsSheet(),
     86    success: true,
     87    description: "Load of https:// stylesheet",
     88  },
     89  {
     90    href: `data:text/css,@import url("${httpsSheet()}")`,
     91    success: true,
     92    description: "Import of https:// stylesheet",
     93  },
     94  {
     95    href: `data:text/css,@import url("data:text/css,@import url('${httpsSheet()}')")`,
     96    success: true,
     97    description: "Import of import of https:// stylesheet",
     98  },
     99 
    100  // Tests with multiple imports some of which are slow and some are fast.
    101  {
    102    href: `data:text/css,@import url("${slowResponse(existingSheet())}"); @import url("${nonexistentSheet()}");`,
    103    success: false,
    104    description: "Slow successful import, fast failing import",
    105  },
    106  {
    107    href: `data:text/css,@import url("${existingSheet()}"); @import url("${slowResponse(nonexistentSheet())}");`,
    108    success: false,
    109    description: "Fast successful import, slow failing import",
    110  }
    111 ];
    112 
    113 // Note: Here we really do need to use "let" at least for the href,
    114 // because we lazily evaluate it in the unreached cases.
    115 for (var test of tests) {
    116  let {href, success, description} = test;
    117  var t = async_test(description);
    118  var link = document.createElement("link");
    119  link.rel = "stylesheet";
    120  hrefString = DEBUG_URLS ? `: ${href}` : "";
    121  if (success) {
    122    link.onload = t.step_func_done(() => {});
    123    link.onerror = t.step_func_done(() => assert_unreached(`error fired when load expected${hrefString}`) );
    124  } else {
    125    link.onerror = t.step_func_done(() => {});
    126    link.onload = t.step_func_done(() => assert_unreached(`load fired when error expected${hrefString}`) );
    127  }
    128  link.href = href;
    129  document.head.appendChild(link);
    130 }
    131 
    132 /* Utility function */
    133 function makeUnique(url) {
    134  // Make sure we copy here, even if the thing coming in is a URL, so we don't
    135  // mutate our caller's data.
    136  url = new URL(url, location.href);
    137  // We want to generate a unique URI to avoid the various caches browsers have
    138  // for stylesheets.  We don't want to just use a counter, because that would
    139  // not be robust to the test being reloaded or othewise run multiple times
    140  // without a browser restart.  We don't want to use timstamps, because those
    141  // are not likely to be unique across calls to this function, especially given
    142  // the degraded timer resolution browsers have due to Spectre.
    143  //
    144  // So just fall back on Math.random() and assume it can't duplicate values.
    145  url.searchParams.append("r", Math.random());
    146  return url;
    147 }
    148 
    149 function existingSheet() {
    150  return makeUnique("resources/good.css");
    151 }
    152 
    153 /**
    154 * Function the add values to the "pipe" search param.  See
    155 * http://wptserve.readthedocs.io/en/latest/pipes.html for why one would do
    156 * this.  Because this param uses a weird '|'-separated syntax instead of just
    157 * using multiple params with the same name, we need some manual code to munge
    158 * the value properly.
    159 */
    160 function addPipe(url, pipeVal) {
    161  url = new URL(url, location.href);
    162  var params = url.searchParams;
    163  var oldVal = params.get("pipe");
    164  if (oldVal) {
    165    params.set("pipe", oldVal + "|" + pipeVal);
    166  } else {
    167    params.set("pipe", pipeVal);
    168  }
    169  return url;
    170 }
    171 
    172 function nonexistentSheet() {
    173  return addPipe(existingSheet(), "status(404)");
    174 }
    175 
    176 function httpSheet() {
    177  var url = existingSheet();
    178  url.protocol = "http";
    179  url.port = {{ports[http][0]}};
    180  return url;
    181 }
    182 
    183 function httpsSheet() {
    184  var url = existingSheet();
    185  url.protocol = "https";
    186  url.port = {{ports[https][0]}};
    187  return url;
    188 }
    189 
    190 function slowResponse(url) {
    191  return addPipe(url, "trickle(d1)");
    192 }