summaryrefslogtreecommitdiffstats
path: root/chrome/browser/net/evicted_domain_cookie_counter.h
blob: 49873fccb14148f43dbecc57f7aa747a305f6829 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_NET_EVICTED_DOMAIN_COOKIE_COUNTER_H_
#define CHROME_BROWSER_NET_EVICTED_DOMAIN_COOKIE_COUNTER_H_

#include <map>
#include <string>

#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
#include "net/cookies/cookie_monster.h"

namespace net {
class CanonicalCookie;
}  // namespace net

namespace chrome_browser_net {

// The Evicted Domain Cookie Counter generates statistics on "wrongly evicted"
// cookies, i.e., cookies that were "evicted" (on reaching domain cookie limit)
// but are then "reinstated" later because they were important. A specific
// scenario is as follows: a long-lived login session cookie gets evicted owing
// to its age, thereby forcing the user to lose session, and is reinstated when
// the user re-authenticates.
//
// A solution to the above problem is the Cookie Priority Field, which enables
// servers to protect important cookies, thereby decreasing the chances that
// these cookies are wrongly evicted. To measure the effectiveness of this
// solution, we will compare eviction user metrics before vs. after the fix.
//
// Specifically, we wish to record user metrics on "reinstatement delay", i.e.,
// the duration between eviction and reinstatement of cookie. We expect that
// after the fix, average reinstatement delays will increase, since low priority
// cookies are less likely to be reinstated after eviction.
//
// Metrics for Google domains are tracked separately.
//
class EvictedDomainCookieCounter : public net::CookieMonster::Delegate {
 public:
  // Structure to store sanitized data from CanonicalCookie.
  struct EvictedCookie {
    EvictedCookie(base::Time eviction_time_in,
                  base::Time expiry_time_in,
                  bool is_google_in)
        : eviction_time(eviction_time_in),
          expiry_time(expiry_time_in),
          is_google(is_google_in) {}

    bool is_expired(const base::Time& current_time) const {
      return !expiry_time.is_null() && current_time >= expiry_time;
    }

    base::Time eviction_time;
    base::Time expiry_time;
    bool is_google;
  };

  class Delegate {
   public:
    virtual ~Delegate() {}

    // Called when a stored evicted cookie is reinstated.
    virtual void Report(const EvictedCookie& evicted_cookie,
                        const base::Time& reinstatement_time) = 0;

    // Getter of time is placed here to enable mocks.
    virtual base::Time CurrentTime() const = 0;
  };

  // |next_cookie_monster_delegate| can be NULL.
  explicit EvictedDomainCookieCounter(
      scoped_refptr<net::CookieMonster::Delegate> next_cookie_monster_delegate);

  // Constructor exposed for testing only.
  EvictedDomainCookieCounter(
      scoped_refptr<net::CookieMonster::Delegate> next_cookie_monster_delegate,
      scoped_ptr<Delegate> cookie_counter_delegate,
      size_t max_size,
      size_t purge_count);

  // Returns the number of evicted cookies stored.
  size_t GetStorageSize() const;

  // CookieMonster::Delegate implementation.
  void OnCookieChanged(const net::CanonicalCookie& cookie,
                       bool removed,
                       ChangeCause cause) override;

 private:
  // Identifier of an evicted cookie.
  typedef std::string EvictedCookieKey;

  // Storage class of evicted cookie.
  typedef std::map<EvictedCookieKey, EvictedCookie*> EvictedCookieMap;

  ~EvictedDomainCookieCounter() override;

  // Computes key for |cookie| compatible with CanonicalCookie::IsEquivalent(),
  // i.e., IsEquivalent(a, b) ==> GetKey(a) == GetKey(b).
  static EvictedCookieKey GetKey(const net::CanonicalCookie& cookie);

  // Comparator for sorting, to make recently evicted cookies appear earlier.
  static bool CompareEvictedCookie(
      const EvictedCookieMap::iterator evicted_cookie1,
      const EvictedCookieMap::iterator evicted_cookie2);

  // If too many evicted cookies are stored, delete the expired ones, then
  // delete cookies that were evicted the longest, until size limit reached.
  void GarbageCollect(const base::Time& current_time);

  // Called when a cookie is evicted. Adds the evicted cookie to storage,
  // possibly replacing an existing equivalent cookie.
  void StoreEvictedCookie(const EvictedCookieKey& key,
                          const net::CanonicalCookie& cookie,
                          const base::Time& current_time);

  // Called when a new cookie is added. If reinstatement occurs, then notifies
  // |cookie_counter_delegate_| and then removes the evicted cookie.
  void ProcessNewCookie(const EvictedCookieKey& key,
                        const net::CanonicalCookie& cookie,
                        const base::Time& current_time);

  // Another delegate to forward events to.
  scoped_refptr<net::CookieMonster::Delegate> next_cookie_monster_delegate_;

  scoped_ptr<Delegate> cookie_counter_delegate_;

  EvictedCookieMap evicted_cookies_;

  // Capacity of the evicted cookie storage, before garbage collection occurs.
  const size_t max_size_;

  // After garbage collection, size reduces to <= |max_size_| - |purge_count_|.
  const size_t purge_count_;

  DISALLOW_COPY_AND_ASSIGN(EvictedDomainCookieCounter);
};

}  // namespace chrome_browser_net

#endif  // CHROME_BROWSER_NET_EVICTED_DOMAIN_COOKIE_COUNTER_H_