| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 106 enable_file_scheme_ = true; | 106 enable_file_scheme_ = true; |
| 107 } | 107 } |
| 108 | 108 |
| 109 CookieMonster::CookieMonster(PersistentCookieStore* store, Delegate* delegate) | 109 CookieMonster::CookieMonster(PersistentCookieStore* store, Delegate* delegate) |
| 110 : initialized_(false), | 110 : initialized_(false), |
| 111 store_(store), | 111 store_(store), |
| 112 last_access_threshold_( | 112 last_access_threshold_( |
| 113 TimeDelta::FromSeconds(kDefaultAccessUpdateThresholdSeconds)), | 113 TimeDelta::FromSeconds(kDefaultAccessUpdateThresholdSeconds)), |
| 114 delegate_(delegate), | 114 delegate_(delegate), |
| 115 last_statistic_record_time_(Time::Now()) { | 115 last_statistic_record_time_(Time::Now()) { |
| 116 InitializeHistograms(); |
| 116 SetDefaultCookieableSchemes(); | 117 SetDefaultCookieableSchemes(); |
| 117 } | 118 } |
| 118 | 119 |
| 119 CookieMonster::~CookieMonster() { | 120 CookieMonster::~CookieMonster() { |
| 120 DeleteAll(false); | 121 DeleteAll(false); |
| 121 } | 122 } |
| 122 | 123 |
| 124 // Initialize all histogram counter variables used in this class. |
| 125 // |
| 126 // Normal histogram usage involves using the macros defined in |
| 127 // histogram.h, which automatically takes care of declaring these |
| 128 // variables (as statics), initializing them, and accumulating into |
| 129 // them, all from a single entry point. Unfortunately, that solution |
| 130 // doesn't work for the CookieMonster, as it's vulnerable to races between |
| 131 // separate threads executing the same functions and hence initializing the |
| 132 // same static variables. There isn't a race danger in the histogram |
| 133 // accumulation calls; they are written to be resilient to simultaneous |
| 134 // calls from multiple threads. |
| 135 // |
| 136 // The solution taken here is to have per-CookieMonster instance |
| 137 // variables that are constructed during CookieMonster construction. |
| 138 // Note that these variables refer to the same underlying histogram, |
| 139 // so we still race (but safely) with other CookieMonster instances |
| 140 // for accumulation. |
| 141 // |
| 142 // To do this we've expanded out the individual histogram macros calls, |
| 143 // with declarations of the variables in the class decl, initialization here |
| 144 // (done from the class constructor) and direct calls to the accumulation |
| 145 // methods where needed. The specific histogram macro calls on which the |
| 146 // initialization is based are included in comments below. |
| 147 void CookieMonster::InitializeHistograms() { |
| 148 // From UMA_HISTOGRAM_CUSTOM_COUNTS |
| 149 histogram_expiration_duration_minutes_ = Histogram::FactoryGet( |
| 150 "net.CookieExpirationDurationMinutes", |
| 151 1, kMinutesInTenYears, 50, |
| 152 Histogram::kUmaTargetedHistogramFlag); |
| 153 histogram_between_access_interval_minutes_ = Histogram::FactoryGet( |
| 154 "net.CookieBetweenAccessIntervalMinutes", |
| 155 1, kMinutesInTenYears, 50, |
| 156 Histogram::kUmaTargetedHistogramFlag); |
| 157 histogram_evicted_last_access_minutes_ = Histogram::FactoryGet( |
| 158 "net.CookieEvictedLastAccessMinutes", |
| 159 1, kMinutesInTenYears, 50, |
| 160 Histogram::kUmaTargetedHistogramFlag); |
| 161 histogram_count_ = Histogram::FactoryGet( |
| 162 "net.CookieCount", 1, 4000, 50, |
| 163 Histogram::kUmaTargetedHistogramFlag); |
| 164 |
| 165 // From UMA_HISTOGRAM_COUNTS_10000 & UMA_HISTOGRAM_CUSTOM_COUNTS |
| 166 histogram_number_duplicate_db_cookies_ = Histogram::FactoryGet( |
| 167 "Net.NumDuplicateCookiesInDb", 1, 10000, 50, |
| 168 Histogram::kUmaTargetedHistogramFlag); |
| 169 |
| 170 // From UMA_HISTOGRAM_ENUMERATION |
| 171 histogram_cookie_deletion_cause_ = LinearHistogram::FactoryGet( |
| 172 "net.CookieDeletionCause", 1, |
| 173 DELETE_COOKIE_LAST_ENTRY, DELETE_COOKIE_LAST_ENTRY + 1, |
| 174 Histogram::kUmaTargetedHistogramFlag); |
| 175 } |
| 176 |
| 123 void CookieMonster::InitStore() { | 177 void CookieMonster::InitStore() { |
| 124 DCHECK(store_) << "Store must exist to initialize"; | 178 DCHECK(store_) << "Store must exist to initialize"; |
| 125 | 179 |
| 126 // Initialize the store and sync in any saved persistent cookies. We don't | 180 // Initialize the store and sync in any saved persistent cookies. We don't |
| 127 // care if it's expired, insert it so it can be garbage collected, removed, | 181 // care if it's expired, insert it so it can be garbage collected, removed, |
| 128 // and sync'd. | 182 // and sync'd. |
| 129 std::vector<KeyedCanonicalCookie> cookies; | 183 std::vector<KeyedCanonicalCookie> cookies; |
| 130 // Reserve space for the maximum amount of cookies a database should have. | 184 // Reserve space for the maximum amount of cookies a database should have. |
| 131 // This prevents multiple vector growth / copies as we append cookies. | 185 // This prevents multiple vector growth / copies as we append cookies. |
| 132 cookies.reserve(kNumCookiesTotal); | 186 cookies.reserve(kNumCookiesTotal); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 155 const std::string key = cur_range_begin->first; // Keep a copy. | 209 const std::string key = cur_range_begin->first; // Keep a copy. |
| 156 CookieMap::iterator cur_range_end = cookies_.upper_bound(key); | 210 CookieMap::iterator cur_range_end = cookies_.upper_bound(key); |
| 157 prev_range_end = cur_range_end; | 211 prev_range_end = cur_range_end; |
| 158 | 212 |
| 159 // Ensure no equivalent cookies for this host. | 213 // Ensure no equivalent cookies for this host. |
| 160 num_duplicates_trimmed += | 214 num_duplicates_trimmed += |
| 161 TrimDuplicateCookiesForHost(key, cur_range_begin, cur_range_end); | 215 TrimDuplicateCookiesForHost(key, cur_range_begin, cur_range_end); |
| 162 } | 216 } |
| 163 | 217 |
| 164 // Record how many duplicates were found in the database. | 218 // Record how many duplicates were found in the database. |
| 165 UMA_HISTOGRAM_COUNTS_10000("Net.NumDuplicateCookiesInDb", | 219 // See InitializeHistograms() for details. |
| 166 num_duplicates_trimmed); | 220 histogram_cookie_deletion_cause_->Add(num_duplicates_trimmed); |
| 167 | 221 |
| 168 // TODO(eroman): Should also verify that there are no cookies with the same | 222 // TODO(eroman): Should also verify that there are no cookies with the same |
| 169 // creation time, since that is assumed to be unique by the rest of the code. | 223 // creation time, since that is assumed to be unique by the rest of the code. |
| 170 } | 224 } |
| 171 | 225 |
| 172 // Our strategy to find duplicates is: | 226 // Our strategy to find duplicates is: |
| 173 // (1) Build a map from (cookiename, cookiepath) to | 227 // (1) Build a map from (cookiename, cookiepath) to |
| 174 // {list of cookies with this signature, sorted by creation time}. | 228 // {list of cookies with this signature, sorted by creation time}. |
| 175 // (2) For each list with more than 1 entry, keep the cookie having the | 229 // (2) For each list with more than 1 entry, keep the cookie having the |
| 176 // most recent creation time, and delete the others. | 230 // most recent creation time, and delete the others. |
| (...skipping 512 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 689 options.exclude_httponly())) { | 743 options.exclude_httponly())) { |
| 690 COOKIE_DLOG(INFO) << "SetCookie() not clobbering httponly cookie"; | 744 COOKIE_DLOG(INFO) << "SetCookie() not clobbering httponly cookie"; |
| 691 return false; | 745 return false; |
| 692 } | 746 } |
| 693 | 747 |
| 694 COOKIE_DLOG(INFO) << "SetCookie() cc: " << (*cc)->DebugString(); | 748 COOKIE_DLOG(INFO) << "SetCookie() cc: " << (*cc)->DebugString(); |
| 695 | 749 |
| 696 // Realize that we might be setting an expired cookie, and the only point | 750 // Realize that we might be setting an expired cookie, and the only point |
| 697 // was to delete the cookie which we've already done. | 751 // was to delete the cookie which we've already done. |
| 698 if (!(*cc)->IsExpired(creation_time)) { | 752 if (!(*cc)->IsExpired(creation_time)) { |
| 699 UMA_HISTOGRAM_CUSTOM_COUNTS( | 753 // See InitializeHistograms() for details. |
| 700 "net.CookieExpirationDurationMinutes", | 754 histogram_expiration_duration_minutes_->Add( |
| 701 ((*cc)->ExpiryDate() - creation_time).InMinutes(), | 755 ((*cc)->ExpiryDate() - creation_time).InMinutes()); |
| 702 1, kMinutesInTenYears, 50); | |
| 703 InternalInsertCookie(cookie_domain, cc->release(), true); | 756 InternalInsertCookie(cookie_domain, cc->release(), true); |
| 704 } | 757 } |
| 705 | 758 |
| 706 // We assume that hopefully setting a cookie will be less common than | 759 // We assume that hopefully setting a cookie will be less common than |
| 707 // querying a cookie. Since setting a cookie can put us over our limits, | 760 // querying a cookie. Since setting a cookie can put us over our limits, |
| 708 // make sure that we garbage collect... We can also make the assumption that | 761 // make sure that we garbage collect... We can also make the assumption that |
| 709 // if a cookie was set, in the common case it will be used soon after, | 762 // if a cookie was set, in the common case it will be used soon after, |
| 710 // and we will purge the expired cookies in GetCookies(). | 763 // and we will purge the expired cookies in GetCookies(). |
| 711 GarbageCollect(creation_time, cookie_domain); | 764 GarbageCollect(creation_time, cookie_domain); |
| 712 | 765 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 729 lock_.AssertAcquired(); | 782 lock_.AssertAcquired(); |
| 730 | 783 |
| 731 // Based off the Mozilla code. When a cookie has been accessed recently, | 784 // Based off the Mozilla code. When a cookie has been accessed recently, |
| 732 // don't bother updating its access time again. This reduces the number of | 785 // don't bother updating its access time again. This reduces the number of |
| 733 // updates we do during pageload, which in turn reduces the chance our storage | 786 // updates we do during pageload, which in turn reduces the chance our storage |
| 734 // backend will hit its batch thresholds and be forced to update. | 787 // backend will hit its batch thresholds and be forced to update. |
| 735 const Time current = Time::Now(); | 788 const Time current = Time::Now(); |
| 736 if ((current - cc->LastAccessDate()) < last_access_threshold_) | 789 if ((current - cc->LastAccessDate()) < last_access_threshold_) |
| 737 return; | 790 return; |
| 738 | 791 |
| 739 UMA_HISTOGRAM_CUSTOM_COUNTS( | 792 // See InitializeHistograms() for details. |
| 740 "net.CookieBetweenAccessIntervalMinutes", | 793 histogram_between_access_interval_minutes_->Add( |
| 741 (current - cc->LastAccessDate()).InMinutes(), | 794 (current - cc->LastAccessDate()).InMinutes()); |
| 742 1, kMinutesInTenYears, 50); | |
| 743 | 795 |
| 744 cc->SetLastAccessDate(current); | 796 cc->SetLastAccessDate(current); |
| 745 if (cc->IsPersistent() && store_) | 797 if (cc->IsPersistent() && store_) |
| 746 store_->UpdateCookieAccessTime(*cc); | 798 store_->UpdateCookieAccessTime(*cc); |
| 747 } | 799 } |
| 748 | 800 |
| 749 void CookieMonster::InternalDeleteCookie(CookieMap::iterator it, | 801 void CookieMonster::InternalDeleteCookie(CookieMap::iterator it, |
| 750 bool sync_to_store, | 802 bool sync_to_store, |
| 751 DeletionCause deletion_cause) { | 803 DeletionCause deletion_cause) { |
| 752 lock_.AssertAcquired(); | 804 lock_.AssertAcquired(); |
| 753 | 805 |
| 754 UMA_HISTOGRAM_ENUMERATION("net.CookieDeletionCause", deletion_cause, | 806 // See InitializeHistograms() for details. |
| 755 DELETE_COOKIE_LAST_ENTRY); | 807 histogram_cookie_deletion_cause_->Add(deletion_cause); |
| 756 | 808 |
| 757 CanonicalCookie* cc = it->second; | 809 CanonicalCookie* cc = it->second; |
| 758 COOKIE_DLOG(INFO) << "InternalDeleteCookie() cc: " << cc->DebugString(); | 810 COOKIE_DLOG(INFO) << "InternalDeleteCookie() cc: " << cc->DebugString(); |
| 759 if (cc->IsPersistent() && store_ && sync_to_store) | 811 if (cc->IsPersistent() && store_ && sync_to_store) |
| 760 store_->DeleteCookie(*cc); | 812 store_->DeleteCookie(*cc); |
| 761 if (delegate_.get()) | 813 if (delegate_.get()) |
| 762 delegate_->OnCookieChanged(it->first, *cc, true); | 814 delegate_->OnCookieChanged(it->first, *cc, true); |
| 763 cookies_.erase(it); | 815 cookies_.erase(it); |
| 764 delete cc; | 816 delete cc; |
| 765 } | 817 } |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 842 // If the range still has too many cookies, delete the least recently used. | 894 // If the range still has too many cookies, delete the least recently used. |
| 843 if (cookie_its.size() > num_max) { | 895 if (cookie_its.size() > num_max) { |
| 844 COOKIE_DLOG(INFO) << "GarbageCollectRange() Deep Garbage Collect."; | 896 COOKIE_DLOG(INFO) << "GarbageCollectRange() Deep Garbage Collect."; |
| 845 // Purge down to (|num_max| - |num_purge|) total cookies. | 897 // Purge down to (|num_max| - |num_purge|) total cookies. |
| 846 DCHECK(num_purge <= num_max); | 898 DCHECK(num_purge <= num_max); |
| 847 num_purge += cookie_its.size() - num_max; | 899 num_purge += cookie_its.size() - num_max; |
| 848 | 900 |
| 849 std::partial_sort(cookie_its.begin(), cookie_its.begin() + num_purge, | 901 std::partial_sort(cookie_its.begin(), cookie_its.begin() + num_purge, |
| 850 cookie_its.end(), LRUCookieSorter); | 902 cookie_its.end(), LRUCookieSorter); |
| 851 for (size_t i = 0; i < num_purge; ++i) { | 903 for (size_t i = 0; i < num_purge; ++i) { |
| 852 UMA_HISTOGRAM_CUSTOM_COUNTS( | 904 // See InitializeHistograms() for details. |
| 853 "net.CookieEvictedLastAccessMinutes", | 905 histogram_evicted_last_access_minutes_->Add( |
| 854 (current - cookie_its[i]->second->LastAccessDate()).InMinutes(), | 906 (current - cookie_its[i]->second->LastAccessDate()).InMinutes()); |
| 855 1, kMinutesInTenYears, 50); | |
| 856 InternalDeleteCookie(cookie_its[i], true, DELETE_COOKIE_EVICTED); | 907 InternalDeleteCookie(cookie_its[i], true, DELETE_COOKIE_EVICTED); |
| 857 } | 908 } |
| 858 | 909 |
| 859 num_deleted += num_purge; | 910 num_deleted += num_purge; |
| 860 } | 911 } |
| 861 | 912 |
| 862 return num_deleted; | 913 return num_deleted; |
| 863 } | 914 } |
| 864 | 915 |
| 865 int CookieMonster::GarbageCollectExpired( | 916 int CookieMonster::GarbageCollectExpired( |
| (...skipping 361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1227 // kRecordStatisticsIntervalSeconds. | 1278 // kRecordStatisticsIntervalSeconds. |
| 1228 // last_statistic_record_time_ is initialized to Now() rather than null | 1279 // last_statistic_record_time_ is initialized to Now() rather than null |
| 1229 // in the constructor so that we won't take statistics right after | 1280 // in the constructor so that we won't take statistics right after |
| 1230 // startup, to avoid bias from browsers that are started but not used. | 1281 // startup, to avoid bias from browsers that are started but not used. |
| 1231 void CookieMonster::RecordPeriodicStats(const base::Time& current_time) { | 1282 void CookieMonster::RecordPeriodicStats(const base::Time& current_time) { |
| 1232 const base::TimeDelta kRecordStatisticsIntervalTime( | 1283 const base::TimeDelta kRecordStatisticsIntervalTime( |
| 1233 base::TimeDelta::FromSeconds(kRecordStatisticsIntervalSeconds)); | 1284 base::TimeDelta::FromSeconds(kRecordStatisticsIntervalSeconds)); |
| 1234 | 1285 |
| 1235 if (current_time - last_statistic_record_time_ > | 1286 if (current_time - last_statistic_record_time_ > |
| 1236 kRecordStatisticsIntervalTime) { | 1287 kRecordStatisticsIntervalTime) { |
| 1237 UMA_HISTOGRAM_CUSTOM_COUNTS("net.CookieCount", cookies_.size(), | 1288 // See InitializeHistograms() for details. |
| 1238 1, 4000, 50); | 1289 histogram_count_->Add(cookies_.size()); |
| 1239 last_statistic_record_time_ = current_time; | 1290 last_statistic_record_time_ = current_time; |
| 1240 } | 1291 } |
| 1241 } | 1292 } |
| 1242 | 1293 |
| 1243 CookieMonster::ParsedCookie::ParsedCookie(const std::string& cookie_line) | 1294 CookieMonster::ParsedCookie::ParsedCookie(const std::string& cookie_line) |
| 1244 : is_valid_(false), | 1295 : is_valid_(false), |
| 1245 path_index_(0), | 1296 path_index_(0), |
| 1246 domain_index_(0), | 1297 domain_index_(0), |
| 1247 expires_index_(0), | 1298 expires_index_(0), |
| 1248 maxage_index_(0), | 1299 maxage_index_(0), |
| (...skipping 375 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1624 | 1675 |
| 1625 std::string CookieMonster::CanonicalCookie::DebugString() const { | 1676 std::string CookieMonster::CanonicalCookie::DebugString() const { |
| 1626 return StringPrintf("name: %s value: %s domain: %s path: %s creation: %" | 1677 return StringPrintf("name: %s value: %s domain: %s path: %s creation: %" |
| 1627 PRId64, | 1678 PRId64, |
| 1628 name_.c_str(), value_.c_str(), | 1679 name_.c_str(), value_.c_str(), |
| 1629 domain_.c_str(), path_.c_str(), | 1680 domain_.c_str(), path_.c_str(), |
| 1630 static_cast<int64>(creation_date_.ToTimeT())); | 1681 static_cast<int64>(creation_date_.ToTimeT())); |
| 1631 } | 1682 } |
| 1632 | 1683 |
| 1633 } // namespace | 1684 } // namespace |
| OLD | NEW |