From a593a16fd9fcd0dd4906673341bc921abb285b97 Mon Sep 17 00:00:00 2001 From: Cronet Mainline Eng Date: Tue, 2 Jan 2024 11:58:25 +0000 Subject: Import Cronet version 121.0.6103.2 FolderOrigin-RevId: /tmp/copybara-origin/src Change-Id: I690becfaba7ad4293eba08b4f9d1aa7f953fce20 --- .../shared_dictionary_isolation_key_unittest.cc | 1 - net/extras/sqlite/cookie_crypto_delegate.h | 4 - .../sqlite/sqlite_persistent_cookie_store.cc | 165 ++++++-------- net/extras/sqlite/sqlite_persistent_cookie_store.h | 2 +- .../sqlite_persistent_cookie_store_unittest.cc | 252 ++++++++++++++------- .../sqlite_persistent_shared_dictionary_store.cc | 35 ++- .../sqlite_persistent_shared_dictionary_store.h | 3 +- ..._persistent_shared_dictionary_store_unittest.cc | 106 +++++++-- 8 files changed, 352 insertions(+), 216 deletions(-) (limited to 'net/extras') diff --git a/net/extras/shared_dictionary/shared_dictionary_isolation_key_unittest.cc b/net/extras/shared_dictionary/shared_dictionary_isolation_key_unittest.cc index 824081155..baa927c6e 100644 --- a/net/extras/shared_dictionary/shared_dictionary_isolation_key_unittest.cc +++ b/net/extras/shared_dictionary/shared_dictionary_isolation_key_unittest.cc @@ -47,7 +47,6 @@ TEST(SharedDictionaryIsolationKeyTest, MaybeCreateWithNonce) { SharedDictionaryIsolationKey::MaybeCreate(net::IsolationInfo::Create( net::IsolationInfo::RequestType::kOther, url::Origin::Create(kUrl1), url::Origin(), net::SiteForCookies(), - /*party_context=*/absl::nullopt, /*nonce=*/base::UnguessableToken::Create())); EXPECT_FALSE(isolation_key); } diff --git a/net/extras/sqlite/cookie_crypto_delegate.h b/net/extras/sqlite/cookie_crypto_delegate.h index e5ad07e2a..2e9fc8ed6 100644 --- a/net/extras/sqlite/cookie_crypto_delegate.h +++ b/net/extras/sqlite/cookie_crypto_delegate.h @@ -14,10 +14,6 @@ class COMPONENT_EXPORT(NET_EXTRAS) CookieCryptoDelegate { public: virtual ~CookieCryptoDelegate() = default; - // Return if cookies should be encrypted on this platform. Decryption of - // previously encrypted cookies is always possible. - virtual bool ShouldEncrypt() = 0; - // Encrypt |plaintext| string and store the result in |ciphertext|. This // method is always functional even if ShouldEncrypt() is false. virtual bool EncryptString(const std::string& plaintext, diff --git a/net/extras/sqlite/sqlite_persistent_cookie_store.cc b/net/extras/sqlite/sqlite_persistent_cookie_store.cc index 5c7d55bd8..e417ac9af 100644 --- a/net/extras/sqlite/sqlite_persistent_cookie_store.cc +++ b/net/extras/sqlite/sqlite_persistent_cookie_store.cc @@ -28,6 +28,7 @@ #include "base/task/sequenced_task_runner.h" #include "base/thread_annotations.h" #include "base/time/time.h" +#include "base/types/optional_ref.h" #include "base/values.h" #include "build/build_config.h" #include "net/cookies/canonical_cookie.h" @@ -122,6 +123,7 @@ namespace { // Version number of the database. // +// 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 // Version 16 - 2021/09/10 - https://crrev.com/c/3152897 @@ -146,6 +148,10 @@ namespace { // Version 4 - 2009/09/01 - https://codereview.chromium.org/183021 // // +// 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 +// draft-ietf-httpbis-rfc6265bis-12. +// // Version 18 adds one new field: "last_update_utc" (if not 0 this represents // the last time the cookie was updated). This is distinct from creation_utc // which is carried forward when cookies are updated. @@ -228,8 +234,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 = 18; -const int kCompatibleVersionNumber = 18; +const int kCurrentVersionNumber = 19; +const int kCompatibleVersionNumber = 19; } // namespace @@ -336,27 +342,15 @@ class SQLitePersistentCookieStore::Backend }; private: - // Creates or loads the SQLite database on background runner. - void LoadAndNotifyInBackground(LoadedCallback loaded_callback); - - // Loads cookies for the domain key (eTLD+1) on background runner. - void LoadKeyAndNotifyInBackground(const std::string& domains, - LoadedCallback loaded_callback); + // Creates or loads the SQLite database on background runner. Supply domain + // key (eTLD+1) to only load for this domain. + void LoadAndNotifyInBackground(base::optional_ref key, + LoadedCallback loaded_callback); // Notifies the CookieMonster when loading completes for a specific domain key // or for all domain keys. Triggers the callback and passes it all cookies // that have been loaded from DB since last IO notification. - void Notify(LoadedCallback loaded_callback, bool load_success); - - // Sends notification when the entire store is loaded, and reports metrics - // for the total time to load and aggregated results from any priority loads - // that occurred. - void CompleteLoadInForeground(LoadedCallback loaded_callback, - bool load_success); - - // Sends notification when a single priority load completes. Updates priority - // load metric data. The data is sent only after the final load completes. - void CompleteLoadForKeyInForeground(LoadedCallback loaded_callback, + void NotifyLoadCompleteInForeground(LoadedCallback loaded_callback, bool load_success); // Initialize the Cookies table. @@ -418,24 +412,6 @@ class SQLitePersistentCookieStore::Backend // If false, we should filter out session cookies when reading the DB. bool restore_old_session_cookies_; - // The cumulative time spent loading the cookies on the background runner. - // Incremented and reported from the background runner. - base::TimeDelta cookie_load_duration_; - - // Guards the following metrics-related properties (only accessed when - // starting/completing priority loads or completing the total load). - base::Lock metrics_lock_; - int num_priority_waiting_ GUARDED_BY(metrics_lock_) = 0; - // The total number of priority requests. - int total_priority_requests_ GUARDED_BY(metrics_lock_) = 0; - // The time when |num_priority_waiting_| incremented to 1. - base::Time current_priority_wait_start_ GUARDED_BY(metrics_lock_); - // The cumulative duration of time when |num_priority_waiting_| was greater - // than 1. - base::TimeDelta priority_wait_duration_ GUARDED_BY(metrics_lock_); - // Class with functions that do cryptographic operations (for protecting - // cookies stored persistently). - // // Not owned. raw_ptr crypto_; }; @@ -669,54 +645,43 @@ 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); +} + } // namespace void SQLitePersistentCookieStore::Backend::Load( LoadedCallback loaded_callback) { PostBackgroundTask(FROM_HERE, base::BindOnce(&Backend::LoadAndNotifyInBackground, this, - std::move(loaded_callback))); + absl::nullopt, std::move(loaded_callback))); } void SQLitePersistentCookieStore::Backend::LoadCookiesForKey( const std::string& key, LoadedCallback loaded_callback) { - { - base::AutoLock locked(metrics_lock_); - if (num_priority_waiting_ == 0) - current_priority_wait_start_ = base::Time::Now(); - num_priority_waiting_++; - total_priority_requests_++; - } - PostBackgroundTask( - FROM_HERE, base::BindOnce(&Backend::LoadKeyAndNotifyInBackground, this, - key, std::move(loaded_callback))); + FROM_HERE, base::BindOnce(&Backend::LoadAndNotifyInBackground, this, key, + std::move(loaded_callback))); } void SQLitePersistentCookieStore::Backend::LoadAndNotifyInBackground( + base::optional_ref key, LoadedCallback loaded_callback) { DCHECK(background_task_runner()->RunsTasksInCurrentSequence()); - IncrementTimeDelta increment(&cookie_load_duration_); - - if (!InitializeDatabase()) { - PostClientTask(FROM_HERE, - base::BindOnce(&Backend::CompleteLoadInForeground, this, - std::move(loaded_callback), false)); - } else { - ChainLoadCookies(std::move(loaded_callback)); - } -} - -void SQLitePersistentCookieStore::Backend::LoadKeyAndNotifyInBackground( - const std::string& key, - LoadedCallback loaded_callback) { - DCHECK(background_task_runner()->RunsTasksInCurrentSequence()); - IncrementTimeDelta increment(&cookie_load_duration_); bool success = false; + if (InitializeDatabase()) { - auto it = keys_to_load_.find(key); + if (!key.has_value()) { + ChainLoadCookies(std::move(loaded_callback)); + return; + } + + auto it = keys_to_load_.find(*key); if (it != keys_to_load_.end()) { success = LoadCookiesForDomains(it->second); keys_to_load_.erase(it); @@ -725,37 +690,10 @@ void SQLitePersistentCookieStore::Backend::LoadKeyAndNotifyInBackground( } } - PostClientTask( - FROM_HERE, - base::BindOnce( - &SQLitePersistentCookieStore::Backend::CompleteLoadForKeyInForeground, - this, std::move(loaded_callback), success)); + FinishedLoadingCookies(std::move(loaded_callback), success); } -void SQLitePersistentCookieStore::Backend::CompleteLoadForKeyInForeground( - LoadedCallback loaded_callback, - bool load_success) { - DCHECK(client_task_runner()->RunsTasksInCurrentSequence()); - - Notify(std::move(loaded_callback), load_success); - - { - base::AutoLock locked(metrics_lock_); - num_priority_waiting_--; - if (num_priority_waiting_ == 0) { - priority_wait_duration_ += - base::Time::Now() - current_priority_wait_start_; - } - } -} - -void SQLitePersistentCookieStore::Backend::CompleteLoadInForeground( - LoadedCallback loaded_callback, - bool load_success) { - Notify(std::move(loaded_callback), load_success); -} - -void SQLitePersistentCookieStore::Backend::Notify( +void SQLitePersistentCookieStore::Backend::NotifyLoadCompleteInForeground( LoadedCallback loaded_callback, bool load_success) { DCHECK(client_task_runner()->RunsTasksInCurrentSequence()); @@ -775,7 +713,7 @@ bool SQLitePersistentCookieStore::Backend::CreateDatabaseSchema() { if (db()->DoesTableExist("cookies")) return true; - return CreateV18Schema(db()); + return CreateV19Schema(db()); } bool SQLitePersistentCookieStore::Backend::DoInitializeDatabase() { @@ -809,7 +747,6 @@ bool SQLitePersistentCookieStore::Backend::DoInitializeDatabase() { void SQLitePersistentCookieStore::Backend::ChainLoadCookies( LoadedCallback loaded_callback) { DCHECK(background_task_runner()->RunsTasksInCurrentSequence()); - IncrementTimeDelta increment(&cookie_load_duration_); bool load_success = true; @@ -1127,6 +1064,38 @@ SQLitePersistentCookieStore::Backend::DoMigrateDatabaseSchema() { } } + if (cur_version == 18) { + SCOPED_UMA_HISTOGRAM_TIMER("Cookie.TimeDatabaseMigrationToV19"); + + sql::Statement update_statement( + db()->GetCachedStatement(SQL_FROM_HERE, + "UPDATE cookies SET expires_utc = ? WHERE " + "has_expires = 1 AND expires_utc > ?")); + if (!update_statement.is_valid()) { + return absl::nullopt; + } + + sql::Transaction transaction(db()); + if (!transaction.Begin()) { + return absl::nullopt; + } + + base::Time expires_cap = base::Time::Now() + base::Days(400); + update_statement.BindTime(0, expires_cap); + update_statement.BindTime(1, expires_cap); + if (!update_statement.Run()) { + 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); @@ -1267,7 +1236,7 @@ void SQLitePersistentCookieStore::Backend::DoCommit() { add_statement.BindString(1, po->cc().Domain()); add_statement.BindString(2, top_frame_site_key); add_statement.BindString(3, po->cc().Name()); - if (crypto_ && crypto_->ShouldEncrypt()) { + if (crypto_) { std::string encrypted_value; if (!crypto_->EncryptString(po->cc().Value(), &encrypted_value)) { DLOG(WARNING) << "Could not encrypt a cookie, skipping add."; @@ -1422,7 +1391,7 @@ void SQLitePersistentCookieStore::Backend::FinishedLoadingCookies( LoadedCallback loaded_callback, bool success) { PostClientTask(FROM_HERE, - base::BindOnce(&Backend::CompleteLoadInForeground, this, + base::BindOnce(&Backend::NotifyLoadCompleteInForeground, this, std::move(loaded_callback), success)); } diff --git a/net/extras/sqlite/sqlite_persistent_cookie_store.h b/net/extras/sqlite/sqlite_persistent_cookie_store.h index e68b3a930..107c26c0f 100644 --- a/net/extras/sqlite/sqlite_persistent_cookie_store.h +++ b/net/extras/sqlite/sqlite_persistent_cookie_store.h @@ -42,7 +42,7 @@ class COMPONENT_EXPORT(NET_EXTRAS) SQLitePersistentCookieStore // Port number to use for cookies whose source port is unknown at the time of // database migration to V13. The value -1 comes from url::PORT_UNSPECIFIED. - static const int kDefaultUnknownPort = -1; + static constexpr int kDefaultUnknownPort = -1; // All blocking database accesses will be performed on // |background_task_runner|, while |client_task_runner| is used to invoke diff --git a/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc b/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc index 68d967070..b9610bc49 100644 --- a/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc +++ b/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc @@ -62,14 +62,11 @@ const base::FilePath::CharType kCookieFilename[] = FILE_PATH_LITERAL("Cookies"); class CookieCryptor : public CookieCryptoDelegate { public: CookieCryptor(); - bool ShouldEncrypt() override; bool EncryptString(const std::string& plaintext, std::string* ciphertext) override; bool DecryptString(const std::string& ciphertext, std::string* plaintext) override; - bool should_encrypt_ = true; - private: std::unique_ptr key_; crypto::Encryptor encryptor_; @@ -86,10 +83,6 @@ CookieCryptor::CookieCryptor() encryptor_.Init(key_.get(), crypto::Encryptor::CBC, iv); } -bool CookieCryptor::ShouldEncrypt() { - return should_encrypt_; -} - bool CookieCryptor::EncryptString(const std::string& plaintext, std::string* ciphertext) { return encryptor_.Encrypt(plaintext, ciphertext); @@ -1087,57 +1080,6 @@ TEST_F(SQLitePersistentCookieStoreTest, UpdateToEncryption) { EXPECT_EQ(contents.find("something456ABC"), std::string::npos); } -TEST_F(SQLitePersistentCookieStoreTest, UpdateFromEncryption) { - CanonicalCookieVector cookies; - - // Create unencrypted cookie store and write something to it. - InitializeStore(true, false); - AddCookie("name", "value123XYZ", "foo.bar", "/", base::Time::Now()); - DestroyStore(); - - // Verify that "value" is not visible in the file. - std::string contents = ReadRawDBContents(); - EXPECT_NE(0U, contents.length()); - EXPECT_EQ(contents.find("value123XYZ"), std::string::npos); - - // Create encrypted cookie store and ensure old cookie still reads. - cookies.clear(); - EXPECT_EQ(0U, cookies.size()); - CreateAndLoad(true, false, &cookies); - EXPECT_EQ(1U, cookies.size()); - EXPECT_EQ("name", cookies[0]->Name()); - EXPECT_EQ("value123XYZ", cookies[0]->Value()); - - // Make sure we can update existing cookie and it writes unencrypted. - cookie_crypto_delegate_->should_encrypt_ = false; - store_->DeleteCookie(*(cookies[0])); - AddCookie("name", "plaintext_value123XYZ", "foo.bar", "/", base::Time::Now()); - AddCookie("other", "something456ABC", "foo.bar", "/", - base::Time::Now() + base::Microseconds(10)); - DestroyStore(); - cookies.clear(); - CreateAndLoad(true, false, &cookies); - EXPECT_EQ(2U, cookies.size()); - CanonicalCookie* cookie_name = nullptr; - CanonicalCookie* cookie_other = nullptr; - if (cookies[0]->Name() == "name") { - cookie_name = cookies[0].get(); - cookie_other = cookies[1].get(); - } else { - cookie_name = cookies[1].get(); - cookie_other = cookies[0].get(); - } - EXPECT_EQ("plaintext_value123XYZ", cookie_name->Value()); - EXPECT_EQ("something456ABC", cookie_other->Value()); - DestroyStore(); - cookies.clear(); - - // Verify that "value" is now visible in the file. - contents = ReadRawDBContents(); - EXPECT_NE(0U, contents.length()); - EXPECT_NE(contents.find("value123XYZ"), std::string::npos); -} - bool CompareCookies(const std::unique_ptr& a, const std::unique_ptr& b) { return a->PartialCompare(*b); @@ -1637,6 +1579,51 @@ bool CreateV17Schema(sql::Database* db) { return CreateV16Schema(db, /*version_override=*/17); } +bool CreateV18Schema(sql::Database* db) { + sql::MetaTable meta_table; + if (!meta_table.Init(db, 18, 18)) { + return false; + } + + // Version 18 schema + static constexpr char kCreateSql[] = + "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," + "UNIQUE (host_key, top_frame_site_key, name, path))"; + + static constexpr char kCreateIndexSql[] = + "CREATE UNIQUE INDEX cookies_unique_index " + "ON cookies(host_key, top_frame_site_key, name, path)"; + + if (!db->Execute(kCreateSql)) { + return false; + } + + if (!db->Execute(kCreateIndexSql)) { + return false; + } + + return true; +} + int GetDBCurrentVersionNumber(sql::Database* db) { static constexpr char kGetDBCurrentVersionQuery[] = "SELECT value FROM meta WHERE key='version'"; @@ -1667,16 +1654,16 @@ std::vector CookiesForMigrationTest() { false /* httponly */, CookieSameSite::UNSPECIFIED, COOKIE_PRIORITY_DEFAULT, true /* same_party */)); cookies.push_back(*CanonicalCookie::CreateUnsafeCookieForTesting( - "C", "B", "example2.com", "/", now, now, now, now, false /* secure */, - false /* httponly */, CookieSameSite::UNSPECIFIED, + "C", "B", "example2.com", "/", now, now + base::Days(399), now, now, + false /* secure */, false /* httponly */, CookieSameSite::UNSPECIFIED, COOKIE_PRIORITY_DEFAULT, false /* same_party */)); cookies.push_back(*CanonicalCookie::CreateUnsafeCookieForTesting( - "A", "B", "example.com", "/path", now, now, now, now, false /* secure */, - false /* httponly */, CookieSameSite::UNSPECIFIED, + "A", "B", "example.com", "/path", now, now + base::Days(400), now, now, + false /* secure */, false /* httponly */, CookieSameSite::UNSPECIFIED, COOKIE_PRIORITY_DEFAULT, false /* same_party */)); cookies.push_back(*CanonicalCookie::CreateUnsafeCookieForTesting( - "C", "B", "example.com", "/path", now, now, now, now, false /* secure */, - false /* httponly */, CookieSameSite::UNSPECIFIED, + "C", "B", "example.com", "/path", now, now + base::Days(401), now, now, + false /* secure */, false /* httponly */, CookieSameSite::UNSPECIFIED, COOKIE_PRIORITY_DEFAULT, false /* same_party */)); return cookies; } @@ -1697,8 +1684,7 @@ bool AddV15CookiesToDB(sql::Database* db) { return false; for (const CanonicalCookie& cookie : cookies) { statement.Reset(true); - statement.BindInt64( - 0, cookie.CreationDate().ToDeltaSinceWindowsEpoch().InMicroseconds()); + statement.BindTime(0, cookie.CreationDate()); std::string top_frame_site_key; EXPECT_TRUE(CookiePartitionKey::Serialize(cookie.PartitionKey(), top_frame_site_key)); @@ -1708,8 +1694,7 @@ bool AddV15CookiesToDB(sql::Database* db) { statement.BindString(4, cookie.Value()); statement.BindBlob(5, base::span()); // encrypted_value statement.BindString(6, cookie.Path()); - statement.BindInt64( - 7, cookie.ExpiryDate().ToDeltaSinceWindowsEpoch().InMicroseconds()); + statement.BindTime(7, cookie.ExpiryDate()); statement.BindInt(8, cookie.IsSecure()); statement.BindInt(9, cookie.IsHttpOnly()); // Note that this, Priority(), and SourceScheme() below nominally rely on @@ -1718,9 +1703,7 @@ bool AddV15CookiesToDB(sql::Database* db) { // relies on that equivalence, so it's not worth the hassle to guarantee // that. statement.BindInt(10, static_cast(cookie.SameSite())); - statement.BindInt64( - 11, - cookie.LastAccessDate().ToDeltaSinceWindowsEpoch().InMicroseconds()); + statement.BindTime(11, cookie.LastAccessDate()); statement.BindInt(12, cookie.IsPersistent()); statement.BindInt(13, cookie.IsPersistent()); statement.BindInt(14, static_cast(cookie.Priority())); @@ -1746,10 +1729,67 @@ bool AddV17CookiesToDB(sql::Database* db) { return AddV16CookiesToDB(db); } +bool AddV18CookiesToDB(sql::Database* db) { + std::vector cookies = CookiesForMigrationTest(); + sql::Statement statement(db->GetCachedStatement( + SQL_FROM_HERE, + "INSERT INTO cookies (creation_utc, top_frame_site_key, host_key, name, " + "value, encrypted_value, path, expires_utc, is_secure, is_httponly, " + "samesite, last_access_utc, has_expires, is_persistent, priority, " + "source_scheme, source_port, is_same_party, last_update_utc) " + "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)")); + if (!statement.is_valid()) { + return false; + } + sql::Transaction transaction(db); + if (!transaction.Begin()) { + return false; + } + for (const CanonicalCookie& cookie : cookies) { + statement.Reset(true); + statement.BindTime(0, cookie.CreationDate()); + std::string top_frame_site_key; + EXPECT_TRUE(CookiePartitionKey::Serialize(cookie.PartitionKey(), + top_frame_site_key)); + statement.BindString(1, top_frame_site_key); + statement.BindString(2, cookie.Domain()); + statement.BindString(3, cookie.Name()); + statement.BindString(4, cookie.Value()); + statement.BindBlob(5, base::span()); // encrypted_value + statement.BindString(6, cookie.Path()); + statement.BindTime(7, cookie.ExpiryDate()); + statement.BindInt(8, cookie.IsSecure()); + statement.BindInt(9, cookie.IsHttpOnly()); + // Note that this, Priority(), and SourceScheme() below nominally rely on + // the enums in sqlite_persistent_cookie_store.cc having the same values as + // the ones in ../../cookies/cookie_constants.h. But nothing in this test + // relies on that equivalence, so it's not worth the hassle to guarantee + // that. + statement.BindInt(10, static_cast(cookie.SameSite())); + statement.BindTime(11, cookie.LastAccessDate()); + statement.BindInt(12, cookie.IsPersistent()); + statement.BindInt(13, cookie.IsPersistent()); + statement.BindInt(14, static_cast(cookie.Priority())); + statement.BindInt(15, static_cast(cookie.SourceScheme())); + statement.BindInt(16, cookie.SourcePort()); + statement.BindInt(17, cookie.IsSameParty()); + statement.BindTime(18, cookie.LastUpdateDate()); + if (!statement.Run()) { + return false; + } + } + if (!transaction.Commit()) { + return false; + } + + return true; +} + // Confirm the cookie list passed in has the above cookies in it. void ConfirmCookiesAfterMigrationTest( std::vector> read_in_cookies, - bool expect_same_party_cookies = false) { + bool expect_same_party_cookies = false, + bool expect_last_update_date = false) { std::sort(read_in_cookies.begin(), read_in_cookies.end(), &CompareCookies); int i = 0; EXPECT_EQ("A", read_in_cookies[i]->Name()); @@ -1759,7 +1799,11 @@ void ConfirmCookiesAfterMigrationTest( EXPECT_TRUE(read_in_cookies[i]->IsSecure()); EXPECT_EQ(CookieSourceScheme::kUnset, read_in_cookies[i]->SourceScheme()); EXPECT_FALSE(read_in_cookies[i]->IsSameParty()); - EXPECT_TRUE(read_in_cookies[i]->LastUpdateDate().is_null()); + EXPECT_EQ(read_in_cookies[i]->LastUpdateDate(), + expect_last_update_date ? read_in_cookies[i]->CreationDate() + : base::Time()); + EXPECT_EQ(read_in_cookies[i]->ExpiryDate(), + read_in_cookies[i]->CreationDate()); i++; EXPECT_EQ("A", read_in_cookies[i]->Name()); @@ -1769,7 +1813,11 @@ void ConfirmCookiesAfterMigrationTest( EXPECT_FALSE(read_in_cookies[i]->IsSecure()); EXPECT_EQ(CookieSourceScheme::kUnset, read_in_cookies[i]->SourceScheme()); EXPECT_FALSE(read_in_cookies[i]->IsSameParty()); - EXPECT_TRUE(read_in_cookies[i]->LastUpdateDate().is_null()); + EXPECT_EQ(read_in_cookies[i]->LastUpdateDate(), + expect_last_update_date ? read_in_cookies[i]->CreationDate() + : base::Time()); + EXPECT_EQ(read_in_cookies[i]->ExpiryDate(), + read_in_cookies[i]->CreationDate() + base::Days(400)); i++; EXPECT_EQ("A", read_in_cookies[i]->Name()); @@ -1779,7 +1827,11 @@ void ConfirmCookiesAfterMigrationTest( EXPECT_TRUE(read_in_cookies[i]->IsSecure()); EXPECT_EQ(CookieSourceScheme::kUnset, read_in_cookies[i]->SourceScheme()); EXPECT_EQ(expect_same_party_cookies, read_in_cookies[i]->IsSameParty()); - EXPECT_TRUE(read_in_cookies[i]->LastUpdateDate().is_null()); + EXPECT_EQ(read_in_cookies[i]->LastUpdateDate(), + expect_last_update_date ? read_in_cookies[i]->CreationDate() + : base::Time()); + EXPECT_EQ(read_in_cookies[i]->ExpiryDate(), + read_in_cookies[i]->CreationDate()); i++; EXPECT_EQ("C", read_in_cookies[i]->Name()); @@ -1789,7 +1841,11 @@ void ConfirmCookiesAfterMigrationTest( EXPECT_TRUE(read_in_cookies[i]->IsSecure()); EXPECT_EQ(CookieSourceScheme::kUnset, read_in_cookies[i]->SourceScheme()); EXPECT_EQ(expect_same_party_cookies, read_in_cookies[i]->IsSameParty()); - EXPECT_TRUE(read_in_cookies[i]->LastUpdateDate().is_null()); + EXPECT_EQ(read_in_cookies[i]->LastUpdateDate(), + expect_last_update_date ? read_in_cookies[i]->CreationDate() + : base::Time()); + EXPECT_EQ(read_in_cookies[i]->ExpiryDate(), + read_in_cookies[i]->CreationDate()); i++; EXPECT_EQ("C", read_in_cookies[i]->Name()); @@ -1799,7 +1855,14 @@ void ConfirmCookiesAfterMigrationTest( EXPECT_FALSE(read_in_cookies[i]->IsSecure()); EXPECT_EQ(CookieSourceScheme::kUnset, read_in_cookies[i]->SourceScheme()); EXPECT_FALSE(read_in_cookies[i]->IsSameParty()); - EXPECT_TRUE(read_in_cookies[i]->LastUpdateDate().is_null()); + EXPECT_EQ(read_in_cookies[i]->LastUpdateDate(), + expect_last_update_date ? read_in_cookies[i]->CreationDate() + : base::Time()); + // The exact time will be within the last minute due to the cap. + EXPECT_LE(read_in_cookies[i]->ExpiryDate(), + base::Time::Now() + base::Days(400)); + EXPECT_GE(read_in_cookies[i]->ExpiryDate(), + base::Time::Now() + base::Days(400) - base::Minutes(1)); i++; EXPECT_EQ("C", read_in_cookies[i]->Name()); @@ -1809,7 +1872,11 @@ void ConfirmCookiesAfterMigrationTest( EXPECT_FALSE(read_in_cookies[i]->IsSecure()); EXPECT_EQ(CookieSourceScheme::kUnset, read_in_cookies[i]->SourceScheme()); EXPECT_FALSE(read_in_cookies[i]->IsSameParty()); - EXPECT_TRUE(read_in_cookies[i]->LastUpdateDate().is_null()); + EXPECT_EQ(read_in_cookies[i]->LastUpdateDate(), + expect_last_update_date ? read_in_cookies[i]->CreationDate() + : base::Time()); + EXPECT_EQ(read_in_cookies[i]->ExpiryDate(), + read_in_cookies[i]->CreationDate() + base::Days(399)); } TEST_F(SQLitePersistentCookieStoreTest, UpgradeToSchemaVersion16) { @@ -1822,7 +1889,8 @@ TEST_F(SQLitePersistentCookieStoreTest, UpgradeToSchemaVersion16) { std::vector> read_in_cookies; CreateAndLoad(false, false, &read_in_cookies); - ConfirmCookiesAfterMigrationTest(std::move(read_in_cookies), true); + ConfirmCookiesAfterMigrationTest(std::move(read_in_cookies), + /*expect_same_party_cookies=*/true); } TEST_F(SQLitePersistentCookieStoreTest, UpgradeToSchemaVersion17) { @@ -1835,7 +1903,8 @@ TEST_F(SQLitePersistentCookieStoreTest, UpgradeToSchemaVersion17) { std::vector> read_in_cookies; CreateAndLoad(false, false, &read_in_cookies); - ConfirmCookiesAfterMigrationTest(std::move(read_in_cookies), true); + ConfirmCookiesAfterMigrationTest(std::move(read_in_cookies), + /*expect_same_party_cookies=*/true); ASSERT_GE(GetDBCurrentVersionNumber(&connection), 17); connection.Close(); } @@ -1852,7 +1921,8 @@ TEST_F(SQLitePersistentCookieStoreTest, UpgradeToSchemaVersion17FromFaultyV16) { std::vector> read_in_cookies; CreateAndLoad(false, false, &read_in_cookies); - ConfirmCookiesAfterMigrationTest(std::move(read_in_cookies), true); + ConfirmCookiesAfterMigrationTest(std::move(read_in_cookies), + /*expect_same_party_cookies=*/true); ASSERT_GE(GetDBCurrentVersionNumber(&connection), 17); connection.Close(); } @@ -1867,11 +1937,29 @@ TEST_F(SQLitePersistentCookieStoreTest, UpgradeToSchemaVersion18) { std::vector> read_in_cookies; CreateAndLoad(false, false, &read_in_cookies); - ConfirmCookiesAfterMigrationTest(std::move(read_in_cookies), true); + ConfirmCookiesAfterMigrationTest(std::move(read_in_cookies), + /*expect_same_party_cookies=*/true); ASSERT_GE(GetDBCurrentVersionNumber(&connection), 18); connection.Close(); } +TEST_F(SQLitePersistentCookieStoreTest, UpgradeToSchemaVersion19) { + // Open db. + sql::Database connection; + ASSERT_TRUE(connection.Open(temp_dir_.GetPath().Append(kCookieFilename))); + ASSERT_TRUE(CreateV18Schema(&connection)); + ASSERT_EQ(GetDBCurrentVersionNumber(&connection), 18); + ASSERT_TRUE(AddV18CookiesToDB(&connection)); + + std::vector> read_in_cookies; + CreateAndLoad(false, false, &read_in_cookies); + ConfirmCookiesAfterMigrationTest(std::move(read_in_cookies), + /*expect_same_party_cookies=*/true, + /*expect_last_update_date=*/true); + ASSERT_GE(GetDBCurrentVersionNumber(&connection), 19); + connection.Close(); +} + class PartitionedCookiesSQLitePersistentCookieStoreTest : public SQLitePersistentCookieStoreTest, public testing::WithParamInterface { diff --git a/net/extras/sqlite/sqlite_persistent_shared_dictionary_store.cc b/net/extras/sqlite/sqlite_persistent_shared_dictionary_store.cc index 2e876ab97..92ad36d8d 100644 --- a/net/extras/sqlite/sqlite_persistent_shared_dictionary_store.cc +++ b/net/extras/sqlite/sqlite_persistent_shared_dictionary_store.cc @@ -275,7 +275,7 @@ class SQLitePersistentSharedDictionaryStore::Backend UsageInfoOrError GetUsageInfoImpl(); OriginListOrError GetOriginsBetweenImpl(const base::Time start_time, const base::Time end_time); - Error ClearAllDictionariesImpl(); + UnguessableTokenSetOrError ClearAllDictionariesImpl(); UnguessableTokenSetOrError ClearDictionariesImpl( base::Time start_time, base::Time end_time, @@ -969,36 +969,47 @@ SQLitePersistentSharedDictionaryStore::Backend::GetOriginsBetweenImpl( return base::ok(std::vector(origins.begin(), origins.end())); } -SQLitePersistentSharedDictionaryStore::Error +SQLitePersistentSharedDictionaryStore::UnguessableTokenSetOrError SQLitePersistentSharedDictionaryStore::Backend::ClearAllDictionariesImpl() { CHECK(background_task_runner()->RunsTasksInCurrentSequence()); if (!InitializeDatabase()) { - return Error::kFailedToInitializeDatabase; + return base::unexpected(Error::kFailedToInitializeDatabase); } sql::Transaction transaction(db()); if (!transaction.Begin()) { - return Error::kFailedToBeginTransaction; + return base::unexpected(Error::kFailedToBeginTransaction); } - static constexpr char kQuery[] = "DELETE FROM dictionaries"; + static constexpr char kQuery[] = + "DELETE FROM dictionaries RETURNING token_high, token_low"; if (!db()->IsSQLValid(kQuery)) { - return Error::kInvalidSql; + return base::unexpected(Error::kInvalidSql); } sql::Statement statement(db()->GetCachedStatement(SQL_FROM_HERE, kQuery)); - if (!statement.Run()) { - return Error::kFailedToExecuteSql; + + std::vector tokens; + while (statement.Step()) { + const int64_t token_high = statement.ColumnInt64(0); + const int64_t token_low = statement.ColumnInt64(1); + absl::optional disk_cache_key_token = + ToUnguessableToken(token_high, token_low); + if (!disk_cache_key_token) { + continue; + } + tokens.emplace_back(*disk_cache_key_token); } if (!meta_table()->SetValue(kTotalDictSizeKey, 0)) { - return Error::kFailedToSetTotalDictSize; + return base::unexpected(Error::kFailedToSetTotalDictSize); } if (!transaction.Commit()) { - return Error::kFailedToCommitTransaction; + return base::unexpected(Error::kFailedToCommitTransaction); } - return Error::kOk; + return base::ok( + std::set(tokens.begin(), tokens.end())); } SQLitePersistentSharedDictionaryStore::UnguessableTokenSetOrError @@ -1701,7 +1712,7 @@ void SQLitePersistentSharedDictionaryStore::GetOriginsBetween( } void SQLitePersistentSharedDictionaryStore::ClearAllDictionaries( - base::OnceCallback callback) { + base::OnceCallback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); backend_->ClearAllDictionaries( WrapCallbackWithWeakPtrCheck(GetWeakPtr(), std::move(callback))); diff --git a/net/extras/sqlite/sqlite_persistent_shared_dictionary_store.h b/net/extras/sqlite/sqlite_persistent_shared_dictionary_store.h index 212285ebe..364aa3edd 100644 --- a/net/extras/sqlite/sqlite_persistent_shared_dictionary_store.h +++ b/net/extras/sqlite/sqlite_persistent_shared_dictionary_store.h @@ -126,7 +126,8 @@ class COMPONENT_EXPORT(NET_EXTRAS) SQLitePersistentSharedDictionaryStore { void GetOriginsBetween(const base::Time start_time, const base::Time end_time, base::OnceCallback callback); - void ClearAllDictionaries(base::OnceCallback callback); + void ClearAllDictionaries( + base::OnceCallback callback); void ClearDictionaries( const base::Time start_time, const base::Time end_time, diff --git a/net/extras/sqlite/sqlite_persistent_shared_dictionary_store_unittest.cc b/net/extras/sqlite/sqlite_persistent_shared_dictionary_store_unittest.cc index 612ee876a..72befec55 100644 --- a/net/extras/sqlite/sqlite_persistent_shared_dictionary_store_unittest.cc +++ b/net/extras/sqlite/sqlite_persistent_shared_dictionary_store_unittest.cc @@ -278,14 +278,18 @@ class SQLitePersistentSharedDictionaryStoreTest : public ::testing::Test, return origins; } - void ClearAllDictionaries() { + std::set ClearAllDictionaries() { base::RunLoop run_loop; + std::set tokens; store_->ClearAllDictionaries(base::BindLambdaForTesting( - [&](SQLitePersistentSharedDictionaryStore::Error error) { - EXPECT_EQ(SQLitePersistentSharedDictionaryStore::Error::kOk, error); + [&](SQLitePersistentSharedDictionaryStore::UnguessableTokenSetOrError + result) { + ASSERT_TRUE(result.has_value()); + tokens = std::move(result.value()); run_loop.Quit(); })); run_loop.Run(); + return tokens; } std::set ClearDictionaries( @@ -399,8 +403,7 @@ class SQLitePersistentSharedDictionaryStoreTest : public ::testing::Test, CHECK(sql::test::CorruptSizeInHeader(GetStroeFilePath())); } - void ManipulateDatabase( - const std::vector& create_table_queries) { + void ManipulateDatabase(const std::vector& queries) { // We don't allow manipulating the database while `store_` exists. ASSERT_FALSE(store_); @@ -411,7 +414,7 @@ class SQLitePersistentSharedDictionaryStoreTest : public ::testing::Test, sql::MetaTable meta_table; ASSERT_TRUE(meta_table.Init(db.get(), kCurrentVersionNumber, kCurrentVersionNumber)); - for (const std::string& query : create_table_queries) { + for (const std::string& query : queries) { ASSERT_TRUE(db->Execute(query.c_str())); } db->Close(); @@ -511,7 +514,9 @@ TEST_F(SQLitePersistentSharedDictionaryStoreTest, SingleDictionary) { dictionary_info_.response_time() + base::Seconds(1)), ElementsAreArray({isolation_key_.frame_origin()})); - ClearAllDictionaries(); + EXPECT_THAT( + ClearAllDictionaries(), + UnorderedElementsAreArray({dictionary_info_.disk_cache_key_token()})); EXPECT_EQ(0u, GetTotalDictionarySize()); EXPECT_TRUE(GetDictionaries(isolation_key_).empty()); @@ -551,8 +556,11 @@ void SQLitePersistentSharedDictionaryStoreTest::RunMultipleDictionariesTest( base::Time latest_response_time = std::max(dictionary_info1.response_time(), dictionary_info2.response_time()); + std::set registered_tokens; + if (isolation_key1 == isolation_key2) { if (expect_merged) { + registered_tokens.insert(expected_info2.disk_cache_key_token()); EXPECT_EQ(dictionary_info2.size(), register_dictionary_result2.total_dictionary_size()); EXPECT_THAT(GetDictionaries(isolation_key1), @@ -571,6 +579,9 @@ void SQLitePersistentSharedDictionaryStoreTest::RunMultipleDictionariesTest( latest_response_time + base::Seconds(1)), ElementsAreArray({isolation_key2.frame_origin()})); } else { + registered_tokens.insert(expected_info1.disk_cache_key_token()); + registered_tokens.insert(expected_info2.disk_cache_key_token()); + EXPECT_EQ(dictionary_info1.size() + dictionary_info2.size(), register_dictionary_result2.total_dictionary_size()); EXPECT_THAT(GetDictionaries(isolation_key1), @@ -589,6 +600,8 @@ void SQLitePersistentSharedDictionaryStoreTest::RunMultipleDictionariesTest( UnorderedElementsAreArray({isolation_key1.frame_origin()})); } } else { + registered_tokens.insert(expected_info1.disk_cache_key_token()); + registered_tokens.insert(expected_info2.disk_cache_key_token()); EXPECT_EQ(dictionary_info1.size() + dictionary_info2.size(), register_dictionary_result2.total_dictionary_size()); EXPECT_THAT(GetDictionaries(isolation_key1), @@ -613,7 +626,8 @@ void SQLitePersistentSharedDictionaryStoreTest::RunMultipleDictionariesTest( isolation_key2.frame_origin()})); } - ClearAllDictionaries(); + EXPECT_THAT(ClearAllDictionaries(), + UnorderedElementsAreArray(registered_tokens)); EXPECT_TRUE(GetDictionaries(isolation_key_).empty()); EXPECT_TRUE(GetAllDictionaries().empty()); EXPECT_TRUE(GetUsageInfo().empty()); @@ -747,13 +761,18 @@ TEST_F(SQLitePersistentSharedDictionaryStoreTest, TEST_F(SQLitePersistentSharedDictionaryStoreTest, GetTotalDictionarySizeErrorFailedToGetTotalDictSize) { CreateStore(); - ClearAllDictionaries(); + EXPECT_TRUE(ClearAllDictionaries().empty()); DestroyStore(); ManipulateDatabase({"DELETE FROM meta WHERE key='total_dict_size'"}); RunGetTotalDictionarySizeFailureTest( SQLitePersistentSharedDictionaryStore::Error::kFailedToGetTotalDictSize); - CheckStoreRecovered(); + + CreateStore(); + // ClearAllDictionaries() resets total_dict_size in metadata. + EXPECT_TRUE(ClearAllDictionaries().empty()); + // So GetTotalDictionarySize() should succeed. + EXPECT_EQ(0u, GetTotalDictionarySize()); } void SQLitePersistentSharedDictionaryStoreTest:: @@ -813,7 +832,12 @@ TEST_F(SQLitePersistentSharedDictionaryStoreTest, RunRegisterDictionaryFailureTest( SQLitePersistentSharedDictionaryStore::Error::kFailedToGetTotalDictSize); - CheckStoreRecovered(); + + CreateStore(); + // ClearAllDictionaries() resets total_dict_size in metadata. + EXPECT_TRUE(ClearAllDictionaries().empty()); + // So RegisterDictionary() should succeed. + RegisterDictionary(isolation_key_, dictionary_info_); } TEST_F(SQLitePersistentSharedDictionaryStoreTest, @@ -1382,8 +1406,10 @@ void SQLitePersistentSharedDictionaryStoreTest:: CreateStore(); base::RunLoop run_loop; store_->ClearAllDictionaries(base::BindLambdaForTesting( - [&](SQLitePersistentSharedDictionaryStore::Error error) { - EXPECT_EQ(expected_error, error); + [&](SQLitePersistentSharedDictionaryStore::UnguessableTokenSetOrError + result) { + ASSERT_FALSE(result.has_value()); + EXPECT_EQ(expected_error, result.error()); run_loop.Quit(); })); run_loop.Run(); @@ -1408,7 +1434,7 @@ TEST_F(SQLitePersistentSharedDictionaryStoreTest, DestroyStore(); MakeFileUnwritable(); RunClearAllDictionariesFailureTest( - SQLitePersistentSharedDictionaryStore::Error::kFailedToExecuteSql); + SQLitePersistentSharedDictionaryStore::Error::kFailedToSetTotalDictSize); } #endif // !BUILDFLAG(IS_FUCHSIA) @@ -1492,6 +1518,17 @@ TEST_F(SQLitePersistentSharedDictionaryStoreTest, RunClearDictionariesFailureTest( base::RepeatingCallback(), SQLitePersistentSharedDictionaryStore::Error::kFailedToGetTotalDictSize); + + CreateStore(); + // ClearAllDictionaries() resets total_dict_size in metadata. + EXPECT_THAT( + ClearAllDictionaries(), + UnorderedElementsAreArray({dictionary_info_.disk_cache_key_token()})); + // So ClearDictionaries() should succeed. + EXPECT_TRUE(ClearDictionaries(base::Time::Now() - base::Seconds(10), + base::Time::Now(), + base::RepeatingCallback()) + .empty()); } void SQLitePersistentSharedDictionaryStoreTest:: @@ -1537,6 +1574,14 @@ TEST_F(SQLitePersistentSharedDictionaryStoreTest, RunClearDictionariesForIsolationKeyFailureTest( SQLitePersistentSharedDictionaryStore::Error::kFailedToGetTotalDictSize); + + CreateStore(); + // ClearAllDictionaries() resets total_dict_size in metadata. + EXPECT_THAT( + ClearAllDictionaries(), + UnorderedElementsAreArray({dictionary_info_.disk_cache_key_token()})); + // So ClearDictionariesForIsolationKey() should succeed. + EXPECT_TRUE(ClearDictionariesForIsolationKey(isolation_key_).empty()); } void SQLitePersistentSharedDictionaryStoreTest:: @@ -1585,6 +1630,14 @@ TEST_F(SQLitePersistentSharedDictionaryStoreTest, RunDeleteExpiredDictionariesFailureTest( SQLitePersistentSharedDictionaryStore::Error::kFailedToGetTotalDictSize); + + CreateStore(); + // ClearAllDictionaries() resets total_dict_size in metadata. + EXPECT_THAT( + ClearAllDictionaries(), + UnorderedElementsAreArray({dictionary_info_.disk_cache_key_token()})); + // So DeleteExpiredDictionaries() should succeed. + EXPECT_TRUE(DeleteExpiredDictionaries(base::Time::Now()).empty()); } void SQLitePersistentSharedDictionaryStoreTest::RunProcessEvictionFailureTest( @@ -1650,6 +1703,17 @@ TEST_F(SQLitePersistentSharedDictionaryStoreTest, RunProcessEvictionFailureTest( SQLitePersistentSharedDictionaryStore::Error::kFailedToGetTotalDictSize); + + CreateStore(); + // ClearAllDictionaries() resets total_dict_size in metadata. + EXPECT_THAT( + ClearAllDictionaries(), + UnorderedElementsAreArray({dictionary_info_.disk_cache_key_token()})); + // So ProcessEviction() should succeed. + EXPECT_TRUE(ProcessEviction( + /*cache_max_size=*/1, /*size_low_watermark=*/1, + /*cache_max_count=*/1, /*count_low_watermark=*/1) + .empty()); } void SQLitePersistentSharedDictionaryStoreTest:: @@ -1717,6 +1781,15 @@ TEST_F(SQLitePersistentSharedDictionaryStoreTest, SQLitePersistentSharedDictionaryStore::Error::kFailedToGetTotalDictSize, DeleteDictionariesByDiskCacheKeyTokens( {dictionary_info_.disk_cache_key_token()})); + + // ClearAllDictionaries() resets total_dict_size in metadata. + EXPECT_THAT( + ClearAllDictionaries(), + UnorderedElementsAreArray({dictionary_info_.disk_cache_key_token()})); + // So DeleteDictionariesByDiskCacheKeyTokens() should succeed. + EXPECT_EQ(SQLitePersistentSharedDictionaryStore::Error::kOk, + DeleteDictionariesByDiskCacheKeyTokens( + {base::UnguessableToken::Create()})); } TEST_F(SQLitePersistentSharedDictionaryStoreTest, InvalidHash) { @@ -1812,9 +1885,8 @@ TEST_F(SQLitePersistentSharedDictionaryStoreTest, ClearAllDictionariesCallbackNotCalledAfterStoreDeleted) { CreateStore(); store_->ClearAllDictionaries(base::BindLambdaForTesting( - [](SQLitePersistentSharedDictionaryStore::Error error) { - EXPECT_TRUE(false) << "Should not be reached."; - })); + [](SQLitePersistentSharedDictionaryStore::UnguessableTokenSetOrError + result) { EXPECT_TRUE(false) << "Should not be reached."; })); store_.reset(); RunUntilIdle(); } -- cgit v1.2.3