summaryrefslogtreecommitdiff
path: root/net/extras/sqlite/sqlite_persistent_cookie_store.cc
diff options
context:
space:
mode:
Diffstat (limited to 'net/extras/sqlite/sqlite_persistent_cookie_store.cc')
-rw-r--r--net/extras/sqlite/sqlite_persistent_cookie_store.cc283
1 files changed, 234 insertions, 49 deletions
diff --git a/net/extras/sqlite/sqlite_persistent_cookie_store.cc b/net/extras/sqlite/sqlite_persistent_cookie_store.cc
index e417ac9af..e639bf1ba 100644
--- a/net/extras/sqlite/sqlite_persistent_cookie_store.cc
+++ b/net/extras/sqlite/sqlite_persistent_cookie_store.cc
@@ -98,19 +98,6 @@ void RecordCookieCommitProblem(CookieCommitProblem event) {
COOKIE_COMMIT_PROBLEM_LAST_ENTRY);
}
-// The persistent cookie store is loaded into memory on eTLD at a time. This
-// variable controls the delay between loading eTLDs, so as to not overload the
-// CPU or I/O with these low priority requests immediately after start up.
-#if BUILDFLAG(IS_IOS)
-// TODO(ellyjones): This should be 200ms, but currently CookieStoreIOS is
-// waiting for -FinishedLoadingCookies to be called after all eTLD cookies are
-// loaded before making any network requests. Changing to 0ms for now.
-// crbug.com/462593
-const int kLoadDelayMilliseconds = 0;
-#else
-const int kLoadDelayMilliseconds = 0;
-#endif
-
} // namespace
namespace net {
@@ -123,6 +110,8 @@ namespace {
// Version number of the database.
//
+// Version 21 - 2023/11/22 - https://crrev.com/c/5049032
+// Version 20 - 2023/11/14 - https://crrev.com/c/5030577
// Version 19 - 2023/09/22 - https://crrev.com/c/4704672
// Version 18 - 2022/04/19 - https://crrev.com/c/3594203
// Version 17 - 2022/01/25 - https://crrev.com/c/3416230
@@ -147,6 +136,11 @@ namespace {
// Version 5 - 2011/12/05 - https://codereview.chromium.org/8533013
// Version 4 - 2009/09/01 - https://codereview.chromium.org/183021
//
+// Version 21 removes the is_same_party column.
+//
+// Version 20 changes the UNIQUE constraint to include the source_scheme and
+// source_port and begins to insert, update, and delete cookies based on their
+// source_scheme and source_port.
//
// Version 19 caps expires_utc to no more than 400 days in the future for all
// stored cookies with has_expires. This is in compliance with section 7.2 of
@@ -178,10 +172,10 @@ namespace {
// happens on Windows, on other OS, this migration is a no-op.
//
// Version 13 adds two new fields: "source_port" (the port number of the source
-// origin, and "same_party" (boolean indicating whether the cookie had a
+// origin, and "is_same_party" (boolean indicating whether the cookie had a
// SameParty attribute). In migrating, source_port defaults to -1
// (url::PORT_UNSPECIFIED) for old entries for which the source port is unknown,
-// and same_party defaults to false.
+// and is_same_party defaults to false.
//
// Version 12 adds a column for "source_scheme" to store whether the
// cookie was set from a URL with a cryptographic scheme.
@@ -234,8 +228,8 @@ namespace {
// Version 3 updated the database to include the last access time, so we can
// expire them in decreasing order of use when we've reached the maximum
// number of cookies.
-const int kCurrentVersionNumber = 19;
-const int kCompatibleVersionNumber = 19;
+const int kCurrentVersionNumber = 21;
+const int kCompatibleVersionNumber = 21;
} // namespace
@@ -286,8 +280,9 @@ class SQLitePersistentCookieStore::Backend
// Creates or loads the SQLite database.
void Load(LoadedCallback loaded_callback);
- // Loads cookies for the domain key (eTLD+1).
- void LoadCookiesForKey(const std::string& domain,
+ // Loads cookies for the domain key (eTLD+1). If no key is supplied then this
+ // behaves identically to `Load`.
+ void LoadCookiesForKey(base::optional_ref<const std::string> key,
LoadedCallback loaded_callback);
// Steps through all results of |statement|, makes a cookie from each, and
@@ -353,6 +348,10 @@ class SQLitePersistentCookieStore::Backend
void NotifyLoadCompleteInForeground(LoadedCallback loaded_callback,
bool load_success);
+ // Called from Load when crypto gets obtained.
+ void CryptoHasInitFromLoad(base::optional_ref<const std::string> key,
+ LoadedCallback loaded_callback);
+
// Initialize the Cookies table.
bool CreateDatabaseSchema() override;
@@ -394,7 +393,8 @@ class SQLitePersistentCookieStore::Backend
}
typedef std::list<std::unique_ptr<PendingOperation>> PendingOperationsForKey;
- typedef std::map<CanonicalCookie::UniqueCookieKey, PendingOperationsForKey>
+ typedef std::map<CanonicalCookie::StrictlyUniqueCookieKey,
+ PendingOperationsForKey>
PendingOperationsMap;
PendingOperationsMap pending_ GUARDED_BY(lock_);
PendingOperationsMap::size_type num_pending_ GUARDED_BY(lock_) = 0;
@@ -645,34 +645,117 @@ bool CreateV18Schema(sql::Database* db) {
return true;
}
-// Initializes the cookies table, returning true on success.
-// The table/index cannot exist when calling this function.
-bool CreateV19Schema(sql::Database* db) {
- return CreateV18Schema(db);
+bool CreateV20Schema(sql::Database* db) {
+ CHECK(!db->DoesTableExist("cookies"));
+
+ const char* kCreateTableQuery =
+ "CREATE TABLE cookies("
+ "creation_utc INTEGER NOT NULL,"
+ "host_key TEXT NOT NULL,"
+ "top_frame_site_key TEXT NOT NULL,"
+ "name TEXT NOT NULL,"
+ "value TEXT NOT NULL,"
+ "encrypted_value BLOB NOT NULL,"
+ "path TEXT NOT NULL,"
+ "expires_utc INTEGER NOT NULL,"
+ "is_secure INTEGER NOT NULL,"
+ "is_httponly INTEGER NOT NULL,"
+ "last_access_utc INTEGER NOT NULL,"
+ "has_expires INTEGER NOT NULL,"
+ "is_persistent INTEGER NOT NULL,"
+ "priority INTEGER NOT NULL,"
+ "samesite INTEGER NOT NULL,"
+ "source_scheme INTEGER NOT NULL,"
+ "source_port INTEGER NOT NULL,"
+ "is_same_party INTEGER NOT NULL,"
+ "last_update_utc INTEGER NOT NULL);";
+
+ const char* kCreateIndexQuery =
+ "CREATE UNIQUE INDEX cookies_unique_index "
+ "ON cookies(host_key, top_frame_site_key, name, path, source_scheme, "
+ "source_port)";
+
+ if (!db->Execute(kCreateTableQuery)) {
+ return false;
+ }
+ if (!db->Execute(kCreateIndexQuery)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool CreateV21Schema(sql::Database* db) {
+ CHECK(!db->DoesTableExist("cookies"));
+
+ const char* kCreateTableQuery =
+ "CREATE TABLE cookies("
+ "creation_utc INTEGER NOT NULL,"
+ "host_key TEXT NOT NULL,"
+ "top_frame_site_key TEXT NOT NULL,"
+ "name TEXT NOT NULL,"
+ "value TEXT NOT NULL,"
+ "encrypted_value BLOB NOT NULL,"
+ "path TEXT NOT NULL,"
+ "expires_utc INTEGER NOT NULL,"
+ "is_secure INTEGER NOT NULL,"
+ "is_httponly INTEGER NOT NULL,"
+ "last_access_utc INTEGER NOT NULL,"
+ "has_expires INTEGER NOT NULL,"
+ "is_persistent INTEGER NOT NULL,"
+ "priority INTEGER NOT NULL,"
+ "samesite INTEGER NOT NULL,"
+ "source_scheme INTEGER NOT NULL,"
+ "source_port INTEGER NOT NULL,"
+ "last_update_utc INTEGER NOT NULL);";
+
+ const char* kCreateIndexQuery =
+ "CREATE UNIQUE INDEX cookies_unique_index "
+ "ON cookies(host_key, top_frame_site_key, name, path, source_scheme, "
+ "source_port)";
+
+ if (!db->Execute(kCreateTableQuery)) {
+ return false;
+ }
+ if (!db->Execute(kCreateIndexQuery)) {
+ return false;
+ }
+
+ return true;
}
} // namespace
void SQLitePersistentCookieStore::Backend::Load(
LoadedCallback loaded_callback) {
- PostBackgroundTask(FROM_HERE,
- base::BindOnce(&Backend::LoadAndNotifyInBackground, this,
- absl::nullopt, std::move(loaded_callback)));
+ LoadCookiesForKey(absl::nullopt, std::move(loaded_callback));
}
void SQLitePersistentCookieStore::Backend::LoadCookiesForKey(
- const std::string& key,
+ base::optional_ref<const std::string> key,
+ LoadedCallback loaded_callback) {
+ if (crypto_) {
+ crypto_->Init(base::BindOnce(&Backend::CryptoHasInitFromLoad, this,
+ key.CopyAsOptional(),
+ std::move(loaded_callback)));
+ } else {
+ CryptoHasInitFromLoad(key, std::move(loaded_callback));
+ }
+}
+
+void SQLitePersistentCookieStore::Backend::CryptoHasInitFromLoad(
+ base::optional_ref<const std::string> key,
LoadedCallback loaded_callback) {
PostBackgroundTask(
- FROM_HERE, base::BindOnce(&Backend::LoadAndNotifyInBackground, this, key,
- std::move(loaded_callback)));
+ FROM_HERE,
+ base::BindOnce(&Backend::LoadAndNotifyInBackground, this,
+ key.CopyAsOptional(), std::move(loaded_callback)));
}
void SQLitePersistentCookieStore::Backend::LoadAndNotifyInBackground(
base::optional_ref<const std::string> key,
LoadedCallback loaded_callback) {
DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
-
bool success = false;
if (InitializeDatabase()) {
@@ -713,7 +796,7 @@ bool SQLitePersistentCookieStore::Backend::CreateDatabaseSchema() {
if (db()->DoesTableExist("cookies"))
return true;
- return CreateV19Schema(db());
+ return CreateV21Schema(db());
}
bool SQLitePersistentCookieStore::Backend::DoInitializeDatabase() {
@@ -764,11 +847,9 @@ void SQLitePersistentCookieStore::Backend::ChainLoadCookies(
// then post a background task to continue chain-load;
// Otherwise notify on client runner.
if (load_success && keys_to_load_.size() > 0) {
- bool success = background_task_runner()->PostDelayedTask(
- FROM_HERE,
- base::BindOnce(&Backend::ChainLoadCookies, this,
- std::move(loaded_callback)),
- base::Milliseconds(kLoadDelayMilliseconds));
+ bool success = background_task_runner()->PostTask(
+ FROM_HERE, base::BindOnce(&Backend::ChainLoadCookies, this,
+ std::move(loaded_callback)));
if (!success) {
LOG(WARNING) << "Failed to post task from " << FROM_HERE.ToString()
<< " to background_task_runner().";
@@ -789,15 +870,14 @@ bool SQLitePersistentCookieStore::Backend::LoadCookiesForDomains(
"SELECT creation_utc, host_key, top_frame_site_key, name, value, path, "
"expires_utc, is_secure, is_httponly, last_access_utc, has_expires, "
"is_persistent, priority, encrypted_value, samesite, source_scheme, "
- "source_port, is_same_party, last_update_utc FROM cookies WHERE "
- "host_key = ?"));
+ "source_port, last_update_utc FROM cookies WHERE host_key = ?"));
} else {
smt.Assign(db()->GetCachedStatement(
SQL_FROM_HERE,
"SELECT creation_utc, host_key, top_frame_site_key, name, value, path, "
"expires_utc, is_secure, is_httponly, last_access_utc, has_expires, "
"is_persistent, priority, encrypted_value, samesite, source_scheme, "
- "source_port, is_same_party, last_update_utc FROM cookies WHERE "
+ "source_port, last_update_utc FROM cookies WHERE "
"host_key = ? AND "
"is_persistent = 1"));
}
@@ -904,14 +984,13 @@ bool SQLitePersistentCookieStore::Backend::MakeCookiesFromSQLStatement(
statement.ColumnTime(0), // creation_utc
statement.ColumnTime(6), // expires_utc
statement.ColumnTime(9), // last_access_utc
- statement.ColumnTime(18), // last_update_utc
+ statement.ColumnTime(17), // last_update_utc
statement.ColumnBool(7), // secure
statement.ColumnBool(8), // http_only
DBCookieSameSiteToCookieSameSite(static_cast<DBCookieSameSite>(
statement.ColumnInt(14))), // samesite
DBCookiePriorityToCookiePriority(static_cast<DBCookiePriority>(
statement.ColumnInt(12))), // priority
- statement.ColumnBool(17), // is_same_party
std::move(cookie_partition_key), // top_frame_site_key
DBToCookieSourceScheme(statement.ColumnInt(15)), // source_scheme
statement.ColumnInt(16)); // source_port
@@ -1096,6 +1175,105 @@ SQLitePersistentCookieStore::Backend::DoMigrateDatabaseSchema() {
}
}
+ if (cur_version == 19) {
+ SCOPED_UMA_HISTOGRAM_TIMER("Cookie.TimeDatabaseMigrationToV20");
+
+ sql::Transaction transaction(db());
+ if (!transaction.Begin()) {
+ return absl::nullopt;
+ }
+
+ if (!db()->Execute("DROP TABLE IF EXISTS cookies_old")) {
+ return absl::nullopt;
+ }
+ if (!db()->Execute("ALTER TABLE cookies RENAME TO cookies_old")) {
+ return absl::nullopt;
+ }
+ if (!db()->Execute("DROP INDEX IF EXISTS cookies_unique_index")) {
+ return absl::nullopt;
+ }
+
+ if (!CreateV20Schema(db())) {
+ return absl::nullopt;
+ }
+
+ static constexpr char insert_cookies_sql[] =
+ "INSERT OR REPLACE INTO cookies "
+ "(creation_utc, host_key, top_frame_site_key, name, value, "
+ "encrypted_value, path, expires_utc, is_secure, is_httponly, "
+ "last_access_utc, has_expires, is_persistent, priority, samesite, "
+ "source_scheme, source_port, is_same_party, last_update_utc) "
+ "SELECT creation_utc, host_key, top_frame_site_key, name, value,"
+ " encrypted_value, path, expires_utc, is_secure, is_httponly,"
+ " last_access_utc, has_expires, is_persistent, priority, "
+ " samesite, source_scheme, source_port, is_same_party, "
+ "last_update_utc "
+ "FROM cookies_old ORDER BY creation_utc ASC";
+ if (!db()->Execute(insert_cookies_sql)) {
+ return absl::nullopt;
+ }
+ if (!db()->Execute("DROP TABLE cookies_old")) {
+ return absl::nullopt;
+ }
+
+ ++cur_version;
+ if (!meta_table()->SetVersionNumber(cur_version) ||
+ !meta_table()->SetCompatibleVersionNumber(
+ std::min(cur_version, kCompatibleVersionNumber)) ||
+ !transaction.Commit()) {
+ return absl::nullopt;
+ }
+ }
+
+ if (cur_version == 20) {
+ SCOPED_UMA_HISTOGRAM_TIMER("Cookie.TimeDatabaseMigrationToV21");
+
+ sql::Transaction transaction(db());
+ if (!transaction.Begin()) {
+ return absl::nullopt;
+ }
+
+ if (!db()->Execute("DROP TABLE IF EXISTS cookies_old")) {
+ return absl::nullopt;
+ }
+ if (!db()->Execute("ALTER TABLE cookies RENAME TO cookies_old")) {
+ return absl::nullopt;
+ }
+ if (!db()->Execute("DROP INDEX IF EXISTS cookies_unique_index")) {
+ return absl::nullopt;
+ }
+
+ if (!CreateV21Schema(db())) {
+ return absl::nullopt;
+ }
+
+ static constexpr char insert_cookies_sql[] =
+ "INSERT OR REPLACE INTO cookies "
+ "(creation_utc, host_key, top_frame_site_key, name, value, "
+ "encrypted_value, path, expires_utc, is_secure, is_httponly, "
+ "last_access_utc, has_expires, is_persistent, priority, samesite, "
+ "source_scheme, source_port, last_update_utc) "
+ "SELECT creation_utc, host_key, top_frame_site_key, name, value,"
+ " encrypted_value, path, expires_utc, is_secure, is_httponly,"
+ " last_access_utc, has_expires, is_persistent, priority, "
+ " samesite, source_scheme, source_port, last_update_utc "
+ "FROM cookies_old ORDER BY creation_utc ASC";
+ if (!db()->Execute(insert_cookies_sql)) {
+ return absl::nullopt;
+ }
+ if (!db()->Execute("DROP TABLE cookies_old")) {
+ return absl::nullopt;
+ }
+
+ ++cur_version;
+ if (!meta_table()->SetVersionNumber(cur_version) ||
+ !meta_table()->SetCompatibleVersionNumber(
+ std::min(cur_version, kCompatibleVersionNumber)) ||
+ !transaction.Commit()) {
+ return absl::nullopt;
+ }
+ }
+
// Put future migration cases here.
return absl::make_optional(cur_version);
@@ -1133,7 +1311,7 @@ void SQLitePersistentCookieStore::Backend::BatchOperation(
base::AutoLock locked(lock_);
// When queueing the operation, see if it overwrites any already pending
// ones for the same row.
- auto key = cc.UniqueKey();
+ auto key = cc.StrictlyUniqueKey();
auto iter_and_result =
pending_.insert(std::make_pair(key, PendingOperationsForKey()));
PendingOperationsForKey& ops_for_key = iter_and_result.first->second;
@@ -1197,22 +1375,24 @@ void SQLitePersistentCookieStore::Backend::DoCommit() {
"INSERT INTO cookies (creation_utc, host_key, top_frame_site_key, name, "
"value, encrypted_value, path, expires_utc, is_secure, is_httponly, "
"last_access_utc, has_expires, is_persistent, priority, samesite, "
- "source_scheme, source_port, is_same_party, last_update_utc) "
- "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
+ "source_scheme, source_port, last_update_utc) "
+ "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
if (!add_statement.is_valid())
return;
sql::Statement update_access_statement(db()->GetCachedStatement(
SQL_FROM_HERE,
"UPDATE cookies SET last_access_utc=? WHERE "
- "name=? AND host_key=? AND top_frame_site_key=? AND path=?"));
+ "name=? AND host_key=? AND top_frame_site_key=? AND path=? AND "
+ "source_scheme=? AND source_port=?"));
if (!update_access_statement.is_valid())
return;
sql::Statement delete_statement(db()->GetCachedStatement(
SQL_FROM_HERE,
"DELETE FROM cookies WHERE "
- "name=? AND host_key=? AND top_frame_site_key=? AND path=?"));
+ "name=? AND host_key=? AND top_frame_site_key=? AND path=? AND "
+ "source_scheme=? AND source_port=?"));
if (!delete_statement.is_valid())
return;
@@ -1264,8 +1444,7 @@ void SQLitePersistentCookieStore::Backend::DoCommit() {
14, CookieSameSiteToDBCookieSameSite(po->cc().SameSite()));
add_statement.BindInt(15, static_cast<int>(po->cc().SourceScheme()));
add_statement.BindInt(16, po->cc().SourcePort());
- add_statement.BindBool(17, po->cc().IsSameParty());
- add_statement.BindTime(18, po->cc().LastUpdateDate());
+ add_statement.BindTime(17, po->cc().LastUpdateDate());
if (!add_statement.Run()) {
DLOG(WARNING) << "Could not add a cookie to the DB.";
RecordCookieCommitProblem(COOKIE_COMMIT_PROBLEM_ADD);
@@ -1279,6 +1458,9 @@ void SQLitePersistentCookieStore::Backend::DoCommit() {
update_access_statement.BindString(2, po->cc().Domain());
update_access_statement.BindString(3, top_frame_site_key);
update_access_statement.BindString(4, po->cc().Path());
+ update_access_statement.BindInt(
+ 5, static_cast<int>(po->cc().SourceScheme()));
+ update_access_statement.BindInt(6, po->cc().SourcePort());
if (!update_access_statement.Run()) {
DLOG(WARNING)
<< "Could not update cookie last access time in the DB.";
@@ -1292,6 +1474,9 @@ void SQLitePersistentCookieStore::Backend::DoCommit() {
delete_statement.BindString(1, po->cc().Domain());
delete_statement.BindString(2, top_frame_site_key);
delete_statement.BindString(3, po->cc().Path());
+ delete_statement.BindInt(4,
+ static_cast<int>(po->cc().SourceScheme()));
+ delete_statement.BindInt(5, po->cc().SourcePort());
if (!delete_statement.Run()) {
DLOG(WARNING) << "Could not delete a cookie from the DB.";
RecordCookieCommitProblem(COOKIE_COMMIT_PROBLEM_DELETE);