Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(239)

Side by Side Diff: net/cookies/evicted_domain_cookie_counter.cc

Issue 12805010: Implementing EvictedDomainCookieCounter to keep user metrics on cookie eviction and reinstatement. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Style fixes; fixing incorrect reinstatement of expired cookie. Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2013 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/cookies/evicted_domain_cookie_counter.h"
6
7 #include <limits>
erikwright (departed) 2013/03/25 17:29:41 What is limits used for?
huangs 2013/03/25 21:02:12 Was to find max int for rand, but no longer needed
8 #include <queue>
9 #include <vector>
10
11 #include "base/metrics/histogram.h"
12 #include "base/stl_util.h"
13 #include "base/string_util.h"
14 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
15 #include "net/cookies/canonical_cookie.h"
16
17 namespace net {
18
19 using base::Time;
20 using base::TimeDelta;
21
22 namespace {
23
24 const size_t kMaxEvictedDomainCookies = 500;
25 const size_t kPurgeEvictedDomainCookies = 100;
26
27 class DelegateImpl : public EvictedDomainCookieCounter::Delegate {
28 public:
29 DelegateImpl();
30
31 // EvictedDomainCookieCounter::Delegate implementation.
32 virtual void Report(const EvictedDomainCookieCounter::EvictedCookie& ec,
33 const Time& reinstatement_time) OVERRIDE;
34 virtual Time CurrentTime() OVERRIDE;
35 };
36
37 DelegateImpl::DelegateImpl() {}
38
39 void DelegateImpl::Report(const EvictedDomainCookieCounter::EvictedCookie& ec,
40 const Time& reinstatement_time) {
41 TimeDelta reinstatement_delay(reinstatement_time - ec.eviction_time_);
42 // Keep separate blocks, since HISTOGRAM_CUSTOM_TIMES is a macro.
erikwright (departed) 2013/03/25 17:29:41 What does this comment mean?
huangs 2013/03/25 21:02:12 It is tempting to "refactor" the code by removing
43 if (ec.is_google_) {
44 HISTOGRAM_CUSTOM_TIMES("Cookie.ReinstatedCookiesGoogle",
45 reinstatement_delay,
46 TimeDelta::FromSeconds(1),
47 TimeDelta::FromDays(7),
48 50);
49 } else {
50 HISTOGRAM_CUSTOM_TIMES("Cookie.ReinstatedCookiesOther",
51 reinstatement_delay,
52 TimeDelta::FromSeconds(1),
53 TimeDelta::FromDays(7),
54 50);
55 }
56 }
57
58 Time DelegateImpl::CurrentTime() {
59 return Time::Now();
60 }
61
62 } // namespace
63
64 EvictedDomainCookieCounter::EvictedDomainCookieCounter(
65 scoped_refptr<CookieMonster::Delegate> next_cookie_monster_delegate)
66 : next_cookie_monster_delegate_(next_cookie_monster_delegate),
67 delegate_(new DelegateImpl),
68 max_size_(kMaxEvictedDomainCookies),
69 purge_count_(kPurgeEvictedDomainCookies) {
70 }
71
72 EvictedDomainCookieCounter::EvictedDomainCookieCounter(
73 scoped_refptr<CookieMonster::Delegate> next_cookie_monster_delegate,
74 scoped_ptr<Delegate> delegate,
75 size_t max_size,
76 size_t purge_count)
77 : next_cookie_monster_delegate_(next_cookie_monster_delegate),
78 delegate_(delegate.Pass()),
79 max_size_(max_size),
80 purge_count_(purge_count) {
81 DCHECK(delegate_);
82 DCHECK(purge_count < max_size_);
83 }
84
85 EvictedDomainCookieCounter::~EvictedDomainCookieCounter() {
86 STLDeleteContainerPairSecondPointers(evicted_cookies_.begin(),
87 evicted_cookies_.end());
88 }
89
90 // static
91 // Simplified from google_util.cc: IsGoogleHostname().
92 bool EvictedDomainCookieCounter::UnsafeIsGoogleCookie(
erikwright (departed) 2013/03/25 17:29:41 Why not just use IsGoogleHostname(cc.Domain(), ALL
huangs 2013/03/25 21:02:12 It's due to target dependency; "net" should not de
93 const CanonicalCookie& cc) {
94 const std::string& host(cc.Domain());
95 size_t tld_length =
96 RegistryControlledDomainService::GetRegistryLength(host, false);
97 if ((tld_length == 0) || (tld_length == std::string::npos))
98 return false;
99
100 std::string host_minus_tld(host, 0, host.length() - tld_length);
101 return LowerCaseEqualsASCII(host_minus_tld, "google.") ||
102 EndsWith(host_minus_tld, ".google.", false);
103 }
104
105 size_t EvictedDomainCookieCounter::GetStorageSize() const {
106 return evicted_cookies_.size();
107 }
108
109 void EvictedDomainCookieCounter::OnCookieChanged(const CanonicalCookie& cc,
110 bool removed,
111 ChangeCause cause) {
112 EvictedDomainCookieCounter::EvictedCookieKey key(GetKey(cc));
113 Time current(delegate_->CurrentTime());
114 if (removed) {
115 if (cause == CookieMonster::Delegate::CHANGE_COOKIE_EVICTED)
116 StoreEvictedCookie(key, cc, current);
117 else // Explicit deletion, so stop tracking.
118 FreeEvictedCookie(key);
119 } else { // Includes adds or updates.
120 ProcessNewCookie(key, cc, current);
121 }
122
123 if (next_cookie_monster_delegate_)
124 next_cookie_monster_delegate_->OnCookieChanged(cc, removed, cause);
125 }
126
127 // static
128 EvictedDomainCookieCounter::EvictedCookieKey
129 EvictedDomainCookieCounter::GetKey(const CanonicalCookie& cc) {
130 return cc.Domain() + ";" + cc.Path() + ";" + cc.Name();
131 }
132
133 void EvictedDomainCookieCounter::FreeEvictedCookie(
134 const EvictedCookieKey& key) {
135 EvictedCookieMap::iterator it = evicted_cookies_.find(key);
136 if (it != evicted_cookies_.end()) {
137 delete it->second;
138 evicted_cookies_.erase(it);
139 }
140 }
141
142 // |current| is passed by value, in case it came from a to-be-deleted element.
143 void EvictedDomainCookieCounter::FreeExpiredEvictedCookies(Time current) {
144 EvictedCookieMap::iterator it = evicted_cookies_.begin();
145 while (it != evicted_cookies_.end()) {
146 if (it->second->is_expired(current)) {
147 delete it->second;
148 evicted_cookies_.erase(it++); // Post-increment idiom.
149 } else {
150 ++it;
151 }
152 }
153 }
154
155 void EvictedDomainCookieCounter::GarbageCollect(const Time& current) {
156 if (evicted_cookies_.size() <= max_size_)
157 return;
158
159 // From |evicted_cookies_|, removed all expired cookies, and remove cookies
160 // with the oldest |eviction_time_| until |size_goal| is attained.
161 size_t size_goal = max_size_ - purge_count_;
162 // Bound on number of non-expired cookies to remove.
163 size_t remove_quota = evicted_cookies_.size() - size_goal;
164 DCHECK(remove_quota > 0);
165
166 typedef EvictedDomainCookieCounter::EvictedCookie* EvictedCookiePtr;
167 // Comparator for a priority_queue<> whose top() element specifies the most
168 // recently evicted cookie.
169 struct EvictedCookieComparator {
170 bool operator() (EvictedCookiePtr ec1, EvictedCookiePtr ec2) {
171 return ec1->eviction_time_ < ec2->eviction_time_;
172 }
173 };
174
175 // Use priority queue to store oldest cookies, resize as necessary.
176 std::priority_queue<EvictedCookiePtr, std::vector<EvictedCookiePtr>,
177 EvictedCookieComparator> oldest_set;
178 for (EvictedCookieMap::iterator it = evicted_cookies_.begin();
179 it != evicted_cookies_.end(); ++it) {
180 if (it->second->is_expired(current)) // Will be removed, so decrease quota.
181 remove_quota = remove_quota ? remove_quota - 1 : 0; // Cap to 0 (size_t).
182 else
183 oldest_set.push(it->second);
184
185 if (oldest_set.size() > remove_quota)
186 oldest_set.pop(); // Spare the youngest element from deletion.
187 }
188 DCHECK(oldest_set.size() <= remove_quota);
189
190 // Mark oldest non-expired cookies as expired, for removal.
191 for (; !oldest_set.empty(); oldest_set.pop())
192 oldest_set.top()->set_expired();
193
194 FreeExpiredEvictedCookies(current);
195 // Apply stricter check if non-expired cookies were deleted.
196 DCHECK(remove_quota ? evicted_cookies_.size() == size_goal :
197 evicted_cookies_.size() <= size_goal);
198 }
199
200 void EvictedDomainCookieCounter::StoreEvictedCookie(const EvictedCookieKey& key,
201 const CanonicalCookie& cc,
202 const Time& current) {
203 if (!cc.IsExpired(current)) {
204 FreeEvictedCookie(key); // Deallocate explicitly.
205
206 EvictedCookie* ec =
207 new EvictedCookie(current, cc.ExpiryDate(), UnsafeIsGoogleCookie(cc));
208 evicted_cookies_.insert(EvictedCookieMap::value_type(key, ec));
209
210 GarbageCollect(current);
211 }
212 }
213
214 void EvictedDomainCookieCounter::ProcessNewCookie(const EvictedCookieKey& key,
215 const CanonicalCookie& cc,
216 const Time& current) {
217 if (!cc.IsExpired(current)) {
erikwright (departed) 2013/03/25 17:29:41 This should never happen. If the pre-expired cooki
huangs 2013/03/25 21:02:12 Done (removed check).
218 EvictedCookieMap::iterator it = evicted_cookies_.find(key);
219 if (it != evicted_cookies_.end()) {
220 if (!it->second->is_expired(current))
221 delegate_->Report(*it->second, current); // Reinstatement.
222 delete it->second;
223 evicted_cookies_.erase(it);
224 }
225 }
226 }
227
228 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698