Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
- Manifest: netwerk/cookie/test/unit/xpcshell.toml
/* Any copyright is dedicated to the Public Domain.
/*
Tests that when network.cookie.valueless_cookie=true (the default), legacy
nameless cookies (name="", value!="") that were stored on disk under the old
behavior are discarded on load rather than surfacing with an unreachable key.
*/
const { TestUtils } = ChromeUtils.importESModule(
);
const USEC_PER_MSEC = 1000;
const ONE_DAY_IN_USEC = 60 * 60 * 24 * USEC_PER_MSEC * 1000;
function initDBWithNamelessCookie(conn, now) {
conn.schemaVersion = 7;
conn.executeSimpleSQL(
"CREATE TABLE moz_cookies (" +
"id INTEGER PRIMARY KEY, " +
"baseDomain TEXT, " +
"originAttributes TEXT NOT NULL DEFAULT '', " +
"name TEXT, " +
"value TEXT, " +
"host TEXT, " +
"path TEXT, " +
"expiry INTEGER, " +
"lastAccessed INTEGER, " +
"creationTime INTEGER, " +
"isSecure INTEGER, " +
"isHttpOnly INTEGER, " +
"appId INTEGER DEFAULT 0, " +
"inBrowserElement INTEGER DEFAULT 0, " +
"CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes)" +
")"
);
conn.executeSimpleSQL(
"CREATE INDEX moz_basedomain ON moz_cookies (baseDomain, originAttributes)"
);
conn.executeSimpleSQL("PRAGMA synchronous = OFF");
conn.executeSimpleSQL("PRAGMA journal_mode = WAL");
conn.executeSimpleSQL("PRAGMA wal_autocheckpoint = 16");
// A legacy nameless cookie: name="", value="nameless" (created by old
// behavior where `Set-Cookie: foo` produced name="" value="foo").
conn.executeSimpleSQL(
`INSERT INTO moz_cookies(baseDomain, host, name, value, path, expiry, lastAccessed, creationTime, isSecure, isHttpOnly)
VALUES ('example.com', 'example.com', '', 'nameless', '/',
${now + ONE_DAY_IN_USEC}, ${now}, ${now - ONE_DAY_IN_USEC}, 0, 0)`
);
// A normal cookie with a name, which must always be retained.
conn.executeSimpleSQL(
`INSERT INTO moz_cookies(baseDomain, host, name, value, path, expiry, lastAccessed, creationTime, isSecure, isHttpOnly)
VALUES ('example.com', 'example.com', 'regular', 'cookie', '/',
${now + ONE_DAY_IN_USEC}, ${now}, ${now - ONE_DAY_IN_USEC}, 0, 0)`
);
}
add_task(async function test_nameless_cookie_discarded_when_pref_enabled() {
let now = Date.now() * USEC_PER_MSEC;
Services.prefs.setBoolPref("network.cookie.valueless_cookie", true);
Services.prefs.setIntPref("network.cookie.cookieBehavior", 0);
Services.prefs.setBoolPref(
"network.cookieJarSettings.unblocked_for_testing",
true
);
do_get_profile();
let dbFile = Services.dirsvc.get("ProfD", Ci.nsIFile);
dbFile.append("cookies.sqlite");
let conn = Services.storage.openDatabase(dbFile);
initDBWithNamelessCookie(conn, now);
conn.close();
// Arm the observer before triggering init so we don't miss the notification.
let dbReadPromise = TestUtils.topicObserved("cookie-db-read");
// Trigger cookie service initialization by accessing cookies.
let { cookies } = Services.cookies;
let exampleCookies = cookies.filter(c => c.host === "example.com");
Assert.equal(
exampleCookies.length,
1,
"Only one cookie should be loaded (nameless one discarded)"
);
Assert.equal(
exampleCookies[0].name,
"regular",
"The remaining cookie has a name"
);
Assert.equal(
exampleCookies[0].value,
"cookie",
"The remaining cookie has the right value"
);
// Wait for InitDBConn to complete; RemoveCookieFromDB is dispatched inside it.
await dbReadPromise;
// RemoveCookieFromDB uses an async statement, so poll until the row is gone.
await TestUtils.waitForCondition(() => {
let checkConn = Services.storage.openDatabase(dbFile);
try {
let stmt = checkConn.createStatement(
"SELECT COUNT(*) FROM moz_cookies WHERE name = '' AND host = 'example.com'"
);
try {
stmt.executeStep();
return stmt.getInt32(0) === 0;
} finally {
stmt.finalize();
}
} finally {
checkConn.close();
}
}, "Nameless cookie should be removed from the SQLite database");
});