tor-browser

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

test_cache2_compression_dictionary.js (4157B)


      1 /*
      2 * Tests for cache2 Compression Dictionary support (draft-ietf-httpbis-compression-dictionary-19)
      3 * - Storing dictionaries via Use-As-Dictionary
      4 * - Using Available-Dictionary for decompression
      5 */
      6 
      7 "use strict";
      8 
      9 // Load cache helpers
     10 Services.scriptloader.loadSubScript("resource://test/head_cache.js", this);
     11 
     12 const { NodeHTTPSServer } = ChromeUtils.importESModule(
     13  "resource://testing-common/NodeServer.sys.mjs"
     14 );
     15 
     16 var server = null;
     17 // Keep these in sync with duplicates below!
     18 const dictContent = "DICTIONARY_DATA";
     19 const decompressedContent = "COMPRESSED_DATA";
     20 const resourcePath = "/resource";
     21 const dictPath = "/dict";
     22 
     23 function makeChan(url) {
     24  let chan = NetUtil.newChannel({
     25    uri: url,
     26    loadUsingSystemPrincipal: true,
     27    contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT,
     28  }).QueryInterface(Ci.nsIHttpChannel);
     29  return chan;
     30 }
     31 
     32 function channelOpenPromise(chan) {
     33  return new Promise(resolve => {
     34    function finish(req, buffer) {
     35      resolve([req, buffer]);
     36    }
     37    chan.asyncOpen(new ChannelListener(finish, null, CL_ALLOW_UNKNOWN_CL));
     38  });
     39 }
     40 
     41 // Serve a dictionary with Use-As-Dictionary header
     42 function serveDictionary(request, response) {
     43  // the server can't see the global versions of these.
     44  // Note: keep in sync with above!
     45  let dict = "dict1";
     46  const dictContent = "DICTIONARY_DATA";
     47  response.writeHead(200, {
     48    "Content-Type": "application/octet-stream",
     49    "Use-As-Dictionary": `match=\"*\", id=\"${dict}\", type=raw`,
     50    "Cache-Control": "max-age=3600",
     51  });
     52  response.end(dictContent, "binary");
     53 }
     54 
     55 // Serve a resource with Available-Dictionary header
     56 function serveCompressedResource(request, response) {
     57  // brotli compressed data is 4 byte magic + 32-byte SHA-256 hash (which we
     58  // don't check)
     59  const compressedContent =
     60    "\xff\x44\x43\x42" +
     61    "12345678901234567890123456789012" +
     62    "\x21\x38\x00\x04COMPRESSED_DATA\x03";
     63  let availDict = request.headers["available-dictionary"];
     64  if (availDict != undefined) {
     65    response.writeHead(200, {
     66      "Content-Type": "application/octet-stream",
     67      "Content-Encoding": "dcb",
     68    });
     69    response.end(compressedContent, "binary");
     70  } else {
     71    response.writeHead(200, {
     72      "Content-Type": "application/octet-stream",
     73    });
     74    response.end("UNCOMPRESSED_DATA", "binary");
     75  }
     76 }
     77 
     78 add_setup(async function () {
     79  Services.prefs.setBoolPref("network.http.dictionaries.enable", true);
     80  if (!server) {
     81    server = new NodeHTTPSServer();
     82    await server.start();
     83    registerCleanupFunction(async () => {
     84      await server.stop();
     85    });
     86 
     87    await server.registerPathHandler(dictPath, serveDictionary);
     88    await server.registerPathHandler(resourcePath, serveCompressedResource);
     89  }
     90 });
     91 
     92 add_task(async function test_resource_without_dictionary() {
     93  let uri = `${server.origin()}${resourcePath}`;
     94  let chan = makeChan(uri);
     95  let [, data] = await channelOpenPromise(chan);
     96  Assert.equal(data, "UNCOMPRESSED_DATA", "Received uncompressed data");
     97 });
     98 
     99 add_task(async function test_store_dictionary() {
    100  let uri = `${server.origin()}${dictPath}`;
    101  let chan = makeChan(uri);
    102  let [, data] = await channelOpenPromise(chan);
    103  Assert.equal(data, dictContent, "Dictionary body matches");
    104 
    105  await new Promise(resolve => {
    106    // Check that dictionary is stored in cache (disk)
    107    let lci = Services.loadContextInfo.custom(false, {
    108      partitionKey: `(https,localhost)`,
    109    });
    110    asyncCheckCacheEntryPresence(uri, "disk", true, lci, resolve);
    111  });
    112 });
    113 
    114 add_task(async function test_use_dictionary_for_resource() {
    115  let uri = `${server.origin()}${resourcePath}`;
    116 
    117  let chan = makeChan(uri);
    118  let [req, data] = await channelOpenPromise(chan);
    119  // Check for expected uncompressed content
    120  Assert.strictEqual(
    121    data,
    122    decompressedContent,
    123    "Received compressed data (decompression not supported in test)"
    124  );
    125  // Check response headers
    126  Assert.equal(
    127    req.getResponseHeader("Content-Encoding"),
    128    "",
    129    "Content-Encoding dcb was removed"
    130  );
    131  let availdict = req.getRequestHeader("available-dictionary");
    132  Assert.equal(availdict, ":iFRBfhN7ePMquH3Lmw/oL4xRkaa8QjW43JQO+04KA7I=:");
    133 });