tor-browser

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

test_alt-data_closeWithStatus.js (4887B)


      1 /**
      2 * Test for the "alternative data stream" - closing the stream with an error.
      3 *
      4 * - we load a URL with preference for an alt data (check what we get is the raw data,
      5 *   since there was nothing previously cached)
      6 * - we store something in alt data (using the asyncWait method)
      7 * - then we abort the operation calling closeWithStatus()
      8 * - we flush the HTTP cache
      9 * - we reload the same URL using a new channel, again prefering the alt data be loaded
     10 * - again we receive the data from the server.
     11 */
     12 
     13 "use strict";
     14 
     15 const { HttpServer } = ChromeUtils.importESModule(
     16  "resource://testing-common/httpd.sys.mjs"
     17 );
     18 
     19 ChromeUtils.defineLazyGetter(this, "URL", function () {
     20  return "http://localhost:" + httpServer.identity.primaryPort + "/content";
     21 });
     22 
     23 var httpServer = null;
     24 
     25 // needs to be rooted
     26 var cacheFlushObserver = (cacheFlushObserver = {
     27  observe() {
     28    cacheFlushObserver = null;
     29    readServerContentAgain();
     30  },
     31 });
     32 
     33 var currentThread = null;
     34 
     35 function make_channel(url) {
     36  return NetUtil.newChannel({ uri: url, loadUsingSystemPrincipal: true });
     37 }
     38 
     39 function inChildProcess() {
     40  return Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
     41 }
     42 
     43 const responseContent = "response body";
     44 const responseContent2 = "response body 2";
     45 const altContent = "!@#$%^&*()";
     46 const altContentType = "text/binary";
     47 
     48 var shouldPassRevalidation = true;
     49 
     50 var cache_storage = null;
     51 
     52 function contentHandler(metadata, response) {
     53  response.setHeader("Content-Type", "text/plain");
     54  response.setHeader("Cache-Control", "no-cache");
     55  response.setHeader("ETag", "test-etag1");
     56 
     57  let etag;
     58  try {
     59    etag = metadata.getHeader("If-None-Match");
     60  } catch (ex) {
     61    etag = "";
     62  }
     63 
     64  if (etag == "test-etag1" && shouldPassRevalidation) {
     65    response.setStatusLine(metadata.httpVersion, 304, "Not Modified");
     66  } else {
     67    var content = shouldPassRevalidation ? responseContent : responseContent2;
     68    response.bodyOutputStream.write(content, content.length);
     69  }
     70 }
     71 
     72 function check_has_alt_data_in_index(aHasAltData, callback) {
     73  if (inChildProcess()) {
     74    callback();
     75    return;
     76  }
     77 
     78  syncWithCacheIOThread(() => {
     79    var hasAltData = {};
     80    cache_storage.getCacheIndexEntryAttrs(createURI(URL), "", hasAltData, {});
     81    Assert.equal(hasAltData.value, aHasAltData);
     82    callback();
     83  }, true);
     84 }
     85 
     86 function run_test() {
     87  do_get_profile();
     88  httpServer = new HttpServer();
     89  httpServer.registerPathHandler("/content", contentHandler);
     90  httpServer.start(-1);
     91  do_test_pending();
     92 
     93  if (!inChildProcess()) {
     94    cache_storage = getCacheStorage("disk");
     95    wait_for_cache_index(asyncOpen);
     96  } else {
     97    asyncOpen();
     98  }
     99 }
    100 
    101 function asyncOpen() {
    102  var chan = make_channel(URL);
    103 
    104  var cc = chan.QueryInterface(Ci.nsICacheInfoChannel);
    105  cc.preferAlternativeDataType(
    106    altContentType,
    107    "",
    108    Ci.nsICacheInfoChannel.ASYNC
    109  );
    110 
    111  chan.asyncOpen(new ChannelListener(readServerContent, null));
    112 }
    113 
    114 function readServerContent(request, buffer) {
    115  var cc = request.QueryInterface(Ci.nsICacheInfoChannel);
    116 
    117  Assert.equal(buffer, responseContent);
    118  Assert.equal(cc.alternativeDataType, "");
    119  check_has_alt_data_in_index(false, () => {
    120    if (!inChildProcess()) {
    121      currentThread = Services.tm.currentThread;
    122    }
    123 
    124    executeSoon(() => {
    125      var os = cc.openAlternativeOutputStream(
    126        altContentType,
    127        altContent.length
    128      );
    129 
    130      var aos = os.QueryInterface(Ci.nsIAsyncOutputStream);
    131      aos.asyncWait(
    132        _ => {
    133          os.write(altContent, altContent.length);
    134          aos.closeWithStatus(Cr.NS_ERROR_FAILURE);
    135          executeSoon(flushAndReadServerContentAgain);
    136        },
    137        0,
    138        0,
    139        currentThread
    140      );
    141    });
    142  });
    143 }
    144 
    145 function flushAndReadServerContentAgain() {
    146  // We need to do a GC pass to ensure the cache entry has been freed.
    147  gc();
    148  if (!inChildProcess()) {
    149    Services.cache2
    150      .QueryInterface(Ci.nsICacheTesting)
    151      .flush(cacheFlushObserver);
    152  } else {
    153    do_send_remote_message("flush");
    154    do_await_remote_message("flushed").then(() => {
    155      readServerContentAgain();
    156    });
    157  }
    158 }
    159 
    160 function readServerContentAgain() {
    161  var chan = make_channel(URL);
    162  var cc = chan.QueryInterface(Ci.nsICacheInfoChannel);
    163  cc.preferAlternativeDataType(
    164    "dummy1",
    165    "text/javascript",
    166    Ci.nsICacheInfoChannel.ASYNC
    167  );
    168  cc.preferAlternativeDataType(
    169    altContentType,
    170    "text/plain",
    171    Ci.nsICacheInfoChannel.ASYNC
    172  );
    173  cc.preferAlternativeDataType("dummy2", "", Ci.nsICacheInfoChannel.ASYNC);
    174 
    175  chan.asyncOpen(new ChannelListener(readServerContentAgainCB, null));
    176 }
    177 
    178 function readServerContentAgainCB(request, buffer) {
    179  var cc = request.QueryInterface(Ci.nsICacheInfoChannel);
    180 
    181  Assert.equal(buffer, responseContent);
    182  Assert.equal(cc.alternativeDataType, "");
    183  check_has_alt_data_in_index(false, () => httpServer.stop(do_test_finished));
    184 }