Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const URL_EXAMPLE =
registerCleanupFunction(() => {
Services.prefs.clearUserPref("network.cookie.cookieBehavior");
Services.prefs.clearUserPref(
"network.cookie.cookieBehavior.optInPartitioning"
);
Services.prefs.clearUserPref("network.cookie.chips.partitionLimitEnabled");
Services.prefs.clearUserPref(
"network.cookie.chips.partitionLimitByteCapacity"
);
Services.prefs.clearUserPref("network.cookie.CHIPS.enabled");
Services.prefs.clearUserPref("network.cookie.chips.partitionLimitDryRun");
Services.cookies.removeAll();
});
// enable chips and chips partition limit
add_setup(async () => {
Services.prefs.setIntPref("network.cookie.cookieBehavior", 5);
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
);
});
const PATH = "/browser/netwerk/cookie/test/browser/";
const PATH_EMPTY = PATH + "file_empty.html";
const FIRST_PARTY = "example.com";
const THIRD_PARTY = "example.org";
const URL_DOCUMENT_FIRSTPARTY = "https://" + FIRST_PARTY + PATH_EMPTY;
const URL_DOCUMENT_THIRDPARTY = "https://" + THIRD_PARTY + PATH_EMPTY;
const COOKIE_PARTITIONED =
"cookie=partitioned; Partitioned; Secure; SameSite=None;";
const COOKIE_UNPARTITIONED = "cookie=unpartitioned; Secure; SameSite=None;";
function createOriginAttributes(partitionKey) {
return JSON.stringify({
firstPartyDomain: "",
geckoViewSessionContextId: "",
inIsolatedMozBrowser: false,
partitionKey,
privateBrowsingId: 0,
userContextId: 0,
});
}
function createPartitionKey(url) {
let uri = NetUtil.newURI(url);
return `(${uri.scheme},${uri.host})`;
}
function createSameSiteForeignPartitionKey(url) {
let uri = NetUtil.newURI(url);
return `(${uri.scheme},${uri.host},f)`;
}
// OriginAttributes used to access partitioned and unpartitioned cookie jars
// in all tests.
const partitionedOAs = createOriginAttributes(
createPartitionKey(URL_DOCUMENT_FIRSTPARTY)
);
const partitionedSameSiteForeignOAs = createOriginAttributes(
createSameSiteForeignPartitionKey(URL_DOCUMENT_FIRSTPARTY)
);
const unpartitionedOAs = createOriginAttributes("");
// cookie bytes >= 4013
var staticCount = 0;
function uniqueLargeCookie(partitioned) {
++staticCount;
var cookie = "largecookie"
.concat(staticCount)
.concat("=")
.concat("1234567890".repeat(400))
.concat("; Secure; SameSite=None;");
if (partitioned) {
return cookie.concat("; Partitioned");
}
return cookie;
}
async function setCookieViaDomOnChild(browser, cookie) {
await SpecialPowers.spawn(browser, [cookie], cookie => {
content.document.cookie = cookie;
});
}
// child-side document sets are byte-limited
add_task(async function test_chips_limit_document_first_party_child() {
const tab = BrowserTestUtils.addTab(gBrowser, URL_DOCUMENT_FIRSTPARTY);
const browser = gBrowser.getBrowserForTab(tab);
await BrowserTestUtils.browserLoaded(browser);
// Set partitioned and unpartitioned cookie from document child-side
// 10240 * 1.2 -> 12288
// fourth will cause purge (> 12288 Bytes)
// and we will purge down to the soft maximum (quota) (10240 Bytes)
await setCookieViaDomOnChild(browser, uniqueLargeCookie(true));
await setCookieViaDomOnChild(browser, uniqueLargeCookie(true));
await setCookieViaDomOnChild(browser, uniqueLargeCookie(true));
await setCookieViaDomOnChild(browser, uniqueLargeCookie(true));
await setCookieViaDomOnChild(browser, uniqueLargeCookie(false));
await setCookieViaDomOnChild(browser, uniqueLargeCookie(false));
await setCookieViaDomOnChild(browser, uniqueLargeCookie(false));
await setCookieViaDomOnChild(browser, uniqueLargeCookie(false));
// Get cookies from partitioned jar
let partitioned = Services.cookies.getCookiesWithOriginAttributes(
partitionedOAs,
FIRST_PARTY
);
// Get cookies from unpartitioned jar
let unpartitioned = Services.cookies.getCookiesWithOriginAttributes(
unpartitionedOAs,
FIRST_PARTY
);
// check that partitioned cookies are purged at maximum
// check that unpartitioned cookies are not
Assert.equal(partitioned.length, 2);
Assert.equal(unpartitioned.length, 4);
// Cleanup
BrowserTestUtils.removeTab(tab);
Services.cookies.removeAll();
});
// chips partitioned 3rd party cookies are subject to chips partition limit
add_task(async function test_chips_limit_third_party() {
const tab = BrowserTestUtils.addTab(gBrowser, URL_DOCUMENT_FIRSTPARTY);
const browser = gBrowser.getBrowserForTab(tab);
await BrowserTestUtils.browserLoaded(browser);
// Spawn document bc
await SpecialPowers.spawn(browser, [URL_DOCUMENT_THIRDPARTY], async url => {
let ifr = content.document.createElement("iframe");
let loadPromise = ContentTaskUtils.waitForEvent(ifr, "load");
ifr.src = url;
content.document.body.appendChild(ifr);
await loadPromise;
// Spawn iframe bc
await SpecialPowers.spawn(await ifr.browsingContext, [], async () => {
function largeCookie(partitioned, index) {
var cookie = "largecookie"
.concat(index)
.concat("=")
.concat("1234567890".repeat(400))
.concat("; Secure; SameSite=None;");
if (partitioned) {
return cookie.concat("; Partitioned");
}
return cookie;
}
content.document.cookie = largeCookie(true, 0);
content.document.cookie = largeCookie(true, 1);
content.document.cookie = largeCookie(true, 2);
content.document.cookie = largeCookie(true, 3);
content.document.cookie = largeCookie(false, 0);
content.document.cookie = largeCookie(false, 1);
content.document.cookie = largeCookie(false, 2);
content.document.cookie = largeCookie(false, 3);
});
});
// Get cookies from partitioned jar
let partitioned = Services.cookies.getCookiesWithOriginAttributes(
partitionedOAs,
THIRD_PARTY
);
// Get cookies from unpartitioned jar
let unpartitioned = Services.cookies.getCookiesWithOriginAttributes(
unpartitionedOAs,
THIRD_PARTY
);
// third party partitioned cookies are subject to the byte limit
// while unpartitioned are blocked
Assert.equal(partitioned.length, 2);
Assert.equal(unpartitioned.length, 0);
// Cleanup
BrowserTestUtils.removeTab(tab);
Services.cookies.removeAll();
});
// same-site foreign partitioned cookies are subject to the limit
// This is ABA scenario: A contains B iframe, which contains A iframe
add_task(async function test_chips_limit_samesite_foreign() {
const tab = BrowserTestUtils.addTab(gBrowser, URL_DOCUMENT_FIRSTPARTY);
const browser = gBrowser.getBrowserForTab(tab);
await BrowserTestUtils.browserLoaded(browser);
// content process (top-level)
await SpecialPowers.spawn(
browser,
[URL_DOCUMENT_THIRDPARTY, URL_DOCUMENT_FIRSTPARTY],
async (url, urlInner) => {
let ifr = content.document.createElement("iframe");
let loadPromise = ContentTaskUtils.waitForEvent(ifr, "load");
ifr.src = url;
content.document.body.appendChild(ifr);
await loadPromise;
// Spawn iframe bc (third-party to top-level)
await SpecialPowers.spawn(
await ifr.browsingContext,
[urlInner],
async urlInner => {
let ifr = content.document.createElement("iframe");
let loadPromise = ContentTaskUtils.waitForEvent(ifr, "load");
ifr.src = urlInner;
content.document.body.appendChild(ifr);
await loadPromise;
// spawn inner iframe (same-site as top-level)
await SpecialPowers.spawn(await ifr.browsingContext, [], async () => {
function largeCookie(partitioned, index) {
var cookie = "largecookie"
.concat(index)
.concat("=")
.concat("1234567890".repeat(400))
.concat("; Secure; SameSite=None;");
if (partitioned) {
return cookie.concat("; Partitioned");
}
return cookie;
}
content.document.cookie = largeCookie(true, 0);
content.document.cookie = largeCookie(true, 1);
content.document.cookie = largeCookie(true, 2);
content.document.cookie = largeCookie(true, 3);
content.document.cookie = largeCookie(false, 0);
content.document.cookie = largeCookie(false, 1);
content.document.cookie = largeCookie(false, 2);
content.document.cookie = largeCookie(false, 3);
});
}
);
}
);
// Get cookies from partitioned jar
let partitioned = Services.cookies.getCookiesWithOriginAttributes(
partitionedSameSiteForeignOAs,
FIRST_PARTY
);
// Get cookies from unpartitioned jar
let unpartitioned = Services.cookies.getCookiesWithOriginAttributes(
unpartitionedOAs, // no such thing as unpartitioned with foreign bit
FIRST_PARTY
);
// same-site foreign partitioned cookies are subject to the byte limit
// unpartitioned are blocked
Assert.equal(partitioned.length, 2);
Assert.equal(unpartitioned.length, 0);
// Cleanup
BrowserTestUtils.removeTab(tab);
Services.cookies.removeAll();
});
// reducing the byte limit pref affects the amount of cookie bytes we trigger at
add_task(async function test_chips_limit_change_byte_limit() {
Services.prefs.setIntPref(
"network.cookie.chips.partitionLimitByteCapacity",
5120 // half the default
);
const tab = BrowserTestUtils.addTab(gBrowser, URL_DOCUMENT_FIRSTPARTY);
const browser = gBrowser.getBrowserForTab(tab);
await BrowserTestUtils.browserLoaded(browser);
// two cookies of this size will exceed the new limit
await setCookieViaDomOnChild(browser, uniqueLargeCookie(true));
await setCookieViaDomOnChild(browser, uniqueLargeCookie(true));
// unpartitioned will be unaffected
await setCookieViaDomOnChild(browser, uniqueLargeCookie(false));
await setCookieViaDomOnChild(browser, uniqueLargeCookie(false));
// Get cookies from partitioned jar
let partitioned = Services.cookies.getCookiesWithOriginAttributes(
partitionedOAs,
FIRST_PARTY
);
// Get cookies from unpartitioned jar
let unpartitioned = Services.cookies.getCookiesWithOriginAttributes(
unpartitionedOAs,
FIRST_PARTY
);
// check that partitioned cookies are purged at maximum
// check that unpartitioned cookies are not
Assert.equal(partitioned.length, 1);
Assert.equal(unpartitioned.length, 2);
// Cleanup
BrowserTestUtils.removeTab(tab);
Services.cookies.removeAll();
});