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