/* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ add_setup(function test_setup() { Services.prefs.setIntPref( "network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN ); Services.prefs.setBoolPref( "network.cookieJarSettings.unblocked_for_testing", true ); Services.prefs.setBoolPref( "network.cookie.cookieBehavior.optInPartitioning", true ); Services.prefs.setBoolPref("network.cookie.CHIPS.enabled", true); Services.prefs.setBoolPref( "network.cookie.chips.partitionLimitEnabled", true ); Services.prefs.setBoolPref( "network.cookie.chips.partitionLimitDryRun", false ); Services.prefs.setIntPref( "network.cookie.chips.partitionLimitByteCapacity", 24 ); }); registerCleanupFunction(() => { Services.prefs.clearUserPref("network.cookie.cookieBehavior"); Services.prefs.clearUserPref( "network.cookie.cookieBehavior.optInPartitioning" ); Services.prefs.clearUserPref( "network.cookieJarSettings.unblocked_for_testing" ); Services.prefs.clearUserPref("network.cookie.CHIPS.enabled"); Services.prefs.clearUserPref("network.cookie.chips.partitionLimitEnabled"); Services.prefs.clearUserPref("network.cookie.chips.partitionLimitDryRun"); Services.prefs.clearUserPref( "network.cookie.chips.partitionLimitByteCapacity" ); Services.cookies.removeAll(); }); function addChipsCookie( name, value, host, expiry, lastAccessed, creationTime, db ) { let cookie = new Cookie( name, value, host, "/", // path expiry, lastAccessed, creationTime, false, // session true, // secure false, // http-only false, // in browser element { partitionKey: "(https,example.com)" }, Ci.nsICookie.SAMESITE_UNSET, Ci.nsICookie.SCHEME_UNSET, true // isPartitioned ); db.insertCookie(cookie); } add_task(async function test_purge_crash() { let profile = do_get_profile(); let dbFile = do_get_cookie_file(profile); Assert.ok(!dbFile.exists()); let schemaDb = new CookieDatabaseConnection(dbFile, 15); let now = Date.now() * 1000; // date in microseconds let past = Math.round(now / 1e3 - 1000); let future = Math.round(now / 1e3 + 1000) + 20000; let host = "example.com"; // add three cookies such that their order in the CookieEntry list is NOT // sorted by age // we set up a few cookies to get close to the chips limit, without going over // if we front-load the list with enough recently used cookies // we can trigger a crash in the CHIPS purging (before our fix in Bug 1971595) addChipsCookie("c4", "4", host, future, past + 4000, past, schemaDb); addChipsCookie("c5", "5", host, future, past + 4000, past, schemaDb); addChipsCookie("c6", "6", host, future, past + 4000, past, schemaDb); addChipsCookie("c7", "7", host, future, past + 4000, past, schemaDb); addChipsCookie("c8", "8", host, future, past + 4000, past, schemaDb); addChipsCookie("c1", "1", host, future, past, past, schemaDb); addChipsCookie("c2", "2", host, future, past + 3000, past, schemaDb); addChipsCookie("c3", "3", host, future, past + 2000, past, schemaDb); // check that the cookies were added to the db Assert.equal(do_count_cookies_in_db(schemaDb.db), 8); // total Assert.equal( do_count_cookies_in_db(schemaDb.db, "example.com"), // per host+OA 8 ); const PATH_EMPTY = "/"; const FIRST_PARTY = "example.com"; const URL_DOCUMENT_FIRSTPARTY = "https://" + FIRST_PARTY + PATH_EMPTY; function createPartitionKey(url) { let uri = NetUtil.newURI(url); return `(${uri.scheme},${uri.host})`; } function createOriginAttributes(partitionKey) { return JSON.stringify({ firstPartyDomain: "", geckoViewSessionContextId: "", inIsolatedMozBrowser: false, partitionKey, privateBrowsingId: 0, userContextId: 0, }); } const partitionedOAs = createOriginAttributes( createPartitionKey(URL_DOCUMENT_FIRSTPARTY) ); // validate the db is as expected // startup the cookie service and check the cookie count // this shouldn't update the lastAccessed values (which determines cookie age) let partitioned = Services.cookies.getCookiesWithOriginAttributes( partitionedOAs, FIRST_PARTY ); // a printed list at this point is expected: c4, c5, ..., c8, c1, ... Assert.equal(partitioned.length, 8); // add a CHIPS cookie - triggers a CHIPS purge // use enough Bytes to trigger the purging of many cookies added before // this is where the crash occurs const cv = Services.cookies.add( host, "/", // path "cxxxxx", // name "yyyyyy", // value true, // secure false, // http-only true, // isSession future, { partitionKey: "(https,example.com)" }, Ci.nsICookie.SAMESITE_UNSET, // SameSite Ci.nsICookie.SCHEME_HTTPS, true // partitioned ); Assert.equal(cv.result, Ci.nsICookieValidation.eOK, "Valid cookie"); // check post-purge cookie count let postPurgeCookies = Services.cookies.getCookiesWithOriginAttributes( partitionedOAs, FIRST_PARTY ); Assert.equal(postPurgeCookies.length, 5); schemaDb.close(); });