Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(409)

Side by Side Diff: net/cookies/cookie_monster.cc

Issue 1770183003: Revert of Evict non-secure cookies less agressively. (patchset #4 id:60001 of https://codereview.ch… (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@2661
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/cookies/cookie_monster.h ('k') | net/cookies/cookie_monster_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // Portions of this code based on Mozilla: 5 // Portions of this code based on Mozilla:
6 // (netwerk/cookie/src/nsCookieService.cpp) 6 // (netwerk/cookie/src/nsCookieService.cpp)
7 /* ***** BEGIN LICENSE BLOCK ***** 7 /* ***** BEGIN LICENSE BLOCK *****
8 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 8 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
9 * 9 *
10 * The contents of this file are subject to the Mozilla Public License Version 10 * The contents of this file are subject to the Mozilla Public License Version
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
104 104
105 namespace net { 105 namespace net {
106 106
107 // See comments at declaration of these variables in cookie_monster.h 107 // See comments at declaration of these variables in cookie_monster.h
108 // for details. 108 // for details.
109 const size_t CookieMonster::kDomainMaxCookies = 180; 109 const size_t CookieMonster::kDomainMaxCookies = 180;
110 const size_t CookieMonster::kDomainPurgeCookies = 30; 110 const size_t CookieMonster::kDomainPurgeCookies = 30;
111 const size_t CookieMonster::kMaxCookies = 3300; 111 const size_t CookieMonster::kMaxCookies = 3300;
112 const size_t CookieMonster::kPurgeCookies = 300; 112 const size_t CookieMonster::kPurgeCookies = 300;
113 113
114 const double CookieMonster::kDomainCookiesQuotaLow = 0.2; 114 const size_t CookieMonster::kDomainCookiesQuotaLow = 30;
115 const double CookieMonster::kDomainCookiesQuotaMedium = 0.333333333333333333333; 115 const size_t CookieMonster::kDomainCookiesQuotaMedium = 50;
116 const double CookieMonster::kDomainCookiesQuotaHigh = 116 const size_t CookieMonster::kDomainCookiesQuotaHigh =
117 1 - kDomainCookiesQuotaLow - kDomainCookiesQuotaMedium; 117 kDomainMaxCookies - kDomainPurgeCookies - kDomainCookiesQuotaLow -
118 kDomainCookiesQuotaMedium;
118 119
119 const int CookieMonster::kSafeFromGlobalPurgeDays = 30; 120 const int CookieMonster::kSafeFromGlobalPurgeDays = 30;
120 121
121 namespace { 122 namespace {
122 123
123 bool ContainsControlCharacter(const std::string& s) { 124 bool ContainsControlCharacter(const std::string& s) {
124 for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) { 125 for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) {
125 if ((*i >= 0) && (*i <= 31)) 126 if ((*i >= 0) && (*i <= 31))
126 return true; 127 return true;
127 } 128 }
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
242 CookieMonster::CookieItVector* non_secure_cookie_its) { 243 CookieMonster::CookieItVector* non_secure_cookie_its) {
243 DCHECK(secure_cookie_its && non_secure_cookie_its); 244 DCHECK(secure_cookie_its && non_secure_cookie_its);
244 for (const auto& curit : cookie_its) { 245 for (const auto& curit : cookie_its) {
245 if (curit->second->IsSecure()) 246 if (curit->second->IsSecure())
246 secure_cookie_its->push_back(curit); 247 secure_cookie_its->push_back(curit);
247 else 248 else
248 non_secure_cookie_its->push_back(curit); 249 non_secure_cookie_its->push_back(curit);
249 } 250 }
250 } 251 }
251 252
253 // Predicate to support PartitionCookieByPriority().
254 struct CookiePriorityEqualsTo
255 : std::unary_function<const CookieMonster::CookieMap::iterator, bool> {
256 explicit CookiePriorityEqualsTo(CookiePriority priority)
257 : priority_(priority) {}
258
259 bool operator()(const CookieMonster::CookieMap::iterator it) const {
260 return it->second->Priority() == priority_;
261 }
262
263 const CookiePriority priority_;
264 };
265
252 // For a CookieItVector iterator range [|it_begin|, |it_end|), 266 // For a CookieItVector iterator range [|it_begin|, |it_end|),
253 // moves all cookies with a given |priority| to the beginning of the list. 267 // moves all cookies with a given |priority| to the beginning of the list.
254 // Returns: An iterator in [it_begin, it_end) to the first element with 268 // Returns: An iterator in [it_begin, it_end) to the first element with
255 // priority != |priority|, or |it_end| if all have priority == |priority|. 269 // priority != |priority|, or |it_end| if all have priority == |priority|.
256 CookieMonster::CookieItVector::iterator PartitionCookieByPriority( 270 CookieMonster::CookieItVector::iterator PartitionCookieByPriority(
257 CookieMonster::CookieItVector::iterator it_begin, 271 CookieMonster::CookieItVector::iterator it_begin,
258 CookieMonster::CookieItVector::iterator it_end, 272 CookieMonster::CookieItVector::iterator it_end,
259 CookiePriority priority) { 273 CookiePriority priority) {
260 return std::partition( 274 return std::partition(it_begin, it_end, CookiePriorityEqualsTo(priority));
261 it_begin, it_end,
262 [priority](const CookieMonster::CookieMap::iterator& it) {
263 return it->second->Priority() == priority;
264 });
265 } 275 }
266 276
267 bool LowerBoundAccessDateComparator(const CookieMonster::CookieMap::iterator it, 277 bool LowerBoundAccessDateComparator(const CookieMonster::CookieMap::iterator it,
268 const Time& access_date) { 278 const Time& access_date) {
269 return it->second->LastAccessDate() < access_date; 279 return it->second->LastAccessDate() < access_date;
270 } 280 }
271 281
272 // For a CookieItVector iterator range [|it_begin|, |it_end|) 282 // For a CookieItVector iterator range [|it_begin|, |it_end|)
273 // from a CookieItVector sorted by LastAccessDate(), returns the 283 // from a CookieItVector sorted by LastAccessDate(), returns the
274 // first iterator with access date >= |access_date|, or cookie_its_end if this 284 // first iterator with access date >= |access_date|, or cookie_its_end if this
(...skipping 1615 matching lines...) Expand 10 before | Expand all | Expand 10 after
1890 bool enforce_strict_secure) { 1900 bool enforce_strict_secure) {
1891 lock_.AssertAcquired(); 1901 lock_.AssertAcquired();
1892 1902
1893 size_t num_deleted = 0; 1903 size_t num_deleted = 0;
1894 Time safe_date(Time::Now() - TimeDelta::FromDays(kSafeFromGlobalPurgeDays)); 1904 Time safe_date(Time::Now() - TimeDelta::FromDays(kSafeFromGlobalPurgeDays));
1895 1905
1896 // Collect garbage for this key, minding cookie priorities. 1906 // Collect garbage for this key, minding cookie priorities.
1897 if (cookies_.count(key) > kDomainMaxCookies) { 1907 if (cookies_.count(key) > kDomainMaxCookies) {
1898 VLOG(kVlogGarbageCollection) << "GarbageCollect() key: " << key; 1908 VLOG(kVlogGarbageCollection) << "GarbageCollect() key: " << key;
1899 1909
1900 CookieItVector cookie_its; 1910 CookieItVector* cookie_its;
1901 1911
1902 // First, we purge all expired cookies for this key (regardless of our 1912 CookieItVector non_expired_cookie_its;
1903 // target number of cookies, as we have no need to keep expired cookies 1913 cookie_its = &non_expired_cookie_its;
1904 // around).
1905 num_deleted += 1914 num_deleted +=
1906 GarbageCollectExpired(current, cookies_.equal_range(key), &cookie_its); 1915 GarbageCollectExpired(current, cookies_.equal_range(key), cookie_its);
1907 1916
1908 if (cookie_its.size() > kDomainMaxCookies) { 1917 CookieItVector secure_cookie_its;
1909 // Then, if we're over the maximum allowed for this key, we'll remove 1918 if (enforce_strict_secure && cookie_its->size() > kDomainMaxCookies) {
1910 // cookies in the following order: 1919 VLOG(kVlogGarbageCollection) << "Garbage collecting non-Secure cookies.";
1911 // 1920 num_deleted +=
1912 // 1. Low-priority non-secure cookies. 1921 GarbageCollectNonSecure(non_expired_cookie_its, &secure_cookie_its);
1913 // 2. Medium-priority non-secure cookies. 1922 cookie_its = &secure_cookie_its;
1914 // 3. High-priority non-secure cookies. 1923 }
1915 // 4. Low-priority secure cookies.
1916 // 5. Medium-priority secure cookies.
1917 // 6. High-priority secure cookies.
1918 //
1919 // Note that this implies that _all_ non-secure cookies will be removed
1920 // before _any_ secure cookie is removed, in accordance with
1921 // https://tools.ietf.org/html/draft-west-leave-secure-cookies-alone
1922 1924
1925 if (cookie_its->size() > kDomainMaxCookies) {
1923 VLOG(kVlogGarbageCollection) << "Deep Garbage Collect domain."; 1926 VLOG(kVlogGarbageCollection) << "Deep Garbage Collect domain.";
1924 size_t purge_goal = 1927 size_t purge_goal =
1925 cookie_its.size() - (kDomainMaxCookies - kDomainPurgeCookies); 1928 cookie_its->size() - (kDomainMaxCookies - kDomainPurgeCookies);
1926 DCHECK(purge_goal > kDomainPurgeCookies); 1929 DCHECK(purge_goal > kDomainPurgeCookies);
1927 1930
1928 // To execute the above removals, we'll divide |cookies_its| into 6 1931 // Boundary iterators into |cookie_its| for different priorities.
1929 // partitions, using 7 boundaries (note that the last boundary is off the 1932 CookieItVector::iterator it_bdd[4];
1930 // end of the list): 1933 // Intialize |it_bdd| while sorting |cookie_its| by priorities.
1931 // 1934 // Schematic: [MLLHMHHLMM] => [LLL|MMMM|HHH], with 4 boundaries.
1932 // If both non-secure and secure cookies are present, the list will look 1935 it_bdd[0] = cookie_its->begin();
1933 // like this: 1936 it_bdd[3] = cookie_its->end();
1934 // 1937 it_bdd[1] =
1935 // LLLLMMMMHHHHHLLLLMMMMHHHH 1938 PartitionCookieByPriority(it_bdd[0], it_bdd[3], COOKIE_PRIORITY_LOW);
1936 // ^ ^ ^ ^ ^ ^ ^ 1939 it_bdd[2] = PartitionCookieByPriority(it_bdd[1], it_bdd[3],
1937 // 0 1 2 3 4 5 6 1940 COOKIE_PRIORITY_MEDIUM);
1938 // 1941 size_t quota[3] = {kDomainCookiesQuotaLow,
1939 // If only secure cookies are present, the list will look like this: 1942 kDomainCookiesQuotaMedium,
1940 // 1943 kDomainCookiesQuotaHigh};
1941 // LLLLMMMMHHHHH
1942 // ^ ^ ^ ^
1943 // 0 4 5 6
1944 // 1
1945 // 2
1946 // 3
1947 //
1948 // If only non-secure cookies are present, the list will look like this:
1949 //
1950 // LLLLMMMMHHHHH
1951 // ^ ^ ^ ^
1952 // 0 1 2 3
1953 // 4
1954 // 5
1955 // 6
1956 CookieItVector::iterator it_bdd[7];
1957 it_bdd[0] = cookie_its.begin();
1958 it_bdd[1] = it_bdd[0];
1959 it_bdd[2] = it_bdd[0];
1960 it_bdd[3] = cookie_its.end();
1961 it_bdd[4] = it_bdd[3];
1962 it_bdd[5] = it_bdd[3];
1963 it_bdd[6] = it_bdd[3];
1964 1944
1965 size_t num_nonsecure = 0; 1945 // Purge domain cookies in 3 rounds.
1946 // Round 1: consider low-priority cookies only: evict least-recently
1947 // accessed, while protecting quota[0] of these from deletion.
1948 // Round 2: consider {low, medium}-priority cookies, evict least-recently
1949 // accessed, while protecting quota[0] + quota[1].
1950 // Round 3: consider all cookies, evict least-recently accessed.
1951 size_t accumulated_quota = 0;
1952 CookieItVector::iterator it_purge_begin = it_bdd[0];
1953 for (int i = 0; i < 3 && purge_goal > 0; ++i) {
1954 accumulated_quota += quota[i];
1966 1955
1967 // Move all non-secure cookies to the front of the list, and set boundary 1956 size_t num_considered = it_bdd[i + 1] - it_purge_begin;
1968 // #3 to the first secure cookie (or off the end of the list, in the case 1957 if (num_considered <= accumulated_quota)
1969 // where no secure cookies are present). 1958 continue;
1970 it_bdd[3] = std::partition(it_bdd[0], it_bdd[6],
1971 [](const CookieMap::iterator& it) {
1972 return !it->second->IsSecure();
1973 });
1974 1959
1975 // If we have non-secure cookies, partition them into priorities: 1960 // Number of cookies that will be purged in this round.
1976 if (it_bdd[3] > it_bdd[0]) { 1961 size_t round_goal =
1977 it_bdd[1] = PartitionCookieByPriority(it_bdd[0], it_bdd[3], 1962 std::min(purge_goal, num_considered - accumulated_quota);
1978 COOKIE_PRIORITY_LOW); 1963 purge_goal -= round_goal;
1979 it_bdd[2] = PartitionCookieByPriority(it_bdd[1], it_bdd[3], 1964
1980 COOKIE_PRIORITY_MEDIUM); 1965 SortLeastRecentlyAccessed(it_purge_begin, it_bdd[i + 1], round_goal);
1981 num_nonsecure = it_bdd[3] - it_bdd[0]; 1966 // Cookies accessed on or after |safe_date| would have been safe from
1967 // global purge, and we want to keep track of this.
1968 CookieItVector::iterator it_purge_end = it_purge_begin + round_goal;
1969 CookieItVector::iterator it_purge_middle =
1970 LowerBoundAccessDate(it_purge_begin, it_purge_end, safe_date);
1971 // Delete cookies accessed before |safe_date|.
1972 num_deleted += GarbageCollectDeleteRange(
1973 current, DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE, it_purge_begin,
1974 it_purge_middle);
1975 // Delete cookies accessed on or after |safe_date|.
1976 num_deleted += GarbageCollectDeleteRange(
1977 current, DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE, it_purge_middle,
1978 it_purge_end);
1979 it_purge_begin = it_purge_end;
1982 } 1980 }
1983
1984 // Likewise, if we have secure cookies, partition them into priorities:
1985 if (it_bdd[3] < it_bdd[6]) {
1986 it_bdd[4] = PartitionCookieByPriority(it_bdd[3], it_bdd[6],
1987 COOKIE_PRIORITY_LOW);
1988 it_bdd[5] = PartitionCookieByPriority(it_bdd[4], it_bdd[6],
1989 COOKIE_PRIORITY_MEDIUM);
1990 }
1991
1992 // Start with the non-secure cookies.
1993 if (purge_goal >= num_nonsecure) {
1994 // If we need to purge more cookies than we have non-secure, remove
1995 // them all, update |purge_goal| then purge the new |purge_goal| from
1996 // the secure cookies.
1997 num_deleted += GarbageCollectDeleteRange(
1998 current, DELETE_COOKIE_NON_SECURE, it_bdd[0], it_bdd[3]);
1999 num_deleted += GarbageCollectNumFromRangeWithQuota(
2000 current, safe_date, purge_goal - num_deleted, it_bdd, GC_SECURE);
2001 } else {
2002 num_deleted += GarbageCollectNumFromRangeWithQuota(
2003 current, safe_date, purge_goal, it_bdd, GC_NONSECURE);
2004 }
2005 purge_goal -= num_deleted;
2006
2007 DCHECK_EQ(0U, purge_goal); 1981 DCHECK_EQ(0U, purge_goal);
2008 } 1982 }
2009 } 1983 }
2010 1984
2011 // Collect garbage for everything. With firefox style we want to preserve 1985 // Collect garbage for everything. With firefox style we want to preserve
2012 // cookies accessed in kSafeFromGlobalPurgeDays, otherwise evict. 1986 // cookies accessed in kSafeFromGlobalPurgeDays, otherwise evict.
2013 if (cookies_.size() > kMaxCookies && earliest_access_time_ < safe_date) { 1987 if (cookies_.size() > kMaxCookies && earliest_access_time_ < safe_date) {
2014 VLOG(kVlogGarbageCollection) << "GarbageCollect() everything"; 1988 VLOG(kVlogGarbageCollection) << "GarbageCollect() everything";
2015 CookieItVector cookie_its; 1989 CookieItVector cookie_its;
2016 1990
(...skipping 27 matching lines...) Expand all
2044 } else { 2018 } else {
2045 num_deleted += GarbageCollectLeastRecentlyAccessed( 2019 num_deleted += GarbageCollectLeastRecentlyAccessed(
2046 current, safe_date, purge_goal, cookie_its); 2020 current, safe_date, purge_goal, cookie_its);
2047 } 2021 }
2048 } 2022 }
2049 } 2023 }
2050 2024
2051 return num_deleted; 2025 return num_deleted;
2052 } 2026 }
2053 2027
2054 size_t CookieMonster::GarbageCollectNumFromRangeWithQuota(
2055 const Time& current,
2056 const Time& safe_date,
2057 size_t purge_goal,
2058 CookieItVector::iterator* it_bdd,
2059 GCType type) {
2060 size_t num_deleted = 0;
2061 size_t begin_partition = type == GC_SECURE ? 3 : 0;
2062 size_t num_cookies = it_bdd[begin_partition + 3] - it_bdd[begin_partition];
2063 size_t num_to_keep = num_cookies - purge_goal;
2064 size_t quota[3] = {std::floor(num_to_keep * kDomainCookiesQuotaLow),
2065 std::floor(num_to_keep * kDomainCookiesQuotaMedium),
2066 std::floor(num_to_keep * kDomainCookiesQuotaHigh)};
2067
2068 // The quota calculation will be up to 3 fewer than the number of
2069 // cookies we can keep. Bump up the numbers to get the right answer:
2070 if (quota[0] + quota[1] + quota[2] < num_to_keep)
2071 quota[2] += 1;
2072 if (quota[0] + quota[1] + quota[2] < num_to_keep)
2073 quota[1] += 1;
2074 if (quota[0] + quota[1] + quota[2] < num_to_keep)
2075 quota[0] += 1;
2076 DCHECK_EQ(num_to_keep, quota[0] + quota[1] + quota[2]);
2077
2078 // Purge domain cookies in 3 rounds.
2079 // Round 1: consider low-priority cookies only: evict least-recently
2080 // accessed, while protecting quota[0] of these from deletion.
2081 // Round 2: consider {low, medium}-priority cookies, evict least-recently
2082 // accessed, while protecting quota[0] + quota[1].
2083 // Round 3: consider all cookies, evict least-recently accessed.
2084 size_t accumulated_quota = 0;
2085 CookieItVector::iterator it_purge_begin = it_bdd[begin_partition];
2086 for (size_t i = 0; i < arraysize(quota) && purge_goal > 0; ++i) {
2087 accumulated_quota += quota[i];
2088
2089 size_t num_considered = it_bdd[i + begin_partition + 1] - it_purge_begin;
2090 if (num_considered <= accumulated_quota)
2091 continue;
2092
2093 // Number of cookies that will be purged in this round.
2094 size_t round_goal =
2095 std::min(purge_goal, num_considered - accumulated_quota);
2096 purge_goal -= round_goal;
2097
2098 SortLeastRecentlyAccessed(it_purge_begin, it_bdd[i + begin_partition + 1],
2099 round_goal);
2100 // Cookies accessed on or after |safe_date| would have been safe from
2101 // global purge, and we want to keep track of this.
2102 CookieItVector::iterator it_purge_end = it_purge_begin + round_goal;
2103 CookieItVector::iterator it_purge_middle =
2104 LowerBoundAccessDate(it_purge_begin, it_purge_end, safe_date);
2105 // Delete cookies accessed before |safe_date|.
2106 num_deleted += GarbageCollectDeleteRange(
2107 current, DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE, it_purge_begin,
2108 it_purge_middle);
2109 // Delete cookies accessed on or after |safe_date|.
2110 num_deleted += GarbageCollectDeleteRange(
2111 current, DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE, it_purge_middle,
2112 it_purge_end);
2113 it_purge_begin = it_purge_end;
2114 }
2115 return num_deleted;
2116 }
2117
2118 size_t CookieMonster::GarbageCollectExpired(const Time& current, 2028 size_t CookieMonster::GarbageCollectExpired(const Time& current,
2119 const CookieMapItPair& itpair, 2029 const CookieMapItPair& itpair,
2120 CookieItVector* cookie_its) { 2030 CookieItVector* cookie_its) {
2121 lock_.AssertAcquired(); 2031 lock_.AssertAcquired();
2122 2032
2123 int num_deleted = 0; 2033 int num_deleted = 0;
2124 for (CookieMap::iterator it = itpair.first, end = itpair.second; it != end;) { 2034 for (CookieMap::iterator it = itpair.first, end = itpair.second; it != end;) {
2125 CookieMap::iterator curit = it; 2035 CookieMap::iterator curit = it;
2126 ++it; 2036 ++it;
2127 2037
(...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after
2428 it != hook_map_.end(); ++it) { 2338 it != hook_map_.end(); ++it) {
2429 std::pair<GURL, std::string> key = it->first; 2339 std::pair<GURL, std::string> key = it->first;
2430 if (cookie.IncludeForRequestURL(key.first, opts) && 2340 if (cookie.IncludeForRequestURL(key.first, opts) &&
2431 cookie.Name() == key.second) { 2341 cookie.Name() == key.second) {
2432 it->second->Notify(cookie, removed); 2342 it->second->Notify(cookie, removed);
2433 } 2343 }
2434 } 2344 }
2435 } 2345 }
2436 2346
2437 } // namespace net 2347 } // namespace net
OLDNEW
« no previous file with comments | « net/cookies/cookie_monster.h ('k') | net/cookies/cookie_monster_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698