1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/extras/sqlite/sqlite_persistent_cookie_store.h"
6
7 #include <stdint.h>
8
9 #include <map>
10 #include <memory>
11 #include <optional>
12 #include <set>
13 #include <utility>
14 #include <vector>
15
16 #include "base/containers/span.h"
17 #include "base/files/file.h"
18 #include "base/files/file_util.h"
19 #include "base/files/scoped_temp_dir.h"
20 #include "base/functional/bind.h"
21 #include "base/functional/callback.h"
22 #include "base/location.h"
23 #include "base/memory/ref_counted.h"
24 #include "base/memory/weak_ptr.h"
25 #include "base/run_loop.h"
26 #include "base/sequence_checker.h"
27 #include "base/strings/stringprintf.h"
28 #include "base/synchronization/waitable_event.h"
29 #include "base/task/sequenced_task_runner.h"
30 #include "base/task/single_thread_task_runner.h"
31 #include "base/task/thread_pool.h"
32 #include "base/test/bind.h"
33 #include "base/test/metrics/histogram_tester.h"
34 #include "base/threading/thread_restrictions.h"
35 #include "base/time/time.h"
36 #include "crypto/encryptor.h"
37 #include "crypto/symmetric_key.h"
38 #include "net/base/test_completion_callback.h"
39 #include "net/cookies/canonical_cookie.h"
40 #include "net/cookies/cookie_constants.h"
41 #include "net/cookies/cookie_inclusion_status.h"
42 #include "net/cookies/cookie_store_test_callbacks.h"
43 #include "net/extras/sqlite/cookie_crypto_delegate.h"
44 #include "net/log/net_log_capture_mode.h"
45 #include "net/log/test_net_log.h"
46 #include "net/log/test_net_log_util.h"
47 #include "net/test/test_with_task_environment.h"
48 #include "sql/database.h"
49 #include "sql/meta_table.h"
50 #include "sql/statement.h"
51 #include "sql/transaction.h"
52 #include "testing/gmock/include/gmock/gmock-matchers.h"
53 #include "testing/gmock/include/gmock/gmock.h"
54 #include "testing/gtest/include/gtest/gtest.h"
55 #include "url/gurl.h"
56 #include "url/third_party/mozilla/url_parse.h"
57
58 namespace net {
59
60 namespace {
61
62 const base::FilePath::CharType kCookieFilename[] = FILE_PATH_LITERAL("Cookies");
63
64 class CookieCryptor : public CookieCryptoDelegate {
65 public:
66 CookieCryptor();
67
68 // net::CookieCryptoDelegate implementation.
69 void Init(base::OnceClosure callback) override;
70 bool EncryptString(const std::string& plaintext,
71 std::string* ciphertext) override;
72 bool DecryptString(const std::string& ciphertext,
73 std::string* plaintext) override;
74
75 // Obtain a closure that can be called to trigger an initialize. If this
76 // instance has already been destructed then the returned base::OnceClosure
77 // does nothing. This allows tests to pass ownership to the CookieCryptor
78 // while still retaining a weak reference to the Init function.
79 base::OnceClosure GetInitClosure(base::OnceClosure callback);
80
81 private:
82 void InitComplete();
83 bool init_ GUARDED_BY_CONTEXT(sequence_checker_) = false;
84 bool initing_ GUARDED_BY_CONTEXT(sequence_checker_) = false;
85 base::OnceClosureList callbacks_ GUARDED_BY_CONTEXT(sequence_checker_);
86 std::unique_ptr<crypto::SymmetricKey> key_;
87 crypto::Encryptor encryptor_;
88 SEQUENCE_CHECKER(sequence_checker_);
89
90 base::WeakPtrFactory<CookieCryptor> weak_ptr_factory_{this};
91 };
92
CookieCryptor()93 CookieCryptor::CookieCryptor()
94 : key_(crypto::SymmetricKey::DeriveKeyFromPasswordUsingPbkdf2(
95 crypto::SymmetricKey::AES,
96 "password",
97 "saltiest",
98 1000,
99 256)) {
100 std::string iv("the iv: 16 bytes");
101 encryptor_.Init(key_.get(), crypto::Encryptor::CBC, iv);
102 DETACH_FROM_SEQUENCE(sequence_checker_);
103 }
104
GetInitClosure(base::OnceClosure callback)105 base::OnceClosure CookieCryptor::GetInitClosure(base::OnceClosure callback) {
106 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
107 return base::BindOnce(&CookieCryptor::Init, weak_ptr_factory_.GetWeakPtr(),
108 std::move(callback));
109 }
110
Init(base::OnceClosure callback)111 void CookieCryptor::Init(base::OnceClosure callback) {
112 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
113 if (init_) {
114 std::move(callback).Run();
115 return;
116 }
117
118 // Callbacks here are owned by test fixtures that outlive the CookieCryptor.
119 callbacks_.AddUnsafe(std::move(callback));
120
121 if (initing_) {
122 return;
123 }
124
125 initing_ = true;
126 base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
127 FROM_HERE,
128 base::BindOnce(&CookieCryptor::InitComplete,
129 weak_ptr_factory_.GetWeakPtr()),
130 base::Milliseconds(100));
131 }
132
EncryptString(const std::string & plaintext,std::string * ciphertext)133 bool CookieCryptor::EncryptString(const std::string& plaintext,
134 std::string* ciphertext) {
135 return encryptor_.Encrypt(plaintext, ciphertext);
136 }
137
DecryptString(const std::string & ciphertext,std::string * plaintext)138 bool CookieCryptor::DecryptString(const std::string& ciphertext,
139 std::string* plaintext) {
140 return encryptor_.Decrypt(ciphertext, plaintext);
141 }
142
InitComplete()143 void CookieCryptor::InitComplete() {
144 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
145 init_ = true;
146 callbacks_.Notify();
147 }
148
149 // Matches the CanonicalCookie's strictly_unique_key and last_access_date
150 // against a unique_ptr<CanonicalCookie>.
151 MATCHER_P2(MatchesCookieKeyAndLastAccessDate,
152 StrictlyUniqueKey,
153 last_access_date,
154 "") {
155 if (!arg) {
156 return false;
157 }
158 const CanonicalCookie& list_cookie = *arg;
159
160 return testing::ExplainMatchResult(StrictlyUniqueKey,
161 list_cookie.StrictlyUniqueKey(),
162 result_listener) &&
163 testing::ExplainMatchResult(
164 last_access_date, list_cookie.LastAccessDate(), result_listener);
165 }
166
167 // Matches every field of a CanonicalCookie against a
168 // unique_ptr<CanonicalCookie>.
169 MATCHER_P(MatchesEveryCookieField, cookie, "") {
170 if (!arg) {
171 return false;
172 }
173 const CanonicalCookie& list_cookie = *arg;
174 return cookie.HasEquivalentDataMembers(list_cookie);
175 }
176
177 } // namespace
178
179 typedef std::vector<std::unique_ptr<CanonicalCookie>> CanonicalCookieVector;
180
181 class SQLitePersistentCookieStoreTest : public TestWithTaskEnvironment {
182 public:
SQLitePersistentCookieStoreTest()183 SQLitePersistentCookieStoreTest()
184 : loaded_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
185 base::WaitableEvent::InitialState::NOT_SIGNALED),
186 db_thread_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
187 base::WaitableEvent::InitialState::NOT_SIGNALED) {}
188
SignalLoadedEvent()189 void SignalLoadedEvent() { loaded_event_.Signal(); }
190
OnLoaded(base::OnceClosure closure,CanonicalCookieVector cookies)191 void OnLoaded(base::OnceClosure closure, CanonicalCookieVector cookies) {
192 cookies_.swap(cookies);
193 std::move(closure).Run();
194 }
195
Load()196 CanonicalCookieVector Load() {
197 base::RunLoop run_loop;
198 CanonicalCookieVector cookies;
199 store_->Load(
200 base::BindLambdaForTesting([&](CanonicalCookieVector obtained_cookies) {
201 cookies.swap(obtained_cookies);
202 run_loop.Quit();
203 }),
204 NetLogWithSource::Make(NetLogSourceType::NONE));
205 run_loop.Run();
206 return cookies;
207 }
208
LoadAsyncAndSignalEvent()209 void LoadAsyncAndSignalEvent() {
210 store_->Load(
211 base::BindOnce(
212 &SQLitePersistentCookieStoreTest::OnLoaded, base::Unretained(this),
213 base::BindOnce(&SQLitePersistentCookieStoreTest::SignalLoadedEvent,
214 base::Unretained(this))),
215 NetLogWithSource::Make(NetLogSourceType::NONE));
216 }
217
Flush()218 void Flush() {
219 base::RunLoop run_loop;
220 store_->Flush(run_loop.QuitClosure());
221 run_loop.Run();
222 }
223
DestroyStore()224 void DestroyStore() {
225 store_ = nullptr;
226 // Make sure we wait until the destructor has run by running all
227 // TaskEnvironment tasks.
228 RunUntilIdle();
229 }
230
Create(bool crypt_cookies,bool restore_old_session_cookies,bool use_current_thread,bool enable_exclusive_access)231 void Create(bool crypt_cookies,
232 bool restore_old_session_cookies,
233 bool use_current_thread,
234 bool enable_exclusive_access) {
235 store_ = base::MakeRefCounted<SQLitePersistentCookieStore>(
236 temp_dir_.GetPath().Append(kCookieFilename),
237 use_current_thread ? base::SingleThreadTaskRunner::GetCurrentDefault()
238 : client_task_runner_,
239 background_task_runner_, restore_old_session_cookies,
240 crypt_cookies ? std::make_unique<CookieCryptor>() : nullptr,
241 enable_exclusive_access);
242 }
243
CreateAndLoad(bool crypt_cookies,bool restore_old_session_cookies)244 CanonicalCookieVector CreateAndLoad(bool crypt_cookies,
245 bool restore_old_session_cookies) {
246 Create(crypt_cookies, restore_old_session_cookies,
247 /*use_current_thread=*/false, /*enable_exclusive_access=*/false);
248 return Load();
249 }
250
InitializeStore(bool crypt,bool restore_old_session_cookies)251 void InitializeStore(bool crypt, bool restore_old_session_cookies) {
252 EXPECT_EQ(0U, CreateAndLoad(crypt, restore_old_session_cookies).size());
253 }
254
WaitOnDBEvent()255 void WaitOnDBEvent() {
256 base::ScopedAllowBaseSyncPrimitivesForTesting allow_base_sync_primitives;
257 db_thread_event_.Wait();
258 }
259
260 // Adds a persistent cookie to store_.
AddCookie(const std::string & name,const std::string & value,const std::string & domain,const std::string & path,const base::Time & creation)261 void AddCookie(const std::string& name,
262 const std::string& value,
263 const std::string& domain,
264 const std::string& path,
265 const base::Time& creation) {
266 store_->AddCookie(*CanonicalCookie::CreateUnsafeCookieForTesting(
267 name, value, domain, path, creation, /*expiration=*/creation,
268 /*last_access=*/base::Time(), /*last_update=*/base::Time(),
269 /*secure=*/false,
270 /*httponly=*/false, CookieSameSite::NO_RESTRICTION,
271 COOKIE_PRIORITY_DEFAULT));
272 }
273
AddCookieWithExpiration(const std::string & name,const std::string & value,const std::string & domain,const std::string & path,const base::Time & creation,const base::Time & expiration)274 void AddCookieWithExpiration(const std::string& name,
275 const std::string& value,
276 const std::string& domain,
277 const std::string& path,
278 const base::Time& creation,
279 const base::Time& expiration) {
280 store_->AddCookie(*CanonicalCookie::CreateUnsafeCookieForTesting(
281 name, value, domain, path, creation, expiration,
282 /*last_access=*/base::Time(), /*last_update=*/base::Time(),
283 /*secure=*/false,
284 /*httponly=*/false, CookieSameSite::NO_RESTRICTION,
285 COOKIE_PRIORITY_DEFAULT));
286 }
287
ReadRawDBContents()288 std::string ReadRawDBContents() {
289 std::string contents;
290 if (!base::ReadFileToString(temp_dir_.GetPath().Append(kCookieFilename),
291 &contents))
292 return std::string();
293 return contents;
294 }
295
SetUp()296 void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); }
297
TearDown()298 void TearDown() override {
299 if (!expect_init_errors_) {
300 EXPECT_THAT(histograms_.GetAllSamples("Cookie.ErrorInitializeDB"),
301 ::testing::IsEmpty());
302 }
303 DestroyStore();
304 }
305
306 protected:
307 const scoped_refptr<base::SequencedTaskRunner> background_task_runner_ =
308 base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()});
309 const scoped_refptr<base::SequencedTaskRunner> client_task_runner_ =
310 base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()});
311 base::WaitableEvent loaded_event_;
312 base::WaitableEvent db_thread_event_;
313 CanonicalCookieVector cookies_;
314 base::ScopedTempDir temp_dir_;
315 scoped_refptr<SQLitePersistentCookieStore> store_;
316 std::unique_ptr<CookieCryptor> cookie_crypto_delegate_;
317 base::HistogramTester histograms_;
318 bool expect_init_errors_ = false;
319 };
320
TEST_F(SQLitePersistentCookieStoreTest,TestInvalidVersionRecovery)321 TEST_F(SQLitePersistentCookieStoreTest, TestInvalidVersionRecovery) {
322 InitializeStore(/*crypt=*/false, /*restore_old_session_cookies=*/false);
323 AddCookie("A", "B", "foo.bar", "/", base::Time::Now());
324 DestroyStore();
325
326 // Load up the store and verify that it has good data in it.
327 CanonicalCookieVector cookies = CreateAndLoad(
328 /*crypt_cookies=*/false, /*restore_old_session_cookies=*/false);
329 ASSERT_EQ(1U, cookies.size());
330 ASSERT_STREQ("foo.bar", cookies[0]->Domain().c_str());
331 ASSERT_STREQ("A", cookies[0]->Name().c_str());
332 ASSERT_STREQ("B", cookies[0]->Value().c_str());
333 DestroyStore();
334 cookies.clear();
335
336 // Now make the version too old to initialize from.
337 {
338 sql::Database db;
339 ASSERT_TRUE(db.Open(temp_dir_.GetPath().Append(kCookieFilename)));
340 sql::MetaTable meta_table;
341 ASSERT_TRUE(meta_table.Init(&db, 1, 1));
342 // Keep in sync with latest unsupported version from:
343 // net/extras/sqlite/sqlite_persistent_cookie_store.cc
344 ASSERT_TRUE(meta_table.SetVersionNumber(17));
345 }
346
347 // Upon loading, the database should be reset to a good, blank state.
348 cookies = CreateAndLoad(/*crypt_cookies=*/false,
349 /*restore_old_session_cookies=*/false);
350 ASSERT_EQ(0U, cookies.size());
351
352 // Verify that, after, recovery, the database persists properly.
353 AddCookie("X", "Y", "foo.bar", "/", base::Time::Now());
354 DestroyStore();
355 cookies = CreateAndLoad(/*crypt_cookies=*/false,
356 /*restore_old_session_cookies=*/false);
357 ASSERT_EQ(1U, cookies.size());
358 ASSERT_STREQ("foo.bar", cookies[0]->Domain().c_str());
359 ASSERT_STREQ("X", cookies[0]->Name().c_str());
360 ASSERT_STREQ("Y", cookies[0]->Value().c_str());
361 }
362
TEST_F(SQLitePersistentCookieStoreTest,TestInvalidMetaTableRecovery)363 TEST_F(SQLitePersistentCookieStoreTest, TestInvalidMetaTableRecovery) {
364 InitializeStore(/*crypt=*/false, /*restore_old_session_cookies=*/false);
365 AddCookie("A", "B", "foo.bar", "/", base::Time::Now());
366 DestroyStore();
367
368 // Load up the store and verify that it has good data in it.
369 CanonicalCookieVector cookies = CreateAndLoad(
370 /*crypt_cookies=*/false, /*restore_old_session_cookies=*/false);
371 ASSERT_EQ(1U, cookies.size());
372 ASSERT_STREQ("foo.bar", cookies[0]->Domain().c_str());
373 ASSERT_STREQ("A", cookies[0]->Name().c_str());
374 ASSERT_STREQ("B", cookies[0]->Value().c_str());
375 DestroyStore();
376 cookies.clear();
377
378 // Now corrupt the meta table.
379 {
380 sql::Database db;
381 ASSERT_TRUE(db.Open(temp_dir_.GetPath().Append(kCookieFilename)));
382 sql::MetaTable meta_table;
383 ASSERT_TRUE(meta_table.Init(&db, 1, 1));
384 ASSERT_TRUE(db.Execute("DELETE FROM meta"));
385 }
386
387 // Upon loading, the database should be reset to a good, blank state.
388 cookies = CreateAndLoad(/*crypt_cookies=*/false,
389 /*restore_old_session_cookies=*/false);
390 ASSERT_EQ(0U, cookies.size());
391
392 // Verify that, after, recovery, the database persists properly.
393 AddCookie("X", "Y", "foo.bar", "/", base::Time::Now());
394 DestroyStore();
395 cookies = CreateAndLoad(/*crypt_cookies=*/false,
396 /*restore_old_session_cookies=*/false);
397 ASSERT_EQ(1U, cookies.size());
398 ASSERT_STREQ("foo.bar", cookies[0]->Domain().c_str());
399 ASSERT_STREQ("X", cookies[0]->Name().c_str());
400 ASSERT_STREQ("Y", cookies[0]->Value().c_str());
401 }
402
403 // Test if data is stored as expected in the SQLite database.
TEST_F(SQLitePersistentCookieStoreTest,TestPersistance)404 TEST_F(SQLitePersistentCookieStoreTest, TestPersistance) {
405 InitializeStore(/*crypt=*/false, /*restore_old_session_cookies=*/false);
406 AddCookie("A", "B", "foo.bar", "/", base::Time::Now());
407 // Replace the store effectively destroying the current one and forcing it
408 // to write its data to disk. Then we can see if after loading it again it
409 // is still there.
410 DestroyStore();
411 // Reload and test for persistence
412 CanonicalCookieVector cookies = CreateAndLoad(
413 /*crypt_cookies=*/false, /*restore_old_session_cookies=*/false);
414 ASSERT_EQ(1U, cookies.size());
415 ASSERT_STREQ("foo.bar", cookies[0]->Domain().c_str());
416 ASSERT_STREQ("A", cookies[0]->Name().c_str());
417 ASSERT_STREQ("B", cookies[0]->Value().c_str());
418
419 // Now delete the cookie and check persistence again.
420 store_->DeleteCookie(*cookies[0]);
421 DestroyStore();
422 cookies.clear();
423
424 // Reload and check if the cookie has been removed.
425 cookies = CreateAndLoad(/*crypt_cookies=*/false,
426 /*restore_old_session_cookies=*/false);
427 ASSERT_EQ(0U, cookies.size());
428 }
429
TEST_F(SQLitePersistentCookieStoreTest,TestSessionCookiesDeletedOnStartup)430 TEST_F(SQLitePersistentCookieStoreTest, TestSessionCookiesDeletedOnStartup) {
431 // Initialize the cookie store with 3 persistent cookies, 5 transient
432 // cookies.
433 InitializeStore(/*crypt=*/false, /*restore_old_session_cookies=*/false);
434
435 // Add persistent cookies.
436 base::Time t = base::Time::Now();
437 AddCookie("A", "B", "a1.com", "/", t);
438 t += base::Microseconds(10);
439 AddCookie("A", "B", "a2.com", "/", t);
440 t += base::Microseconds(10);
441 AddCookie("A", "B", "a3.com", "/", t);
442
443 // Add transient cookies.
444 t += base::Microseconds(10);
445 AddCookieWithExpiration("A", "B", "b1.com", "/", t, base::Time());
446 t += base::Microseconds(10);
447 AddCookieWithExpiration("A", "B", "b2.com", "/", t, base::Time());
448 t += base::Microseconds(10);
449 AddCookieWithExpiration("A", "B", "b3.com", "/", t, base::Time());
450 t += base::Microseconds(10);
451 AddCookieWithExpiration("A", "B", "b4.com", "/", t, base::Time());
452 t += base::Microseconds(10);
453 AddCookieWithExpiration("A", "B", "b5.com", "/", t, base::Time());
454 DestroyStore();
455
456 // Load the store a second time. Before the store finishes loading, add a
457 // transient cookie and flush it to disk.
458 store_ = base::MakeRefCounted<SQLitePersistentCookieStore>(
459 temp_dir_.GetPath().Append(kCookieFilename), client_task_runner_,
460 background_task_runner_, false, nullptr, false);
461
462 // Posting a blocking task to db_thread_ makes sure that the DB thread waits
463 // until both Load and Flush have been posted to its task queue.
464 background_task_runner_->PostTask(
465 FROM_HERE, base::BindOnce(&SQLitePersistentCookieStoreTest::WaitOnDBEvent,
466 base::Unretained(this)));
467 LoadAsyncAndSignalEvent();
468 t += base::Microseconds(10);
469 AddCookieWithExpiration("A", "B", "c.com", "/", t, base::Time());
470 base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
471 base::WaitableEvent::InitialState::NOT_SIGNALED);
472 store_->Flush(
473 base::BindOnce(&base::WaitableEvent::Signal, base::Unretained(&event)));
474
475 // Now the DB-thread queue contains:
476 // (active:)
477 // 1. Wait (on db_event)
478 // (pending:)
479 // 2. "Init And Chain-Load First Domain"
480 // 3. Add Cookie (c.com)
481 // 4. Flush Cookie (c.com)
482 db_thread_event_.Signal();
483 event.Wait();
484 loaded_event_.Wait();
485 cookies_.clear();
486 DestroyStore();
487
488 // Load the store a third time, this time restoring session cookies. The
489 // store should contain exactly 4 cookies: the 3 persistent, and "c.com",
490 // which was added during the second cookie store load.
491 store_ = base::MakeRefCounted<SQLitePersistentCookieStore>(
492 temp_dir_.GetPath().Append(kCookieFilename), client_task_runner_,
493 background_task_runner_, true, nullptr, false);
494 LoadAsyncAndSignalEvent();
495 loaded_event_.Wait();
496 ASSERT_EQ(4u, cookies_.size());
497 }
498
499 // Test that priority load of cookies for a specific domain key could be
500 // completed before the entire store is loaded.
TEST_F(SQLitePersistentCookieStoreTest,TestLoadCookiesForKey)501 TEST_F(SQLitePersistentCookieStoreTest, TestLoadCookiesForKey) {
502 InitializeStore(/*crypt=*/true, /*restore_old_session_cookies=*/false);
503 base::Time t = base::Time::Now();
504 AddCookie("A", "B", "foo.bar", "/", t);
505 t += base::Microseconds(10);
506 AddCookie("A", "B", "www.aaa.com", "/", t);
507 t += base::Microseconds(10);
508 AddCookie("A", "B", "travel.aaa.com", "/", t);
509 t += base::Microseconds(10);
510 AddCookie("A", "B", "www.bbb.com", "/", t);
511 DestroyStore();
512
513 auto cookie_crypto_delegate = std::make_unique<CookieCryptor>();
514 base::RunLoop cookie_crypto_loop;
515 auto init_closure =
516 cookie_crypto_delegate->GetInitClosure(cookie_crypto_loop.QuitClosure());
517
518 // base::test::TaskEnvironment runs |background_task_runner_| and
519 // |client_task_runner_| on the same thread. Therefore, when a
520 // |background_task_runner_| task is blocked, |client_task_runner_| tasks
521 // can't run. To allow precise control of |background_task_runner_| without
522 // preventing client tasks to run, use
523 // base::SingleThreadTaskRunner::GetCurrentDefault() instead of
524 // |client_task_runner_| for this test.
525 store_ = base::MakeRefCounted<SQLitePersistentCookieStore>(
526 temp_dir_.GetPath().Append(kCookieFilename),
527 base::SingleThreadTaskRunner::GetCurrentDefault(),
528 background_task_runner_,
529 /*restore_old_session_cookies=*/false, std::move(cookie_crypto_delegate),
530 /*enable_exclusive_access=*/false);
531
532 // Posting a blocking task to db_thread_ makes sure that the DB thread waits
533 // until both Load and LoadCookiesForKey have been posted to its task queue.
534 background_task_runner_->PostTask(
535 FROM_HERE, base::BindOnce(&SQLitePersistentCookieStoreTest::WaitOnDBEvent,
536 base::Unretained(this)));
537 RecordingNetLogObserver net_log_observer;
538 LoadAsyncAndSignalEvent();
539 base::RunLoop run_loop;
540 net_log_observer.SetObserverCaptureMode(NetLogCaptureMode::kDefault);
541 store_->LoadCookiesForKey(
542 "aaa.com",
543 base::BindOnce(&SQLitePersistentCookieStoreTest::OnLoaded,
544 base::Unretained(this), run_loop.QuitClosure()));
545
546 // Complete the initialization of the cookie crypto delegate. This ensures
547 // that any background tasks from the Load or the LoadCookiesForKey are posted
548 // to the background_task_runner_.
549 std::move(init_closure).Run();
550 cookie_crypto_loop.Run();
551
552 // Post a final blocking task to the background_task_runner_ to ensure no
553 // other cookie loads take place during the test.
554 background_task_runner_->PostTask(
555 FROM_HERE, base::BindOnce(&SQLitePersistentCookieStoreTest::WaitOnDBEvent,
556 base::Unretained(this)));
557
558 // Now the DB-thread queue contains:
559 // (active:)
560 // 1. Wait (on db_event)
561 // (pending:)
562 // 2. "Init And Chain-Load First Domain"
563 // 3. Priority Load (aaa.com)
564 // 4. Wait (on db_event)
565 db_thread_event_.Signal();
566
567 // Wait until the OnKeyLoaded callback has run.
568 run_loop.Run();
569 EXPECT_FALSE(loaded_event_.IsSignaled());
570
571 std::set<std::string> cookies_loaded;
572 for (CanonicalCookieVector::const_iterator it = cookies_.begin();
573 it != cookies_.end(); ++it) {
574 cookies_loaded.insert((*it)->Domain().c_str());
575 }
576 cookies_.clear();
577 ASSERT_GT(4U, cookies_loaded.size());
578 ASSERT_EQ(true, cookies_loaded.find("www.aaa.com") != cookies_loaded.end());
579 ASSERT_EQ(true,
580 cookies_loaded.find("travel.aaa.com") != cookies_loaded.end());
581
582 db_thread_event_.Signal();
583
584 RunUntilIdle();
585 EXPECT_TRUE(loaded_event_.IsSignaled());
586
587 for (CanonicalCookieVector::const_iterator it = cookies_.begin();
588 it != cookies_.end(); ++it) {
589 cookies_loaded.insert((*it)->Domain().c_str());
590 }
591 ASSERT_EQ(4U, cookies_loaded.size());
592 ASSERT_EQ(cookies_loaded.find("foo.bar") != cookies_loaded.end(), true);
593 ASSERT_EQ(cookies_loaded.find("www.bbb.com") != cookies_loaded.end(), true);
594 cookies_.clear();
595
596 store_ = nullptr;
597 auto entries = net_log_observer.GetEntries();
598 size_t pos = ExpectLogContainsSomewhere(
599 entries, 0, NetLogEventType::COOKIE_PERSISTENT_STORE_LOAD,
600 NetLogEventPhase::BEGIN);
601 pos = ExpectLogContainsSomewhere(
602 entries, pos, NetLogEventType::COOKIE_PERSISTENT_STORE_LOAD,
603 NetLogEventPhase::END);
604 pos = ExpectLogContainsSomewhere(
605 entries, 0, NetLogEventType::COOKIE_PERSISTENT_STORE_LOAD,
606 NetLogEventPhase::BEGIN);
607 pos = ExpectLogContainsSomewhere(
608 entries, pos, NetLogEventType::COOKIE_PERSISTENT_STORE_KEY_LOAD_STARTED,
609 NetLogEventPhase::NONE);
610 EXPECT_FALSE(GetOptionalStringValueFromParams(entries[pos], "key"));
611 pos = ExpectLogContainsSomewhere(
612 entries, pos, NetLogEventType::COOKIE_PERSISTENT_STORE_KEY_LOAD_COMPLETED,
613 NetLogEventPhase::NONE);
614 pos = ExpectLogContainsSomewhere(
615 entries, pos, NetLogEventType::COOKIE_PERSISTENT_STORE_LOAD,
616 NetLogEventPhase::END);
617 ExpectLogContainsSomewhere(entries, pos,
618 NetLogEventType::COOKIE_PERSISTENT_STORE_CLOSED,
619 NetLogEventPhase::NONE);
620 }
621
TEST_F(SQLitePersistentCookieStoreTest,TestBeforeCommitCallback)622 TEST_F(SQLitePersistentCookieStoreTest, TestBeforeCommitCallback) {
623 InitializeStore(/*crypt=*/false, /*restore_old_session_cookies=*/false);
624
625 struct Counter {
626 int count = 0;
627 void increment() { count++; }
628 };
629
630 Counter counter;
631 store_->SetBeforeCommitCallback(
632 base::BindRepeating(&Counter::increment, base::Unretained(&counter)));
633
634 // The implementation of SQLitePersistentCookieStore::Backend flushes changes
635 // after 30s or 512 pending operations. Add 512 cookies to the store to test
636 // that the callback gets called when SQLitePersistentCookieStore internally
637 // flushes its store.
638 for (int i = 0; i < 512; i++) {
639 // Each cookie needs a unique timestamp for creation_utc (see DB schema).
640 base::Time t = base::Time::Now() + base::Microseconds(i);
641 AddCookie(base::StringPrintf("%d", i), "foo", "example.com", "/", t);
642 }
643
644 RunUntilIdle();
645 EXPECT_GT(counter.count, 0);
646
647 DestroyStore();
648 }
649
650 // Test that we can force the database to be written by calling Flush().
TEST_F(SQLitePersistentCookieStoreTest,TestFlush)651 TEST_F(SQLitePersistentCookieStoreTest, TestFlush) {
652 InitializeStore(/*crypt=*/false, /*restore_old_session_cookies=*/false);
653 // File timestamps don't work well on all platforms, so we'll determine
654 // whether the DB file has been modified by checking its size.
655 base::FilePath path = temp_dir_.GetPath().Append(kCookieFilename);
656 base::File::Info info;
657 ASSERT_TRUE(base::GetFileInfo(path, &info));
658 int64_t base_size = info.size;
659
660 // Write some large cookies, so the DB will have to expand by several KB.
661 for (char c = 'a'; c < 'z'; ++c) {
662 // Each cookie needs a unique timestamp for creation_utc (see DB schema).
663 base::Time t = base::Time::Now() + base::Microseconds(c);
664 std::string name(1, c);
665 std::string value(1000, c);
666 AddCookie(name, value, "foo.bar", "/", t);
667 }
668
669 Flush();
670
671 // We forced a write, so now the file will be bigger.
672 ASSERT_TRUE(base::GetFileInfo(path, &info));
673 ASSERT_GT(info.size, base_size);
674 }
675
676 // Test loading old session cookies from the disk.
TEST_F(SQLitePersistentCookieStoreTest,TestLoadOldSessionCookies)677 TEST_F(SQLitePersistentCookieStoreTest, TestLoadOldSessionCookies) {
678 InitializeStore(/*crypt=*/false, /*restore_old_session_cookies=*/true);
679
680 // Add a session cookie.
681 store_->AddCookie(*CanonicalCookie::CreateUnsafeCookieForTesting(
682 "C", "D", "sessioncookie.com", "/", /*creation=*/base::Time::Now(),
683 /*expiration=*/base::Time(),
684 /*last_access=*/base::Time(), /*last_update=*/base::Time(),
685 /*secure=*/false, /*httponly=*/false, CookieSameSite::NO_RESTRICTION,
686 COOKIE_PRIORITY_DEFAULT));
687
688 // Force the store to write its data to the disk.
689 DestroyStore();
690
691 // Create a store that loads session cookies and test that the session cookie
692 // was loaded.
693 CanonicalCookieVector cookies = CreateAndLoad(
694 /*crypt_cookies=*/false, /*restore_old_session_cookies=*/true);
695
696 ASSERT_EQ(1U, cookies.size());
697 ASSERT_STREQ("sessioncookie.com", cookies[0]->Domain().c_str());
698 ASSERT_STREQ("C", cookies[0]->Name().c_str());
699 ASSERT_STREQ("D", cookies[0]->Value().c_str());
700 ASSERT_EQ(COOKIE_PRIORITY_DEFAULT, cookies[0]->Priority());
701 }
702
703 // Test refusing to load old session cookies from the disk.
TEST_F(SQLitePersistentCookieStoreTest,TestDontLoadOldSessionCookies)704 TEST_F(SQLitePersistentCookieStoreTest, TestDontLoadOldSessionCookies) {
705 InitializeStore(/*crypt=*/false, /*restore_old_session_cookies=*/true);
706
707 // Add a session cookie.
708 store_->AddCookie(*CanonicalCookie::CreateUnsafeCookieForTesting(
709 "C", "D", "sessioncookie.com", "/", /*creation=*/base::Time::Now(),
710 /*expiration=*/base::Time(),
711 /*last_access=*/base::Time(), /*last_update=*/base::Time(),
712 /*secure=*/false, /*httponly=*/false, CookieSameSite::NO_RESTRICTION,
713 COOKIE_PRIORITY_DEFAULT));
714
715 // Force the store to write its data to the disk.
716 DestroyStore();
717
718 // Create a store that doesn't load old session cookies and test that the
719 // session cookie was not loaded.
720 CanonicalCookieVector cookies = CreateAndLoad(
721 /*crypt_cookies=*/false, /*restore_old_session_cookies=*/false);
722 ASSERT_EQ(0U, cookies.size());
723
724 // The store should also delete the session cookie. Wait until that has been
725 // done.
726 DestroyStore();
727
728 // Create a store that loads old session cookies and test that the session
729 // cookie is gone.
730 cookies = CreateAndLoad(/*crypt_cookies=*/false,
731 /*restore_old_session_cookies=*/true);
732 ASSERT_EQ(0U, cookies.size());
733 }
734
735 // Confirm bad cookies on disk don't get looaded, and that we also remove them
736 // from the database.
TEST_F(SQLitePersistentCookieStoreTest,FilterBadCookiesAndFixupDb)737 TEST_F(SQLitePersistentCookieStoreTest, FilterBadCookiesAndFixupDb) {
738 // Create an on-disk store.
739 InitializeStore(/*crypt=*/false, /*restore_old_session_cookies=*/true);
740 DestroyStore();
741
742 // Add some cookies in by hand.
743 base::FilePath store_name(temp_dir_.GetPath().Append(kCookieFilename));
744 std::unique_ptr<sql::Database> db(std::make_unique<sql::Database>());
745 ASSERT_TRUE(db->Open(store_name));
746 sql::Statement stmt(db->GetUniqueStatement(
747 "INSERT INTO cookies (creation_utc, host_key, top_frame_site_key, name, "
748 "value, encrypted_value, path, expires_utc, is_secure, is_httponly, "
749 "samesite, last_access_utc, has_expires, is_persistent, priority, "
750 "source_scheme, source_port, last_update_utc, source_type, "
751 "has_cross_site_ancestor) "
752 "VALUES (?,?,?,?,?,'',?,0,0,0,0,0,1,1,0,?,?,?,0,0)"));
753 ASSERT_TRUE(stmt.is_valid());
754
755 struct CookieInfo {
756 const char* domain;
757 const char* name;
758 const char* value;
759 const char* path;
760 } cookies_info[] = {// A couple non-canonical cookies.
761 {"google.izzle", "A=", "B", "/path"},
762 {"google.izzle", "C ", "D", "/path"},
763
764 // A canonical cookie for same eTLD+1. This one will get
765 // dropped out of precaution to avoid confusing the site,
766 // even though there is nothing wrong with it.
767 {"sub.google.izzle", "E", "F", "/path"},
768
769 // A canonical cookie for another eTLD+1
770 {"chromium.org", "G", "H", "/dir"}};
771
772 int64_t creation_time = 1;
773 base::Time last_update(base::Time::Now());
774 for (auto& cookie_info : cookies_info) {
775 stmt.Reset(true);
776
777 stmt.BindInt64(0, creation_time++);
778 stmt.BindString(1, cookie_info.domain);
779 // TODO(crbug.com/1225444) Test some non-empty values when CanonicalCookie
780 // supports partition key.
781 stmt.BindString(2, net::kEmptyCookiePartitionKey);
782 stmt.BindString(3, cookie_info.name);
783 stmt.BindString(4, cookie_info.value);
784 stmt.BindString(5, cookie_info.path);
785 stmt.BindInt(6, static_cast<int>(CookieSourceScheme::kUnset));
786 stmt.BindInt(7, SQLitePersistentCookieStore::kDefaultUnknownPort);
787 stmt.BindTime(8, last_update);
788 ASSERT_TRUE(stmt.Run());
789 }
790 stmt.Clear();
791 db.reset();
792
793 // Reopen the store and confirm that the only cookie loaded is the
794 // canonical one on an unrelated domain.
795 CanonicalCookieVector cookies = CreateAndLoad(
796 /*crypt_cookies=*/false, /*restore_old_session_cookies=*/false);
797 ASSERT_EQ(1U, cookies.size());
798 EXPECT_STREQ("chromium.org", cookies[0]->Domain().c_str());
799 EXPECT_STREQ("G", cookies[0]->Name().c_str());
800 EXPECT_STREQ("H", cookies[0]->Value().c_str());
801 EXPECT_STREQ("/dir", cookies[0]->Path().c_str());
802 EXPECT_EQ(last_update, cookies[0]->LastUpdateDate());
803 DestroyStore();
804
805 // Make sure that we only have one row left.
806 db = std::make_unique<sql::Database>();
807 ASSERT_TRUE(db->Open(store_name));
808 sql::Statement verify_stmt(db->GetUniqueStatement("SELECT * FROM COOKIES"));
809 ASSERT_TRUE(verify_stmt.is_valid());
810
811 EXPECT_TRUE(verify_stmt.Step());
812 EXPECT_TRUE(verify_stmt.Succeeded());
813 // Confirm only one match.
814 EXPECT_FALSE(verify_stmt.Step());
815 }
816
TEST_F(SQLitePersistentCookieStoreTest,PersistIsPersistent)817 TEST_F(SQLitePersistentCookieStoreTest, PersistIsPersistent) {
818 InitializeStore(/*crypt=*/false, /*restore_old_session_cookies=*/true);
819 static const char kSessionName[] = "session";
820 static const char kPersistentName[] = "persistent";
821
822 // Add a session cookie.
823 store_->AddCookie(*CanonicalCookie::CreateUnsafeCookieForTesting(
824 kSessionName, "val", "sessioncookie.com", "/",
825 /*creation=*/base::Time::Now(),
826 /*expiration=*/base::Time(), /*last_access=*/base::Time(),
827 /*last_update=*/base::Time(), /*secure=*/false, /*httponly=*/false,
828 CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT));
829 // Add a persistent cookie.
830 store_->AddCookie(*CanonicalCookie::CreateUnsafeCookieForTesting(
831 kPersistentName, "val", "sessioncookie.com", "/",
832 /*creation=*/base::Time::Now() - base::Days(1),
833 /*expiration=*/base::Time::Now() + base::Days(1),
834 /*last_access=*/base::Time(), /*last_update=*/base::Time(),
835 /*secure=*/false, /*httponly=*/false, CookieSameSite::NO_RESTRICTION,
836 COOKIE_PRIORITY_DEFAULT));
837
838 // Force the store to write its data to the disk.
839 DestroyStore();
840
841 // Create a store that loads session cookie and test that the IsPersistent
842 // attribute is restored.
843 CanonicalCookieVector cookies = CreateAndLoad(
844 /*crypt_cookies=*/false, /*restore_old_session_cookies=*/true);
845 ASSERT_EQ(2U, cookies.size());
846
847 std::map<std::string, CanonicalCookie*> cookie_map;
848 for (const auto& cookie : cookies)
849 cookie_map[cookie->Name()] = cookie.get();
850
851 auto it = cookie_map.find(kSessionName);
852 ASSERT_TRUE(it != cookie_map.end());
853 EXPECT_FALSE(cookie_map[kSessionName]->IsPersistent());
854
855 it = cookie_map.find(kPersistentName);
856 ASSERT_TRUE(it != cookie_map.end());
857 EXPECT_TRUE(cookie_map[kPersistentName]->IsPersistent());
858 }
859
TEST_F(SQLitePersistentCookieStoreTest,PriorityIsPersistent)860 TEST_F(SQLitePersistentCookieStoreTest, PriorityIsPersistent) {
861 static const char kDomain[] = "sessioncookie.com";
862 static const char kLowName[] = "low";
863 static const char kMediumName[] = "medium";
864 static const char kHighName[] = "high";
865 static const char kCookieValue[] = "value";
866 static const char kCookiePath[] = "/";
867
868 InitializeStore(/*crypt=*/false, /*restore_old_session_cookies=*/true);
869
870 // Add a low-priority persistent cookie.
871 store_->AddCookie(*CanonicalCookie::CreateUnsafeCookieForTesting(
872 kLowName, kCookieValue, kDomain, kCookiePath,
873 /*creation=*/base::Time::Now() - base::Minutes(1),
874 /*expiration=*/base::Time::Now() + base::Days(1),
875 /*last_access=*/base::Time(), /*last_update=*/base::Time(),
876 /*secure=*/false, /*httponly=*/false, CookieSameSite::NO_RESTRICTION,
877 COOKIE_PRIORITY_LOW));
878
879 // Add a medium-priority persistent cookie.
880 store_->AddCookie(*CanonicalCookie::CreateUnsafeCookieForTesting(
881 kMediumName, kCookieValue, kDomain, kCookiePath,
882 /*creation=*/base::Time::Now() - base::Minutes(2),
883 /*expiration=*/base::Time::Now() + base::Days(1),
884 /*last_access=*/base::Time(), /*last_update=*/base::Time(),
885 /*secure=*/false, /*httponly=*/false, CookieSameSite::NO_RESTRICTION,
886 COOKIE_PRIORITY_MEDIUM));
887
888 // Add a high-priority persistent cookie.
889 store_->AddCookie(*CanonicalCookie::CreateUnsafeCookieForTesting(
890 kHighName, kCookieValue, kDomain, kCookiePath,
891 /*creation=*/base::Time::Now() - base::Minutes(3),
892 /*expiration=*/base::Time::Now() + base::Days(1),
893 /*last_access=*/base::Time(), /*last_update=*/base::Time(),
894 /*secure=*/false, /*httponly=*/false, CookieSameSite::NO_RESTRICTION,
895 COOKIE_PRIORITY_HIGH));
896
897 // Force the store to write its data to the disk.
898 DestroyStore();
899
900 // Create a store that loads session cookie and test that the priority
901 // attribute values are restored.
902 CanonicalCookieVector cookies = CreateAndLoad(
903 /*crypt_cookies=*/false, /*restore_old_session_cookies=*/true);
904 ASSERT_EQ(3U, cookies.size());
905
906 // Put the cookies into a map, by name, so we can easily find them.
907 std::map<std::string, CanonicalCookie*> cookie_map;
908 for (const auto& cookie : cookies)
909 cookie_map[cookie->Name()] = cookie.get();
910
911 // Validate that each cookie has the correct priority.
912 auto it = cookie_map.find(kLowName);
913 ASSERT_TRUE(it != cookie_map.end());
914 EXPECT_EQ(COOKIE_PRIORITY_LOW, cookie_map[kLowName]->Priority());
915
916 it = cookie_map.find(kMediumName);
917 ASSERT_TRUE(it != cookie_map.end());
918 EXPECT_EQ(COOKIE_PRIORITY_MEDIUM, cookie_map[kMediumName]->Priority());
919
920 it = cookie_map.find(kHighName);
921 ASSERT_TRUE(it != cookie_map.end());
922 EXPECT_EQ(COOKIE_PRIORITY_HIGH, cookie_map[kHighName]->Priority());
923 }
924
TEST_F(SQLitePersistentCookieStoreTest,SameSiteIsPersistent)925 TEST_F(SQLitePersistentCookieStoreTest, SameSiteIsPersistent) {
926 const char kDomain[] = "sessioncookie.com";
927 const char kNoneName[] = "none";
928 const char kLaxName[] = "lax";
929 const char kStrictName[] = "strict";
930 const char kCookieValue[] = "value";
931 const char kCookiePath[] = "/";
932
933 InitializeStore(/*crypt=*/false, /*restore_old_session_cookies=*/true);
934
935 // Add a non-samesite persistent cookie.
936 store_->AddCookie(*CanonicalCookie::CreateUnsafeCookieForTesting(
937 kNoneName, kCookieValue, kDomain, kCookiePath,
938 /*creation=*/base::Time::Now() - base::Minutes(1),
939 /*expiration=*/base::Time::Now() + base::Days(1),
940 /*last_access=*/base::Time(), /*last_update=*/base::Time(),
941 /*secure=*/false, /*httponly=*/false, CookieSameSite::NO_RESTRICTION,
942 COOKIE_PRIORITY_DEFAULT));
943
944 // Add a lax-samesite persistent cookie.
945 store_->AddCookie(*CanonicalCookie::CreateUnsafeCookieForTesting(
946 kLaxName, kCookieValue, kDomain, kCookiePath,
947 /*creation=*/base::Time::Now() - base::Minutes(2),
948 /*expiration=*/base::Time::Now() + base::Days(1),
949 /*last_access=*/base::Time(), /*last_update=*/base::Time(),
950 /*secure=*/false, /*httponly=*/false, CookieSameSite::LAX_MODE,
951 COOKIE_PRIORITY_DEFAULT));
952
953 // Add a strict-samesite persistent cookie.
954 store_->AddCookie(*CanonicalCookie::CreateUnsafeCookieForTesting(
955 kStrictName, kCookieValue, kDomain, kCookiePath,
956 /*creation=*/base::Time::Now() - base::Minutes(3),
957 /*expiration=*/base::Time::Now() + base::Days(1),
958 /*last_access=*/base::Time(), /*last_update=*/base::Time(),
959 /*secure=*/false, /*httponly=*/false, CookieSameSite::STRICT_MODE,
960 COOKIE_PRIORITY_DEFAULT));
961
962 // Force the store to write its data to the disk.
963 DestroyStore();
964
965 // Create a store that loads session cookie and test that the SameSite
966 // attribute values are restored.
967 CanonicalCookieVector cookies = CreateAndLoad(
968 /*crypt_cookies=*/false, /*restore_old_session_cookies=*/true);
969 ASSERT_EQ(3U, cookies.size());
970
971 // Put the cookies into a map, by name, for comparison below.
972 std::map<std::string, CanonicalCookie*> cookie_map;
973 for (const auto& cookie : cookies)
974 cookie_map[cookie->Name()] = cookie.get();
975
976 // Validate that each cookie has the correct SameSite.
977 ASSERT_EQ(1u, cookie_map.count(kNoneName));
978 EXPECT_EQ(CookieSameSite::NO_RESTRICTION, cookie_map[kNoneName]->SameSite());
979
980 ASSERT_EQ(1u, cookie_map.count(kLaxName));
981 EXPECT_EQ(CookieSameSite::LAX_MODE, cookie_map[kLaxName]->SameSite());
982
983 ASSERT_EQ(1u, cookie_map.count(kStrictName));
984 EXPECT_EQ(CookieSameSite::STRICT_MODE, cookie_map[kStrictName]->SameSite());
985 }
986
TEST_F(SQLitePersistentCookieStoreTest,SameSiteExtendedTreatedAsUnspecified)987 TEST_F(SQLitePersistentCookieStoreTest, SameSiteExtendedTreatedAsUnspecified) {
988 constexpr char kDomain[] = "sessioncookie.com";
989 constexpr char kExtendedName[] = "extended";
990 constexpr char kCookieValue[] = "value";
991 constexpr char kCookiePath[] = "/";
992
993 InitializeStore(/*crypt=*/false, /*restore_old_session_cookies=*/true);
994
995 // Add an extended-samesite persistent cookie by first adding a strict-same
996 // site cookie, then turning that into the legacy extended-samesite state with
997 // direct SQL DB access.
998 store_->AddCookie(*CanonicalCookie::CreateUnsafeCookieForTesting(
999 kExtendedName, kCookieValue, kDomain, kCookiePath,
1000 /*creation=*/base::Time::Now() - base::Minutes(1),
1001 /*expiration=*/base::Time::Now() + base::Days(1),
1002 /*last_access=*/base::Time(), /*last_update=*/base::Time(),
1003 /*secure=*/false, /*httponly=*/false, CookieSameSite::STRICT_MODE,
1004 COOKIE_PRIORITY_DEFAULT));
1005
1006 // Force the store to write its data to the disk.
1007 DestroyStore();
1008
1009 // Open db.
1010 sql::Database connection;
1011 ASSERT_TRUE(connection.Open(temp_dir_.GetPath().Append(kCookieFilename)));
1012 std::string update_stmt(
1013 "UPDATE cookies SET samesite=3" // 3 is Extended.
1014 " WHERE samesite=2" // 2 is Strict.
1015 );
1016 ASSERT_TRUE(connection.Execute(update_stmt.c_str()));
1017 connection.Close();
1018
1019 // Create a store that loads session cookie and test that the
1020 // SameSite=Extended attribute values is ignored.
1021 CanonicalCookieVector cookies = CreateAndLoad(
1022 /*crypt_cookies=*/false, /*restore_old_session_cookies=*/true);
1023 ASSERT_EQ(1U, cookies.size());
1024
1025 // Validate that the cookie has the correct SameSite.
1026 EXPECT_EQ(kExtendedName, cookies[0]->Name());
1027 EXPECT_EQ(CookieSameSite::UNSPECIFIED, cookies[0]->SameSite());
1028 }
1029
TEST_F(SQLitePersistentCookieStoreTest,SourcePortIsPersistent)1030 TEST_F(SQLitePersistentCookieStoreTest, SourcePortIsPersistent) {
1031 const char kDomain[] = "sessioncookie.com";
1032 const char kCookieValue[] = "value";
1033 const char kCookiePath[] = "/";
1034
1035 struct CookieTestValues {
1036 std::string name;
1037 int port;
1038 };
1039
1040 const std::vector<CookieTestValues> kTestCookies = {
1041 {"1", 80},
1042 {"2", 443},
1043 {"3", 1234},
1044 {"4", url::PORT_UNSPECIFIED},
1045 {"5", url::PORT_INVALID}};
1046
1047 InitializeStore(/*crypt=*/false, /*restore_old_session_cookies=*/true);
1048
1049 for (const auto& input : kTestCookies) {
1050 // Add some persistent cookies.
1051 store_->AddCookie(*CanonicalCookie::CreateUnsafeCookieForTesting(
1052 input.name, kCookieValue, kDomain, kCookiePath,
1053 /*creation=*/base::Time::Now() - base::Minutes(1),
1054 /*expiration=*/base::Time::Now() + base::Days(1),
1055 /*last_access=*/base::Time(), /*last_update=*/base::Time(),
1056 /*secure=*/true, /*httponly=*/false, CookieSameSite::LAX_MODE,
1057 COOKIE_PRIORITY_DEFAULT,
1058 /*partition_key=*/std::nullopt,
1059 CookieSourceScheme::kUnset /* Doesn't matter for this test. */,
1060 input.port));
1061 }
1062
1063 // Force the store to write its data to the disk.
1064 DestroyStore();
1065
1066 // Create a store that loads session cookie and test that the source_port
1067 // attribute values are restored.
1068 CanonicalCookieVector cookies = CreateAndLoad(
1069 /*crypt_cookies=*/false, /*restore_old_session_cookies=*/true);
1070 ASSERT_EQ(kTestCookies.size(), cookies.size());
1071
1072 // Put the cookies into a map, by name, for comparison below.
1073 std::map<std::string, CanonicalCookie*> cookie_map;
1074 for (const auto& cookie : cookies)
1075 cookie_map[cookie->Name()] = cookie.get();
1076
1077 for (const auto& expected : kTestCookies) {
1078 ASSERT_EQ(1u, cookie_map.count(expected.name));
1079 ASSERT_EQ(expected.port, cookie_map[expected.name]->SourcePort());
1080 }
1081 }
1082
TEST_F(SQLitePersistentCookieStoreTest,UpdateToEncryption)1083 TEST_F(SQLitePersistentCookieStoreTest, UpdateToEncryption) {
1084
1085 // Create unencrypted cookie store and write something to it.
1086 InitializeStore(/*crypt=*/false, /*restore_old_session_cookies=*/false);
1087 AddCookie("name", "value123XYZ", "foo.bar", "/", base::Time::Now());
1088 DestroyStore();
1089
1090 // Verify that "value" is visible in the file. This is necessary in order to
1091 // have confidence in a later test that "encrypted_value" is not visible.
1092 std::string contents = ReadRawDBContents();
1093 EXPECT_NE(0U, contents.length());
1094 EXPECT_NE(contents.find("value123XYZ"), std::string::npos);
1095
1096 // Create encrypted cookie store and ensure old cookie still reads.
1097 CanonicalCookieVector cookies = CreateAndLoad(
1098 /*crypt_cookies=*/true, /*restore_old_session_cookies=*/false);
1099 EXPECT_EQ(1U, cookies.size());
1100 EXPECT_EQ("name", cookies[0]->Name());
1101 EXPECT_EQ("value123XYZ", cookies[0]->Value());
1102
1103 // Make sure we can update existing cookie and add new cookie as encrypted.
1104 store_->DeleteCookie(*(cookies[0]));
1105 AddCookie("name", "encrypted_value123XYZ", "foo.bar", "/", base::Time::Now());
1106 AddCookie("other", "something456ABC", "foo.bar", "/",
1107 base::Time::Now() + base::Microseconds(10));
1108 DestroyStore();
1109 cookies = CreateAndLoad(/*crypt_cookies=*/true,
1110 /*restore_old_session_cookies=*/false);
1111 EXPECT_EQ(2U, cookies.size());
1112 CanonicalCookie* cookie_name = nullptr;
1113 CanonicalCookie* cookie_other = nullptr;
1114 if (cookies[0]->Name() == "name") {
1115 cookie_name = cookies[0].get();
1116 cookie_other = cookies[1].get();
1117 } else {
1118 cookie_name = cookies[1].get();
1119 cookie_other = cookies[0].get();
1120 }
1121 EXPECT_EQ("encrypted_value123XYZ", cookie_name->Value());
1122 EXPECT_EQ("something456ABC", cookie_other->Value());
1123 DestroyStore();
1124
1125 // Examine the real record to make sure plaintext version doesn't exist.
1126 sql::Database db;
1127 sql::Statement smt;
1128
1129 ASSERT_TRUE(db.Open(temp_dir_.GetPath().Append(kCookieFilename)));
1130 smt.Assign(db.GetCachedStatement(SQL_FROM_HERE,
1131 "SELECT * "
1132 "FROM cookies "
1133 "WHERE host_key = 'foo.bar'"));
1134 int resultcount = 0;
1135 for (; smt.Step(); ++resultcount) {
1136 for (int i = 0; i < smt.ColumnCount(); i++) {
1137 EXPECT_EQ(smt.ColumnString(i).find("value"), std::string::npos);
1138 EXPECT_EQ(smt.ColumnString(i).find("something"), std::string::npos);
1139 }
1140 }
1141 EXPECT_EQ(2, resultcount);
1142
1143 // Verify that "encrypted_value" is NOT visible in the file.
1144 contents = ReadRawDBContents();
1145 EXPECT_NE(0U, contents.length());
1146 EXPECT_EQ(contents.find("encrypted_value123XYZ"), std::string::npos);
1147 EXPECT_EQ(contents.find("something456ABC"), std::string::npos);
1148 }
1149
CompareCookies(const std::unique_ptr<CanonicalCookie> & a,const std::unique_ptr<CanonicalCookie> & b)1150 bool CompareCookies(const std::unique_ptr<CanonicalCookie>& a,
1151 const std::unique_ptr<CanonicalCookie>& b) {
1152 return a->PartialCompare(*b);
1153 }
1154
1155 // Confirm the store can handle having cookies with identical creation
1156 // times stored in it.
TEST_F(SQLitePersistentCookieStoreTest,IdenticalCreationTimes)1157 TEST_F(SQLitePersistentCookieStoreTest, IdenticalCreationTimes) {
1158 InitializeStore(/*crypt=*/false, /*restore_old_session_cookies=*/false);
1159 base::Time cookie_time(base::Time::Now());
1160 base::Time cookie_expiry(cookie_time + base::Days(1));
1161 AddCookieWithExpiration("A", "B", "example.com", "/", cookie_time,
1162 cookie_expiry);
1163 AddCookieWithExpiration("C", "B", "example.com", "/", cookie_time,
1164 cookie_expiry);
1165 AddCookieWithExpiration("A", "B", "example2.com", "/", cookie_time,
1166 cookie_expiry);
1167 AddCookieWithExpiration("C", "B", "example2.com", "/", cookie_time,
1168 cookie_expiry);
1169 AddCookieWithExpiration("A", "B", "example.com", "/path", cookie_time,
1170 cookie_expiry);
1171 AddCookieWithExpiration("C", "B", "example.com", "/path", cookie_time,
1172 cookie_expiry);
1173 Flush();
1174 DestroyStore();
1175
1176 CanonicalCookieVector read_in_cookies = CreateAndLoad(
1177 /*crypt_cookies=*/false, /*restore_old_session_cookies=*/false);
1178 ASSERT_EQ(6u, read_in_cookies.size());
1179
1180 std::sort(read_in_cookies.begin(), read_in_cookies.end(), &CompareCookies);
1181 int i = 0;
1182 EXPECT_EQ("A", read_in_cookies[i]->Name());
1183 EXPECT_EQ("example.com", read_in_cookies[i]->Domain());
1184 EXPECT_EQ("/", read_in_cookies[i]->Path());
1185
1186 i++;
1187 EXPECT_EQ("A", read_in_cookies[i]->Name());
1188 EXPECT_EQ("example.com", read_in_cookies[i]->Domain());
1189 EXPECT_EQ("/path", read_in_cookies[i]->Path());
1190
1191 i++;
1192 EXPECT_EQ("A", read_in_cookies[i]->Name());
1193 EXPECT_EQ("example2.com", read_in_cookies[i]->Domain());
1194 EXPECT_EQ("/", read_in_cookies[i]->Path());
1195
1196 i++;
1197 EXPECT_EQ("C", read_in_cookies[i]->Name());
1198 EXPECT_EQ("example.com", read_in_cookies[i]->Domain());
1199 EXPECT_EQ("/", read_in_cookies[i]->Path());
1200
1201 i++;
1202 EXPECT_EQ("C", read_in_cookies[i]->Name());
1203 EXPECT_EQ("example.com", read_in_cookies[i]->Domain());
1204 EXPECT_EQ("/path", read_in_cookies[i]->Path());
1205
1206 i++;
1207 EXPECT_EQ("C", read_in_cookies[i]->Name());
1208 EXPECT_EQ("example2.com", read_in_cookies[i]->Domain());
1209 EXPECT_EQ("/", read_in_cookies[i]->Path());
1210 }
1211
TEST_F(SQLitePersistentCookieStoreTest,KeyInconsistency)1212 TEST_F(SQLitePersistentCookieStoreTest, KeyInconsistency) {
1213 // Regression testcase for previous disagreement between CookieMonster
1214 // and SQLitePersistentCookieStoreTest as to what keys to LoadCookiesForKey
1215 // mean. The particular example doesn't, of course, represent an actual in-use
1216 // scenario, but while the inconstancy could happen with chrome-extension
1217 // URLs in real life, it was irrelevant for them in practice since their
1218 // rows would get key = "" which would get sorted before actual domains,
1219 // and therefore get loaded first by CookieMonster::FetchAllCookiesIfNecessary
1220 // with the task runners involved ensuring that would finish before the
1221 // incorrect LoadCookiesForKey got the chance to run.
1222 //
1223 // This test uses a URL that used to be treated differently by the two
1224 // layers that also sorts after other rows to avoid this scenario.
1225
1226 // SQLitePersistentCookieStore will run its callbacks on what's passed to it
1227 // as |client_task_runner|, and CookieMonster expects to get callbacks from
1228 // its PersistentCookieStore on the same thread as its methods are invoked on;
1229 // so to avoid needing to post every CookieMonster API call, this uses the
1230 // current thread for SQLitePersistentCookieStore's |client_task_runner|.
1231 // Note: Cookie encryption is explicitly enabled here to verify threading
1232 // model with async initialization functions correctly.
1233 Create(/*crypt_cookies=*/true, /*restore_old_session_cookies=*/false,
1234 /*use_current_thread=*/true, /*enable_exclusive_access=*/false);
1235
1236 // Create a cookie on a scheme that doesn't handle cookies by default,
1237 // and save it.
1238 std::unique_ptr<CookieMonster> cookie_monster =
1239 std::make_unique<CookieMonster>(store_.get(), /*net_log=*/nullptr);
1240 ResultSavingCookieCallback<bool> cookie_scheme_callback1;
1241 cookie_monster->SetCookieableSchemes({"ftp", "http"},
1242 cookie_scheme_callback1.MakeCallback());
1243 cookie_scheme_callback1.WaitUntilDone();
1244 EXPECT_TRUE(cookie_scheme_callback1.result());
1245 ResultSavingCookieCallback<CookieAccessResult> set_cookie_callback;
1246 GURL ftp_url("ftp://subdomain.ftperiffic.com/page/");
1247 auto cookie = CanonicalCookie::CreateForTesting(ftp_url, "A=B; max-age=3600",
1248 base::Time::Now());
1249 cookie_monster->SetCanonicalCookieAsync(std::move(cookie), ftp_url,
1250 CookieOptions::MakeAllInclusive(),
1251 set_cookie_callback.MakeCallback());
1252 set_cookie_callback.WaitUntilDone();
1253 EXPECT_TRUE(set_cookie_callback.result().status.IsInclude());
1254
1255 // Also insert a whole bunch of cookies to slow down the background loading of
1256 // all the cookies.
1257 for (int i = 0; i < 50; ++i) {
1258 ResultSavingCookieCallback<CookieAccessResult> set_cookie_callback2;
1259 GURL url(base::StringPrintf("http://example%d.com/", i));
1260 auto canonical_cookie = CanonicalCookie::CreateForTesting(
1261 url, "A=B; max-age=3600", base::Time::Now());
1262 cookie_monster->SetCanonicalCookieAsync(
1263 std::move(canonical_cookie), url, CookieOptions::MakeAllInclusive(),
1264 set_cookie_callback2.MakeCallback());
1265 set_cookie_callback2.WaitUntilDone();
1266 EXPECT_TRUE(set_cookie_callback2.result().status.IsInclude());
1267 }
1268
1269 net::TestClosure flush_closure;
1270 cookie_monster->FlushStore(flush_closure.closure());
1271 flush_closure.WaitForResult();
1272 cookie_monster = nullptr;
1273
1274 // Re-create the PersistentCookieStore & CookieMonster. Note that the
1275 // destroyed store's ops will happen on same runners as the previous
1276 // instances, so they should complete before the new PersistentCookieStore
1277 // starts looking at the state on disk.
1278 Create(/*crypt_cookies=*/true, /*restore_old_session_cookies=*/false,
1279 /*use_current_thread=*/true, /*enable_exclusive_access=*/false);
1280 cookie_monster =
1281 std::make_unique<CookieMonster>(store_.get(), /*net_log=*/nullptr);
1282 ResultSavingCookieCallback<bool> cookie_scheme_callback2;
1283 cookie_monster->SetCookieableSchemes({"ftp", "http"},
1284 cookie_scheme_callback2.MakeCallback());
1285 cookie_scheme_callback2.WaitUntilDone();
1286 EXPECT_TRUE(cookie_scheme_callback2.result());
1287
1288 // Now try to get the cookie back.
1289 GetCookieListCallback get_callback;
1290 cookie_monster->GetCookieListWithOptionsAsync(
1291 GURL("ftp://subdomain.ftperiffic.com/page"),
1292 CookieOptions::MakeAllInclusive(), CookiePartitionKeyCollection(),
1293 base::BindOnce(&GetCookieListCallback::Run,
1294 base::Unretained(&get_callback)));
1295 get_callback.WaitUntilDone();
1296 ASSERT_EQ(1u, get_callback.cookies().size());
1297 EXPECT_EQ("A", get_callback.cookies()[0].Name());
1298 EXPECT_EQ("B", get_callback.cookies()[0].Value());
1299 EXPECT_EQ("subdomain.ftperiffic.com", get_callback.cookies()[0].Domain());
1300 }
1301
TEST_F(SQLitePersistentCookieStoreTest,OpsIfInitFailed)1302 TEST_F(SQLitePersistentCookieStoreTest, OpsIfInitFailed) {
1303 // Test to make sure we don't leak pending operations when initialization
1304 // fails really hard. To inject the failure, we put a directory where the
1305 // database file ought to be. This test relies on an external leak checker
1306 // (e.g. lsan) to actual catch thing.
1307 ASSERT_TRUE(
1308 base::CreateDirectory(temp_dir_.GetPath().Append(kCookieFilename)));
1309 Create(/*crypt_cookies=*/false, /*restore_old_session_cookies=*/false,
1310 /*use_current_thread=*/true,
1311 /*enable_exclusive_access=*/false);
1312 std::unique_ptr<CookieMonster> cookie_monster =
1313 std::make_unique<CookieMonster>(store_.get(), /*net_log=*/nullptr);
1314
1315 ResultSavingCookieCallback<CookieAccessResult> set_cookie_callback;
1316 GURL url("http://www.example.com/");
1317 auto cookie = CanonicalCookie::CreateForTesting(url, "A=B; max-age=3600",
1318 base::Time::Now());
1319 cookie_monster->SetCanonicalCookieAsync(std::move(cookie), url,
1320 CookieOptions::MakeAllInclusive(),
1321 set_cookie_callback.MakeCallback());
1322 set_cookie_callback.WaitUntilDone();
1323 EXPECT_TRUE(set_cookie_callback.result().status.IsInclude());
1324
1325 // Things should commit once going out of scope.
1326 expect_init_errors_ = true;
1327 }
1328
TEST_F(SQLitePersistentCookieStoreTest,Coalescing)1329 TEST_F(SQLitePersistentCookieStoreTest, Coalescing) {
1330 enum class Op { kAdd, kDelete, kUpdate };
1331
1332 struct TestCase {
1333 std::vector<Op> operations;
1334 size_t expected_queue_length;
1335 };
1336
1337 std::vector<TestCase> testcases = {
1338 {{Op::kAdd, Op::kDelete}, 1u},
1339 {{Op::kUpdate, Op::kDelete}, 1u},
1340 {{Op::kAdd, Op::kUpdate, Op::kDelete}, 1u},
1341 {{Op::kUpdate, Op::kUpdate}, 1u},
1342 {{Op::kAdd, Op::kUpdate, Op::kUpdate}, 2u},
1343 {{Op::kDelete, Op::kAdd}, 2u},
1344 {{Op::kDelete, Op::kAdd, Op::kUpdate}, 3u},
1345 {{Op::kDelete, Op::kAdd, Op::kUpdate, Op::kUpdate}, 3u},
1346 {{Op::kDelete, Op::kDelete}, 1u},
1347 {{Op::kDelete, Op::kAdd, Op::kDelete}, 1u},
1348 {{Op::kDelete, Op::kAdd, Op::kUpdate, Op::kDelete}, 1u}};
1349
1350 std::unique_ptr<CanonicalCookie> cookie = CanonicalCookie::CreateForTesting(
1351 GURL("http://www.example.com/path"), "Tasty=Yes", base::Time::Now());
1352
1353 for (const TestCase& testcase : testcases) {
1354 Create(/*crypt_cookies=*/false, /*restore_old_session_cookies=*/false,
1355 /*use_current_thread=*/true,
1356 /*enable_exclusive_access=*/false);
1357
1358 base::RunLoop run_loop;
1359 store_->Load(base::BindLambdaForTesting(
1360 [&](CanonicalCookieVector cookies) { run_loop.Quit(); }),
1361 NetLogWithSource());
1362 run_loop.Run();
1363
1364 // Wedge the background thread to make sure that it doesn't start consuming
1365 // the queue.
1366 background_task_runner_->PostTask(
1367 FROM_HERE,
1368 base::BindOnce(&SQLitePersistentCookieStoreTest::WaitOnDBEvent,
1369 base::Unretained(this)));
1370
1371 // Now run the ops, and check how much gets queued.
1372 for (const Op op : testcase.operations) {
1373 switch (op) {
1374 case Op::kAdd:
1375 store_->AddCookie(*cookie);
1376 break;
1377
1378 case Op::kDelete:
1379 store_->DeleteCookie(*cookie);
1380 break;
1381
1382 case Op::kUpdate:
1383 store_->UpdateCookieAccessTime(*cookie);
1384 break;
1385 }
1386 }
1387
1388 EXPECT_EQ(testcase.expected_queue_length,
1389 store_->GetQueueLengthForTesting());
1390
1391 db_thread_event_.Signal();
1392 DestroyStore();
1393 }
1394 }
1395
TEST_F(SQLitePersistentCookieStoreTest,NoCoalesceUnrelated)1396 TEST_F(SQLitePersistentCookieStoreTest, NoCoalesceUnrelated) {
1397 Create(/*crypt_cookies=*/false, /*restore_old_session_cookies=*/false,
1398 /*use_current_thread=*/true,
1399 /*enable_exclusive_access=*/false);
1400
1401 base::RunLoop run_loop;
1402 store_->Load(base::BindLambdaForTesting(
1403 [&](CanonicalCookieVector cookies) { run_loop.Quit(); }),
1404 NetLogWithSource());
1405 run_loop.Run();
1406
1407 std::unique_ptr<CanonicalCookie> cookie1 = CanonicalCookie::CreateForTesting(
1408 GURL("http://www.example.com/path"), "Tasty=Yes", base::Time::Now());
1409
1410 std::unique_ptr<CanonicalCookie> cookie2 = CanonicalCookie::CreateForTesting(
1411 GURL("http://not.example.com/path"), "Tasty=No", base::Time::Now());
1412
1413 // Wedge the background thread to make sure that it doesn't start consuming
1414 // the queue.
1415 background_task_runner_->PostTask(
1416 FROM_HERE, base::BindOnce(&SQLitePersistentCookieStoreTest::WaitOnDBEvent,
1417 base::Unretained(this)));
1418
1419 store_->AddCookie(*cookie1);
1420 store_->DeleteCookie(*cookie2);
1421 // delete on cookie2 shouldn't cancel op on unrelated cookie1.
1422 EXPECT_EQ(2u, store_->GetQueueLengthForTesting());
1423
1424 db_thread_event_.Signal();
1425 }
1426
1427 // Locking is only supported on Windows.
1428 #if BUILDFLAG(IS_WIN)
1429
1430 class SQLitePersistentCookieStoreExclusiveAccessTest
1431 : public SQLitePersistentCookieStoreTest,
1432 public ::testing::WithParamInterface<bool> {
1433 protected:
ShouldBeExclusive()1434 const bool& ShouldBeExclusive() { return GetParam(); }
1435 };
1436
TEST_P(SQLitePersistentCookieStoreExclusiveAccessTest,LockedStore)1437 TEST_P(SQLitePersistentCookieStoreExclusiveAccessTest, LockedStore) {
1438 Create(/*crypt_cookies=*/false, /*restore_old_session_cookies=*/false,
1439 /*use_current_thread=*/true,
1440 /*enable_exclusive_access=*/ShouldBeExclusive());
1441
1442 base::RunLoop run_loop;
1443 store_->Load(base::BindLambdaForTesting(
1444 [&](CanonicalCookieVector cookies) { run_loop.Quit(); }),
1445 NetLogWithSource());
1446 run_loop.Run();
1447
1448 std::unique_ptr<CanonicalCookie> cookie = CanonicalCookie::CreateForTesting(
1449 GURL("http://www.example.com/path"), "Tasty=Yes", base::Time::Now());
1450
1451 // Wedge the background thread to make sure that it doesn't start consuming
1452 // the queue.
1453 background_task_runner_->PostTask(
1454 FROM_HERE, base::BindOnce(&SQLitePersistentCookieStoreTest::WaitOnDBEvent,
1455 base::Unretained(this)));
1456
1457 store_->AddCookie(*cookie);
1458
1459 {
1460 base::File file(
1461 temp_dir_.GetPath().Append(kCookieFilename),
1462 base::File::Flags::FLAG_OPEN_ALWAYS | base::File::Flags::FLAG_READ);
1463 // If locked, should not be able to open file even for read.
1464 EXPECT_EQ(ShouldBeExclusive(), !file.IsValid());
1465 }
1466
1467 db_thread_event_.Signal();
1468 }
1469
TEST_P(SQLitePersistentCookieStoreExclusiveAccessTest,LockedStoreAlreadyOpen)1470 TEST_P(SQLitePersistentCookieStoreExclusiveAccessTest, LockedStoreAlreadyOpen) {
1471 base::HistogramTester histograms;
1472 base::File file(
1473 temp_dir_.GetPath().Append(kCookieFilename),
1474 base::File::Flags::FLAG_CREATE | base::File::Flags::FLAG_READ);
1475 ASSERT_TRUE(file.IsValid());
1476
1477 Create(/*crypt_cookies=*/false, /*restore_old_session_cookies=*/false,
1478 /*use_current_thread=*/true,
1479 /*enable_exclusive_access=*/ShouldBeExclusive());
1480
1481 base::RunLoop run_loop;
1482 store_->Load(base::BindLambdaForTesting(
1483 [&](CanonicalCookieVector cookies) { run_loop.Quit(); }),
1484 NetLogWithSource());
1485 run_loop.Run();
1486
1487 // Note: The non-exclusive path is verified in the TearDown for the fixture.
1488 if (ShouldBeExclusive()) {
1489 expect_init_errors_ = true;
1490 histograms.ExpectUniqueSample("Cookie.ErrorInitializeDB",
1491 sql::SqliteLoggedResultCode::kCantOpen, 1);
1492 histograms.ExpectUniqueSample("Cookie.WinGetLastErrorInitializeDB",
1493 ERROR_SHARING_VIOLATION, 1);
1494 }
1495 }
1496
1497 INSTANTIATE_TEST_SUITE_P(All,
1498 SQLitePersistentCookieStoreExclusiveAccessTest,
1499 ::testing::Bool(),
__anon856c6d780702(const auto& info) 1500 [](const auto& info) {
1501 return info.param ? "Exclusive" : "NotExclusive";
1502 });
1503
1504 #endif // BUILDFLAG(IS_WIN)
1505
TEST_F(SQLitePersistentCookieStoreTest,CorruptStore)1506 TEST_F(SQLitePersistentCookieStoreTest, CorruptStore) {
1507 base::HistogramTester histograms;
1508 base::WriteFile(temp_dir_.GetPath().Append(kCookieFilename),
1509 "SQLite format 3 foobarfoobarfoobar");
1510
1511 Create(/*crypt_cookies=*/false, /*restore_old_session_cookies=*/false,
1512 /*use_current_thread=*/true,
1513 /*enable_exclusive_access=*/false);
1514
1515 base::RunLoop run_loop;
1516 store_->Load(base::BindLambdaForTesting(
1517 [&](CanonicalCookieVector cookies) { run_loop.Quit(); }),
1518 NetLogWithSource());
1519 run_loop.Run();
1520
1521 expect_init_errors_ = true;
1522 histograms.ExpectUniqueSample("Cookie.ErrorInitializeDB",
1523 sql::SqliteLoggedResultCode::kNotADatabase, 1);
1524 }
1525
CreateV18Schema(sql::Database * db)1526 bool CreateV18Schema(sql::Database* db) {
1527 sql::MetaTable meta_table;
1528 if (!meta_table.Init(db, 18, 18)) {
1529 return false;
1530 }
1531
1532 // Version 18 schema
1533 static constexpr char kCreateSql[] =
1534 "CREATE TABLE cookies("
1535 "creation_utc INTEGER NOT NULL,"
1536 "host_key TEXT NOT NULL,"
1537 "top_frame_site_key TEXT NOT NULL,"
1538 "name TEXT NOT NULL,"
1539 "value TEXT NOT NULL,"
1540 "encrypted_value BLOB NOT NULL,"
1541 "path TEXT NOT NULL,"
1542 "expires_utc INTEGER NOT NULL,"
1543 "is_secure INTEGER NOT NULL,"
1544 "is_httponly INTEGER NOT NULL,"
1545 "last_access_utc INTEGER NOT NULL,"
1546 "has_expires INTEGER NOT NULL,"
1547 "is_persistent INTEGER NOT NULL,"
1548 "priority INTEGER NOT NULL,"
1549 "samesite INTEGER NOT NULL,"
1550 "source_scheme INTEGER NOT NULL,"
1551 "source_port INTEGER NOT NULL,"
1552 "is_same_party INTEGER NOT NULL,"
1553 "last_update_utc INTEGER NOT NULL,"
1554 "UNIQUE (host_key, top_frame_site_key, name, path))";
1555
1556 static constexpr char kCreateIndexSql[] =
1557 "CREATE UNIQUE INDEX cookies_unique_index "
1558 "ON cookies(host_key, top_frame_site_key, name, path)";
1559
1560 return db->Execute(kCreateSql) && db->Execute(kCreateIndexSql);
1561 }
1562
CreateV20Schema(sql::Database * db)1563 bool CreateV20Schema(sql::Database* db) {
1564 sql::MetaTable meta_table;
1565 if (!meta_table.Init(db, 20, 20)) {
1566 return false;
1567 }
1568
1569 // Version 20 schema
1570 static constexpr char kCreateSql[] =
1571 "CREATE TABLE cookies("
1572 "creation_utc INTEGER NOT NULL,"
1573 "host_key TEXT NOT NULL,"
1574 "top_frame_site_key TEXT NOT NULL,"
1575 "name TEXT NOT NULL,"
1576 "value TEXT NOT NULL,"
1577 "encrypted_value BLOB NOT NULL,"
1578 "path TEXT NOT NULL,"
1579 "expires_utc INTEGER NOT NULL,"
1580 "is_secure INTEGER NOT NULL,"
1581 "is_httponly INTEGER NOT NULL,"
1582 "last_access_utc INTEGER NOT NULL,"
1583 "has_expires INTEGER NOT NULL,"
1584 "is_persistent INTEGER NOT NULL,"
1585 "priority INTEGER NOT NULL,"
1586 "samesite INTEGER NOT NULL,"
1587 "source_scheme INTEGER NOT NULL,"
1588 "source_port INTEGER NOT NULL,"
1589 "is_same_party INTEGER NOT NULL,"
1590 "last_update_utc INTEGER NOT NULL,"
1591 "UNIQUE (host_key, top_frame_site_key, name, path, source_scheme, "
1592 "source_port))";
1593
1594 static constexpr char kCreateIndexSql[] =
1595 "CREATE UNIQUE INDEX cookies_unique_index "
1596 "ON cookies(host_key, top_frame_site_key, name, path, source_scheme, "
1597 "source_port)";
1598
1599 return db->Execute(kCreateSql) && db->Execute(kCreateIndexSql);
1600 }
1601
CreateV21Schema(sql::Database * db)1602 bool CreateV21Schema(sql::Database* db) {
1603 sql::MetaTable meta_table;
1604 if (!meta_table.Init(db, 21, 21)) {
1605 return false;
1606 }
1607
1608 // Version 21 schema
1609 static constexpr char kCreateSql[] =
1610 "CREATE TABLE cookies("
1611 "creation_utc INTEGER NOT NULL,"
1612 "host_key TEXT NOT NULL,"
1613 "top_frame_site_key TEXT NOT NULL,"
1614 "name TEXT NOT NULL,"
1615 "value TEXT NOT NULL,"
1616 "encrypted_value BLOB NOT NULL,"
1617 "path TEXT NOT NULL,"
1618 "expires_utc INTEGER NOT NULL,"
1619 "is_secure INTEGER NOT NULL,"
1620 "is_httponly INTEGER NOT NULL,"
1621 "last_access_utc INTEGER NOT NULL,"
1622 "has_expires INTEGER NOT NULL,"
1623 "is_persistent INTEGER NOT NULL,"
1624 "priority INTEGER NOT NULL,"
1625 "samesite INTEGER NOT NULL,"
1626 "source_scheme INTEGER NOT NULL,"
1627 "source_port INTEGER NOT NULL,"
1628 "last_update_utc INTEGER NOT NULL,"
1629 "UNIQUE (host_key, top_frame_site_key, name, path, source_scheme, "
1630 "source_port))";
1631
1632 static constexpr char kCreateIndexSql[] =
1633 "CREATE UNIQUE INDEX cookies_unique_index "
1634 "ON cookies(host_key, top_frame_site_key, name, path, source_scheme, "
1635 "source_port)";
1636
1637 return db->Execute(kCreateSql) && db->Execute(kCreateIndexSql);
1638 }
1639
CreateV22Schema(sql::Database * db)1640 bool CreateV22Schema(sql::Database* db) {
1641 sql::MetaTable meta_table;
1642 if (!meta_table.Init(db, 22, 22)) {
1643 return false;
1644 }
1645
1646 // Version 22 schema
1647 static constexpr char kCreateSql[] =
1648 "CREATE TABLE cookies("
1649 "creation_utc INTEGER NOT NULL,"
1650 "host_key TEXT NOT NULL,"
1651 "top_frame_site_key TEXT NOT NULL,"
1652 "name TEXT NOT NULL,"
1653 "value TEXT NOT NULL,"
1654 "encrypted_value BLOB NOT NULL,"
1655 "path TEXT NOT NULL,"
1656 "expires_utc INTEGER NOT NULL,"
1657 "is_secure INTEGER NOT NULL,"
1658 "is_httponly INTEGER NOT NULL,"
1659 "last_access_utc INTEGER NOT NULL,"
1660 "has_expires INTEGER NOT NULL,"
1661 "is_persistent INTEGER NOT NULL,"
1662 "priority INTEGER NOT NULL,"
1663 "samesite INTEGER NOT NULL,"
1664 "source_scheme INTEGER NOT NULL,"
1665 "source_port INTEGER NOT NULL,"
1666 "last_update_utc INTEGER NOT NULL,"
1667 "source_type INTEGER NOT NULL,"
1668 "UNIQUE (host_key, top_frame_site_key, name, path, source_scheme, "
1669 "source_port))";
1670
1671 static constexpr char kCreateIndexSql[] =
1672 "CREATE UNIQUE INDEX cookies_unique_index "
1673 "ON cookies(host_key, top_frame_site_key, name, path, source_scheme, "
1674 "source_port)";
1675
1676 return db->Execute(kCreateSql) && db->Execute(kCreateIndexSql);
1677 }
1678
GetDBCurrentVersionNumber(sql::Database * db)1679 int GetDBCurrentVersionNumber(sql::Database* db) {
1680 static constexpr char kGetDBCurrentVersionQuery[] =
1681 "SELECT value FROM meta WHERE key='version'";
1682 sql::Statement statement(db->GetUniqueStatement(kGetDBCurrentVersionQuery));
1683 statement.Step();
1684 return statement.ColumnInt(0);
1685 }
1686
CookiesForMigrationTest()1687 std::vector<CanonicalCookie> CookiesForMigrationTest() {
1688 const base::Time now = base::Time::Now();
1689
1690 std::vector<CanonicalCookie> cookies;
1691 cookies.push_back(*CanonicalCookie::CreateUnsafeCookieForTesting(
1692 "A", "B", "example.com", "/", /*creation=*/now, /*expiration=*/now,
1693 /*last_access=*/now, /*last_update=*/now, /*secure=*/true,
1694 /*httponly=*/false, CookieSameSite::UNSPECIFIED,
1695 COOKIE_PRIORITY_DEFAULT));
1696 cookies.push_back(*CanonicalCookie::CreateUnsafeCookieForTesting(
1697 "C", "B", "example.com", "/", /*creation=*/now, /*expiration=*/now,
1698 /*last_access=*/now, /*last_update=*/now, /*secure=*/true,
1699 /*httponly=*/false, CookieSameSite::UNSPECIFIED,
1700 COOKIE_PRIORITY_DEFAULT));
1701 cookies.push_back(*CanonicalCookie::CreateUnsafeCookieForTesting(
1702 "A", "B", "example2.com", "/", /*creation=*/now, /*expiration=*/now,
1703 /*last_access=*/now, /*last_update=*/now, /*secure=*/true,
1704 /*httponly=*/false, CookieSameSite::UNSPECIFIED,
1705 COOKIE_PRIORITY_DEFAULT));
1706 cookies.push_back(*CanonicalCookie::CreateUnsafeCookieForTesting(
1707 "C", "B", "example2.com", "/", /*creation=*/now,
1708 /*expiration=*/now + base::Days(399), /*last_access=*/now,
1709 /*last_update=*/now,
1710 /*secure=*/false, /*httponly=*/false, CookieSameSite::UNSPECIFIED,
1711 COOKIE_PRIORITY_DEFAULT));
1712 cookies.push_back(*CanonicalCookie::CreateUnsafeCookieForTesting(
1713 "A", "B", "example.com", "/path", /*creation=*/now,
1714 /*expiration=*/now + base::Days(400), /*last_access=*/now,
1715 /*last_update=*/now,
1716 /*secure=*/false, /*httponly=*/false, CookieSameSite::UNSPECIFIED,
1717 COOKIE_PRIORITY_DEFAULT));
1718 cookies.push_back(*CanonicalCookie::CreateUnsafeCookieForTesting(
1719 "C", "B", "example.com", "/path", /*creation=*/now,
1720 /*expiration=*/now + base::Days(401), /*last_access=*/now,
1721 /*last_update=*/now,
1722 /*secure=*/false, /*httponly=*/false, CookieSameSite::UNSPECIFIED,
1723 COOKIE_PRIORITY_DEFAULT));
1724 return cookies;
1725 }
1726
1727 // Versions 18, 19, and 20 use the same schema so they can reuse this function.
1728 // AddV20CookiesToDB (and future versions) need to set max_expiration_delta to
1729 // base::Days(400) to simulate expiration limits introduced in version 19.
AddV18CookiesToDB(sql::Database * db,base::TimeDelta max_expiration_delta)1730 bool AddV18CookiesToDB(sql::Database* db,
1731 base::TimeDelta max_expiration_delta) {
1732 std::vector<CanonicalCookie> cookies = CookiesForMigrationTest();
1733 sql::Statement statement(db->GetCachedStatement(
1734 SQL_FROM_HERE,
1735 "INSERT INTO cookies (creation_utc, top_frame_site_key, host_key, name, "
1736 "value, encrypted_value, path, expires_utc, is_secure, is_httponly, "
1737 "samesite, last_access_utc, has_expires, is_persistent, priority, "
1738 "source_scheme, source_port, is_same_party, last_update_utc) "
1739 "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
1740 if (!statement.is_valid()) {
1741 return false;
1742 }
1743 sql::Transaction transaction(db);
1744 if (!transaction.Begin()) {
1745 return false;
1746 }
1747 for (const CanonicalCookie& cookie : cookies) {
1748 base::Time max_expiration(cookie.CreationDate() + max_expiration_delta);
1749
1750 statement.Reset(true);
1751 statement.BindTime(0, cookie.CreationDate());
1752 // TODO (crbug.com/326605834) Once ancestor chain bit changes are
1753 // implemented update this method utilize the ancestor bit.
1754 base::expected<CookiePartitionKey::SerializedCookiePartitionKey,
1755 std::string>
1756 serialized_partition_key =
1757 CookiePartitionKey::Serialize(cookie.PartitionKey());
1758 EXPECT_TRUE(serialized_partition_key.has_value());
1759
1760 statement.BindString(1, serialized_partition_key->TopLevelSite());
1761 statement.BindString(2, cookie.Domain());
1762 statement.BindString(3, cookie.Name());
1763 statement.BindString(4, cookie.Value());
1764 statement.BindBlob(5, base::span<uint8_t>()); // encrypted_value
1765 statement.BindString(6, cookie.Path());
1766 statement.BindTime(7, std::min(cookie.ExpiryDate(), max_expiration));
1767 statement.BindInt(8, cookie.SecureAttribute());
1768 statement.BindInt(9, cookie.IsHttpOnly());
1769 // Note that this, Priority(), and SourceScheme() below nominally rely on
1770 // the enums in sqlite_persistent_cookie_store.cc having the same values as
1771 // the ones in ../../cookies/cookie_constants.h. But nothing in this test
1772 // relies on that equivalence, so it's not worth the hassle to guarantee
1773 // that.
1774 statement.BindInt(10, static_cast<int>(cookie.SameSite()));
1775 statement.BindTime(11, cookie.LastAccessDate());
1776 statement.BindInt(12, cookie.IsPersistent());
1777 statement.BindInt(13, cookie.IsPersistent());
1778 statement.BindInt(14, static_cast<int>(cookie.Priority()));
1779 statement.BindInt(15, static_cast<int>(cookie.SourceScheme()));
1780 statement.BindInt(16, cookie.SourcePort());
1781 statement.BindInt(17, /*is_same_party=*/false);
1782 statement.BindTime(18, cookie.LastUpdateDate());
1783 if (!statement.Run()) {
1784 return false;
1785 }
1786 }
1787 return transaction.Commit();
1788 }
1789
AddV20CookiesToDB(sql::Database * db)1790 bool AddV20CookiesToDB(sql::Database* db) {
1791 return AddV18CookiesToDB(db, base::Days(400));
1792 }
1793
AddV21CookiesToDB(sql::Database * db)1794 bool AddV21CookiesToDB(sql::Database* db) {
1795 std::vector<CanonicalCookie> cookies = CookiesForMigrationTest();
1796 sql::Statement statement(db->GetCachedStatement(
1797 SQL_FROM_HERE,
1798 "INSERT INTO cookies (creation_utc, top_frame_site_key, host_key, name, "
1799 "value, encrypted_value, path, expires_utc, is_secure, is_httponly, "
1800 "samesite, last_access_utc, has_expires, is_persistent, priority, "
1801 "source_scheme, source_port, last_update_utc) "
1802 "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
1803 if (!statement.is_valid()) {
1804 return false;
1805 }
1806 sql::Transaction transaction(db);
1807 if (!transaction.Begin()) {
1808 return false;
1809 }
1810 for (const CanonicalCookie& cookie : cookies) {
1811 base::Time max_expiration(cookie.CreationDate() + base::Days(400));
1812
1813 statement.Reset(true);
1814 statement.BindTime(0, cookie.CreationDate());
1815 // TODO (crbug.com/326605834) Once ancestor chain bit changes are
1816 // implemented update this method utilize the ancestor bit.
1817 base::expected<CookiePartitionKey::SerializedCookiePartitionKey,
1818 std::string>
1819 serialized_partition_key =
1820 CookiePartitionKey::Serialize(cookie.PartitionKey());
1821 EXPECT_TRUE(serialized_partition_key.has_value());
1822
1823 statement.BindString(1, serialized_partition_key->TopLevelSite());
1824 statement.BindString(2, cookie.Domain());
1825 statement.BindString(3, cookie.Name());
1826 statement.BindString(4, cookie.Value());
1827 statement.BindBlob(5, base::span<uint8_t>()); // encrypted_value
1828 statement.BindString(6, cookie.Path());
1829 statement.BindTime(7, std::min(cookie.ExpiryDate(), max_expiration));
1830 statement.BindInt(8, cookie.SecureAttribute());
1831 statement.BindInt(9, cookie.IsHttpOnly());
1832 // Note that this, Priority(), and SourceScheme() below nominally rely on
1833 // the enums in sqlite_persistent_cookie_store.cc having the same values as
1834 // the ones in ../../cookies/cookie_constants.h. But nothing in this test
1835 // relies on that equivalence, so it's not worth the hassle to guarantee
1836 // that.
1837 statement.BindInt(10, static_cast<int>(cookie.SameSite()));
1838 statement.BindTime(11, cookie.LastAccessDate());
1839 statement.BindInt(12, cookie.IsPersistent());
1840 statement.BindInt(13, cookie.IsPersistent());
1841 statement.BindInt(14, static_cast<int>(cookie.Priority()));
1842 statement.BindInt(15, static_cast<int>(cookie.SourceScheme()));
1843 statement.BindInt(16, cookie.SourcePort());
1844 statement.BindTime(17, cookie.LastUpdateDate());
1845 if (!statement.Run()) {
1846 return false;
1847 }
1848 }
1849 return transaction.Commit();
1850 }
1851
AddV22CookiesToDB(sql::Database * db,const std::vector<CanonicalCookie> & cookies)1852 bool AddV22CookiesToDB(sql::Database* db,
1853 const std::vector<CanonicalCookie>& cookies) {
1854 sql::Statement statement(db->GetCachedStatement(
1855 SQL_FROM_HERE,
1856 "INSERT INTO cookies (creation_utc, top_frame_site_key, host_key, name, "
1857 "value, encrypted_value, path, expires_utc, is_secure, is_httponly, "
1858 "samesite, last_access_utc, has_expires, is_persistent, priority, "
1859 "source_scheme, source_port, last_update_utc, source_type) "
1860 "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
1861 if (!statement.is_valid()) {
1862 return false;
1863 }
1864 sql::Transaction transaction(db);
1865 if (!transaction.Begin()) {
1866 return false;
1867 }
1868 for (const CanonicalCookie& cookie : cookies) {
1869 base::Time max_expiration(cookie.CreationDate() + base::Days(400));
1870
1871 statement.Reset(true);
1872 statement.BindTime(0, cookie.CreationDate());
1873 // TODO (crbug.com/326605834) Once ancestor chain bit changes are
1874 // implemented update this method utilize the ancestor bit.
1875 base::expected<CookiePartitionKey::SerializedCookiePartitionKey,
1876 std::string>
1877 serialized_partition_key =
1878 CookiePartitionKey::Serialize(cookie.PartitionKey());
1879 EXPECT_TRUE(serialized_partition_key.has_value());
1880
1881 statement.BindString(1, serialized_partition_key->TopLevelSite());
1882 statement.BindString(2, cookie.Domain());
1883 statement.BindString(3, cookie.Name());
1884 statement.BindString(4, cookie.Value());
1885 statement.BindBlob(5, base::span<uint8_t>()); // encrypted_value
1886 statement.BindString(6, cookie.Path());
1887 statement.BindTime(7, std::min(cookie.ExpiryDate(), max_expiration));
1888 statement.BindInt(8, cookie.SecureAttribute());
1889 statement.BindInt(9, cookie.IsHttpOnly());
1890 // Note that this, Priority(), and SourceScheme() below nominally rely on
1891 // the enums in sqlite_persistent_cookie_store.cc having the same values as
1892 // the ones in ../../cookies/cookie_constants.h. But nothing in this test
1893 // relies on that equivalence, so it's not worth the hassle to guarantee
1894 // that.
1895 statement.BindInt(10, static_cast<int>(cookie.SameSite()));
1896 statement.BindTime(11, cookie.LastAccessDate());
1897 statement.BindInt(12, cookie.IsPersistent());
1898 statement.BindInt(13, cookie.IsPersistent());
1899 statement.BindInt(14, static_cast<int>(cookie.Priority()));
1900 statement.BindInt(15, static_cast<int>(cookie.SourceScheme()));
1901 statement.BindInt(16, cookie.SourcePort());
1902 statement.BindTime(17, cookie.LastUpdateDate());
1903 statement.BindInt(18, static_cast<int>(cookie.SourceType()));
1904 if (!statement.Run()) {
1905 return false;
1906 }
1907 }
1908 return transaction.Commit();
1909 }
1910
1911 // Confirm the cookie list passed in has the above cookies in it.
ConfirmCookiesAfterMigrationTest(std::vector<std::unique_ptr<CanonicalCookie>> read_in_cookies,bool expect_last_update_date=false)1912 void ConfirmCookiesAfterMigrationTest(
1913 std::vector<std::unique_ptr<CanonicalCookie>> read_in_cookies,
1914 bool expect_last_update_date = false) {
1915 ASSERT_EQ(read_in_cookies.size(), 6u);
1916
1917 std::sort(read_in_cookies.begin(), read_in_cookies.end(), &CompareCookies);
1918 int i = 0;
1919 EXPECT_EQ("A", read_in_cookies[i]->Name());
1920 EXPECT_EQ("B", read_in_cookies[i]->Value());
1921 EXPECT_EQ("example.com", read_in_cookies[i]->Domain());
1922 EXPECT_EQ("/", read_in_cookies[i]->Path());
1923 EXPECT_TRUE(read_in_cookies[i]->SecureAttribute());
1924 EXPECT_EQ(CookieSourceScheme::kSecure, read_in_cookies[i]->SourceScheme());
1925 EXPECT_EQ(read_in_cookies[i]->LastUpdateDate(),
1926 expect_last_update_date ? read_in_cookies[i]->CreationDate()
1927 : base::Time());
1928 EXPECT_EQ(read_in_cookies[i]->ExpiryDate(),
1929 read_in_cookies[i]->CreationDate());
1930 EXPECT_EQ(read_in_cookies[i]->SourceType(), CookieSourceType::kUnknown);
1931
1932 i++;
1933 EXPECT_EQ("A", read_in_cookies[i]->Name());
1934 EXPECT_EQ("B", read_in_cookies[i]->Value());
1935 EXPECT_EQ("example.com", read_in_cookies[i]->Domain());
1936 EXPECT_EQ("/path", read_in_cookies[i]->Path());
1937 EXPECT_FALSE(read_in_cookies[i]->SecureAttribute());
1938 EXPECT_EQ(CookieSourceScheme::kUnset, read_in_cookies[i]->SourceScheme());
1939 EXPECT_EQ(read_in_cookies[i]->LastUpdateDate(),
1940 expect_last_update_date ? read_in_cookies[i]->CreationDate()
1941 : base::Time());
1942 EXPECT_EQ(read_in_cookies[i]->ExpiryDate(),
1943 read_in_cookies[i]->CreationDate() + base::Days(400));
1944 EXPECT_EQ(read_in_cookies[i]->SourceType(), CookieSourceType::kUnknown);
1945
1946 i++;
1947 EXPECT_EQ("A", read_in_cookies[i]->Name());
1948 EXPECT_EQ("B", read_in_cookies[i]->Value());
1949 EXPECT_EQ("example2.com", read_in_cookies[i]->Domain());
1950 EXPECT_EQ("/", read_in_cookies[i]->Path());
1951 EXPECT_TRUE(read_in_cookies[i]->SecureAttribute());
1952 EXPECT_EQ(CookieSourceScheme::kSecure, read_in_cookies[i]->SourceScheme());
1953 EXPECT_EQ(read_in_cookies[i]->LastUpdateDate(),
1954 expect_last_update_date ? read_in_cookies[i]->CreationDate()
1955 : base::Time());
1956 EXPECT_EQ(read_in_cookies[i]->ExpiryDate(),
1957 read_in_cookies[i]->CreationDate());
1958 EXPECT_EQ(read_in_cookies[i]->SourceType(), CookieSourceType::kUnknown);
1959
1960 i++;
1961 EXPECT_EQ("C", read_in_cookies[i]->Name());
1962 EXPECT_EQ("B", read_in_cookies[i]->Value());
1963 EXPECT_EQ("example.com", read_in_cookies[i]->Domain());
1964 EXPECT_EQ("/", read_in_cookies[i]->Path());
1965 EXPECT_TRUE(read_in_cookies[i]->SecureAttribute());
1966 EXPECT_EQ(CookieSourceScheme::kSecure, read_in_cookies[i]->SourceScheme());
1967 EXPECT_EQ(read_in_cookies[i]->LastUpdateDate(),
1968 expect_last_update_date ? read_in_cookies[i]->CreationDate()
1969 : base::Time());
1970 EXPECT_EQ(read_in_cookies[i]->ExpiryDate(),
1971 read_in_cookies[i]->CreationDate());
1972 EXPECT_EQ(read_in_cookies[i]->SourceType(), CookieSourceType::kUnknown);
1973
1974 i++;
1975 EXPECT_EQ("C", read_in_cookies[i]->Name());
1976 EXPECT_EQ("B", read_in_cookies[i]->Value());
1977 EXPECT_EQ("example.com", read_in_cookies[i]->Domain());
1978 EXPECT_EQ("/path", read_in_cookies[i]->Path());
1979 EXPECT_FALSE(read_in_cookies[i]->SecureAttribute());
1980 EXPECT_EQ(CookieSourceScheme::kUnset, read_in_cookies[i]->SourceScheme());
1981 EXPECT_EQ(read_in_cookies[i]->LastUpdateDate(),
1982 expect_last_update_date ? read_in_cookies[i]->CreationDate()
1983 : base::Time());
1984 // The exact time will be within the last minute due to the cap.
1985 EXPECT_LE(read_in_cookies[i]->ExpiryDate(),
1986 base::Time::Now() + base::Days(400));
1987 EXPECT_GE(read_in_cookies[i]->ExpiryDate(),
1988 base::Time::Now() + base::Days(400) - base::Minutes(1));
1989 EXPECT_EQ(read_in_cookies[i]->SourceType(), CookieSourceType::kUnknown);
1990
1991 i++;
1992 EXPECT_EQ("C", read_in_cookies[i]->Name());
1993 EXPECT_EQ("B", read_in_cookies[i]->Value());
1994 EXPECT_EQ("example2.com", read_in_cookies[i]->Domain());
1995 EXPECT_EQ("/", read_in_cookies[i]->Path());
1996 EXPECT_FALSE(read_in_cookies[i]->SecureAttribute());
1997 EXPECT_EQ(CookieSourceScheme::kUnset, read_in_cookies[i]->SourceScheme());
1998 EXPECT_EQ(read_in_cookies[i]->LastUpdateDate(),
1999 expect_last_update_date ? read_in_cookies[i]->CreationDate()
2000 : base::Time());
2001 EXPECT_EQ(read_in_cookies[i]->ExpiryDate(),
2002 read_in_cookies[i]->CreationDate() + base::Days(399));
2003 EXPECT_EQ(read_in_cookies[i]->SourceType(), CookieSourceType::kUnknown);
2004 }
2005
ConfirmDatabaseVersionAfterMigration(const base::FilePath path,int version)2006 void ConfirmDatabaseVersionAfterMigration(const base::FilePath path,
2007 int version) {
2008 sql::Database connection;
2009 ASSERT_TRUE(connection.Open(path));
2010 ASSERT_GE(GetDBCurrentVersionNumber(&connection), version);
2011 }
2012
TEST_F(SQLitePersistentCookieStoreTest,UpgradeToSchemaVersion19)2013 TEST_F(SQLitePersistentCookieStoreTest, UpgradeToSchemaVersion19) {
2014 // Open db.
2015 const base::FilePath database_path =
2016 temp_dir_.GetPath().Append(kCookieFilename);
2017 {
2018 sql::Database connection;
2019 ASSERT_TRUE(connection.Open(database_path));
2020 ASSERT_TRUE(CreateV18Schema(&connection));
2021 ASSERT_EQ(GetDBCurrentVersionNumber(&connection), 18);
2022 ASSERT_TRUE(AddV18CookiesToDB(&connection, base::TimeDelta::Max()));
2023 }
2024
2025 CanonicalCookieVector read_in_cookies = CreateAndLoad(
2026 /*crypt_cookies=*/false, /*restore_old_session_cookies=*/false);
2027 ASSERT_NO_FATAL_FAILURE(
2028 ConfirmCookiesAfterMigrationTest(std::move(read_in_cookies),
2029 /*expect_last_update_date=*/true));
2030 DestroyStore();
2031
2032 ASSERT_NO_FATAL_FAILURE(
2033 ConfirmDatabaseVersionAfterMigration(database_path, 19));
2034 }
2035
TEST_F(SQLitePersistentCookieStoreTest,UpgradeToSchemaVersion20)2036 TEST_F(SQLitePersistentCookieStoreTest, UpgradeToSchemaVersion20) {
2037 // Open db.
2038 const base::FilePath database_path =
2039 temp_dir_.GetPath().Append(kCookieFilename);
2040 {
2041 sql::Database connection;
2042 ASSERT_TRUE(connection.Open(database_path));
2043 // V19's schema is the same as V18, so we can reuse the creation function.
2044 ASSERT_TRUE(CreateV18Schema(&connection));
2045 ASSERT_EQ(GetDBCurrentVersionNumber(&connection), 18);
2046 ASSERT_TRUE(AddV18CookiesToDB(&connection, base::TimeDelta::Max()));
2047 }
2048
2049 CanonicalCookieVector read_in_cookies = CreateAndLoad(
2050 /*crypt_cookies=*/false, /*restore_old_session_cookies=*/false);
2051 ASSERT_NO_FATAL_FAILURE(
2052 ConfirmCookiesAfterMigrationTest(std::move(read_in_cookies),
2053 /*expect_last_update_date=*/true));
2054 DestroyStore();
2055
2056 ASSERT_NO_FATAL_FAILURE(
2057 ConfirmDatabaseVersionAfterMigration(database_path, 20));
2058 }
2059
TEST_F(SQLitePersistentCookieStoreTest,UpgradeToSchemaVersion21)2060 TEST_F(SQLitePersistentCookieStoreTest, UpgradeToSchemaVersion21) {
2061 // Open db.
2062 const base::FilePath database_path =
2063 temp_dir_.GetPath().Append(kCookieFilename);
2064 {
2065 sql::Database connection;
2066 ASSERT_TRUE(connection.Open(database_path));
2067 ASSERT_TRUE(CreateV20Schema(&connection));
2068 ASSERT_EQ(GetDBCurrentVersionNumber(&connection), 20);
2069 ASSERT_TRUE(AddV20CookiesToDB(&connection));
2070 }
2071
2072 CanonicalCookieVector read_in_cookies = CreateAndLoad(
2073 /*crypt_cookies=*/false, /*restore_old_session_cookies=*/false);
2074 ASSERT_NO_FATAL_FAILURE(
2075 ConfirmCookiesAfterMigrationTest(std::move(read_in_cookies),
2076 /*expect_last_update_date=*/true));
2077 DestroyStore();
2078
2079 ASSERT_NO_FATAL_FAILURE(
2080 ConfirmDatabaseVersionAfterMigration(database_path, 21));
2081 }
2082
TEST_F(SQLitePersistentCookieStoreTest,UpgradeToSchemaVersion22)2083 TEST_F(SQLitePersistentCookieStoreTest, UpgradeToSchemaVersion22) {
2084 // Open db.
2085 const base::FilePath database_path =
2086 temp_dir_.GetPath().Append(kCookieFilename);
2087 {
2088 sql::Database connection;
2089 ASSERT_TRUE(connection.Open(database_path));
2090 ASSERT_TRUE(CreateV21Schema(&connection));
2091 ASSERT_EQ(GetDBCurrentVersionNumber(&connection), 21);
2092 ASSERT_TRUE(AddV21CookiesToDB(&connection));
2093 }
2094
2095 CanonicalCookieVector read_in_cookies = CreateAndLoad(
2096 /*crypt_cookies=*/false, /*restore_old_session_cookies=*/false);
2097 ASSERT_NO_FATAL_FAILURE(
2098 ConfirmCookiesAfterMigrationTest(std::move(read_in_cookies),
2099 /*expect_last_update_date=*/true));
2100 DestroyStore();
2101
2102 ASSERT_NO_FATAL_FAILURE(
2103 ConfirmDatabaseVersionAfterMigration(database_path, 22));
2104 }
2105
TEST_F(SQLitePersistentCookieStoreTest,UpgradeToSchemaVersion23)2106 TEST_F(SQLitePersistentCookieStoreTest, UpgradeToSchemaVersion23) {
2107 // Open db.
2108 const base::FilePath database_path =
2109 temp_dir_.GetPath().Append(kCookieFilename);
2110 {
2111 sql::Database connection;
2112 ASSERT_TRUE(connection.Open(database_path));
2113 ASSERT_TRUE(CreateV22Schema(&connection));
2114 ASSERT_EQ(GetDBCurrentVersionNumber(&connection), 22);
2115 ASSERT_TRUE(AddV22CookiesToDB(&connection, CookiesForMigrationTest()));
2116 }
2117
2118 CanonicalCookieVector read_in_cookies = CreateAndLoad(
2119 /*crypt_cookies=*/false, /*restore_old_session_cookies=*/false);
2120 ASSERT_NO_FATAL_FAILURE(
2121 ConfirmCookiesAfterMigrationTest(std::move(read_in_cookies),
2122 /*expect_last_update_date=*/true));
2123 DestroyStore();
2124
2125 ASSERT_NO_FATAL_FAILURE(
2126 ConfirmDatabaseVersionAfterMigration(database_path, 23));
2127 }
2128
TEST_F(SQLitePersistentCookieStoreTest,UpgradeToSchemaVersion23_ConfirmSourceSchemeRecalculation)2129 TEST_F(SQLitePersistentCookieStoreTest,
2130 UpgradeToSchemaVersion23_ConfirmSourceSchemeRecalculation) {
2131 const base::FilePath database_path =
2132 temp_dir_.GetPath().Append(kCookieFilename);
2133 const base::Time now = base::Time::Now();
2134 std::vector<CanonicalCookie> cookies;
2135
2136 cookies.push_back(*CanonicalCookie::CreateUnsafeCookieForTesting(
2137 "secure_true", "A", "example.com", "/", now, now, now, now,
2138 /*secure=*/true, /*httponly=*/false, CookieSameSite::UNSPECIFIED,
2139 COOKIE_PRIORITY_DEFAULT, std::optional<CookiePartitionKey>(),
2140 CookieSourceScheme::kUnset));
2141
2142 cookies.push_back(*CanonicalCookie::CreateUnsafeCookieForTesting(
2143 "secure_false", "B", "example.com", "/", now, now, now, now,
2144 /*secure=*/false, /*httponly=*/false, CookieSameSite::UNSPECIFIED,
2145 COOKIE_PRIORITY_DEFAULT, std::optional<CookiePartitionKey>(),
2146 CookieSourceScheme::kUnset));
2147
2148 // Open database, populate and close db.
2149 {
2150 sql::Database db;
2151 ASSERT_TRUE(db.Open(database_path));
2152 ASSERT_TRUE(CreateV22Schema(&db));
2153 ASSERT_EQ(GetDBCurrentVersionNumber(&db), 22);
2154 ASSERT_TRUE(AddV22CookiesToDB(&db, cookies));
2155 }
2156
2157 CanonicalCookieVector read_in_cookies = CreateAndLoad(
2158 /*crypt_cookies=*/false, /*restore_old_session_cookies=*/true);
2159
2160 EXPECT_EQ(read_in_cookies.size(), cookies.size());
2161
2162 // Reopen database for testing.
2163 sql::Database connection;
2164 ASSERT_TRUE(connection.Open(database_path));
2165 ASSERT_GE(GetDBCurrentVersionNumber(&connection), 23);
2166 for (const auto& cookie : cookies) {
2167 sql::Statement verify_stmt(connection.GetUniqueStatement(
2168 "SELECT source_scheme FROM cookies WHERE is_secure=?"));
2169
2170 verify_stmt.BindBool(0, cookie.SecureAttribute());
2171
2172 ASSERT_TRUE(verify_stmt.is_valid());
2173
2174 EXPECT_TRUE(verify_stmt.Step());
2175 EXPECT_EQ(
2176 static_cast<int>(cookie.SecureAttribute() ? CookieSourceScheme::kSecure
2177 : CookieSourceScheme::kUnset),
2178 verify_stmt.ColumnInt(0));
2179 // Confirm that exactly one cookie matches the SQL query
2180 EXPECT_FALSE(verify_stmt.Step());
2181 }
2182 }
2183
2184 class SQLitePersistentCookieStoreTest_OriginBoundCookies
2185 : public SQLitePersistentCookieStoreTest {
2186 public:
2187 // Creates and stores 4 cookies that differ only by scheme and/or port. When
2188 // this function returns, the store will be created and all the cookies loaded
2189 // into cookies_.
InitializeTest()2190 void InitializeTest() {
2191 InitializeStore(/*crypt=*/false, /*restore_old_session_cookies=*/false);
2192
2193 basic_cookie_ = CanonicalCookie::CreateForTesting(
2194 basic_url_, "a=b; max-age=100000", /*creation_time=*/base::Time::Now());
2195
2196 http_cookie_ = std::make_unique<CanonicalCookie>(*basic_cookie_);
2197 http_cookie_->SetSourceScheme(CookieSourceScheme::kNonSecure);
2198
2199 port_444_cookie_ = std::make_unique<CanonicalCookie>(*basic_cookie_);
2200 port_444_cookie_->SetSourcePort(444);
2201
2202 http_444_cookie_ = std::make_unique<CanonicalCookie>(*basic_cookie_);
2203 http_444_cookie_->SetSourceScheme(CookieSourceScheme::kNonSecure);
2204 http_444_cookie_->SetSourcePort(444);
2205
2206 store_->AddCookie(*basic_cookie_);
2207 store_->AddCookie(*http_cookie_);
2208 store_->AddCookie(*port_444_cookie_);
2209 store_->AddCookie(*http_444_cookie_);
2210 // Force the store to write its data to the disk.
2211 DestroyStore();
2212
2213 cookies_ = CreateAndLoad(/*crypt_cookies=*/false,
2214 /*restore_old_session_cookies=*/false);
2215
2216 EXPECT_EQ(cookies_.size(), 4UL);
2217 }
2218
2219 GURL basic_url_ = GURL("https://example.com");
2220 std::unique_ptr<net::CanonicalCookie> basic_cookie_;
2221 std::unique_ptr<net::CanonicalCookie> http_cookie_;
2222 std::unique_ptr<net::CanonicalCookie> port_444_cookie_;
2223 std::unique_ptr<net::CanonicalCookie> http_444_cookie_;
2224
2225 CanonicalCookieVector cookies_;
2226 };
2227
2228 // Tests that cookies which differ only in their scheme and port are considered
2229 // distinct.
TEST_F(SQLitePersistentCookieStoreTest_OriginBoundCookies,UniquenessConstraint)2230 TEST_F(SQLitePersistentCookieStoreTest_OriginBoundCookies,
2231 UniquenessConstraint) {
2232 InitializeTest();
2233
2234 // Try to add another cookie that is the same as basic_cookie_ except that its
2235 // value is different. Value isn't considered as part of the unique constraint
2236 // and so this cookie won't be considered unique and should fail to be added.
2237 auto basic_cookie2 =
2238 CanonicalCookie::CreateForTesting(basic_url_, "a=b2; max-age=100000",
2239 /*creation_time=*/base::Time::Now());
2240
2241 store_->AddCookie(*basic_cookie2);
2242
2243 // Force the store to write its data to the disk.
2244 DestroyStore();
2245
2246 cookies_.clear();
2247 cookies_ = CreateAndLoad(/*crypt_cookies=*/false,
2248 /*restore_old_session_cookies=*/false);
2249
2250 // Confirm that basic_cookie2 failed to be added.
2251 EXPECT_THAT(cookies_, testing::UnorderedElementsAre(
2252 MatchesEveryCookieField(*basic_cookie_),
2253 MatchesEveryCookieField(*http_cookie_),
2254 MatchesEveryCookieField(*port_444_cookie_),
2255 MatchesEveryCookieField(*http_444_cookie_)));
2256 }
2257
2258 // Tests that deleting a cookie correctly takes the scheme and port into
2259 // account.
TEST_F(SQLitePersistentCookieStoreTest_OriginBoundCookies,DeleteCookie)2260 TEST_F(SQLitePersistentCookieStoreTest_OriginBoundCookies, DeleteCookie) {
2261 InitializeTest();
2262
2263 // Try to delete just one of the cookies.
2264 store_->DeleteCookie(*http_444_cookie_);
2265 DestroyStore();
2266 cookies_.clear();
2267
2268 cookies_ = CreateAndLoad(/*crypt_cookies=*/false,
2269 /*restore_old_session_cookies=*/false);
2270
2271 // Only the single cookie should be deleted.
2272 EXPECT_THAT(cookies_, testing::UnorderedElementsAre(
2273 MatchesEveryCookieField(*basic_cookie_),
2274 MatchesEveryCookieField(*http_cookie_),
2275 MatchesEveryCookieField(*port_444_cookie_)));
2276 }
2277
2278 // Tests that updating a cookie correctly takes the scheme and port into
2279 // account.
TEST_F(SQLitePersistentCookieStoreTest_OriginBoundCookies,UpdateCookieAccessTime)2280 TEST_F(SQLitePersistentCookieStoreTest_OriginBoundCookies,
2281 UpdateCookieAccessTime) {
2282 InitializeTest();
2283
2284 base::Time basic_last_access = basic_cookie_->LastAccessDate();
2285 base::Time http_last_access = http_cookie_->LastAccessDate();
2286 base::Time port_444_last_access = port_444_cookie_->LastAccessDate();
2287 base::Time http_444_last_access = http_444_cookie_->LastAccessDate();
2288
2289 base::Time new_last_access = http_444_last_access + base::Hours(1);
2290 http_444_cookie_->SetLastAccessDate(new_last_access);
2291
2292 store_->UpdateCookieAccessTime(*http_444_cookie_);
2293 DestroyStore();
2294 cookies_.clear();
2295
2296 cookies_ = CreateAndLoad(/*crypt_cookies=*/false,
2297 /*restore_old_session_cookies=*/false);
2298
2299 // All loaded cookies' should have their original LastAccessDate() except for
2300 // the one updated to new_last_access.
2301 EXPECT_THAT(
2302 cookies_,
2303 testing::UnorderedElementsAre(
2304 MatchesCookieKeyAndLastAccessDate(basic_cookie_->StrictlyUniqueKey(),
2305 basic_last_access),
2306 MatchesCookieKeyAndLastAccessDate(http_cookie_->StrictlyUniqueKey(),
2307 http_last_access),
2308 MatchesCookieKeyAndLastAccessDate(
2309 port_444_cookie_->StrictlyUniqueKey(), port_444_last_access),
2310 MatchesCookieKeyAndLastAccessDate(
2311 http_444_cookie_->StrictlyUniqueKey(), new_last_access)));
2312 }
2313
TEST_F(SQLitePersistentCookieStoreTest,SavingPartitionedCookies)2314 TEST_F(SQLitePersistentCookieStoreTest, SavingPartitionedCookies) {
2315 InitializeStore(/*crypt=*/false, /*restore_old_session_cookies=*/false);
2316
2317 store_->AddCookie(*CanonicalCookie::CreateUnsafeCookieForTesting(
2318 "__Host-foo", "bar", GURL("https://example.com/").host(), "/",
2319 /*creation=*/base::Time::Now(),
2320 /*expiration=*/base::Time::Now() + base::Days(1),
2321 /*last_access=*/base::Time::Now(),
2322 /*last_update=*/base::Time::Now(), /*secure=*/true, /*httponly=*/false,
2323 CookieSameSite::UNSPECIFIED, COOKIE_PRIORITY_DEFAULT,
2324 CookiePartitionKey::FromURLForTesting(GURL("https://toplevelsite.com"))));
2325 Flush();
2326
2327 std::string got_db_content(ReadRawDBContents());
2328 EXPECT_NE(got_db_content.find("__Host-foo"), std::string::npos);
2329
2330 DestroyStore();
2331 }
2332
TEST_F(SQLitePersistentCookieStoreTest,LoadingPartitionedCookies)2333 TEST_F(SQLitePersistentCookieStoreTest, LoadingPartitionedCookies) {
2334 InitializeStore(/*crypt=*/false, /*restore_old_session_cookies=*/false);
2335 DestroyStore();
2336
2337 // Insert a partitioned cookie into the database manually.
2338 base::FilePath store_name(temp_dir_.GetPath().Append(kCookieFilename));
2339 std::unique_ptr<sql::Database> db(std::make_unique<sql::Database>());
2340 ASSERT_TRUE(db->Open(store_name));
2341
2342 sql::Statement stmt(db->GetUniqueStatement(
2343 "INSERT INTO cookies (creation_utc, host_key, top_frame_site_key, name, "
2344 "value, encrypted_value, path, expires_utc, is_secure, is_httponly, "
2345 "samesite, last_access_utc, has_expires, is_persistent, priority, "
2346 "source_scheme, source_port, last_update_utc, source_type, "
2347 "has_cross_site_ancestor) "
2348 "VALUES (?,?,?,?,?,'',?,?,1,0,0,?,1,1,0,?,?,?,0, 1)"));
2349 ASSERT_TRUE(stmt.is_valid());
2350
2351 base::Time creation(base::Time::Now());
2352 base::Time expiration(creation + base::Days(1));
2353 base::Time last_access(base::Time::Now());
2354 base::Time last_update(base::Time::Now());
2355
2356 stmt.BindTime(0, creation);
2357 stmt.BindString(1, GURL("https://www.example.com/").host());
2358 stmt.BindString(2, "https://toplevelsite.com");
2359 stmt.BindString(3, "__Host-foo");
2360 stmt.BindString(4, "bar");
2361 stmt.BindString(5, "/");
2362 stmt.BindTime(6, expiration);
2363 stmt.BindTime(7, last_access);
2364 stmt.BindInt(8, static_cast<int>(CookieSourceScheme::kUnset));
2365 stmt.BindInt(9, SQLitePersistentCookieStore::kDefaultUnknownPort);
2366 stmt.BindTime(10, last_update);
2367 ASSERT_TRUE(stmt.Run());
2368 stmt.Clear();
2369 db.reset();
2370
2371 CanonicalCookieVector cookies = CreateAndLoad(
2372 /*crypt_cookies=*/false, /*restore_old_session_cookies=*/false);
2373
2374 EXPECT_EQ(1u, cookies.size());
2375 auto cc = std::move(cookies[0]);
2376 EXPECT_EQ("__Host-foo", cc->Name());
2377 EXPECT_EQ("bar", cc->Value());
2378 EXPECT_EQ(GURL("https://www.example.com/").host(), cc->Domain());
2379 EXPECT_TRUE(cc->IsPartitioned());
2380 EXPECT_EQ(
2381 CookiePartitionKey::FromURLForTesting(GURL("https://toplevelsite.com")),
2382 cc->PartitionKey());
2383 EXPECT_EQ(last_update, cc->LastUpdateDate());
2384 }
2385
CreatePartitionedCookie(const std::string & name,const std::string & domain,const std::string & top_frame_site_key,CookiePartitionKey::AncestorChainBit ancestor_chain_bit,CookieSourceScheme scheme=CookieSourceScheme::kUnset,bool partitioned_cookies_enabled=true)2386 std::unique_ptr<CanonicalCookie> CreatePartitionedCookie(
2387 const std::string& name,
2388 const std::string& domain,
2389 const std::string& top_frame_site_key,
2390 CookiePartitionKey::AncestorChainBit ancestor_chain_bit,
2391 CookieSourceScheme scheme = CookieSourceScheme::kUnset,
2392 bool partitioned_cookies_enabled = true) {
2393 const base::Time now = base::Time::Now();
2394
2395 return CanonicalCookie::CreateUnsafeCookieForTesting(
2396 name, "B", domain, "/", now, now, now, now, /*secure=*/true,
2397 /*httponly=*/false, CookieSameSite::UNSPECIFIED, COOKIE_PRIORITY_DEFAULT,
2398 partitioned_cookies_enabled
2399 ? CookiePartitionKey::FromURLForTesting(GURL(top_frame_site_key),
2400 ancestor_chain_bit)
2401 :
2402 /* std::nullopt can't be used because of the ternary evaluation might
2403 result in different types */
2404 std::optional<CookiePartitionKey>(),
2405 scheme);
2406 }
2407
2408 // Pairs contain a cookie, and hard coded value for has_cross_site_ancestor
2409 // value.
2410 //
2411 // During migration we have no way of knowing if a cross site ancestor was
2412 // present. When the existing domain and the top_level_site of the partition key
2413 // are the same. The default behavior is to set the cross site value to
2414 // kSameSite, so ignore the kCrossSite cookie when testing migration.
2415 std::vector<std::pair<CanonicalCookie, std::string>>
GenerateHasCrossSiteAncestorCookiesAndVals(bool migrating=false)2416 GenerateHasCrossSiteAncestorCookiesAndVals(bool migrating = false) {
2417 std::vector<std::pair<CanonicalCookie, std::string>> results;
2418 const std::string default_domain = "example.com";
2419
2420 // Key and domain are the same site
2421 results.emplace_back(
2422 *CreatePartitionedCookie("A", default_domain, "https://www.example.com",
2423 CookiePartitionKey::AncestorChainBit::kSameSite),
2424 "0");
2425 if (!migrating) {
2426 // Key and domain are the same site but with kCrossSite
2427 results.emplace_back(*CreatePartitionedCookie(
2428 "B", default_domain, "https://www.example.com",
2429 CookiePartitionKey::AncestorChainBit::kCrossSite),
2430 "1");
2431 }
2432 // Key and domain are different
2433 results.emplace_back(*CreatePartitionedCookie(
2434 "C", default_domain, "https://www.toplevelsite.com",
2435 CookiePartitionKey::AncestorChainBit::kCrossSite),
2436 "1");
2437 // Domain is a substring
2438 results.emplace_back(*CreatePartitionedCookie(
2439 "D", "ample.com", "https://www.example.com",
2440 CookiePartitionKey::AncestorChainBit::kCrossSite),
2441 "1");
2442 // http check kNonSecure scheme match.
2443 results.emplace_back(
2444 *CreatePartitionedCookie("E", default_domain, "http://www.example.com",
2445 CookiePartitionKey::AncestorChainBit::kSameSite),
2446 "0");
2447
2448 return results;
2449 }
2450
TEST_F(SQLitePersistentCookieStoreTest,UpgradeToSchemaVersion23_AddingHasCrossSiteAncestor)2451 TEST_F(SQLitePersistentCookieStoreTest,
2452 UpgradeToSchemaVersion23_AddingHasCrossSiteAncestor) {
2453 const base::FilePath database_path =
2454 temp_dir_.GetPath().Append(kCookieFilename);
2455
2456 std::vector<std::pair<CanonicalCookie, std::string>>
2457 cookies_and_expected_values =
2458 GenerateHasCrossSiteAncestorCookiesAndVals(true);
2459
2460 std::vector<CanonicalCookie> cookies;
2461 for (auto cookie_pair : cookies_and_expected_values) {
2462 cookies.push_back(cookie_pair.first);
2463 }
2464 // Open database, populate and close db.
2465 {
2466 sql::Database db;
2467 ASSERT_TRUE(db.Open(database_path));
2468 ASSERT_TRUE(CreateV22Schema(&db));
2469 ASSERT_EQ(GetDBCurrentVersionNumber(&db), 22);
2470 ASSERT_TRUE(AddV22CookiesToDB(&db, cookies));
2471 }
2472
2473 CanonicalCookieVector read_in_cookies = CreateAndLoad(
2474 /*crypt_cookies=*/false, /*restore_old_session_cookies=*/true);
2475
2476 EXPECT_EQ(read_in_cookies.size(), cookies.size());
2477
2478 // Reopen database for testing.
2479 sql::Database connection;
2480 ASSERT_TRUE(connection.Open(database_path));
2481 ASSERT_GE(GetDBCurrentVersionNumber(&connection), 23);
2482
2483 for (const auto& cookie_pair : cookies_and_expected_values) {
2484 // TODO (crbug.com/326605834) Once ancestor chain bit changes are
2485 // implemented update this method utilize the ancestor bit.
2486 base::expected<CookiePartitionKey::SerializedCookiePartitionKey,
2487 std::string>
2488 serialized_partition_key =
2489 CookiePartitionKey::Serialize(cookie_pair.first.PartitionKey());
2490 ASSERT_TRUE(serialized_partition_key.has_value());
2491
2492 sql::Statement verify_stmt(connection.GetUniqueStatement(
2493 "SELECT name FROM cookies WHERE host_key=?"
2494 " AND top_frame_site_key=?"
2495 " AND has_cross_site_ancestor=?"));
2496
2497 verify_stmt.BindString(0, cookie_pair.first.Domain());
2498 verify_stmt.BindString(1, serialized_partition_key->TopLevelSite());
2499 verify_stmt.BindString(2, cookie_pair.second);
2500
2501 ASSERT_TRUE(verify_stmt.is_valid());
2502 EXPECT_TRUE(verify_stmt.Step());
2503 EXPECT_EQ(cookie_pair.first.Name(), verify_stmt.ColumnString(0));
2504 // Confirm that exactly one cookie matches the SQL query
2505 EXPECT_FALSE(verify_stmt.Step());
2506 }
2507 }
2508
TEST_F(SQLitePersistentCookieStoreTest,TestValueOfHasCrossSiteAncestorOnDoCommit)2509 TEST_F(SQLitePersistentCookieStoreTest,
2510 TestValueOfHasCrossSiteAncestorOnDoCommit) {
2511 InitializeStore(/*crypt=*/false, /*restore_old_session_cookies=*/false);
2512
2513 std::vector<std::pair<CanonicalCookie, std::string>>
2514 cookies_and_expected_values =
2515 GenerateHasCrossSiteAncestorCookiesAndVals();
2516 for (const auto& cookie_pair : cookies_and_expected_values) {
2517 store_->AddCookie(cookie_pair.first);
2518 }
2519
2520 // Force the store to write its data to the disk.
2521 DestroyStore();
2522
2523 cookies_ = CreateAndLoad(/*crypt_cookies=*/false,
2524 /*restore_old_session_cookies=*/false);
2525 EXPECT_EQ(cookies_.size(), cookies_and_expected_values.size());
2526
2527 sql::Database connection;
2528 ASSERT_TRUE(connection.Open(temp_dir_.GetPath().Append(kCookieFilename)));
2529 ASSERT_EQ(GetDBCurrentVersionNumber(&connection), 23);
2530
2531 for (const auto& cookie_pair : cookies_and_expected_values) {
2532 // TODO (crbug.com/326605834) Once ancestor chain bit changes are
2533 // implemented update this method utilize the ancestor bit.
2534 base::expected<CookiePartitionKey::SerializedCookiePartitionKey,
2535 std::string>
2536 serialized_partition_key =
2537 CookiePartitionKey::Serialize(cookie_pair.first.PartitionKey());
2538 ASSERT_TRUE(serialized_partition_key.has_value());
2539
2540 sql::Statement verify_stmt(connection.GetUniqueStatement(
2541 "SELECT name FROM cookies WHERE host_key=?"
2542 " AND top_frame_site_key=?"
2543 " AND has_cross_site_ancestor=?"));
2544
2545 verify_stmt.BindString(0, cookie_pair.first.Domain());
2546 verify_stmt.BindString(1, serialized_partition_key->TopLevelSite());
2547 verify_stmt.BindString(2, cookie_pair.second);
2548 ASSERT_TRUE(verify_stmt.is_valid());
2549
2550 EXPECT_TRUE(verify_stmt.Step());
2551 EXPECT_EQ(cookie_pair.first.Name(), verify_stmt.ColumnString(0));
2552 // Confirm that exactly one cookie matches the SQL query
2553 EXPECT_FALSE(verify_stmt.Step());
2554 }
2555 }
2556
2557 } // namespace net
2558