OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Portions of this code based on Mozilla: | 5 // Portions of this code based on Mozilla: |
6 // (netwerk/cookie/src/nsCookieService.cpp) | 6 // (netwerk/cookie/src/nsCookieService.cpp) |
7 /* ***** BEGIN LICENSE BLOCK ***** | 7 /* ***** BEGIN LICENSE BLOCK ***** |
8 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 | 8 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
9 * | 9 * |
10 * The contents of this file are subject to the Mozilla Public License Version | 10 * The contents of this file are subject to the Mozilla Public License Version |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
48 #include <functional> | 48 #include <functional> |
49 #include <set> | 49 #include <set> |
50 | 50 |
51 #include "base/basictypes.h" | 51 #include "base/basictypes.h" |
52 #include "base/bind.h" | 52 #include "base/bind.h" |
53 #include "base/callback.h" | 53 #include "base/callback.h" |
54 #include "base/logging.h" | 54 #include "base/logging.h" |
55 #include "base/memory/scoped_ptr.h" | 55 #include "base/memory/scoped_ptr.h" |
56 #include "base/message_loop/message_loop.h" | 56 #include "base/message_loop/message_loop.h" |
57 #include "base/message_loop/message_loop_proxy.h" | 57 #include "base/message_loop/message_loop_proxy.h" |
| 58 #include "base/metrics/field_trial.h" |
58 #include "base/metrics/histogram.h" | 59 #include "base/metrics/histogram.h" |
59 #include "base/profiler/scoped_tracker.h" | 60 #include "base/profiler/scoped_tracker.h" |
60 #include "base/strings/string_util.h" | 61 #include "base/strings/string_util.h" |
61 #include "base/strings/stringprintf.h" | 62 #include "base/strings/stringprintf.h" |
62 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" | 63 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
63 #include "net/cookies/canonical_cookie.h" | 64 #include "net/cookies/canonical_cookie.h" |
64 #include "net/cookies/cookie_util.h" | 65 #include "net/cookies/cookie_util.h" |
65 #include "net/cookies/parsed_cookie.h" | 66 #include "net/cookies/parsed_cookie.h" |
66 | 67 |
67 using base::Time; | 68 using base::Time; |
68 using base::TimeDelta; | 69 using base::TimeDelta; |
69 using base::TimeTicks; | 70 using base::TimeTicks; |
70 | 71 |
71 // In steady state, most cookie requests can be satisfied by the in memory | 72 // In steady state, most cookie requests can be satisfied by the in memory |
72 // cookie monster store. However, if a request comes in during the initial | 73 // cookie monster store. If the cookie request cannot be satisfied by the in |
73 // cookie load, it must be delayed until that load completes. That is done by | 74 // memory store, the relevant cookies must be fetched from the persistent |
74 // queueing it on CookieMonster::tasks_pending_ and running it when notification | 75 // store. The task is queued in CookieMonster::tasks_pending_ if it requires |
75 // of cookie load completion is received via CookieMonster::OnLoaded. This | 76 // all cookies to be loaded from the backend, or tasks_pending_for_key_ if it |
76 // callback is passed to the persistent store from CookieMonster::InitStore(), | 77 // only requires all cookies associated with an eTLD+1. |
77 // which is called on the first operation invoked on the CookieMonster. | |
78 // | 78 // |
79 // On the browser critical paths (e.g. for loading initial web pages in a | 79 // On the browser critical paths (e.g. for loading initial web pages in a |
80 // session restore) it may take too long to wait for the full load. If a cookie | 80 // session restore) it may take too long to wait for the full load. If a cookie |
81 // request is for a specific URL, DoCookieTaskForURL is called, which triggers a | 81 // request is for a specific URL, DoCookieTaskForURL is called, which triggers a |
82 // priority load if the key is not loaded yet by calling PersistentCookieStore | 82 // priority load if the key is not loaded yet by calling PersistentCookieStore |
83 // :: LoadCookiesForKey. The request is queued in | 83 // :: LoadCookiesForKey. The request is queued in |
84 // CookieMonster::tasks_pending_for_key_ and executed upon receiving | 84 // CookieMonster::tasks_pending_for_key_ and executed upon receiving |
85 // notification of key load completion via CookieMonster::OnKeyLoaded(). If | 85 // notification of key load completion via CookieMonster::OnKeyLoaded(). If |
86 // multiple requests for the same eTLD+1 are received before key load | 86 // multiple requests for the same eTLD+1 are received before key load |
87 // completion, only the first request calls | 87 // completion, only the first request calls |
88 // PersistentCookieStore::LoadCookiesForKey, all subsequent requests are queued | 88 // PersistentCookieStore::LoadCookiesForKey, all subsequent requests are queued |
89 // in CookieMonster::tasks_pending_for_key_ and executed upon receiving | 89 // in CookieMonster::tasks_pending_for_key_ and executed upon receiving |
90 // notification of key load completion triggered by the first request for the | 90 // notification of key load completion triggered by the first request for the |
91 // same eTLD+1. | 91 // same eTLD+1. |
92 | 92 |
93 static const int kMinutesInTenYears = 10 * 365 * 24 * 60; | 93 static const int kMinutesInTenYears = 10 * 365 * 24 * 60; |
94 | 94 |
| 95 namespace { |
| 96 |
| 97 const char kFetchWhenNecessaryName[] = "FetchWhenNecessary"; |
| 98 const char kAlwaysFetchName[] = "AlwaysFetch"; |
| 99 const char kCookieMonsterFetchStrategyName[] = "CookieMonsterFetchStrategy"; |
| 100 |
| 101 } // namespace |
| 102 |
95 namespace net { | 103 namespace net { |
96 | 104 |
97 // See comments at declaration of these variables in cookie_monster.h | 105 // See comments at declaration of these variables in cookie_monster.h |
98 // for details. | 106 // for details. |
99 const size_t CookieMonster::kDomainMaxCookies = 180; | 107 const size_t CookieMonster::kDomainMaxCookies = 180; |
100 const size_t CookieMonster::kDomainPurgeCookies = 30; | 108 const size_t CookieMonster::kDomainPurgeCookies = 30; |
101 const size_t CookieMonster::kMaxCookies = 3300; | 109 const size_t CookieMonster::kMaxCookies = 3300; |
102 const size_t CookieMonster::kPurgeCookies = 300; | 110 const size_t CookieMonster::kPurgeCookies = 300; |
103 | 111 |
104 const size_t CookieMonster::kDomainCookiesQuotaLow = 30; | 112 const size_t CookieMonster::kDomainCookiesQuotaLow = 30; |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
322 const CanonicalCookie& cookie, | 330 const CanonicalCookie& cookie, |
323 bool removed) { | 331 bool removed) { |
324 proxy->PostTask(FROM_HERE, base::Bind(callback, cookie, removed)); | 332 proxy->PostTask(FROM_HERE, base::Bind(callback, cookie, removed)); |
325 } | 333 } |
326 | 334 |
327 } // namespace | 335 } // namespace |
328 | 336 |
329 CookieMonster::CookieMonster(PersistentCookieStore* store, | 337 CookieMonster::CookieMonster(PersistentCookieStore* store, |
330 CookieMonsterDelegate* delegate) | 338 CookieMonsterDelegate* delegate) |
331 : initialized_(false), | 339 : initialized_(false), |
332 loaded_(false), | 340 started_fetching_all_cookies_(false), |
| 341 finished_fetching_all_cookies_(false), |
| 342 fetch_strategy_(kUnknownFetch), |
333 store_(store), | 343 store_(store), |
334 last_access_threshold_( | 344 last_access_threshold_( |
335 TimeDelta::FromSeconds(kDefaultAccessUpdateThresholdSeconds)), | 345 TimeDelta::FromSeconds(kDefaultAccessUpdateThresholdSeconds)), |
336 delegate_(delegate), | 346 delegate_(delegate), |
337 last_statistic_record_time_(Time::Now()), | 347 last_statistic_record_time_(Time::Now()), |
338 keep_expired_cookies_(false), | 348 keep_expired_cookies_(false), |
339 persist_session_cookies_(false) { | 349 persist_session_cookies_(false) { |
340 InitializeHistograms(); | 350 InitializeHistograms(); |
341 SetDefaultCookieableSchemes(); | 351 SetDefaultCookieableSchemes(); |
342 } | 352 } |
343 | 353 |
344 CookieMonster::CookieMonster(PersistentCookieStore* store, | 354 CookieMonster::CookieMonster(PersistentCookieStore* store, |
345 CookieMonsterDelegate* delegate, | 355 CookieMonsterDelegate* delegate, |
346 int last_access_threshold_milliseconds) | 356 int last_access_threshold_milliseconds) |
347 : initialized_(false), | 357 : initialized_(false), |
348 loaded_(false), | 358 started_fetching_all_cookies_(false), |
| 359 finished_fetching_all_cookies_(false), |
| 360 fetch_strategy_(kUnknownFetch), |
349 store_(store), | 361 store_(store), |
350 last_access_threshold_(base::TimeDelta::FromMilliseconds( | 362 last_access_threshold_(base::TimeDelta::FromMilliseconds( |
351 last_access_threshold_milliseconds)), | 363 last_access_threshold_milliseconds)), |
352 delegate_(delegate), | 364 delegate_(delegate), |
353 last_statistic_record_time_(base::Time::Now()), | 365 last_statistic_record_time_(base::Time::Now()), |
354 keep_expired_cookies_(false), | 366 keep_expired_cookies_(false), |
355 persist_session_cookies_(false) { | 367 persist_session_cookies_(false) { |
356 InitializeHistograms(); | 368 InitializeHistograms(); |
357 SetDefaultCookieableSchemes(); | 369 SetDefaultCookieableSchemes(); |
358 } | 370 } |
(...skipping 725 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1084 scoped_refptr<DeleteSessionCookiesTask> task = | 1096 scoped_refptr<DeleteSessionCookiesTask> task = |
1085 new DeleteSessionCookiesTask(this, callback); | 1097 new DeleteSessionCookiesTask(this, callback); |
1086 | 1098 |
1087 DoCookieTask(task); | 1099 DoCookieTask(task); |
1088 } | 1100 } |
1089 | 1101 |
1090 void CookieMonster::DoCookieTask( | 1102 void CookieMonster::DoCookieTask( |
1091 const scoped_refptr<CookieMonsterTask>& task_item) { | 1103 const scoped_refptr<CookieMonsterTask>& task_item) { |
1092 { | 1104 { |
1093 base::AutoLock autolock(lock_); | 1105 base::AutoLock autolock(lock_); |
1094 InitIfNecessary(); | 1106 MarkCookieStoreAsInitialized(); |
1095 if (!loaded_) { | 1107 FetchAllCookiesIfNecessary(); |
| 1108 if (!finished_fetching_all_cookies_ && store_.get()) { |
1096 tasks_pending_.push(task_item); | 1109 tasks_pending_.push(task_item); |
1097 return; | 1110 return; |
1098 } | 1111 } |
1099 } | 1112 } |
1100 | 1113 |
1101 task_item->Run(); | 1114 task_item->Run(); |
1102 } | 1115 } |
1103 | 1116 |
1104 void CookieMonster::DoCookieTaskForURL( | 1117 void CookieMonster::DoCookieTaskForURL( |
1105 const scoped_refptr<CookieMonsterTask>& task_item, | 1118 const scoped_refptr<CookieMonsterTask>& task_item, |
1106 const GURL& url) { | 1119 const GURL& url) { |
1107 { | 1120 { |
1108 base::AutoLock autolock(lock_); | 1121 base::AutoLock autolock(lock_); |
1109 InitIfNecessary(); | 1122 MarkCookieStoreAsInitialized(); |
| 1123 if (ShouldFetchAllCookiesWhenFetchingAnyCookie()) |
| 1124 FetchAllCookiesIfNecessary(); |
1110 // If cookies for the requested domain key (eTLD+1) have been loaded from DB | 1125 // If cookies for the requested domain key (eTLD+1) have been loaded from DB |
1111 // then run the task, otherwise load from DB. | 1126 // then run the task, otherwise load from DB. |
1112 if (!loaded_) { | 1127 if (!finished_fetching_all_cookies_ && store_.get()) { |
1113 // Checks if the domain key has been loaded. | 1128 // Checks if the domain key has been loaded. |
1114 std::string key( | 1129 std::string key( |
1115 cookie_util::GetEffectiveDomain(url.scheme(), url.host())); | 1130 cookie_util::GetEffectiveDomain(url.scheme(), url.host())); |
1116 if (keys_loaded_.find(key) == keys_loaded_.end()) { | 1131 if (keys_loaded_.find(key) == keys_loaded_.end()) { |
1117 std::map<std::string, | 1132 std::map<std::string, |
1118 std::deque<scoped_refptr<CookieMonsterTask>>>::iterator it = | 1133 std::deque<scoped_refptr<CookieMonsterTask>>>::iterator it = |
1119 tasks_pending_for_key_.find(key); | 1134 tasks_pending_for_key_.find(key); |
1120 if (it == tasks_pending_for_key_.end()) { | 1135 if (it == tasks_pending_for_key_.end()) { |
1121 store_->LoadCookiesForKey( | 1136 store_->LoadCookiesForKey( |
1122 key, base::Bind(&CookieMonster::OnKeyLoaded, this, key)); | 1137 key, base::Bind(&CookieMonster::OnKeyLoaded, this, key)); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1160 return false; | 1175 return false; |
1161 | 1176 |
1162 CookieOptions options; | 1177 CookieOptions options; |
1163 options.set_include_httponly(); | 1178 options.set_include_httponly(); |
1164 options.set_include_first_party_only(); | 1179 options.set_include_first_party_only(); |
1165 return SetCanonicalCookie(&cc, creation_time, options); | 1180 return SetCanonicalCookie(&cc, creation_time, options); |
1166 } | 1181 } |
1167 | 1182 |
1168 bool CookieMonster::ImportCookies(const CookieList& list) { | 1183 bool CookieMonster::ImportCookies(const CookieList& list) { |
1169 base::AutoLock autolock(lock_); | 1184 base::AutoLock autolock(lock_); |
1170 InitIfNecessary(); | 1185 MarkCookieStoreAsInitialized(); |
| 1186 if (ShouldFetchAllCookiesWhenFetchingAnyCookie()) |
| 1187 FetchAllCookiesIfNecessary(); |
1171 for (net::CookieList::const_iterator iter = list.begin(); iter != list.end(); | 1188 for (net::CookieList::const_iterator iter = list.begin(); iter != list.end(); |
1172 ++iter) { | 1189 ++iter) { |
1173 scoped_ptr<CanonicalCookie> cookie(new CanonicalCookie(*iter)); | 1190 scoped_ptr<CanonicalCookie> cookie(new CanonicalCookie(*iter)); |
1174 net::CookieOptions options; | 1191 net::CookieOptions options; |
1175 options.set_include_httponly(); | 1192 options.set_include_httponly(); |
1176 options.set_include_first_party_only(); | 1193 options.set_include_first_party_only(); |
1177 if (!SetCanonicalCookie(&cookie, cookie->CreationDate(), options)) | 1194 if (!SetCanonicalCookie(&cookie, cookie->CreationDate(), options)) |
1178 return false; | 1195 return false; |
1179 } | 1196 } |
1180 return true; | 1197 return true; |
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1466 bool CookieMonster::SetCookieWithCreationTime(const GURL& url, | 1483 bool CookieMonster::SetCookieWithCreationTime(const GURL& url, |
1467 const std::string& cookie_line, | 1484 const std::string& cookie_line, |
1468 const base::Time& creation_time) { | 1485 const base::Time& creation_time) { |
1469 DCHECK(!store_.get()) << "This method is only to be used by unit-tests."; | 1486 DCHECK(!store_.get()) << "This method is only to be used by unit-tests."; |
1470 base::AutoLock autolock(lock_); | 1487 base::AutoLock autolock(lock_); |
1471 | 1488 |
1472 if (!HasCookieableScheme(url)) { | 1489 if (!HasCookieableScheme(url)) { |
1473 return false; | 1490 return false; |
1474 } | 1491 } |
1475 | 1492 |
1476 InitIfNecessary(); | 1493 MarkCookieStoreAsInitialized(); |
| 1494 if (ShouldFetchAllCookiesWhenFetchingAnyCookie()) |
| 1495 FetchAllCookiesIfNecessary(); |
| 1496 |
1477 return SetCookieWithCreationTimeAndOptions(url, cookie_line, creation_time, | 1497 return SetCookieWithCreationTimeAndOptions(url, cookie_line, creation_time, |
1478 CookieOptions()); | 1498 CookieOptions()); |
1479 } | 1499 } |
1480 | 1500 |
1481 void CookieMonster::InitStore() { | 1501 void CookieMonster::MarkCookieStoreAsInitialized() { |
| 1502 initialized_ = true; |
| 1503 } |
| 1504 |
| 1505 void CookieMonster::FetchAllCookiesIfNecessary() { |
| 1506 if (store_.get() && !started_fetching_all_cookies_) { |
| 1507 started_fetching_all_cookies_ = true; |
| 1508 FetchAllCookies(); |
| 1509 } |
| 1510 } |
| 1511 |
| 1512 bool CookieMonster::ShouldFetchAllCookiesWhenFetchingAnyCookie() { |
| 1513 if (fetch_strategy_ == kUnknownFetch) { |
| 1514 const std::string group_name = |
| 1515 base::FieldTrialList::FindFullName(kCookieMonsterFetchStrategyName); |
| 1516 if (group_name == kFetchWhenNecessaryName) { |
| 1517 fetch_strategy_ = kFetchWhenNecessary; |
| 1518 } else if (group_name == kAlwaysFetchName) { |
| 1519 fetch_strategy_ = kAlwaysFetch; |
| 1520 } else { |
| 1521 // The logic in the conditional is redundant, but it makes trials of |
| 1522 // the Finch experiment more explicit. |
| 1523 fetch_strategy_ = kAlwaysFetch; |
| 1524 } |
| 1525 } |
| 1526 |
| 1527 return fetch_strategy_ == kAlwaysFetch; |
| 1528 } |
| 1529 |
| 1530 void CookieMonster::FetchAllCookies() { |
1482 DCHECK(store_.get()) << "Store must exist to initialize"; | 1531 DCHECK(store_.get()) << "Store must exist to initialize"; |
| 1532 DCHECK(!finished_fetching_all_cookies_) |
| 1533 << "All cookies have already been fetched."; |
1483 | 1534 |
1484 // We bind in the current time so that we can report the wall-clock time for | 1535 // We bind in the current time so that we can report the wall-clock time for |
1485 // loading cookies. | 1536 // loading cookies. |
1486 store_->Load(base::Bind(&CookieMonster::OnLoaded, this, TimeTicks::Now())); | 1537 store_->Load(base::Bind(&CookieMonster::OnLoaded, this, TimeTicks::Now())); |
1487 } | 1538 } |
1488 | 1539 |
1489 void CookieMonster::OnLoaded(TimeTicks beginning_time, | 1540 void CookieMonster::OnLoaded(TimeTicks beginning_time, |
1490 const std::vector<CanonicalCookie*>& cookies) { | 1541 const std::vector<CanonicalCookie*>& cookies) { |
1491 StoreLoadedCookies(cookies); | 1542 StoreLoadedCookies(cookies); |
1492 histogram_time_blocked_on_load_->AddTime(TimeTicks::Now() - beginning_time); | 1543 histogram_time_blocked_on_load_->AddTime(TimeTicks::Now() - beginning_time); |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1587 // since they are expected to be much fewer than total DB. | 1638 // since they are expected to be much fewer than total DB. |
1588 EnsureCookiesMapIsValid(); | 1639 EnsureCookiesMapIsValid(); |
1589 } | 1640 } |
1590 | 1641 |
1591 void CookieMonster::InvokeQueue() { | 1642 void CookieMonster::InvokeQueue() { |
1592 while (true) { | 1643 while (true) { |
1593 scoped_refptr<CookieMonsterTask> request_task; | 1644 scoped_refptr<CookieMonsterTask> request_task; |
1594 { | 1645 { |
1595 base::AutoLock autolock(lock_); | 1646 base::AutoLock autolock(lock_); |
1596 if (tasks_pending_.empty()) { | 1647 if (tasks_pending_.empty()) { |
1597 loaded_ = true; | 1648 finished_fetching_all_cookies_ = true; |
1598 creation_times_.clear(); | 1649 creation_times_.clear(); |
1599 keys_loaded_.clear(); | 1650 keys_loaded_.clear(); |
1600 break; | 1651 break; |
1601 } | 1652 } |
1602 request_task = tasks_pending_.front(); | 1653 request_task = tasks_pending_.front(); |
1603 tasks_pending_.pop(); | 1654 tasks_pending_.pop(); |
1604 } | 1655 } |
1605 request_task->Run(); | 1656 request_task->Run(); |
1606 } | 1657 } |
1607 } | 1658 } |
(...skipping 765 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2373 it != hook_map_.end(); ++it) { | 2424 it != hook_map_.end(); ++it) { |
2374 std::pair<GURL, std::string> key = it->first; | 2425 std::pair<GURL, std::string> key = it->first; |
2375 if (cookie.IncludeForRequestURL(key.first, opts) && | 2426 if (cookie.IncludeForRequestURL(key.first, opts) && |
2376 cookie.Name() == key.second) { | 2427 cookie.Name() == key.second) { |
2377 it->second->Notify(cookie, removed); | 2428 it->second->Notify(cookie, removed); |
2378 } | 2429 } |
2379 } | 2430 } |
2380 } | 2431 } |
2381 | 2432 |
2382 } // namespace net | 2433 } // namespace net |
OLD | NEW |