diff options
Diffstat (limited to 'net/extras/sqlite/sqlite_persistent_cookie_store.cc')
-rw-r--r-- | net/extras/sqlite/sqlite_persistent_cookie_store.cc | 283 |
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); |