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