1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 "content/browser/net/sqlite_persistent_cookie_store.h" 6 7 #include <map> 8 #include <set> 9 10 #include "base/bind.h" 11 #include "base/callback.h" 12 #include "base/file_util.h" 13 #include "base/files/scoped_temp_dir.h" 14 #include "base/memory/ref_counted.h" 15 #include "base/message_loop/message_loop.h" 16 #include "base/sequenced_task_runner.h" 17 #include "base/stl_util.h" 18 #include "base/synchronization/waitable_event.h" 19 #include "base/test/sequenced_worker_pool_owner.h" 20 #include "base/threading/sequenced_worker_pool.h" 21 #include "base/time/time.h" 22 #include "content/public/browser/cookie_crypto_delegate.h" 23 #include "content/public/browser/cookie_store_factory.h" 24 #include "crypto/encryptor.h" 25 #include "crypto/symmetric_key.h" 26 #include "net/cookies/canonical_cookie.h" 27 #include "net/cookies/cookie_constants.h" 28 #include "sql/connection.h" 29 #include "sql/meta_table.h" 30 #include "sql/statement.h" 31 #include "testing/gtest/include/gtest/gtest.h" 32 #include "url/gurl.h" 33 34 namespace content { 35 36 namespace { 37 38 const base::FilePath::CharType kCookieFilename[] = FILE_PATH_LITERAL("Cookies"); 39 40 class CookieCryptor : public content::CookieCryptoDelegate { 41 public: 42 CookieCryptor(); 43 virtual bool EncryptString(const std::string& plaintext, 44 std::string* ciphertext) OVERRIDE; 45 virtual bool DecryptString(const std::string& ciphertext, 46 std::string* plaintext) OVERRIDE; 47 48 private: 49 scoped_ptr<crypto::SymmetricKey> key_; 50 crypto::Encryptor encryptor_; 51 }; 52 53 CookieCryptor::CookieCryptor() : key_( 54 crypto::SymmetricKey::DeriveKeyFromPassword( 55 crypto::SymmetricKey::AES, "password", "saltiest", 1000, 256)) { 56 std::string iv("the iv: 16 bytes"); 57 encryptor_.Init(key_.get(), crypto::Encryptor::CBC, iv); 58 } 59 60 bool CookieCryptor::EncryptString(const std::string& plaintext, 61 std::string* ciphertext) { 62 return encryptor_.Encrypt(plaintext, ciphertext); 63 } 64 65 bool CookieCryptor::DecryptString(const std::string& ciphertext, 66 std::string* plaintext) { 67 return encryptor_.Decrypt(ciphertext, plaintext); 68 } 69 70 } // namespace 71 72 typedef std::vector<net::CanonicalCookie*> CanonicalCookieVector; 73 74 class SQLitePersistentCookieStoreTest : public testing::Test { 75 public: 76 SQLitePersistentCookieStoreTest() 77 : pool_owner_(new base::SequencedWorkerPoolOwner(3, "Background Pool")), 78 loaded_event_(false, false), 79 key_loaded_event_(false, false), 80 db_thread_event_(false, false) { 81 } 82 83 void OnLoaded(const CanonicalCookieVector& cookies) { 84 cookies_ = cookies; 85 loaded_event_.Signal(); 86 } 87 88 void OnKeyLoaded(const CanonicalCookieVector& cookies) { 89 cookies_ = cookies; 90 key_loaded_event_.Signal(); 91 } 92 93 void Load(CanonicalCookieVector* cookies) { 94 EXPECT_FALSE(loaded_event_.IsSignaled()); 95 store_->Load(base::Bind(&SQLitePersistentCookieStoreTest::OnLoaded, 96 base::Unretained(this))); 97 loaded_event_.Wait(); 98 *cookies = cookies_; 99 } 100 101 void Flush() { 102 base::WaitableEvent event(false, false); 103 store_->Flush(base::Bind(&base::WaitableEvent::Signal, 104 base::Unretained(&event))); 105 event.Wait(); 106 } 107 108 scoped_refptr<base::SequencedTaskRunner> background_task_runner() { 109 return pool_owner_->pool()->GetSequencedTaskRunner( 110 pool_owner_->pool()->GetNamedSequenceToken("background")); 111 } 112 113 scoped_refptr<base::SequencedTaskRunner> client_task_runner() { 114 return pool_owner_->pool()->GetSequencedTaskRunner( 115 pool_owner_->pool()->GetNamedSequenceToken("client")); 116 } 117 118 void DestroyStore() { 119 store_ = NULL; 120 // Make sure we wait until the destructor has run by shutting down the pool 121 // resetting the owner (whose destructor blocks on the pool completion). 122 pool_owner_->pool()->Shutdown(); 123 // Create a new pool for the few tests that create multiple stores. In other 124 // cases this is wasted but harmless. 125 pool_owner_.reset(new base::SequencedWorkerPoolOwner(3, "Background Pool")); 126 } 127 128 void CreateAndLoad(bool crypt_cookies, 129 bool restore_old_session_cookies, 130 CanonicalCookieVector* cookies) { 131 if (crypt_cookies) 132 cookie_crypto_delegate_.reset(new CookieCryptor()); 133 134 store_ = new SQLitePersistentCookieStore( 135 temp_dir_.path().Append(kCookieFilename), 136 client_task_runner(), 137 background_task_runner(), 138 restore_old_session_cookies, 139 NULL, 140 cookie_crypto_delegate_.get()); 141 Load(cookies); 142 } 143 144 void InitializeStore(bool crypt, bool restore_old_session_cookies) { 145 CanonicalCookieVector cookies; 146 CreateAndLoad(crypt, restore_old_session_cookies, &cookies); 147 EXPECT_EQ(0U, cookies.size()); 148 } 149 150 // We have to create this method to wrap WaitableEvent::Wait, since we cannot 151 // bind a non-void returning method as a Closure. 152 void WaitOnDBEvent() { 153 db_thread_event_.Wait(); 154 } 155 156 // Adds a persistent cookie to store_. 157 void AddCookie(const std::string& name, 158 const std::string& value, 159 const std::string& domain, 160 const std::string& path, 161 const base::Time& creation) { 162 store_->AddCookie( 163 net::CanonicalCookie(GURL(), name, value, domain, path, creation, 164 creation, creation, false, false, 165 net::COOKIE_PRIORITY_DEFAULT)); 166 } 167 168 std::string ReadRawDBContents() { 169 std::string contents; 170 if (!base::ReadFileToString(temp_dir_.path().Append(kCookieFilename), 171 &contents)) 172 return std::string(); 173 return contents; 174 } 175 176 virtual void SetUp() OVERRIDE { 177 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 178 } 179 180 virtual void TearDown() OVERRIDE { 181 DestroyStore(); 182 pool_owner_->pool()->Shutdown(); 183 } 184 185 protected: 186 base::MessageLoop main_loop_; 187 scoped_ptr<base::SequencedWorkerPoolOwner> pool_owner_; 188 base::WaitableEvent loaded_event_; 189 base::WaitableEvent key_loaded_event_; 190 base::WaitableEvent db_thread_event_; 191 CanonicalCookieVector cookies_; 192 base::ScopedTempDir temp_dir_; 193 scoped_refptr<SQLitePersistentCookieStore> store_; 194 scoped_ptr<content::CookieCryptoDelegate> cookie_crypto_delegate_; 195 }; 196 197 TEST_F(SQLitePersistentCookieStoreTest, TestInvalidMetaTableRecovery) { 198 InitializeStore(false, false); 199 AddCookie("A", "B", "foo.bar", "/", base::Time::Now()); 200 DestroyStore(); 201 202 // Load up the store and verify that it has good data in it. 203 CanonicalCookieVector cookies; 204 CreateAndLoad(false, false, &cookies); 205 ASSERT_EQ(1U, cookies.size()); 206 ASSERT_STREQ("foo.bar", cookies[0]->Domain().c_str()); 207 ASSERT_STREQ("A", cookies[0]->Name().c_str()); 208 ASSERT_STREQ("B", cookies[0]->Value().c_str()); 209 DestroyStore(); 210 STLDeleteElements(&cookies); 211 212 // Now corrupt the meta table. 213 { 214 sql::Connection db; 215 ASSERT_TRUE(db.Open(temp_dir_.path().Append(kCookieFilename))); 216 sql::MetaTable meta_table_; 217 meta_table_.Init(&db, 1, 1); 218 ASSERT_TRUE(db.Execute("DELETE FROM meta")); 219 db.Close(); 220 } 221 222 // Upon loading, the database should be reset to a good, blank state. 223 CreateAndLoad(false, false, &cookies); 224 ASSERT_EQ(0U, cookies.size()); 225 226 // Verify that, after, recovery, the database persists properly. 227 AddCookie("X", "Y", "foo.bar", "/", base::Time::Now()); 228 DestroyStore(); 229 CreateAndLoad(false, false, &cookies); 230 ASSERT_EQ(1U, cookies.size()); 231 ASSERT_STREQ("foo.bar", cookies[0]->Domain().c_str()); 232 ASSERT_STREQ("X", cookies[0]->Name().c_str()); 233 ASSERT_STREQ("Y", cookies[0]->Value().c_str()); 234 STLDeleteElements(&cookies); 235 } 236 237 // Test if data is stored as expected in the SQLite database. 238 TEST_F(SQLitePersistentCookieStoreTest, TestPersistance) { 239 InitializeStore(false, false); 240 AddCookie("A", "B", "foo.bar", "/", base::Time::Now()); 241 // Replace the store effectively destroying the current one and forcing it 242 // to write its data to disk. Then we can see if after loading it again it 243 // is still there. 244 DestroyStore(); 245 // Reload and test for persistence 246 CanonicalCookieVector cookies; 247 CreateAndLoad(false, false, &cookies); 248 ASSERT_EQ(1U, cookies.size()); 249 ASSERT_STREQ("foo.bar", cookies[0]->Domain().c_str()); 250 ASSERT_STREQ("A", cookies[0]->Name().c_str()); 251 ASSERT_STREQ("B", cookies[0]->Value().c_str()); 252 253 // Now delete the cookie and check persistence again. 254 store_->DeleteCookie(*cookies[0]); 255 DestroyStore(); 256 STLDeleteElements(&cookies); 257 258 // Reload and check if the cookie has been removed. 259 CreateAndLoad(false, false, &cookies); 260 ASSERT_EQ(0U, cookies.size()); 261 } 262 263 // Test that priority load of cookies for a specfic domain key could be 264 // completed before the entire store is loaded 265 TEST_F(SQLitePersistentCookieStoreTest, TestLoadCookiesForKey) { 266 InitializeStore(false, false); 267 base::Time t = base::Time::Now(); 268 AddCookie("A", "B", "foo.bar", "/", t); 269 t += base::TimeDelta::FromInternalValue(10); 270 AddCookie("A", "B", "www.aaa.com", "/", t); 271 t += base::TimeDelta::FromInternalValue(10); 272 AddCookie("A", "B", "travel.aaa.com", "/", t); 273 t += base::TimeDelta::FromInternalValue(10); 274 AddCookie("A", "B", "www.bbb.com", "/", t); 275 DestroyStore(); 276 277 store_ = new SQLitePersistentCookieStore( 278 temp_dir_.path().Append(kCookieFilename), 279 client_task_runner(), 280 background_task_runner(), 281 false, NULL, NULL); 282 283 // Posting a blocking task to db_thread_ makes sure that the DB thread waits 284 // until both Load and LoadCookiesForKey have been posted to its task queue. 285 background_task_runner()->PostTask( 286 FROM_HERE, 287 base::Bind(&SQLitePersistentCookieStoreTest::WaitOnDBEvent, 288 base::Unretained(this))); 289 store_->Load(base::Bind(&SQLitePersistentCookieStoreTest::OnLoaded, 290 base::Unretained(this))); 291 store_->LoadCookiesForKey("aaa.com", 292 base::Bind(&SQLitePersistentCookieStoreTest::OnKeyLoaded, 293 base::Unretained(this))); 294 background_task_runner()->PostTask( 295 FROM_HERE, 296 base::Bind(&SQLitePersistentCookieStoreTest::WaitOnDBEvent, 297 base::Unretained(this))); 298 299 // Now the DB-thread queue contains: 300 // (active:) 301 // 1. Wait (on db_event) 302 // (pending:) 303 // 2. "Init And Chain-Load First Domain" 304 // 3. Priority Load (aaa.com) 305 // 4. Wait (on db_event) 306 db_thread_event_.Signal(); 307 key_loaded_event_.Wait(); 308 ASSERT_EQ(loaded_event_.IsSignaled(), false); 309 std::set<std::string> cookies_loaded; 310 for (CanonicalCookieVector::const_iterator it = cookies_.begin(); 311 it != cookies_.end(); 312 ++it) { 313 cookies_loaded.insert((*it)->Domain().c_str()); 314 } 315 STLDeleteElements(&cookies_); 316 ASSERT_GT(4U, cookies_loaded.size()); 317 ASSERT_EQ(true, cookies_loaded.find("www.aaa.com") != cookies_loaded.end()); 318 ASSERT_EQ(true, 319 cookies_loaded.find("travel.aaa.com") != cookies_loaded.end()); 320 321 db_thread_event_.Signal(); 322 loaded_event_.Wait(); 323 for (CanonicalCookieVector::const_iterator it = cookies_.begin(); 324 it != cookies_.end(); 325 ++it) { 326 cookies_loaded.insert((*it)->Domain().c_str()); 327 } 328 ASSERT_EQ(4U, cookies_loaded.size()); 329 ASSERT_EQ(cookies_loaded.find("foo.bar") != cookies_loaded.end(), 330 true); 331 ASSERT_EQ(cookies_loaded.find("www.bbb.com") != cookies_loaded.end(), true); 332 STLDeleteElements(&cookies_); 333 } 334 335 // Test that we can force the database to be written by calling Flush(). 336 TEST_F(SQLitePersistentCookieStoreTest, TestFlush) { 337 InitializeStore(false, false); 338 // File timestamps don't work well on all platforms, so we'll determine 339 // whether the DB file has been modified by checking its size. 340 base::FilePath path = temp_dir_.path().Append(kCookieFilename); 341 base::File::Info info; 342 ASSERT_TRUE(base::GetFileInfo(path, &info)); 343 int64 base_size = info.size; 344 345 // Write some large cookies, so the DB will have to expand by several KB. 346 for (char c = 'a'; c < 'z'; ++c) { 347 // Each cookie needs a unique timestamp for creation_utc (see DB schema). 348 base::Time t = base::Time::Now() + base::TimeDelta::FromMicroseconds(c); 349 std::string name(1, c); 350 std::string value(1000, c); 351 AddCookie(name, value, "foo.bar", "/", t); 352 } 353 354 Flush(); 355 356 // We forced a write, so now the file will be bigger. 357 ASSERT_TRUE(base::GetFileInfo(path, &info)); 358 ASSERT_GT(info.size, base_size); 359 } 360 361 // Test loading old session cookies from the disk. 362 TEST_F(SQLitePersistentCookieStoreTest, TestLoadOldSessionCookies) { 363 InitializeStore(false, true); 364 365 // Add a session cookie. 366 store_->AddCookie( 367 net::CanonicalCookie( 368 GURL(), "C", "D", "sessioncookie.com", "/", base::Time::Now(), 369 base::Time(), base::Time::Now(), false, false, 370 net::COOKIE_PRIORITY_DEFAULT)); 371 372 // Force the store to write its data to the disk. 373 DestroyStore(); 374 375 // Create a store that loads session cookies and test that the session cookie 376 // was loaded. 377 CanonicalCookieVector cookies; 378 CreateAndLoad(false, true, &cookies); 379 380 ASSERT_EQ(1U, cookies.size()); 381 ASSERT_STREQ("sessioncookie.com", cookies[0]->Domain().c_str()); 382 ASSERT_STREQ("C", cookies[0]->Name().c_str()); 383 ASSERT_STREQ("D", cookies[0]->Value().c_str()); 384 ASSERT_EQ(net::COOKIE_PRIORITY_DEFAULT, cookies[0]->Priority()); 385 386 STLDeleteElements(&cookies); 387 } 388 389 // Test loading old session cookies from the disk. 390 TEST_F(SQLitePersistentCookieStoreTest, TestDontLoadOldSessionCookies) { 391 InitializeStore(false, true); 392 393 // Add a session cookie. 394 store_->AddCookie( 395 net::CanonicalCookie( 396 GURL(), "C", "D", "sessioncookie.com", "/", base::Time::Now(), 397 base::Time(), base::Time::Now(), false, false, 398 net::COOKIE_PRIORITY_DEFAULT)); 399 400 // Force the store to write its data to the disk. 401 DestroyStore(); 402 403 // Create a store that doesn't load old session cookies and test that the 404 // session cookie was not loaded. 405 CanonicalCookieVector cookies; 406 CreateAndLoad(false, false, &cookies); 407 ASSERT_EQ(0U, cookies.size()); 408 409 // The store should also delete the session cookie. Wait until that has been 410 // done. 411 DestroyStore(); 412 413 // Create a store that loads old session cookies and test that the session 414 // cookie is gone. 415 CreateAndLoad(false, true, &cookies); 416 ASSERT_EQ(0U, cookies.size()); 417 } 418 419 TEST_F(SQLitePersistentCookieStoreTest, PersistIsPersistent) { 420 InitializeStore(false, true); 421 static const char kSessionName[] = "session"; 422 static const char kPersistentName[] = "persistent"; 423 424 // Add a session cookie. 425 store_->AddCookie( 426 net::CanonicalCookie( 427 GURL(), kSessionName, "val", "sessioncookie.com", "/", 428 base::Time::Now(), base::Time(), base::Time::Now(), false, false, 429 net::COOKIE_PRIORITY_DEFAULT)); 430 // Add a persistent cookie. 431 store_->AddCookie( 432 net::CanonicalCookie( 433 GURL(), kPersistentName, "val", "sessioncookie.com", "/", 434 base::Time::Now() - base::TimeDelta::FromDays(1), 435 base::Time::Now() + base::TimeDelta::FromDays(1), 436 base::Time::Now(), false, false, 437 net::COOKIE_PRIORITY_DEFAULT)); 438 439 // Force the store to write its data to the disk. 440 DestroyStore(); 441 442 // Create a store that loads session cookie and test that the IsPersistent 443 // attribute is restored. 444 CanonicalCookieVector cookies; 445 CreateAndLoad(false, true, &cookies); 446 ASSERT_EQ(2U, cookies.size()); 447 448 std::map<std::string, net::CanonicalCookie*> cookie_map; 449 for (CanonicalCookieVector::const_iterator it = cookies.begin(); 450 it != cookies.end(); 451 ++it) { 452 cookie_map[(*it)->Name()] = *it; 453 } 454 455 std::map<std::string, net::CanonicalCookie*>::const_iterator it = 456 cookie_map.find(kSessionName); 457 ASSERT_TRUE(it != cookie_map.end()); 458 EXPECT_FALSE(cookie_map[kSessionName]->IsPersistent()); 459 460 it = cookie_map.find(kPersistentName); 461 ASSERT_TRUE(it != cookie_map.end()); 462 EXPECT_TRUE(cookie_map[kPersistentName]->IsPersistent()); 463 464 STLDeleteElements(&cookies); 465 } 466 467 TEST_F(SQLitePersistentCookieStoreTest, PriorityIsPersistent) { 468 static const char kLowName[] = "low"; 469 static const char kMediumName[] = "medium"; 470 static const char kHighName[] = "high"; 471 static const char kCookieDomain[] = "sessioncookie.com"; 472 static const char kCookieValue[] = "value"; 473 static const char kCookiePath[] = "/"; 474 475 InitializeStore(false, true); 476 477 // Add a low-priority persistent cookie. 478 store_->AddCookie( 479 net::CanonicalCookie( 480 GURL(), kLowName, kCookieValue, kCookieDomain, kCookiePath, 481 base::Time::Now() - base::TimeDelta::FromMinutes(1), 482 base::Time::Now() + base::TimeDelta::FromDays(1), 483 base::Time::Now(), false, false, 484 net::COOKIE_PRIORITY_LOW)); 485 486 // Add a medium-priority persistent cookie. 487 store_->AddCookie( 488 net::CanonicalCookie( 489 GURL(), kMediumName, kCookieValue, kCookieDomain, kCookiePath, 490 base::Time::Now() - base::TimeDelta::FromMinutes(2), 491 base::Time::Now() + base::TimeDelta::FromDays(1), 492 base::Time::Now(), false, false, 493 net::COOKIE_PRIORITY_MEDIUM)); 494 495 // Add a high-priority peristent cookie. 496 store_->AddCookie( 497 net::CanonicalCookie( 498 GURL(), kHighName, kCookieValue, kCookieDomain, kCookiePath, 499 base::Time::Now() - base::TimeDelta::FromMinutes(3), 500 base::Time::Now() + base::TimeDelta::FromDays(1), 501 base::Time::Now(), false, false, 502 net::COOKIE_PRIORITY_HIGH)); 503 504 // Force the store to write its data to the disk. 505 DestroyStore(); 506 507 // Create a store that loads session cookie and test that the priority 508 // attribute values are restored. 509 CanonicalCookieVector cookies; 510 CreateAndLoad(false, true, &cookies); 511 ASSERT_EQ(3U, cookies.size()); 512 513 // Put the cookies into a map, by name, so we can easily find them. 514 std::map<std::string, net::CanonicalCookie*> cookie_map; 515 for (CanonicalCookieVector::const_iterator it = cookies.begin(); 516 it != cookies.end(); 517 ++it) { 518 cookie_map[(*it)->Name()] = *it; 519 } 520 521 // Validate that each cookie has the correct priority. 522 std::map<std::string, net::CanonicalCookie*>::const_iterator it = 523 cookie_map.find(kLowName); 524 ASSERT_TRUE(it != cookie_map.end()); 525 EXPECT_EQ(net::COOKIE_PRIORITY_LOW, cookie_map[kLowName]->Priority()); 526 527 it = cookie_map.find(kMediumName); 528 ASSERT_TRUE(it != cookie_map.end()); 529 EXPECT_EQ(net::COOKIE_PRIORITY_MEDIUM, cookie_map[kMediumName]->Priority()); 530 531 it = cookie_map.find(kHighName); 532 ASSERT_TRUE(it != cookie_map.end()); 533 EXPECT_EQ(net::COOKIE_PRIORITY_HIGH, cookie_map[kHighName]->Priority()); 534 535 STLDeleteElements(&cookies); 536 } 537 538 TEST_F(SQLitePersistentCookieStoreTest, UpdateToEncryption) { 539 CanonicalCookieVector cookies; 540 541 // Create unencrypted cookie store and write something to it. 542 InitializeStore(false, false); 543 AddCookie("name", "value123XYZ", "foo.bar", "/", base::Time::Now()); 544 DestroyStore(); 545 546 // Verify that "value" is visible in the file. This is necessary in order to 547 // have confidence in a later test that "encrypted_value" is not visible. 548 std::string contents = ReadRawDBContents(); 549 EXPECT_NE(0U, contents.length()); 550 EXPECT_NE(contents.find("value123XYZ"), std::string::npos); 551 552 // Create encrypted cookie store and ensure old cookie still reads. 553 STLDeleteElements(&cookies_); 554 EXPECT_EQ(0U, cookies_.size()); 555 CreateAndLoad(true, false, &cookies); 556 EXPECT_EQ(1U, cookies_.size()); 557 EXPECT_EQ("name", cookies_[0]->Name()); 558 EXPECT_EQ("value123XYZ", cookies_[0]->Value()); 559 560 // Make sure we can update existing cookie and add new cookie as encrypted. 561 store_->DeleteCookie(*(cookies_[0])); 562 AddCookie("name", "encrypted_value123XYZ", "foo.bar", "/", base::Time::Now()); 563 AddCookie("other", "something456ABC", "foo.bar", "/", 564 base::Time::Now() + base::TimeDelta::FromInternalValue(10)); 565 DestroyStore(); 566 STLDeleteElements(&cookies_); 567 CreateAndLoad(true, false, &cookies); 568 EXPECT_EQ(2U, cookies_.size()); 569 net::CanonicalCookie* cookie_name = NULL; 570 net::CanonicalCookie* cookie_other = NULL; 571 if (cookies_[0]->Name() == "name") { 572 cookie_name = cookies_[0]; 573 cookie_other = cookies_[1]; 574 } else { 575 cookie_name = cookies_[1]; 576 cookie_other = cookies_[0]; 577 } 578 EXPECT_EQ("encrypted_value123XYZ", cookie_name->Value()); 579 EXPECT_EQ("something456ABC", cookie_other->Value()); 580 DestroyStore(); 581 STLDeleteElements(&cookies_); 582 583 // Examine the real record to make sure plaintext version doesn't exist. 584 sql::Connection db; 585 sql::Statement smt; 586 int resultcount = 0; 587 ASSERT_TRUE(db.Open(temp_dir_.path().Append(kCookieFilename))); 588 smt.Assign(db.GetCachedStatement(SQL_FROM_HERE, 589 "SELECT * " 590 "FROM cookies " 591 "WHERE host_key = 'foo.bar'")); 592 while (smt.Step()) { 593 resultcount++; 594 for (int i=0; i < smt.ColumnCount(); i++) { 595 EXPECT_EQ(smt.ColumnString(i).find("value"), std::string::npos); 596 EXPECT_EQ(smt.ColumnString(i).find("something"), std::string::npos); 597 } 598 } 599 EXPECT_EQ(2, resultcount); 600 601 // Verify that "encrypted_value" is NOT visible in the file. 602 contents = ReadRawDBContents(); 603 EXPECT_NE(0U, contents.length()); 604 EXPECT_EQ(contents.find("encrypted_value123XYZ"), std::string::npos); 605 EXPECT_EQ(contents.find("something456ABC"), std::string::npos); 606 } 607 608 } // namespace content 609