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