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 |