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