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

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

Issue 1705753002: Evict non-secure cookies less agressively. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 10 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
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 size_t CookieMonster::kDomainCookiesQuotaLow = 30; 114 const float CookieMonster::kDomainCookiesQuotaLow = 0.2;
115 const size_t CookieMonster::kDomainCookiesQuotaMedium = 50; 115 const float CookieMonster::kDomainCookiesQuotaMedium = 0.3333333333333333333333;
116 const size_t CookieMonster::kDomainCookiesQuotaHigh = 116 const float CookieMonster::kDomainCookiesQuotaHigh =
117 kDomainMaxCookies - kDomainPurgeCookies - kDomainCookiesQuotaLow - 117 1 - kDomainCookiesQuotaLow - kDomainCookiesQuotaMedium;
118 kDomainCookiesQuotaMedium;
119 118
120 const int CookieMonster::kSafeFromGlobalPurgeDays = 30; 119 const int CookieMonster::kSafeFromGlobalPurgeDays = 30;
121 120
122 namespace { 121 namespace {
123 122
124 bool ContainsControlCharacter(const std::string& s) { 123 bool ContainsControlCharacter(const std::string& s) {
125 for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) { 124 for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) {
126 if ((*i >= 0) && (*i <= 31)) 125 if ((*i >= 0) && (*i <= 31))
127 return true; 126 return true;
128 } 127 }
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 CookieMonster::CookieItVector* non_secure_cookie_its) { 242 CookieMonster::CookieItVector* non_secure_cookie_its) {
244 DCHECK(secure_cookie_its && non_secure_cookie_its); 243 DCHECK(secure_cookie_its && non_secure_cookie_its);
245 for (const auto& curit : cookie_its) { 244 for (const auto& curit : cookie_its) {
246 if (curit->second->IsSecure()) 245 if (curit->second->IsSecure())
247 secure_cookie_its->push_back(curit); 246 secure_cookie_its->push_back(curit);
248 else 247 else
249 non_secure_cookie_its->push_back(curit); 248 non_secure_cookie_its->push_back(curit);
250 } 249 }
251 } 250 }
252 251
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
266 // For a CookieItVector iterator range [|it_begin|, |it_end|), 252 // For a CookieItVector iterator range [|it_begin|, |it_end|),
267 // moves all cookies with a given |priority| to the beginning of the list. 253 // moves all cookies with a given |priority| to the beginning of the list.
268 // Returns: An iterator in [it_begin, it_end) to the first element with 254 // Returns: An iterator in [it_begin, it_end) to the first element with
269 // priority != |priority|, or |it_end| if all have priority == |priority|. 255 // priority != |priority|, or |it_end| if all have priority == |priority|.
270 CookieMonster::CookieItVector::iterator PartitionCookieByPriority( 256 CookieMonster::CookieItVector::iterator PartitionCookieByPriority(
271 CookieMonster::CookieItVector::iterator it_begin, 257 CookieMonster::CookieItVector::iterator it_begin,
272 CookieMonster::CookieItVector::iterator it_end, 258 CookieMonster::CookieItVector::iterator it_end,
273 CookiePriority priority) { 259 CookiePriority priority) {
274 return std::partition(it_begin, it_end, CookiePriorityEqualsTo(priority)); 260 return std::partition(
261 it_begin, it_end,
262 [priority](const CookieMonster::CookieMap::iterator& it) {
263 return it->second->Priority() == priority;
264 });
275 } 265 }
276 266
277 bool LowerBoundAccessDateComparator(const CookieMonster::CookieMap::iterator it, 267 bool LowerBoundAccessDateComparator(const CookieMonster::CookieMap::iterator it,
278 const Time& access_date) { 268 const Time& access_date) {
279 return it->second->LastAccessDate() < access_date; 269 return it->second->LastAccessDate() < access_date;
280 } 270 }
281 271
282 // For a CookieItVector iterator range [|it_begin|, |it_end|) 272 // For a CookieItVector iterator range [|it_begin|, |it_end|)
283 // from a CookieItVector sorted by LastAccessDate(), returns the 273 // from a CookieItVector sorted by LastAccessDate(), returns the
284 // first iterator with access date >= |access_date|, or cookie_its_end if this 274 // first iterator with access date >= |access_date|, or cookie_its_end if this
(...skipping 1648 matching lines...) Expand 10 before | Expand all | Expand 10 after
1933 bool enforce_strict_secure) { 1923 bool enforce_strict_secure) {
1934 lock_.AssertAcquired(); 1924 lock_.AssertAcquired();
1935 1925
1936 size_t num_deleted = 0; 1926 size_t num_deleted = 0;
1937 Time safe_date(Time::Now() - TimeDelta::FromDays(kSafeFromGlobalPurgeDays)); 1927 Time safe_date(Time::Now() - TimeDelta::FromDays(kSafeFromGlobalPurgeDays));
1938 1928
1939 // Collect garbage for this key, minding cookie priorities. 1929 // Collect garbage for this key, minding cookie priorities.
1940 if (cookies_.count(key) > kDomainMaxCookies) { 1930 if (cookies_.count(key) > kDomainMaxCookies) {
1941 VLOG(kVlogGarbageCollection) << "GarbageCollect() key: " << key; 1931 VLOG(kVlogGarbageCollection) << "GarbageCollect() key: " << key;
1942 1932
1943 CookieItVector* cookie_its; 1933 CookieItVector cookie_its;
1944 1934
1945 CookieItVector non_expired_cookie_its; 1935 // First, we purge all expired cookies for this key (regardless of our
1946 cookie_its = &non_expired_cookie_its; 1936 // target number of cookies, as we have no need to keep expired cookies
1937 // around).
1947 num_deleted += 1938 num_deleted +=
1948 GarbageCollectExpired(current, cookies_.equal_range(key), cookie_its); 1939 GarbageCollectExpired(current, cookies_.equal_range(key), &cookie_its);
1949 1940
1950 CookieItVector secure_cookie_its; 1941 if (cookie_its.size() > kDomainMaxCookies) {
1951 if (enforce_strict_secure && cookie_its->size() > kDomainMaxCookies) { 1942 // Then, if we're over the maximum allowed for this key, we'll remove
1952 VLOG(kVlogGarbageCollection) << "Garbage collecting non-Secure cookies."; 1943 // cookies in the following order:
1953 num_deleted += 1944 //
1954 GarbageCollectNonSecure(non_expired_cookie_its, &secure_cookie_its); 1945 // 1. Low-priority non-secure cookies.
1955 cookie_its = &secure_cookie_its; 1946 // 2. Medium-priority non-secure cookies.
1956 } 1947 // 3. High-priority non-secure cookies.
1948 // 4. Low-priority secure cookies.
1949 // 5. Medium-priority secure cookies.
1950 // 6. High-priority secure cookies.
1951 //
1952 // Note that this implies that _all_ non-secure cookies will be removed
1953 // before _any_ secure cookie is removed, in accordance with
1954 // https://tools.ietf.org/html/draft-west-leave-secure-cookies-alone-05
jww 2016/02/18 01:05:19 Should this link really have the '-05' at the end?
1957 1955
1958 if (cookie_its->size() > kDomainMaxCookies) {
1959 VLOG(kVlogGarbageCollection) << "Deep Garbage Collect domain."; 1956 VLOG(kVlogGarbageCollection) << "Deep Garbage Collect domain.";
1960 size_t purge_goal = 1957 size_t purge_goal =
1961 cookie_its->size() - (kDomainMaxCookies - kDomainPurgeCookies); 1958 cookie_its.size() - (kDomainMaxCookies - kDomainPurgeCookies);
1962 DCHECK(purge_goal > kDomainPurgeCookies); 1959 DCHECK(purge_goal > kDomainPurgeCookies);
1963 1960
1964 // Boundary iterators into |cookie_its| for different priorities. 1961 // To execute the above removals, we'll divide |cookies_its| into 6
1965 CookieItVector::iterator it_bdd[4]; 1962 // partitions, using 7 boundaries (note that the last boundary is off the
1966 // Intialize |it_bdd| while sorting |cookie_its| by priorities. 1963 // end of the list):
1967 // Schematic: [MLLHMHHLMM] => [LLL|MMMM|HHH], with 4 boundaries. 1964 //
1968 it_bdd[0] = cookie_its->begin(); 1965 // If both non-secure and secure cookies are present, the list will look
1969 it_bdd[3] = cookie_its->end(); 1966 // like this:
1970 it_bdd[1] = 1967 //
1971 PartitionCookieByPriority(it_bdd[0], it_bdd[3], COOKIE_PRIORITY_LOW); 1968 // LLLLMMMMHHHHHLLLLMMMMHHHH
1972 it_bdd[2] = PartitionCookieByPriority(it_bdd[1], it_bdd[3], 1969 // ^ ^ ^ ^ ^ ^ ^
1973 COOKIE_PRIORITY_MEDIUM); 1970 // 0 1 2 3 4 5 6
1974 size_t quota[3] = {kDomainCookiesQuotaLow, 1971 //
1975 kDomainCookiesQuotaMedium, 1972 // If only secure cookies are present, the list will look like this:
1976 kDomainCookiesQuotaHigh}; 1973 //
1974 // LLLLMMMMHHHHH
1975 // ^ ^ ^ ^
1976 // 0 4 5 6
1977 // 1
1978 // 2
1979 // 3
1980 //
1981 // If only non-secure cookies are present, the list will look like this:
1982 //
1983 // LLLLMMMMHHHHH
1984 // ^ ^ ^ ^
1985 // 0 1 2 3
1986 // 4
1987 // 5
1988 // 6
1989 CookieItVector::iterator it_bdd[7];
1990 it_bdd[0] = cookie_its.begin();
1991 it_bdd[1] = it_bdd[0];
1992 it_bdd[2] = it_bdd[0];
1993 it_bdd[3] = cookie_its.end();
1994 it_bdd[4] = it_bdd[3];
1995 it_bdd[5] = it_bdd[3];
1996 it_bdd[6] = it_bdd[3];
1977 1997
1978 // Purge domain cookies in 3 rounds. 1998 size_t num_secure = 0;
1979 // Round 1: consider low-priority cookies only: evict least-recently 1999 size_t num_nonsecure = 0;
1980 // accessed, while protecting quota[0] of these from deletion.
1981 // Round 2: consider {low, medium}-priority cookies, evict least-recently
1982 // accessed, while protecting quota[0] + quota[1].
1983 // Round 3: consider all cookies, evict least-recently accessed.
1984 size_t accumulated_quota = 0;
1985 CookieItVector::iterator it_purge_begin = it_bdd[0];
1986 for (int i = 0; i < 3 && purge_goal > 0; ++i) {
1987 accumulated_quota += quota[i];
1988 2000
1989 size_t num_considered = it_bdd[i + 1] - it_purge_begin; 2001 // Move all non-secure cookies to the front of the list, and set boundary
1990 if (num_considered <= accumulated_quota) 2002 // #3 to the first secure cookie (or off the end of the list, in the case
1991 continue; 2003 // where no secure cookies are present).
2004 it_bdd[3] = std::partition(it_bdd[0], it_bdd[6],
2005 [](const CookieMap::iterator& it) {
2006 return !it->second->IsSecure();
2007 });
1992 2008
1993 // Number of cookies that will be purged in this round. 2009 // If we have non-secure cookies, partition them into priorities:
1994 size_t round_goal = 2010 if (it_bdd[3] > it_bdd[0]) {
1995 std::min(purge_goal, num_considered - accumulated_quota); 2011 it_bdd[1] = PartitionCookieByPriority(it_bdd[0], it_bdd[3],
1996 purge_goal -= round_goal; 2012 COOKIE_PRIORITY_LOW);
2013 it_bdd[2] = PartitionCookieByPriority(it_bdd[1], it_bdd[3],
2014 COOKIE_PRIORITY_MEDIUM);
mmenke 2016/02/17 18:41:31 This seems so much more complicated than necessary
2015 num_nonsecure = it_bdd[3] - it_bdd[0];
2016 }
1997 2017
1998 SortLeastRecentlyAccessed(it_purge_begin, it_bdd[i + 1], round_goal); 2018 // Likewise, if we have secure cookies, partition them into priorities:
1999 // Cookies accessed on or after |safe_date| would have been safe from 2019 if (it_bdd[3] < it_bdd[6]) {
2000 // global purge, and we want to keep track of this. 2020 it_bdd[4] = PartitionCookieByPriority(it_bdd[3], it_bdd[6],
2001 CookieItVector::iterator it_purge_end = it_purge_begin + round_goal; 2021 COOKIE_PRIORITY_LOW);
2002 CookieItVector::iterator it_purge_middle = 2022 it_bdd[5] = PartitionCookieByPriority(it_bdd[4], it_bdd[6],
2003 LowerBoundAccessDate(it_purge_begin, it_purge_end, safe_date); 2023 COOKIE_PRIORITY_MEDIUM);
2004 // Delete cookies accessed before |safe_date|. 2024 num_secure = it_bdd[6] - it_bdd[3];
2025 }
2026
2027 // Start with the non-secure cookies.
2028 if (purge_goal >= num_nonsecure) {
2029 // If we need to purge more cookies than we have non-secure, remove
2030 // them all, update |purge_goal| then purge the new |purge_goal| from
2031 // the secure cookies.
2005 num_deleted += GarbageCollectDeleteRange( 2032 num_deleted += GarbageCollectDeleteRange(
2006 current, DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE, it_purge_begin, 2033 current, DELETE_COOKIE_NON_SECURE, it_bdd[0], it_bdd[3]);
2007 it_purge_middle); 2034 num_deleted += GarbageCollectNumFromRangeWithQuota(
2008 // Delete cookies accessed on or after |safe_date|. 2035 current, safe_date, purge_goal - num_deleted, it_bdd, GC_SECURE);
2009 num_deleted += GarbageCollectDeleteRange( 2036 } else {
2010 current, DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE, it_purge_middle, 2037 num_deleted += GarbageCollectNumFromRangeWithQuota(
2011 it_purge_end); 2038 current, safe_date, purge_goal, it_bdd, GC_NONSECURE);
2012 it_purge_begin = it_purge_end;
2013 } 2039 }
2040 purge_goal -= num_deleted;
2041
2014 DCHECK_EQ(0U, purge_goal); 2042 DCHECK_EQ(0U, purge_goal);
2015 } 2043 }
2016 } 2044 }
2017 2045
2018 // Collect garbage for everything. With firefox style we want to preserve 2046 // Collect garbage for everything. With firefox style we want to preserve
2019 // cookies accessed in kSafeFromGlobalPurgeDays, otherwise evict. 2047 // cookies accessed in kSafeFromGlobalPurgeDays, otherwise evict.
2020 if (cookies_.size() > kMaxCookies && earliest_access_time_ < safe_date) { 2048 if (cookies_.size() > kMaxCookies && earliest_access_time_ < safe_date) {
2021 VLOG(kVlogGarbageCollection) << "GarbageCollect() everything"; 2049 VLOG(kVlogGarbageCollection) << "GarbageCollect() everything";
2022 CookieItVector cookie_its; 2050 CookieItVector cookie_its;
2023 2051
(...skipping 27 matching lines...) Expand all
2051 } else { 2079 } else {
2052 num_deleted += GarbageCollectLeastRecentlyAccessed( 2080 num_deleted += GarbageCollectLeastRecentlyAccessed(
2053 current, safe_date, purge_goal, cookie_its); 2081 current, safe_date, purge_goal, cookie_its);
2054 } 2082 }
2055 } 2083 }
2056 } 2084 }
2057 2085
2058 return num_deleted; 2086 return num_deleted;
2059 } 2087 }
2060 2088
2089 size_t CookieMonster::GarbageCollectNumFromRangeWithQuota(
2090 const Time& current,
2091 const Time& safe_date,
2092 size_t purge_goal,
2093 CookieItVector::iterator* it_bdd,
2094 GCType type) {
2095 size_t num_deleted = 0;
2096 size_t begin_partition = type == GC_SECURE ? 3 : 0;
2097 size_t num_cookies = it_bdd[begin_partition + 3] - it_bdd[begin_partition];
2098 size_t num_to_keep = num_cookies - purge_goal;
2099 size_t quota[3] = {std::floor(num_to_keep * kDomainCookiesQuotaLow),
2100 std::floor(num_to_keep * kDomainCookiesQuotaMedium),
2101 std::floor(num_to_keep * kDomainCookiesQuotaHigh)};
2102
2103 // The quota calculation will be up to 3 fewer than the number of
2104 // cookies we can keep. Bump up the numbers to get the right answer:
2105 if (quota[0] + quota[1] + quota[2] < num_to_keep)
2106 quota[2] += 1;
2107 if (quota[0] + quota[1] + quota[2] < num_to_keep)
2108 quota[1] += 1;
2109 if (quota[0] + quota[1] + quota[2] < num_to_keep)
2110 quota[0] += 1;
2111 DCHECK_EQ(num_to_keep, quota[0] + quota[1] + quota[2]);
2112
2113 // Purge domain cookies in 3 rounds.
2114 // Round 1: consider low-priority cookies only: evict least-recently
2115 // accessed, while protecting quota[0] of these from deletion.
2116 // Round 2: consider {low, medium}-priority cookies, evict least-recently
2117 // accessed, while protecting quota[0] + quota[1].
2118 // Round 3: consider all cookies, evict least-recently accessed.
2119 size_t accumulated_quota = 0;
2120 CookieItVector::iterator it_purge_begin = it_bdd[begin_partition];
2121 for (int i = 0; i < 3 && purge_goal > 0; ++i) {
jww 2016/02/18 01:05:19 'i < 3' -> 'i < ARRAY_SIZE(quota)' in case the len
2122 accumulated_quota += quota[i];
2123
2124 size_t num_considered = it_bdd[i + begin_partition + 1] - it_purge_begin;
2125 if (num_considered <= accumulated_quota)
2126 continue;
2127
2128 // Number of cookies that will be purged in this round.
2129 size_t round_goal =
2130 std::min(purge_goal, num_considered - accumulated_quota);
2131 purge_goal -= round_goal;
2132
2133 SortLeastRecentlyAccessed(it_purge_begin, it_bdd[i + begin_partition + 1],
2134 round_goal);
2135 // Cookies accessed on or after |safe_date| would have been safe from
2136 // global purge, and we want to keep track of this.
2137 CookieItVector::iterator it_purge_end = it_purge_begin + round_goal;
2138 CookieItVector::iterator it_purge_middle =
2139 LowerBoundAccessDate(it_purge_begin, it_purge_end, safe_date);
2140 // Delete cookies accessed before |safe_date|.
2141 num_deleted += GarbageCollectDeleteRange(
2142 current, DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE, it_purge_begin,
2143 it_purge_middle);
2144 // Delete cookies accessed on or after |safe_date|.
2145 num_deleted += GarbageCollectDeleteRange(
2146 current, DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE, it_purge_middle,
2147 it_purge_end);
2148 it_purge_begin = it_purge_end;
2149 }
2150 return num_deleted;
2151 }
2152
2061 size_t CookieMonster::GarbageCollectExpired(const Time& current, 2153 size_t CookieMonster::GarbageCollectExpired(const Time& current,
2062 const CookieMapItPair& itpair, 2154 const CookieMapItPair& itpair,
2063 CookieItVector* cookie_its) { 2155 CookieItVector* cookie_its) {
2064 lock_.AssertAcquired(); 2156 lock_.AssertAcquired();
2065 2157
2066 int num_deleted = 0; 2158 int num_deleted = 0;
2067 for (CookieMap::iterator it = itpair.first, end = itpair.second; it != end;) { 2159 for (CookieMap::iterator it = itpair.first, end = itpair.second; it != end;) {
2068 CookieMap::iterator curit = it; 2160 CookieMap::iterator curit = it;
2069 ++it; 2161 ++it;
2070 2162
(...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after
2371 it != hook_map_.end(); ++it) { 2463 it != hook_map_.end(); ++it) {
2372 std::pair<GURL, std::string> key = it->first; 2464 std::pair<GURL, std::string> key = it->first;
2373 if (cookie.IncludeForRequestURL(key.first, opts) && 2465 if (cookie.IncludeForRequestURL(key.first, opts) &&
2374 cookie.Name() == key.second) { 2466 cookie.Name() == key.second) {
2375 it->second->Notify(cookie, removed); 2467 it->second->Notify(cookie, removed);
2376 } 2468 }
2377 } 2469 }
2378 } 2470 }
2379 2471
2380 } // namespace net 2472 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698