Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
- Manifest: netwerk/test/unit/xpcshell.toml
"use strict";
// A read-only cache hit must not rewrite the entry file. Frecency and the access
// stats (lastFetched/fetchCount) are kept in memory and in the central index;
// the per-entry file is only rewritten when its data or headers actually change.
// Rewriting it on every hit generates IO and triggers on-access anti-malware
// scans, which is what this change avoids.
function openEntry(behavior, meta, data, url = URL) {
return new Promise(resolve => {
asyncOpenCacheEntry(
url,
"disk",
Ci.nsICacheStorage.OPEN_NORMALLY,
null,
new OpenCallback(behavior, meta, data, resolve)
);
});
}
function flushCache() {
return new Promise(resolve => {
Services.cache2.QueryInterface(Ci.nsICacheTesting).flush({
QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
observe() {
resolve();
},
});
});
}
function listEntryFiles() {
let dir = getDiskCacheDirectory();
dir.append("entries");
Assert.ok(dir.exists(), "entries directory exists");
let files = [];
let e = dir.directoryEntries;
while (e.hasMoreElements()) {
files.push(e.nextFile);
}
return files;
}
async function readSingleEntryFile() {
let files = listEntryFiles();
Assert.equal(files.length, 1, "exactly one entry file on disk");
return IOUtils.read(files[0].path);
}
function bytesEqual(a, b) {
if (a.length != b.length) {
return false;
}
for (let i = 0; i < a.length; i++) {
if (a[i] != b[i]) {
return false;
}
}
return true;
}
add_task(async function test_no_rewrite_on_read_hit() {
do_get_profile();
// Create the entry and persist it to disk. WAITFORWRITE makes the callback
// fire only after the data write completes; flushCache() then forces the
// metadata to disk and closes the entry.
await openEntry(NEW | WAITFORWRITE, "metadata", "0123456789");
await new Promise(wait_for_cache_index);
await flushCache();
let baseline = await readSingleEntryFile();
// Several read-only hits. Each updates frecency and lastFetched/fetchCount in
// memory and the index. flushCache() purges the memory pools, which closes the
// entry; under the old behavior a dirtied entry would be written back here.
for (let i = 0; i < 3; i++) {
await openEntry(NORMAL, "metadata", "0123456789");
await flushCache();
}
let after = await readSingleEntryFile();
Assert.ok(
bytesEqual(baseline, after),
"entry file is byte-identical after read-only hits (no metadata rewrite)"
);
});