1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file.
4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#ifndef CHROME_BROWSER_NET_EVICTED_DOMAIN_COOKIE_COUNTER_H_
6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#define CHROME_BROWSER_NET_EVICTED_DOMAIN_COOKIE_COUNTER_H_
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <map>
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <string>
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/basictypes.h"
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/compiler_specific.h"
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/memory/ref_counted.h"
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/memory/scoped_ptr.h"
15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cookies/cookie_monster.h"
17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace net {
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class CanonicalCookie;
20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace net
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace chrome_browser_net {
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// The Evicted Domain Cookie Counter generates statistics on "wrongly evicted"
25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// cookies, i.e., cookies that were "evicted" (on reaching domain cookie limit)
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// but are then "reinstated" later because they were important. A specific
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// scenario is as follows: a long-lived login session cookie gets evicted owing
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// to its age, thereby forcing the user to lose session, and is reinstated when
29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// the user re-authenticates.
30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// A solution to the above problem is the Cookie Priority Field, which enables
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// servers to protect important cookies, thereby decreasing the chances that
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// these cookies are wrongly evicted. To measure the effectiveness of this
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// solution, we will compare eviction user metrics before vs. after the fix.
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Specifically, we wish to record user metrics on "reinstatement delay", i.e.,
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// the duration between eviction and reinstatement of cookie. We expect that
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// after the fix, average reinstatement delays will increase, since low priority
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// cookies are less likely to be reinstated after eviction.
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Metrics for Google domains are tracked separately.
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)//
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class EvictedDomainCookieCounter : public net::CookieMonster::Delegate {
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public:
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Structure to store sanitized data from CanonicalCookie.
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  struct EvictedCookie {
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    EvictedCookie(base::Time eviction_time_in,
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                  base::Time expiry_time_in,
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                  bool is_google_in)
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        : eviction_time(eviction_time_in),
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          expiry_time(expiry_time_in),
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          is_google(is_google_in) {}
53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    bool is_expired(const base::Time& current_time) const {
55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return !expiry_time.is_null() && current_time >= expiry_time;
56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::Time eviction_time;
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::Time expiry_time;
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    bool is_google;
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  };
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  class Delegate {
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)   public:
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    virtual ~Delegate() {}
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Called when a stored evicted cookie is reinstated.
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    virtual void Report(const EvictedCookie& evicted_cookie,
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        const base::Time& reinstatement_time) = 0;
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Getter of time is placed here to enable mocks.
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    virtual base::Time CurrentTime() const = 0;
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  };
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // |next_cookie_monster_delegate| can be NULL.
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  explicit EvictedDomainCookieCounter(
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      scoped_refptr<net::CookieMonster::Delegate> next_cookie_monster_delegate);
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Constructor exposed for testing only.
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EvictedDomainCookieCounter(
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      scoped_refptr<net::CookieMonster::Delegate> next_cookie_monster_delegate,
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      scoped_ptr<Delegate> cookie_counter_delegate,
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      size_t max_size,
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      size_t purge_count);
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Returns the number of evicted cookies stored.
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  size_t GetStorageSize() const;
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // CookieMonster::Delegate implementation.
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual void OnCookieChanged(const net::CanonicalCookie& cookie,
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                               bool removed,
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                               ChangeCause cause) OVERRIDE;
93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  virtual void OnLoaded() OVERRIDE;
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private:
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Identifier of an evicted cookie.
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  typedef std::string EvictedCookieKey;
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Storage class of evicted cookie.
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  typedef std::map<EvictedCookieKey, EvictedCookie*> EvictedCookieMap;
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual ~EvictedDomainCookieCounter();
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Computes key for |cookie| compatible with CanonicalCookie::IsEquivalent(),
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // i.e., IsEquivalent(a, b) ==> GetKey(a) == GetKey(b).
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  static EvictedCookieKey GetKey(const net::CanonicalCookie& cookie);
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Comparator for sorting, to make recently evicted cookies appear earlier.
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  static bool CompareEvictedCookie(
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const EvictedCookieMap::iterator evicted_cookie1,
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const EvictedCookieMap::iterator evicted_cookie2);
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // If too many evicted cookies are stored, delete the expired ones, then
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // delete cookies that were evicted the longest, until size limit reached.
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  void GarbageCollect(const base::Time& current_time);
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Called when a cookie is evicted. Adds the evicted cookie to storage,
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // possibly replacing an existing equivalent cookie.
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  void StoreEvictedCookie(const EvictedCookieKey& key,
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          const net::CanonicalCookie& cookie,
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                          const base::Time& current_time);
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Called when a new cookie is added. If reinstatement occurs, then notifies
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // |cookie_counter_delegate_| and then removes the evicted cookie.
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  void ProcessNewCookie(const EvictedCookieKey& key,
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        const net::CanonicalCookie& cookie,
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        const base::Time& current_time);
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Another delegate to forward events to.
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_refptr<net::CookieMonster::Delegate> next_cookie_monster_delegate_;
131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<Delegate> cookie_counter_delegate_;
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EvictedCookieMap evicted_cookies_;
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Capacity of the evicted cookie storage, before garbage collection occurs.
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const size_t max_size_;
138c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // After garbage collection, size reduces to <= |max_size_| - |purge_count_|.
140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const size_t purge_count_;
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(EvictedDomainCookieCounter);
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace chrome_browser_net
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif  // CHROME_BROWSER_NET_EVICTED_DOMAIN_COOKIE_COUNTER_H_
148