| 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 |