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 { EvictedCookieEvictedCookie47 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 is_expiredEvictedCookie54 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: ~Delegate()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 virtual void OnLoaded() OVERRIDE; 94 95 private: 96 // Identifier of an evicted cookie. 97 typedef std::string EvictedCookieKey; 98 99 // Storage class of evicted cookie. 100 typedef std::map<EvictedCookieKey, EvictedCookie*> EvictedCookieMap; 101 102 virtual ~EvictedDomainCookieCounter(); 103 104 // Computes key for |cookie| compatible with CanonicalCookie::IsEquivalent(), 105 // i.e., IsEquivalent(a, b) ==> GetKey(a) == GetKey(b). 106 static EvictedCookieKey GetKey(const net::CanonicalCookie& cookie); 107 108 // Comparator for sorting, to make recently evicted cookies appear earlier. 109 static bool CompareEvictedCookie( 110 const EvictedCookieMap::iterator evicted_cookie1, 111 const EvictedCookieMap::iterator evicted_cookie2); 112 113 // If too many evicted cookies are stored, delete the expired ones, then 114 // delete cookies that were evicted the longest, until size limit reached. 115 void GarbageCollect(const base::Time& current_time); 116 117 // Called when a cookie is evicted. Adds the evicted cookie to storage, 118 // possibly replacing an existing equivalent cookie. 119 void StoreEvictedCookie(const EvictedCookieKey& key, 120 const net::CanonicalCookie& cookie, 121 const base::Time& current_time); 122 123 // Called when a new cookie is added. If reinstatement occurs, then notifies 124 // |cookie_counter_delegate_| and then removes the evicted cookie. 125 void ProcessNewCookie(const EvictedCookieKey& key, 126 const net::CanonicalCookie& cookie, 127 const base::Time& current_time); 128 129 // Another delegate to forward events to. 130 scoped_refptr<net::CookieMonster::Delegate> next_cookie_monster_delegate_; 131 132 scoped_ptr<Delegate> cookie_counter_delegate_; 133 134 EvictedCookieMap evicted_cookies_; 135 136 // Capacity of the evicted cookie storage, before garbage collection occurs. 137 const size_t max_size_; 138 139 // After garbage collection, size reduces to <= |max_size_| - |purge_count_|. 140 const size_t purge_count_; 141 142 DISALLOW_COPY_AND_ASSIGN(EvictedDomainCookieCounter); 143 }; 144 145 } // namespace chrome_browser_net 146 147 #endif // CHROME_BROWSER_NET_EVICTED_DOMAIN_COOKIE_COUNTER_H_ 148