/* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; requestLongerTimeout(2); 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 CONTAINER_PRINCIPAL_A = Services.scriptSecurityManager.createContentPrincipal( Services.io.newURI(ORIGIN_A), { userContextId: 2 } ); const CONTAINER_PRINCIPAL_A_SUB = Services.scriptSecurityManager.createContentPrincipal( Services.io.newURI(ORIGIN_A_SUB), { userContextId: 2 } ); 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); // Stylesheets are cached per process, so we need to keep tabs open for the // duration of a test. let tabs = {}; function getTestURLForOrigin(origin) { return ( TEST_ROOT_DIR.replace("chrome://mochitests/content", origin) + "file_css_cache.html" ); } async function testCached(origin, isCached) { let principal = Services.scriptSecurityManager.createContentPrincipalFromOrigin(origin); let url = getTestURLForOrigin(principal.originNoSuffix); let numParsed; let tab = tabs[principal.origin]; let loadedPromise; if (!tab) { info("Creating new tab for " + url); tab = gBrowser.addTab(url, { triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), userContextId: principal.originAttributes.userContextId, }); gBrowser.selectedTab = tab; loadedPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser); tabs[principal.origin] = tab; } else { loadedPromise = BrowserTestUtils.browserLoaded(tab.linkedBrowser); tab.linkedBrowser.reload(); } await loadedPromise; numParsed = await SpecialPowers.spawn(tab.linkedBrowser, [], () => { return SpecialPowers.getDOMWindowUtils(content).parsedStyleSheets; }); ok( numParsed == 0 || numParsed == 1, `Where did that stylesheet come from expected 0 or 1, got ${numParsed}` ); // Stylesheets is cached if numParsed is 0. is(!numParsed, isCached, `${origin} is${isCached ? " " : " not "}cached`); } async function addTestTabs() { 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); // Add more entries for ORIGIN_A but set a different user context. await testCached(CONTAINER_PRINCIPAL_A.origin, false); // Add another entry for ORIGIN_A but set a different user context. await testCached(CONTAINER_PRINCIPAL_A_SUB.origin, false); // Test that the cache has been populated. await testCached(ORIGIN_A, true); 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); await testCached(CONTAINER_PRINCIPAL_A.origin, true); await testCached(CONTAINER_PRINCIPAL_A_SUB.origin, true); } async function cleanupTestTabs() { Object.values(tabs).forEach(BrowserTestUtils.removeTab); tabs = {}; } 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_CSS_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); // User context 2 not cleared because we clear by exact principal. await testCached(CONTAINER_PRINCIPAL_A.origin, true); await testCached(CONTAINER_PRINCIPAL_A_SUB.origin, true); // Cleanup cleanupTestTabs(); ChromeUtils.clearResourceCache({ types: ["stylesheet"], }); }); add_task(async function test_deleteBySite() { await addTestTabs(); // Clear data for base domain of A. info("Clearing cache for (schemeless) site " + BASE_DOMAIN_A); await new Promise(resolve => { Services.clearData.deleteDataFromSite( BASE_DOMAIN_A, {}, false, Ci.nsIClearDataService.CLEAR_CSS_CACHE, resolve ); }); // 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); // User context 2 also cleared because we passed the wildcard // OriginAttributesPattern {} above. await testCached(CONTAINER_PRINCIPAL_A.origin, false); await testCached(CONTAINER_PRINCIPAL_A_SUB.origin, false); // Entries for B should still exist. await testCached(ORIGIN_B, true); await testCached(ORIGIN_B_SUB, true); await testCached(ORIGIN_B_HTTP, true); // Cleanup cleanupTestTabs(); ChromeUtils.clearResourceCache(["stylesheet"]); }); add_task(async function test_deleteBySite_oa_pattern() { await addTestTabs(); // Clear data for site A. info("Clearing cache for (schemeless) site+pattern " + BASE_DOMAIN_A); await new Promise(resolve => { Services.clearData.deleteDataFromSite( BASE_DOMAIN_A, { userContextId: CONTAINER_PRINCIPAL_A.originAttributes.userContextId }, false, Ci.nsIClearDataService.CLEAR_CSS_CACHE, resolve ); }); // Normal entries should not have been cleared. await testCached(ORIGIN_A, true); await testCached(ORIGIN_A_SUB, true); await testCached(ORIGIN_A_HTTP, true); // Container entries should have been cleared because we have targeted them with the pattern. await testCached(CONTAINER_PRINCIPAL_A.origin, false); await testCached(CONTAINER_PRINCIPAL_A_SUB.origin, false); // Entries for unrelated site B should still exist. await testCached(ORIGIN_B, true); await testCached(ORIGIN_B_SUB, true); await testCached(ORIGIN_B_HTTP, true); // Cleanup cleanupTestTabs(); ChromeUtils.clearResourceCache(["stylesheet"]); });