231 lines
7.2 KiB
JavaScript
231 lines
7.2 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
"use strict";
|
|
|
|
const BASE_DOMAIN_A = "example.com";
|
|
const ORIGIN_A = `https://${BASE_DOMAIN_A}`;
|
|
const ORIGIN_A_HTTP = `http://${BASE_DOMAIN_A}`;
|
|
const ORIGIN_A_SUB = `https://test1.${BASE_DOMAIN_A}`;
|
|
|
|
const BASE_DOMAIN_B = "example.org";
|
|
const ORIGIN_B = `https://${BASE_DOMAIN_B}`;
|
|
const ORIGIN_B_HTTP = `http://${BASE_DOMAIN_B}`;
|
|
const ORIGIN_B_SUB = `https://test1.${BASE_DOMAIN_B}`;
|
|
|
|
const TEST_ROOT_DIR = getRootDirectory(gTestPath);
|
|
|
|
// Images are cached per process, so we need to keep tabs open for the
|
|
// duration of a test.
|
|
let originToTabs = {};
|
|
|
|
function getTestURLForOrigin(origin) {
|
|
return TEST_ROOT_DIR.replace("chrome://mochitests/content", origin);
|
|
}
|
|
|
|
async function testCached(
|
|
origin,
|
|
isCached,
|
|
testPartitioned = false,
|
|
isTODO = false
|
|
) {
|
|
let tabs = originToTabs[origin];
|
|
|
|
for (let tab of tabs) {
|
|
// For the partition test we inspect the cache state of the iframe.
|
|
let browsingContext = testPartitioned
|
|
? tab.linkedBrowser.browsingContext.children[0]
|
|
: tab.linkedBrowser.browsingContext;
|
|
let actualCached = await SpecialPowers.spawn(browsingContext, [], () => {
|
|
let imgUrl = content.document.querySelector("img").src;
|
|
let imageCache = SpecialPowers.Cc[
|
|
"@mozilla.org/image/tools;1"
|
|
].getService(Ci.imgITools);
|
|
let uri = SpecialPowers.Services.io.newURI(imgUrl);
|
|
let properties = imageCache
|
|
.getImgCacheForDocument(content.document)
|
|
.findEntryProperties(uri, content.document);
|
|
return !!properties;
|
|
});
|
|
|
|
let msg = `${origin}${isCached ? " " : " not "}cached`;
|
|
if (testPartitioned) {
|
|
msg = "Partitioned under " + msg;
|
|
}
|
|
|
|
if (isTODO) {
|
|
todo(actualCached, isCached, msg);
|
|
} else {
|
|
is(actualCached, isCached, msg);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates tabs and loads images in first party and third party context.
|
|
* @returns {Promise} - Promise which resolves once all tabs are initialized,
|
|
* {@link originToTabs} is populated and (sub-)resources have loaded.
|
|
*/
|
|
function addTestTabs() {
|
|
// Adding two tabs for ORIGIN_A so we can test clearing for a principal
|
|
// cross-process (non-fission).
|
|
let promises = [
|
|
[ORIGIN_A, ORIGIN_B],
|
|
[ORIGIN_A, ORIGIN_B],
|
|
[ORIGIN_A_SUB, ORIGIN_B_SUB],
|
|
[ORIGIN_A_HTTP, ORIGIN_B_HTTP],
|
|
[ORIGIN_B, ORIGIN_A],
|
|
[ORIGIN_B_SUB, ORIGIN_A_SUB],
|
|
[ORIGIN_B_HTTP, ORIGIN_A_HTTP],
|
|
].map(async ([firstParty, thirdParty]) => {
|
|
let urlFirstParty =
|
|
getTestURLForOrigin(firstParty) + "file_image_cache.html";
|
|
let urlThirdParty =
|
|
getTestURLForOrigin(thirdParty) + "file_image_cache.html";
|
|
|
|
info("Creating new tab for " + urlFirstParty);
|
|
let tab = BrowserTestUtils.addTab(gBrowser, urlFirstParty);
|
|
await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
|
|
|
info("Creating iframe for " + urlThirdParty);
|
|
await SpecialPowers.spawn(tab.linkedBrowser, [urlThirdParty], async url => {
|
|
let iframe = content.document.createElement("iframe");
|
|
iframe.src = url;
|
|
|
|
let loadPromise = ContentTaskUtils.waitForEvent(iframe, "load", false);
|
|
content.document.body.appendChild(iframe);
|
|
await loadPromise;
|
|
});
|
|
|
|
let tabs = originToTabs[firstParty];
|
|
if (!tabs) {
|
|
tabs = [];
|
|
originToTabs[firstParty] = tabs;
|
|
}
|
|
tabs.push(tab);
|
|
});
|
|
|
|
return Promise.all(promises);
|
|
}
|
|
|
|
function cleanup() {
|
|
Object.values(originToTabs).flat().forEach(BrowserTestUtils.removeTab);
|
|
originToTabs = {};
|
|
let imageCache = Cc["@mozilla.org/image/tools;1"]
|
|
.getService(Ci.imgITools)
|
|
.getImgCacheForDocument(null);
|
|
imageCache.clearCache(); // no parameter=all
|
|
}
|
|
|
|
add_setup(function () {
|
|
cleanup();
|
|
});
|
|
|
|
add_task(async function test_deleteByPrincipal() {
|
|
await SpecialPowers.setBoolPref("dom.security.https_first", false);
|
|
await addTestTabs();
|
|
|
|
// Clear data for content principal of A
|
|
info("Clearing cache for principal " + ORIGIN_A);
|
|
await new Promise(resolve => {
|
|
Services.clearData.deleteDataFromPrincipal(
|
|
Services.scriptSecurityManager.createContentPrincipalFromOrigin(ORIGIN_A),
|
|
false,
|
|
Ci.nsIClearDataService.CLEAR_IMAGE_CACHE,
|
|
resolve
|
|
);
|
|
});
|
|
|
|
// Only the cache entry for ORIGIN_A should have been cleared.
|
|
await testCached(ORIGIN_A, false);
|
|
await testCached(ORIGIN_A_SUB, true);
|
|
await testCached(ORIGIN_A_HTTP, true);
|
|
await testCached(ORIGIN_B, true);
|
|
await testCached(ORIGIN_B_SUB, true);
|
|
await testCached(ORIGIN_B_HTTP, true);
|
|
|
|
// No partitioned cache should have been cleared.
|
|
await testCached(ORIGIN_A, true, true);
|
|
await testCached(ORIGIN_A_SUB, true, true);
|
|
await testCached(ORIGIN_A_HTTP, true, true);
|
|
// TODO: ImageCacheCleaner deleteByPrincipal does not look at the cache key's
|
|
// isolationKey and thus over-clears. In this case it clears cache for A
|
|
// partitioned under B, even though the test principal does not set a
|
|
// partitionKey.
|
|
// See Bug 1713088.
|
|
await testCached(ORIGIN_B, true, true, true);
|
|
await testCached(ORIGIN_B_SUB, true, true);
|
|
await testCached(ORIGIN_B_HTTP, true, true);
|
|
|
|
cleanup();
|
|
});
|
|
|
|
add_task(async function test_deleteBySite() {
|
|
await SpecialPowers.setBoolPref("dom.security.https_first", false);
|
|
await addTestTabs();
|
|
|
|
// Clear data for site A.
|
|
info("Clearing cache for site " + BASE_DOMAIN_A);
|
|
await new Promise(resolve => {
|
|
Services.clearData.deleteDataFromSite(
|
|
BASE_DOMAIN_A,
|
|
{},
|
|
false,
|
|
Ci.nsIClearDataService.CLEAR_IMAGE_CACHE,
|
|
resolve
|
|
);
|
|
});
|
|
|
|
info("All entries for A should have been cleared.");
|
|
await testCached(ORIGIN_A, false);
|
|
await testCached(ORIGIN_A_SUB, false);
|
|
await testCached(ORIGIN_A_HTTP, false);
|
|
|
|
info("Entries for B should still exist");
|
|
await testCached(ORIGIN_B, true);
|
|
await testCached(ORIGIN_B_SUB, true);
|
|
await testCached(ORIGIN_B_HTTP, true);
|
|
|
|
info("All partitioned entries for B under A should have been cleared.");
|
|
await testCached(ORIGIN_A, false, true);
|
|
await testCached(ORIGIN_A_SUB, false, true);
|
|
await testCached(ORIGIN_A_HTTP, false, true);
|
|
|
|
info("All partitioned entries of A under B should have been cleared.");
|
|
await testCached(ORIGIN_B, false, true);
|
|
await testCached(ORIGIN_B_SUB, false, true);
|
|
await testCached(ORIGIN_B_HTTP, false, true);
|
|
|
|
cleanup();
|
|
});
|
|
|
|
add_task(async function test_deleteAll() {
|
|
await addTestTabs();
|
|
|
|
// Clear the whole image cache across processes.
|
|
info("Clearing cache for base domain " + BASE_DOMAIN_A);
|
|
await new Promise(resolve => {
|
|
Services.clearData.deleteData(
|
|
Ci.nsIClearDataService.CLEAR_IMAGE_CACHE,
|
|
resolve
|
|
);
|
|
});
|
|
|
|
// All entries should have been cleared.
|
|
await testCached(ORIGIN_A, false);
|
|
await testCached(ORIGIN_A_SUB, false);
|
|
await testCached(ORIGIN_A_HTTP, false);
|
|
await testCached(ORIGIN_B, false);
|
|
await testCached(ORIGIN_B_SUB, false);
|
|
await testCached(ORIGIN_B_HTTP, false);
|
|
|
|
// All partitioned entries should have been cleared.
|
|
await testCached(ORIGIN_A, false, true);
|
|
await testCached(ORIGIN_A_SUB, false, true);
|
|
await testCached(ORIGIN_A_HTTP, false, true);
|
|
await testCached(ORIGIN_B, false, true);
|
|
await testCached(ORIGIN_B_SUB, false, true);
|
|
await testCached(ORIGIN_B_HTTP, false, true);
|
|
|
|
cleanup();
|
|
});
|