Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / net / evicted_domain_cookie_counter.cc
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 "chrome/browser/net/evicted_domain_cookie_counter.h"
6
7 #include <algorithm>
8 #include <vector>
9
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"
15
16 namespace chrome_browser_net {
17
18 using base::Time;
19 using base::TimeDelta;
20
21 namespace {
22
23 const size_t kMaxEvictedDomainCookies = 500;
24 const size_t kPurgeEvictedDomainCookies = 100;
25
26 class DelegateImpl : public EvictedDomainCookieCounter::Delegate {
27  public:
28   DelegateImpl();
29
30   // EvictedDomainCookieCounter::Delegate implementation.
31   void Report(const EvictedDomainCookieCounter::EvictedCookie& evicted_cookie,
32               const Time& reinstatement_time) override;
33   Time CurrentTime() const override;
34 };
35
36 DelegateImpl::DelegateImpl() {}
37
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);
57   }
58 }
59
60 Time DelegateImpl::CurrentTime() const {
61   return Time::Now();
62 }
63
64 }  // namespace
65
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) {
72 }
73
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_);
85 }
86
87 EvictedDomainCookieCounter::~EvictedDomainCookieCounter() {
88   STLDeleteContainerPairSecondPointers(evicted_cookies_.begin(),
89                                        evicted_cookies_.end());
90 }
91
92 size_t EvictedDomainCookieCounter::GetStorageSize() const {
93   return evicted_cookies_.size();
94 }
95
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);
107   }
108
109   if (next_cookie_monster_delegate_.get())
110     next_cookie_monster_delegate_->OnCookieChanged(cookie, removed, cause);
111 }
112
113 void EvictedDomainCookieCounter::OnLoaded() {
114   if (next_cookie_monster_delegate_.get())
115     next_cookie_monster_delegate_->OnLoaded();
116 }
117
118 // static
119 EvictedDomainCookieCounter::EvictedCookieKey
120     EvictedDomainCookieCounter::GetKey(const net::CanonicalCookie& cookie) {
121   return cookie.Domain() + ";" + cookie.Path() + ";" + cookie.Name();
122 }
123
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;
130 }
131
132 void EvictedDomainCookieCounter::GarbageCollect(const Time& current_time) {
133   if (evicted_cookies_.size() <= max_size_)
134     return;
135
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);
142
143   std::vector<EvictedCookieMap::iterator> remove_list;
144   remove_list.reserve(evicted_cookies_.size());
145
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;
157     }
158   }
159
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]);
166   }
167
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);
171 }
172
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;
188   }
189
190   GarbageCollect(current_time);
191 }
192
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);
203   }
204 }
205
206 }  // namespace chrome_browser_net