Home | History | Annotate | Download | only in net
      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