OLD | NEW |
| (Empty) |
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/files/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_store_factory.h" | |
23 #include "crypto/encryptor.h" | |
24 #include "crypto/symmetric_key.h" | |
25 #include "net/cookies/canonical_cookie.h" | |
26 #include "net/cookies/cookie_constants.h" | |
27 #include "net/extras/sqlite/cookie_crypto_delegate.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 net::CookieCryptoDelegate { | |
41 public: | |
42 CookieCryptor(); | |
43 bool EncryptString(const std::string& plaintext, | |
44 std::string* ciphertext) override; | |
45 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(net::CanonicalCookie( | |
163 GURL(), name, value, domain, path, creation, creation, creation, false, | |
164 false, false, net::COOKIE_PRIORITY_DEFAULT)); | |
165 } | |
166 | |
167 void AddCookieWithExpiration(const std::string& name, | |
168 const std::string& value, | |
169 const std::string& domain, | |
170 const std::string& path, | |
171 const base::Time& creation, | |
172 const base::Time& expiration) { | |
173 store_->AddCookie(net::CanonicalCookie( | |
174 GURL(), name, value, domain, path, creation, expiration, creation, | |
175 false, false, false, net::COOKIE_PRIORITY_DEFAULT)); | |
176 } | |
177 | |
178 std::string ReadRawDBContents() { | |
179 std::string contents; | |
180 if (!base::ReadFileToString(temp_dir_.path().Append(kCookieFilename), | |
181 &contents)) | |
182 return std::string(); | |
183 return contents; | |
184 } | |
185 | |
186 void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); } | |
187 | |
188 void TearDown() override { | |
189 DestroyStore(); | |
190 pool_owner_->pool()->Shutdown(); | |
191 } | |
192 | |
193 protected: | |
194 base::MessageLoop main_loop_; | |
195 scoped_ptr<base::SequencedWorkerPoolOwner> pool_owner_; | |
196 base::WaitableEvent loaded_event_; | |
197 base::WaitableEvent key_loaded_event_; | |
198 base::WaitableEvent db_thread_event_; | |
199 CanonicalCookieVector cookies_; | |
200 base::ScopedTempDir temp_dir_; | |
201 scoped_refptr<SQLitePersistentCookieStore> store_; | |
202 scoped_ptr<net::CookieCryptoDelegate> cookie_crypto_delegate_; | |
203 }; | |
204 | |
205 TEST_F(SQLitePersistentCookieStoreTest, TestInvalidMetaTableRecovery) { | |
206 InitializeStore(false, false); | |
207 AddCookie("A", "B", "foo.bar", "/", base::Time::Now()); | |
208 DestroyStore(); | |
209 | |
210 // Load up the store and verify that it has good data in it. | |
211 CanonicalCookieVector cookies; | |
212 CreateAndLoad(false, false, &cookies); | |
213 ASSERT_EQ(1U, cookies.size()); | |
214 ASSERT_STREQ("foo.bar", cookies[0]->Domain().c_str()); | |
215 ASSERT_STREQ("A", cookies[0]->Name().c_str()); | |
216 ASSERT_STREQ("B", cookies[0]->Value().c_str()); | |
217 DestroyStore(); | |
218 STLDeleteElements(&cookies); | |
219 | |
220 // Now corrupt the meta table. | |
221 { | |
222 sql::Connection db; | |
223 ASSERT_TRUE(db.Open(temp_dir_.path().Append(kCookieFilename))); | |
224 sql::MetaTable meta_table_; | |
225 meta_table_.Init(&db, 1, 1); | |
226 ASSERT_TRUE(db.Execute("DELETE FROM meta")); | |
227 db.Close(); | |
228 } | |
229 | |
230 // Upon loading, the database should be reset to a good, blank state. | |
231 CreateAndLoad(false, false, &cookies); | |
232 ASSERT_EQ(0U, cookies.size()); | |
233 | |
234 // Verify that, after, recovery, the database persists properly. | |
235 AddCookie("X", "Y", "foo.bar", "/", base::Time::Now()); | |
236 DestroyStore(); | |
237 CreateAndLoad(false, false, &cookies); | |
238 ASSERT_EQ(1U, cookies.size()); | |
239 ASSERT_STREQ("foo.bar", cookies[0]->Domain().c_str()); | |
240 ASSERT_STREQ("X", cookies[0]->Name().c_str()); | |
241 ASSERT_STREQ("Y", cookies[0]->Value().c_str()); | |
242 STLDeleteElements(&cookies); | |
243 } | |
244 | |
245 // Test if data is stored as expected in the SQLite database. | |
246 TEST_F(SQLitePersistentCookieStoreTest, TestPersistance) { | |
247 InitializeStore(false, false); | |
248 AddCookie("A", "B", "foo.bar", "/", base::Time::Now()); | |
249 // Replace the store effectively destroying the current one and forcing it | |
250 // to write its data to disk. Then we can see if after loading it again it | |
251 // is still there. | |
252 DestroyStore(); | |
253 // Reload and test for persistence | |
254 CanonicalCookieVector cookies; | |
255 CreateAndLoad(false, false, &cookies); | |
256 ASSERT_EQ(1U, cookies.size()); | |
257 ASSERT_STREQ("foo.bar", cookies[0]->Domain().c_str()); | |
258 ASSERT_STREQ("A", cookies[0]->Name().c_str()); | |
259 ASSERT_STREQ("B", cookies[0]->Value().c_str()); | |
260 | |
261 // Now delete the cookie and check persistence again. | |
262 store_->DeleteCookie(*cookies[0]); | |
263 DestroyStore(); | |
264 STLDeleteElements(&cookies); | |
265 | |
266 // Reload and check if the cookie has been removed. | |
267 CreateAndLoad(false, false, &cookies); | |
268 ASSERT_EQ(0U, cookies.size()); | |
269 } | |
270 | |
271 TEST_F(SQLitePersistentCookieStoreTest, TestSessionCookiesDeletedOnStartup) { | |
272 // Initialize the cookie store with 3 persistent cookies, 5 transient | |
273 // cookies. | |
274 InitializeStore(false, false); | |
275 | |
276 // Add persistent cookies. | |
277 base::Time t = base::Time::Now(); | |
278 AddCookie("A", "B", "a1.com", "/", t); | |
279 t += base::TimeDelta::FromInternalValue(10); | |
280 AddCookie("A", "B", "a2.com", "/", t); | |
281 t += base::TimeDelta::FromInternalValue(10); | |
282 AddCookie("A", "B", "a3.com", "/", t); | |
283 | |
284 // Add transient cookies. | |
285 t += base::TimeDelta::FromInternalValue(10); | |
286 AddCookieWithExpiration("A", "B", "b1.com", "/", t, base::Time()); | |
287 t += base::TimeDelta::FromInternalValue(10); | |
288 AddCookieWithExpiration("A", "B", "b2.com", "/", t, base::Time()); | |
289 t += base::TimeDelta::FromInternalValue(10); | |
290 AddCookieWithExpiration("A", "B", "b3.com", "/", t, base::Time()); | |
291 t += base::TimeDelta::FromInternalValue(10); | |
292 AddCookieWithExpiration("A", "B", "b4.com", "/", t, base::Time()); | |
293 t += base::TimeDelta::FromInternalValue(10); | |
294 AddCookieWithExpiration("A", "B", "b5.com", "/", t, base::Time()); | |
295 DestroyStore(); | |
296 | |
297 // Load the store a second time. Before the store finishes loading, add a | |
298 // transient cookie and flush it to disk. | |
299 store_ = new SQLitePersistentCookieStore( | |
300 temp_dir_.path().Append(kCookieFilename), | |
301 client_task_runner(), | |
302 background_task_runner(), | |
303 false, NULL, NULL); | |
304 | |
305 // Posting a blocking task to db_thread_ makes sure that the DB thread waits | |
306 // until both Load and Flush have been posted to its task queue. | |
307 background_task_runner()->PostTask( | |
308 FROM_HERE, | |
309 base::Bind(&SQLitePersistentCookieStoreTest::WaitOnDBEvent, | |
310 base::Unretained(this))); | |
311 store_->Load(base::Bind(&SQLitePersistentCookieStoreTest::OnLoaded, | |
312 base::Unretained(this))); | |
313 t += base::TimeDelta::FromInternalValue(10); | |
314 AddCookieWithExpiration("A", "B", "c.com", "/", t, base::Time()); | |
315 base::WaitableEvent event(false, false); | |
316 store_->Flush(base::Bind(&base::WaitableEvent::Signal, | |
317 base::Unretained(&event))); | |
318 | |
319 // Now the DB-thread queue contains: | |
320 // (active:) | |
321 // 1. Wait (on db_event) | |
322 // (pending:) | |
323 // 2. "Init And Chain-Load First Domain" | |
324 // 3. Add Cookie (c.com) | |
325 // 4. Flush Cookie (c.com) | |
326 db_thread_event_.Signal(); | |
327 event.Wait(); | |
328 loaded_event_.Wait(); | |
329 STLDeleteElements(&cookies_); | |
330 DestroyStore(); | |
331 | |
332 // Load the store a third time, this time restoring session cookies. The | |
333 // store should contain exactly 4 cookies: the 3 persistent, and "c.com", | |
334 // which was added during the second cookie store load. | |
335 store_ = new SQLitePersistentCookieStore( | |
336 temp_dir_.path().Append(kCookieFilename), | |
337 client_task_runner(), | |
338 background_task_runner(), | |
339 true, NULL, NULL); | |
340 store_->Load(base::Bind(&SQLitePersistentCookieStoreTest::OnLoaded, | |
341 base::Unretained(this))); | |
342 loaded_event_.Wait(); | |
343 ASSERT_EQ(4u, cookies_.size()); | |
344 STLDeleteElements(&cookies_); | |
345 } | |
346 | |
347 // Test that priority load of cookies for a specfic domain key could be | |
348 // completed before the entire store is loaded | |
349 TEST_F(SQLitePersistentCookieStoreTest, TestLoadCookiesForKey) { | |
350 InitializeStore(false, false); | |
351 base::Time t = base::Time::Now(); | |
352 AddCookie("A", "B", "foo.bar", "/", t); | |
353 t += base::TimeDelta::FromInternalValue(10); | |
354 AddCookie("A", "B", "www.aaa.com", "/", t); | |
355 t += base::TimeDelta::FromInternalValue(10); | |
356 AddCookie("A", "B", "travel.aaa.com", "/", t); | |
357 t += base::TimeDelta::FromInternalValue(10); | |
358 AddCookie("A", "B", "www.bbb.com", "/", t); | |
359 DestroyStore(); | |
360 | |
361 store_ = new SQLitePersistentCookieStore( | |
362 temp_dir_.path().Append(kCookieFilename), | |
363 client_task_runner(), | |
364 background_task_runner(), | |
365 false, NULL, NULL); | |
366 | |
367 // Posting a blocking task to db_thread_ makes sure that the DB thread waits | |
368 // until both Load and LoadCookiesForKey have been posted to its task queue. | |
369 background_task_runner()->PostTask( | |
370 FROM_HERE, | |
371 base::Bind(&SQLitePersistentCookieStoreTest::WaitOnDBEvent, | |
372 base::Unretained(this))); | |
373 store_->Load(base::Bind(&SQLitePersistentCookieStoreTest::OnLoaded, | |
374 base::Unretained(this))); | |
375 store_->LoadCookiesForKey("aaa.com", | |
376 base::Bind(&SQLitePersistentCookieStoreTest::OnKeyLoaded, | |
377 base::Unretained(this))); | |
378 background_task_runner()->PostTask( | |
379 FROM_HERE, | |
380 base::Bind(&SQLitePersistentCookieStoreTest::WaitOnDBEvent, | |
381 base::Unretained(this))); | |
382 | |
383 // Now the DB-thread queue contains: | |
384 // (active:) | |
385 // 1. Wait (on db_event) | |
386 // (pending:) | |
387 // 2. "Init And Chain-Load First Domain" | |
388 // 3. Priority Load (aaa.com) | |
389 // 4. Wait (on db_event) | |
390 db_thread_event_.Signal(); | |
391 key_loaded_event_.Wait(); | |
392 ASSERT_EQ(loaded_event_.IsSignaled(), false); | |
393 std::set<std::string> cookies_loaded; | |
394 for (CanonicalCookieVector::const_iterator it = cookies_.begin(); | |
395 it != cookies_.end(); | |
396 ++it) { | |
397 cookies_loaded.insert((*it)->Domain().c_str()); | |
398 } | |
399 STLDeleteElements(&cookies_); | |
400 ASSERT_GT(4U, cookies_loaded.size()); | |
401 ASSERT_EQ(true, cookies_loaded.find("www.aaa.com") != cookies_loaded.end()); | |
402 ASSERT_EQ(true, | |
403 cookies_loaded.find("travel.aaa.com") != cookies_loaded.end()); | |
404 | |
405 db_thread_event_.Signal(); | |
406 loaded_event_.Wait(); | |
407 for (CanonicalCookieVector::const_iterator it = cookies_.begin(); | |
408 it != cookies_.end(); | |
409 ++it) { | |
410 cookies_loaded.insert((*it)->Domain().c_str()); | |
411 } | |
412 ASSERT_EQ(4U, cookies_loaded.size()); | |
413 ASSERT_EQ(cookies_loaded.find("foo.bar") != cookies_loaded.end(), | |
414 true); | |
415 ASSERT_EQ(cookies_loaded.find("www.bbb.com") != cookies_loaded.end(), true); | |
416 STLDeleteElements(&cookies_); | |
417 } | |
418 | |
419 // Test that we can force the database to be written by calling Flush(). | |
420 TEST_F(SQLitePersistentCookieStoreTest, TestFlush) { | |
421 InitializeStore(false, false); | |
422 // File timestamps don't work well on all platforms, so we'll determine | |
423 // whether the DB file has been modified by checking its size. | |
424 base::FilePath path = temp_dir_.path().Append(kCookieFilename); | |
425 base::File::Info info; | |
426 ASSERT_TRUE(base::GetFileInfo(path, &info)); | |
427 int64 base_size = info.size; | |
428 | |
429 // Write some large cookies, so the DB will have to expand by several KB. | |
430 for (char c = 'a'; c < 'z'; ++c) { | |
431 // Each cookie needs a unique timestamp for creation_utc (see DB schema). | |
432 base::Time t = base::Time::Now() + base::TimeDelta::FromMicroseconds(c); | |
433 std::string name(1, c); | |
434 std::string value(1000, c); | |
435 AddCookie(name, value, "foo.bar", "/", t); | |
436 } | |
437 | |
438 Flush(); | |
439 | |
440 // We forced a write, so now the file will be bigger. | |
441 ASSERT_TRUE(base::GetFileInfo(path, &info)); | |
442 ASSERT_GT(info.size, base_size); | |
443 } | |
444 | |
445 // Test loading old session cookies from the disk. | |
446 TEST_F(SQLitePersistentCookieStoreTest, TestLoadOldSessionCookies) { | |
447 InitializeStore(false, true); | |
448 | |
449 // Add a session cookie. | |
450 store_->AddCookie(net::CanonicalCookie(GURL(), "C", "D", "sessioncookie.com", | |
451 "/", base::Time::Now(), base::Time(), | |
452 base::Time::Now(), false, false, false, | |
453 net::COOKIE_PRIORITY_DEFAULT)); | |
454 | |
455 // Force the store to write its data to the disk. | |
456 DestroyStore(); | |
457 | |
458 // Create a store that loads session cookies and test that the session cookie | |
459 // was loaded. | |
460 CanonicalCookieVector cookies; | |
461 CreateAndLoad(false, true, &cookies); | |
462 | |
463 ASSERT_EQ(1U, cookies.size()); | |
464 ASSERT_STREQ("sessioncookie.com", cookies[0]->Domain().c_str()); | |
465 ASSERT_STREQ("C", cookies[0]->Name().c_str()); | |
466 ASSERT_STREQ("D", cookies[0]->Value().c_str()); | |
467 ASSERT_EQ(net::COOKIE_PRIORITY_DEFAULT, cookies[0]->Priority()); | |
468 | |
469 STLDeleteElements(&cookies); | |
470 } | |
471 | |
472 // Test loading old session cookies from the disk. | |
473 TEST_F(SQLitePersistentCookieStoreTest, TestDontLoadOldSessionCookies) { | |
474 InitializeStore(false, true); | |
475 | |
476 // Add a session cookie. | |
477 store_->AddCookie(net::CanonicalCookie(GURL(), "C", "D", "sessioncookie.com", | |
478 "/", base::Time::Now(), base::Time(), | |
479 base::Time::Now(), false, false, false, | |
480 net::COOKIE_PRIORITY_DEFAULT)); | |
481 | |
482 // Force the store to write its data to the disk. | |
483 DestroyStore(); | |
484 | |
485 // Create a store that doesn't load old session cookies and test that the | |
486 // session cookie was not loaded. | |
487 CanonicalCookieVector cookies; | |
488 CreateAndLoad(false, false, &cookies); | |
489 ASSERT_EQ(0U, cookies.size()); | |
490 | |
491 // The store should also delete the session cookie. Wait until that has been | |
492 // done. | |
493 DestroyStore(); | |
494 | |
495 // Create a store that loads old session cookies and test that the session | |
496 // cookie is gone. | |
497 CreateAndLoad(false, true, &cookies); | |
498 ASSERT_EQ(0U, cookies.size()); | |
499 } | |
500 | |
501 TEST_F(SQLitePersistentCookieStoreTest, PersistIsPersistent) { | |
502 InitializeStore(false, true); | |
503 static const char kSessionName[] = "session"; | |
504 static const char kPersistentName[] = "persistent"; | |
505 | |
506 // Add a session cookie. | |
507 store_->AddCookie(net::CanonicalCookie( | |
508 GURL(), kSessionName, "val", "sessioncookie.com", "/", base::Time::Now(), | |
509 base::Time(), base::Time::Now(), false, false, false, | |
510 net::COOKIE_PRIORITY_DEFAULT)); | |
511 // Add a persistent cookie. | |
512 store_->AddCookie(net::CanonicalCookie( | |
513 GURL(), kPersistentName, "val", "sessioncookie.com", "/", | |
514 base::Time::Now() - base::TimeDelta::FromDays(1), | |
515 base::Time::Now() + base::TimeDelta::FromDays(1), base::Time::Now(), | |
516 false, false, false, net::COOKIE_PRIORITY_DEFAULT)); | |
517 | |
518 // Force the store to write its data to the disk. | |
519 DestroyStore(); | |
520 | |
521 // Create a store that loads session cookie and test that the IsPersistent | |
522 // attribute is restored. | |
523 CanonicalCookieVector cookies; | |
524 CreateAndLoad(false, true, &cookies); | |
525 ASSERT_EQ(2U, cookies.size()); | |
526 | |
527 std::map<std::string, net::CanonicalCookie*> cookie_map; | |
528 for (CanonicalCookieVector::const_iterator it = cookies.begin(); | |
529 it != cookies.end(); | |
530 ++it) { | |
531 cookie_map[(*it)->Name()] = *it; | |
532 } | |
533 | |
534 std::map<std::string, net::CanonicalCookie*>::const_iterator it = | |
535 cookie_map.find(kSessionName); | |
536 ASSERT_TRUE(it != cookie_map.end()); | |
537 EXPECT_FALSE(cookie_map[kSessionName]->IsPersistent()); | |
538 | |
539 it = cookie_map.find(kPersistentName); | |
540 ASSERT_TRUE(it != cookie_map.end()); | |
541 EXPECT_TRUE(cookie_map[kPersistentName]->IsPersistent()); | |
542 | |
543 STLDeleteElements(&cookies); | |
544 } | |
545 | |
546 TEST_F(SQLitePersistentCookieStoreTest, PriorityIsPersistent) { | |
547 static const char kLowName[] = "low"; | |
548 static const char kMediumName[] = "medium"; | |
549 static const char kHighName[] = "high"; | |
550 static const char kCookieDomain[] = "sessioncookie.com"; | |
551 static const char kCookieValue[] = "value"; | |
552 static const char kCookiePath[] = "/"; | |
553 | |
554 InitializeStore(false, true); | |
555 | |
556 // Add a low-priority persistent cookie. | |
557 store_->AddCookie(net::CanonicalCookie( | |
558 GURL(), kLowName, kCookieValue, kCookieDomain, kCookiePath, | |
559 base::Time::Now() - base::TimeDelta::FromMinutes(1), | |
560 base::Time::Now() + base::TimeDelta::FromDays(1), base::Time::Now(), | |
561 false, false, false, net::COOKIE_PRIORITY_LOW)); | |
562 | |
563 // Add a medium-priority persistent cookie. | |
564 store_->AddCookie(net::CanonicalCookie( | |
565 GURL(), kMediumName, kCookieValue, kCookieDomain, kCookiePath, | |
566 base::Time::Now() - base::TimeDelta::FromMinutes(2), | |
567 base::Time::Now() + base::TimeDelta::FromDays(1), base::Time::Now(), | |
568 false, false, false, net::COOKIE_PRIORITY_MEDIUM)); | |
569 | |
570 // Add a high-priority peristent cookie. | |
571 store_->AddCookie(net::CanonicalCookie( | |
572 GURL(), kHighName, kCookieValue, kCookieDomain, kCookiePath, | |
573 base::Time::Now() - base::TimeDelta::FromMinutes(3), | |
574 base::Time::Now() + base::TimeDelta::FromDays(1), base::Time::Now(), | |
575 false, false, false, net::COOKIE_PRIORITY_HIGH)); | |
576 | |
577 // Force the store to write its data to the disk. | |
578 DestroyStore(); | |
579 | |
580 // Create a store that loads session cookie and test that the priority | |
581 // attribute values are restored. | |
582 CanonicalCookieVector cookies; | |
583 CreateAndLoad(false, true, &cookies); | |
584 ASSERT_EQ(3U, cookies.size()); | |
585 | |
586 // Put the cookies into a map, by name, so we can easily find them. | |
587 std::map<std::string, net::CanonicalCookie*> cookie_map; | |
588 for (CanonicalCookieVector::const_iterator it = cookies.begin(); | |
589 it != cookies.end(); | |
590 ++it) { | |
591 cookie_map[(*it)->Name()] = *it; | |
592 } | |
593 | |
594 // Validate that each cookie has the correct priority. | |
595 std::map<std::string, net::CanonicalCookie*>::const_iterator it = | |
596 cookie_map.find(kLowName); | |
597 ASSERT_TRUE(it != cookie_map.end()); | |
598 EXPECT_EQ(net::COOKIE_PRIORITY_LOW, cookie_map[kLowName]->Priority()); | |
599 | |
600 it = cookie_map.find(kMediumName); | |
601 ASSERT_TRUE(it != cookie_map.end()); | |
602 EXPECT_EQ(net::COOKIE_PRIORITY_MEDIUM, cookie_map[kMediumName]->Priority()); | |
603 | |
604 it = cookie_map.find(kHighName); | |
605 ASSERT_TRUE(it != cookie_map.end()); | |
606 EXPECT_EQ(net::COOKIE_PRIORITY_HIGH, cookie_map[kHighName]->Priority()); | |
607 | |
608 STLDeleteElements(&cookies); | |
609 } | |
610 | |
611 TEST_F(SQLitePersistentCookieStoreTest, UpdateToEncryption) { | |
612 CanonicalCookieVector cookies; | |
613 | |
614 // Create unencrypted cookie store and write something to it. | |
615 InitializeStore(false, false); | |
616 AddCookie("name", "value123XYZ", "foo.bar", "/", base::Time::Now()); | |
617 DestroyStore(); | |
618 | |
619 // Verify that "value" is visible in the file. This is necessary in order to | |
620 // have confidence in a later test that "encrypted_value" is not visible. | |
621 std::string contents = ReadRawDBContents(); | |
622 EXPECT_NE(0U, contents.length()); | |
623 EXPECT_NE(contents.find("value123XYZ"), std::string::npos); | |
624 | |
625 // Create encrypted cookie store and ensure old cookie still reads. | |
626 STLDeleteElements(&cookies_); | |
627 EXPECT_EQ(0U, cookies_.size()); | |
628 CreateAndLoad(true, false, &cookies); | |
629 EXPECT_EQ(1U, cookies_.size()); | |
630 EXPECT_EQ("name", cookies_[0]->Name()); | |
631 EXPECT_EQ("value123XYZ", cookies_[0]->Value()); | |
632 | |
633 // Make sure we can update existing cookie and add new cookie as encrypted. | |
634 store_->DeleteCookie(*(cookies_[0])); | |
635 AddCookie("name", "encrypted_value123XYZ", "foo.bar", "/", base::Time::Now()); | |
636 AddCookie("other", "something456ABC", "foo.bar", "/", | |
637 base::Time::Now() + base::TimeDelta::FromInternalValue(10)); | |
638 DestroyStore(); | |
639 STLDeleteElements(&cookies_); | |
640 CreateAndLoad(true, false, &cookies); | |
641 EXPECT_EQ(2U, cookies_.size()); | |
642 net::CanonicalCookie* cookie_name = NULL; | |
643 net::CanonicalCookie* cookie_other = NULL; | |
644 if (cookies_[0]->Name() == "name") { | |
645 cookie_name = cookies_[0]; | |
646 cookie_other = cookies_[1]; | |
647 } else { | |
648 cookie_name = cookies_[1]; | |
649 cookie_other = cookies_[0]; | |
650 } | |
651 EXPECT_EQ("encrypted_value123XYZ", cookie_name->Value()); | |
652 EXPECT_EQ("something456ABC", cookie_other->Value()); | |
653 DestroyStore(); | |
654 STLDeleteElements(&cookies_); | |
655 | |
656 // Examine the real record to make sure plaintext version doesn't exist. | |
657 sql::Connection db; | |
658 sql::Statement smt; | |
659 int resultcount = 0; | |
660 ASSERT_TRUE(db.Open(temp_dir_.path().Append(kCookieFilename))); | |
661 smt.Assign(db.GetCachedStatement(SQL_FROM_HERE, | |
662 "SELECT * " | |
663 "FROM cookies " | |
664 "WHERE host_key = 'foo.bar'")); | |
665 while (smt.Step()) { | |
666 resultcount++; | |
667 for (int i=0; i < smt.ColumnCount(); i++) { | |
668 EXPECT_EQ(smt.ColumnString(i).find("value"), std::string::npos); | |
669 EXPECT_EQ(smt.ColumnString(i).find("something"), std::string::npos); | |
670 } | |
671 } | |
672 EXPECT_EQ(2, resultcount); | |
673 | |
674 // Verify that "encrypted_value" is NOT visible in the file. | |
675 contents = ReadRawDBContents(); | |
676 EXPECT_NE(0U, contents.length()); | |
677 EXPECT_EQ(contents.find("encrypted_value123XYZ"), std::string::npos); | |
678 EXPECT_EQ(contents.find("something456ABC"), std::string::npos); | |
679 } | |
680 | |
681 } // namespace content | |
OLD | NEW |