tor-browser

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

test_cache_orphaned_body.html (6875B)


      1 <!-- Any copyright is dedicated to the Public Domain.
      2   - http://creativecommons.org/publicdomain/zero/1.0/ -->
      3 <!DOCTYPE HTML>
      4 <html>
      5 <head>
      6  <title>Test Cache with QuotaManager Restart</title>
      7  <script src="/tests/SimpleTest/SimpleTest.js"></script>
      8  <script type="text/javascript" src="large_url_list.js"></script>
      9  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
     10 </head>
     11 <body>
     12 <script class="testbody" type="text/javascript">
     13 function setupTestIframe() {
     14  return new Promise(function(resolve) {
     15    var iframe = document.createElement("iframe");
     16    iframe.src = "empty.html";
     17    iframe.onload = function() {
     18      window.caches = iframe.contentWindow.caches;
     19      resolve();
     20    };
     21    document.body.appendChild(iframe);
     22  });
     23 }
     24 
     25 function clearStorage() {
     26  return new Promise(function(resolve) {
     27    var qms = SpecialPowers.Services.qms;
     28    var principal = SpecialPowers.wrap(document).nodePrincipal;
     29    var request = qms.clearStoragesForPrincipal(principal);
     30    var cb = SpecialPowers.wrapCallback(resolve);
     31    request.callback = cb;
     32  });
     33 }
     34 
     35 function storageUsage() {
     36  return new Promise(function(resolve) {
     37    var qms = SpecialPowers.Services.qms;
     38    var principal = SpecialPowers.wrap(document).nodePrincipal;
     39    var cb = SpecialPowers.wrapCallback(function(request) {
     40      var result = request.result;
     41      resolve(result.usage);
     42    });
     43    qms.getUsageForPrincipal(principal, cb);
     44  });
     45 }
     46 
     47 function groupUsage() {
     48  return new Promise(function(resolve) {
     49   navigator.storage.estimate().then(storageEstimation => {
     50     resolve(storageEstimation.usage, 0);
     51   });
     52  });
     53 }
     54 
     55 function workerGroupUsage() {
     56  return new Promise(function(resolve) {
     57    function workerScript() {
     58      navigator.storage.estimate().then(storageEstimation => {
     59        postMessage(storageEstimation.usage);
     60      });
     61    }
     62 
     63    let url =
     64      URL.createObjectURL(new Blob(["(", workerScript.toString(), ")()"]));
     65 
     66    let worker = new Worker(url);
     67    worker.onmessage = function(e) {
     68      resolve(e.data, 0);
     69    };
     70  });
     71 }
     72 
     73 function resetStorage() {
     74  return new Promise(function(resolve) {
     75    var qms = SpecialPowers.Services.qms;
     76    var principal = SpecialPowers.wrap(document).nodePrincipal;
     77    var request = qms.resetStoragesForPrincipal(principal);
     78    var cb = SpecialPowers.wrapCallback(resolve);
     79    request.callback = cb;
     80  });
     81 }
     82 
     83 function gc() {
     84  return new Promise(function(resolve) {
     85    SpecialPowers.exactGC(resolve);
     86  });
     87 }
     88 
     89 SimpleTest.waitForExplicitFinish();
     90 SpecialPowers.pushPrefEnv({
     91  "set": [["dom.caches.testing.enabled", true],
     92          ["dom.quotaManager.testing", true]]
     93 }, function() {
     94  var name = "orphanedBodyOwner";
     95  var cache = null;
     96  var response = null;
     97  var initialUsage = 0;
     98  var fullUsage = 0;
     99  var endUsage = 0;
    100  var url = "test_cache_add.js";
    101 
    102  // start from a fresh origin directory so other tests do not influence our
    103  // results
    104  setupTestIframe().then(function() {
    105    return clearStorage();
    106  }).then(function() {
    107    return storageUsage();
    108  }).then(function(usage) {
    109    is(0, usage, "disk usage should be zero to start");
    110  })
    111 
    112  // Initialize and populate an initial cache to get the base sqlite pages
    113  // and directory structure allocated.
    114  .then(function() {
    115    return caches.open(name);
    116  }).then(function(c) {
    117    return c.add(url);
    118  }).then(function() {
    119    return gc();
    120  }).then(function() {
    121    return caches.delete(name);
    122  }).then(function(deleted) {
    123    ok(deleted, "cache should be deleted");
    124 
    125    // This is a bit superfluous, but its necessary to make sure the Cache is
    126    // fully deleted before we proceed.  The deletion actually takes place in
    127    // two async steps.  We don't want to resetStorage() until the second step
    128    // has taken place.  This extra Cache operation ensure that all the
    129    // runnables have been flushed through the threads, etc.
    130    return caches.has(name);
    131  })
    132 
    133  // Now measure initial disk usage
    134  .then(function() {
    135    return resetStorage();
    136  }).then(function() {
    137    return storageUsage();
    138  }).then(function(usage) {
    139    initialUsage = usage;
    140  })
    141 
    142  // Now re-populate the Cache object
    143  .then(function() {
    144    return caches.open(name);
    145  }).then(function(c) {
    146    cache = c;
    147    return cache.add(url);
    148  })
    149 
    150  // Get a reference to the body we've stored in the Cache.
    151  .then(function() {
    152    return cache.match(url);
    153  }).then(function(r) {
    154    response = r;
    155    return cache.delete(url);
    156  }).then(function(result) {
    157    ok(result, "Cache entry should be deleted");
    158  })
    159 
    160  // Reset the quota dir while the cache entry is deleted, but still referenced
    161  // from the DOM.  This forces the body to be orphaned.
    162  .then(function() {
    163    return resetStorage();
    164  }).then(function() {
    165    return storageUsage();
    166  }).then(function(usage) {
    167    fullUsage = usage;
    168    ok(fullUsage > initialUsage, "disk usage should have grown");
    169  })
    170 
    171  // Test groupUsage()
    172  .then(function() {
    173    return resetStorage();
    174  }).then(function() {
    175    return groupUsage();
    176  }).then(function(usage) {
    177    fullUsage = usage;
    178    ok(fullUsage > initialUsage, "disk group usage should have grown");
    179  })
    180 
    181  // Test workerGroupUsage()
    182  .then(function() {
    183    return resetStorage();
    184  }).then(function() {
    185    return workerGroupUsage();
    186  }).then(function(usage) {
    187    fullUsage = usage;
    188    ok(fullUsage > initialUsage, "disk group usage on worker should have grown");
    189  })
    190 
    191  // Now perform a new Cache operation that will reopen the origin.  This
    192  // should clean up the orphaned body.
    193  .then(function() {
    194    return caches.match(url);
    195  }).then(function(r) {
    196    ok(!r, "response should not exist in storage");
    197  })
    198 
    199  // Finally, verify orphaned data was cleaned up by re-checking the disk
    200  // usage.  Reset the storage first to ensure any WAL transaction files
    201  // are flushed before measuring the usage.
    202  .then(function() {
    203    return resetStorage();
    204  }).then(function() {
    205    return storageUsage();
    206  }).then(function(usage) {
    207    endUsage = usage;
    208    dump("### ### initial:" + initialUsage + ", full:" + fullUsage +
    209         ", end:" + endUsage + "\n");
    210    ok(endUsage < fullUsage, "disk usage should have shrank");
    211    is(endUsage, initialUsage, "disk usage should return to original");
    212  })
    213 
    214  // Verify that the stale, orphaned response cannot be put back into
    215  // the cache.
    216  .then(function() {
    217    ok(!response.bodyUsed, "response body should not be considered used");
    218    return cache.put(url, response).then(function() {
    219        ok(false, "Should not be able to store stale orphaned body.");
    220      }).catch(function(e) {
    221        is(e.name, "TypeError", "storing a stale orphaned body should throw TypeError");
    222      });
    223  }).then(function() {
    224    ok(response.bodyUsed, "attempting to store response should mark body used");
    225  })
    226 
    227  .then(function() {
    228    SimpleTest.finish();
    229  });
    230 });
    231 </script>
    232 </body>
    233 </html>