| // 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_ |