Roll src/third_party/WebKit 8b42d1d:744641d (svn 186770:186771)
[chromium-blink-merge.git] / chrome / browser / net / evicted_domain_cookie_counter.cc
blobfa3086440fc2b9bf6c9db56384d8d82d38e1a9c4
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.
5 #include "chrome/browser/net/evicted_domain_cookie_counter.h"
7 #include <algorithm>
8 #include <vector>
10 #include "base/metrics/histogram.h"
11 #include "base/stl_util.h"
12 #include "base/strings/string_util.h"
13 #include "components/google/core/browser/google_util.h"
14 #include "net/cookies/canonical_cookie.h"
16 namespace chrome_browser_net {
18 using base::Time;
19 using base::TimeDelta;
21 namespace {
23 const size_t kMaxEvictedDomainCookies = 500;
24 const size_t kPurgeEvictedDomainCookies = 100;
26 class DelegateImpl : public EvictedDomainCookieCounter::Delegate {
27 public:
28 DelegateImpl();
30 // EvictedDomainCookieCounter::Delegate implementation.
31 void Report(const EvictedDomainCookieCounter::EvictedCookie& evicted_cookie,
32 const Time& reinstatement_time) override;
33 Time CurrentTime() const override;
36 DelegateImpl::DelegateImpl() {}
38 void DelegateImpl::Report(
39 const EvictedDomainCookieCounter::EvictedCookie& evicted_cookie,
40 const Time& reinstatement_time) {
41 TimeDelta reinstatement_delay(
42 reinstatement_time - evicted_cookie.eviction_time);
43 // Need to duplicate UMA_HISTOGRAM_CUSTOM_TIMES(), since it is a macro that
44 // defines a static variable.
45 if (evicted_cookie.is_google) {
46 UMA_HISTOGRAM_CUSTOM_TIMES("Cookie.ReinstatedCookiesGoogle",
47 reinstatement_delay,
48 TimeDelta::FromSeconds(1),
49 TimeDelta::FromDays(7),
50 50);
51 } else {
52 UMA_HISTOGRAM_CUSTOM_TIMES("Cookie.ReinstatedCookiesOther",
53 reinstatement_delay,
54 TimeDelta::FromSeconds(1),
55 TimeDelta::FromDays(7),
56 50);
60 Time DelegateImpl::CurrentTime() const {
61 return Time::Now();
64 } // namespace
66 EvictedDomainCookieCounter::EvictedDomainCookieCounter(
67 scoped_refptr<net::CookieMonster::Delegate> next_cookie_monster_delegate)
68 : next_cookie_monster_delegate_(next_cookie_monster_delegate),
69 cookie_counter_delegate_(new DelegateImpl),
70 max_size_(kMaxEvictedDomainCookies),
71 purge_count_(kPurgeEvictedDomainCookies) {
74 EvictedDomainCookieCounter::EvictedDomainCookieCounter(
75 scoped_refptr<net::CookieMonster::Delegate> next_cookie_monster_delegate,
76 scoped_ptr<Delegate> cookie_counter_delegate,
77 size_t max_size,
78 size_t purge_count)
79 : next_cookie_monster_delegate_(next_cookie_monster_delegate),
80 cookie_counter_delegate_(cookie_counter_delegate.Pass()),
81 max_size_(max_size),
82 purge_count_(purge_count) {
83 DCHECK(cookie_counter_delegate_);
84 DCHECK_LT(purge_count, max_size_);
87 EvictedDomainCookieCounter::~EvictedDomainCookieCounter() {
88 STLDeleteContainerPairSecondPointers(evicted_cookies_.begin(),
89 evicted_cookies_.end());
92 size_t EvictedDomainCookieCounter::GetStorageSize() const {
93 return evicted_cookies_.size();
96 void EvictedDomainCookieCounter::OnCookieChanged(
97 const net::CanonicalCookie& cookie,
98 bool removed,
99 ChangeCause cause) {
100 EvictedDomainCookieCounter::EvictedCookieKey key(GetKey(cookie));
101 Time current_time(cookie_counter_delegate_->CurrentTime());
102 if (removed) {
103 if (cause == net::CookieMonster::Delegate::CHANGE_COOKIE_EVICTED)
104 StoreEvictedCookie(key, cookie, current_time);
105 } else { // Includes adds or updates.
106 ProcessNewCookie(key, cookie, current_time);
109 if (next_cookie_monster_delegate_.get())
110 next_cookie_monster_delegate_->OnCookieChanged(cookie, removed, cause);
113 void EvictedDomainCookieCounter::OnLoaded() {
114 if (next_cookie_monster_delegate_.get())
115 next_cookie_monster_delegate_->OnLoaded();
118 // static
119 EvictedDomainCookieCounter::EvictedCookieKey
120 EvictedDomainCookieCounter::GetKey(const net::CanonicalCookie& cookie) {
121 return cookie.Domain() + ";" + cookie.Path() + ";" + cookie.Name();
124 // static
125 bool EvictedDomainCookieCounter::CompareEvictedCookie(
126 const EvictedCookieMap::iterator evicted_cookie1,
127 const EvictedCookieMap::iterator evicted_cookie2) {
128 return evicted_cookie1->second->eviction_time
129 < evicted_cookie2->second->eviction_time;
132 void EvictedDomainCookieCounter::GarbageCollect(const Time& current_time) {
133 if (evicted_cookies_.size() <= max_size_)
134 return;
136 // From |evicted_cookies_|, removed all expired cookies, and remove cookies
137 // with the oldest |eviction_time| so that |size_goal| is attained.
138 size_t size_goal = max_size_ - purge_count_;
139 // Bound on number of non-expired cookies to remove.
140 size_t remove_quota = evicted_cookies_.size() - size_goal;
141 DCHECK_GT(remove_quota, 0u);
143 std::vector<EvictedCookieMap::iterator> remove_list;
144 remove_list.reserve(evicted_cookies_.size());
146 EvictedCookieMap::iterator it = evicted_cookies_.begin();
147 while (it != evicted_cookies_.end()) {
148 if (it->second->is_expired(current_time)) {
149 delete it->second;
150 evicted_cookies_.erase(it++); // Post-increment idiom for in-loop removal.
151 if (remove_quota)
152 --remove_quota;
153 } else {
154 if (remove_quota) // Don't bother storing if quota met.
155 remove_list.push_back(it);
156 ++it;
160 // Free the oldest |remove_quota| non-expired cookies.
161 std::partial_sort(remove_list.begin(), remove_list.begin() + remove_quota,
162 remove_list.end(), CompareEvictedCookie);
163 for (size_t i = 0; i < remove_quota; ++i) {
164 delete remove_list[i]->second;
165 evicted_cookies_.erase(remove_list[i]);
168 // Apply stricter check if non-expired cookies were deleted.
169 DCHECK(remove_quota ? evicted_cookies_.size() == size_goal :
170 evicted_cookies_.size() <= size_goal);
173 void EvictedDomainCookieCounter::StoreEvictedCookie(
174 const EvictedCookieKey& key,
175 const net::CanonicalCookie& cookie,
176 const Time& current_time) {
177 bool is_google = google_util::IsGoogleHostname(
178 cookie.Domain(), google_util::ALLOW_SUBDOMAIN);
179 EvictedCookie* evicted_cookie =
180 new EvictedCookie(current_time, cookie.ExpiryDate(), is_google);
181 std::pair<EvictedCookieMap::iterator, bool> prev_entry =
182 evicted_cookies_.insert(
183 EvictedCookieMap::value_type(key, evicted_cookie));
184 if (!prev_entry.second) {
185 NOTREACHED();
186 delete prev_entry.first->second;
187 prev_entry.first->second = evicted_cookie;
190 GarbageCollect(current_time);
193 void EvictedDomainCookieCounter::ProcessNewCookie(
194 const EvictedCookieKey& key,
195 const net::CanonicalCookie& cc,
196 const Time& current_time) {
197 EvictedCookieMap::iterator it = evicted_cookies_.find(key);
198 if (it != evicted_cookies_.end()) {
199 if (!it->second->is_expired(current_time)) // Reinstatement.
200 cookie_counter_delegate_->Report(*it->second, current_time);
201 delete it->second;
202 evicted_cookies_.erase(it);
206 } // namespace chrome_browser_net