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

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

Issue 1767513004: Clean up cookie eviction. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
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 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
155 // sorts by creation time (oldest first). 155 // sorts by creation time (oldest first).
156 // The RFC says the sort order for the domain attribute is undefined. 156 // The RFC says the sort order for the domain attribute is undefined.
157 bool CookieSorter(CanonicalCookie* cc1, CanonicalCookie* cc2) { 157 bool CookieSorter(CanonicalCookie* cc1, CanonicalCookie* cc2) {
158 if (cc1->Path().length() == cc2->Path().length()) 158 if (cc1->Path().length() == cc2->Path().length())
159 return cc1->CreationDate() < cc2->CreationDate(); 159 return cc1->CreationDate() < cc2->CreationDate();
160 return cc1->Path().length() > cc2->Path().length(); 160 return cc1->Path().length() > cc2->Path().length();
161 } 161 }
162 162
163 bool LRACookieSorter(const CookieMonster::CookieMap::iterator& it1, 163 bool LRACookieSorter(const CookieMonster::CookieMap::iterator& it1,
164 const CookieMonster::CookieMap::iterator& it2) { 164 const CookieMonster::CookieMap::iterator& it2) {
165 // Cookies accessed less recently should be deleted first.
166 if (it1->second->LastAccessDate() != it2->second->LastAccessDate()) 165 if (it1->second->LastAccessDate() != it2->second->LastAccessDate())
167 return it1->second->LastAccessDate() < it2->second->LastAccessDate(); 166 return it1->second->LastAccessDate() < it2->second->LastAccessDate();
168 167
169 // In rare cases we might have two cookies with identical last access times. 168 // Ensure stability for == last access times by falling back to creation.
170 // To preserve the stability of the sort, in these cases prefer to delete
171 // older cookies over newer ones. CreationDate() is guaranteed to be unique.
172 return it1->second->CreationDate() < it2->second->CreationDate(); 169 return it1->second->CreationDate() < it2->second->CreationDate();
173 } 170 }
174 171
175 // Compare cookies using name, domain and path, so that "equivalent" cookies 172 // Compare cookies using name, domain and path, so that "equivalent" cookies
176 // (per RFC 2965) are equal to each other. 173 // (per RFC 2965) are equal to each other.
177 bool PartialDiffCookieSorter(const CanonicalCookie& a, 174 bool PartialDiffCookieSorter(const CanonicalCookie& a,
178 const CanonicalCookie& b) { 175 const CanonicalCookie& b) {
179 return a.PartialCompare(b); 176 return a.PartialCompare(b);
180 } 177 }
181 178
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 CookieMonster::CookieItVector* non_secure_cookie_its) { 240 CookieMonster::CookieItVector* non_secure_cookie_its) {
244 DCHECK(secure_cookie_its && non_secure_cookie_its); 241 DCHECK(secure_cookie_its && non_secure_cookie_its);
245 for (const auto& curit : cookie_its) { 242 for (const auto& curit : cookie_its) {
246 if (curit->second->IsSecure()) 243 if (curit->second->IsSecure())
247 secure_cookie_its->push_back(curit); 244 secure_cookie_its->push_back(curit);
248 else 245 else
249 non_secure_cookie_its->push_back(curit); 246 non_secure_cookie_its->push_back(curit);
250 } 247 }
251 } 248 }
252 249
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|),
267 // 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
269 // priority != |priority|, or |it_end| if all have priority == |priority|.
270 CookieMonster::CookieItVector::iterator PartitionCookieByPriority(
271 CookieMonster::CookieItVector::iterator it_begin,
272 CookieMonster::CookieItVector::iterator it_end,
273 CookiePriority priority) {
274 return std::partition(it_begin, it_end, CookiePriorityEqualsTo(priority));
275 }
276
277 bool LowerBoundAccessDateComparator(const CookieMonster::CookieMap::iterator it, 250 bool LowerBoundAccessDateComparator(const CookieMonster::CookieMap::iterator it,
278 const Time& access_date) { 251 const Time& access_date) {
279 return it->second->LastAccessDate() < access_date; 252 return it->second->LastAccessDate() < access_date;
280 } 253 }
281 254
282 // For a CookieItVector iterator range [|it_begin|, |it_end|) 255 // For a CookieItVector iterator range [|it_begin|, |it_end|)
283 // from a CookieItVector sorted by LastAccessDate(), returns the 256 // from a CookieItVector sorted by LastAccessDate(), returns the
284 // first iterator with access date >= |access_date|, or cookie_its_end if this 257 // first iterator with access date >= |access_date|, or cookie_its_end if this
285 // holds for all. 258 // holds for all.
286 CookieMonster::CookieItVector::iterator LowerBoundAccessDate( 259 CookieMonster::CookieItVector::iterator LowerBoundAccessDate(
(...skipping 1581 matching lines...) Expand 10 before | Expand all | Expand 10 after
1868 if (cookies_.count(key) > kDomainMaxCookies) { 1841 if (cookies_.count(key) > kDomainMaxCookies) {
1869 VLOG(kVlogGarbageCollection) << "GarbageCollect() key: " << key; 1842 VLOG(kVlogGarbageCollection) << "GarbageCollect() key: " << key;
1870 1843
1871 CookieItVector* cookie_its; 1844 CookieItVector* cookie_its;
1872 1845
1873 CookieItVector non_expired_cookie_its; 1846 CookieItVector non_expired_cookie_its;
1874 cookie_its = &non_expired_cookie_its; 1847 cookie_its = &non_expired_cookie_its;
1875 num_deleted += 1848 num_deleted +=
1876 GarbageCollectExpired(current, cookies_.equal_range(key), cookie_its); 1849 GarbageCollectExpired(current, cookies_.equal_range(key), cookie_its);
1877 1850
1851 // TODO(mkwst): Soften this.
1878 CookieItVector secure_cookie_its; 1852 CookieItVector secure_cookie_its;
1879 if (enforce_strict_secure && cookie_its->size() > kDomainMaxCookies) { 1853 if (enforce_strict_secure && cookie_its->size() > kDomainMaxCookies) {
1880 VLOG(kVlogGarbageCollection) << "Garbage collecting non-Secure cookies."; 1854 VLOG(kVlogGarbageCollection) << "Garbage collecting non-Secure cookies.";
1881 num_deleted += 1855 num_deleted +=
1882 GarbageCollectNonSecure(non_expired_cookie_its, &secure_cookie_its); 1856 GarbageCollectNonSecure(non_expired_cookie_its, &secure_cookie_its);
1883 cookie_its = &secure_cookie_its; 1857 cookie_its = &secure_cookie_its;
1884 } 1858 }
1885 1859
1886 if (cookie_its->size() > kDomainMaxCookies) { 1860 if (cookie_its->size() > kDomainMaxCookies) {
1887 VLOG(kVlogGarbageCollection) << "Deep Garbage Collect domain."; 1861 VLOG(kVlogGarbageCollection) << "Deep Garbage Collect domain.";
1888 size_t purge_goal = 1862 size_t purge_goal =
1889 cookie_its->size() - (kDomainMaxCookies - kDomainPurgeCookies); 1863 cookie_its->size() - (kDomainMaxCookies - kDomainPurgeCookies);
1890 DCHECK(purge_goal > kDomainPurgeCookies); 1864 DCHECK(purge_goal > kDomainPurgeCookies);
1891 1865
1892 // Boundary iterators into |cookie_its| for different priorities. 1866 // Sort the cookies by access date, from least-recent to most-recent.
1893 CookieItVector::iterator it_bdd[4]; 1867 std::sort(cookie_its->begin(), cookie_its->end(), LRACookieSorter);
1894 // Intialize |it_bdd| while sorting |cookie_its| by priorities.
1895 // Schematic: [MLLHMHHLMM] => [LLL|MMMM|HHH], with 4 boundaries.
1896 it_bdd[0] = cookie_its->begin();
1897 it_bdd[3] = cookie_its->end();
1898 it_bdd[1] =
1899 PartitionCookieByPriority(it_bdd[0], it_bdd[3], COOKIE_PRIORITY_LOW);
1900 it_bdd[2] = PartitionCookieByPriority(it_bdd[1], it_bdd[3],
1901 COOKIE_PRIORITY_MEDIUM);
1902 size_t quota[3] = {kDomainCookiesQuotaLow,
1903 kDomainCookiesQuotaMedium,
1904 kDomainCookiesQuotaHigh};
1905 1868
1906 // Purge domain cookies in 3 rounds. 1869 // Remove all but the kDomainCookiesQuotaLow most-recently accessed
1907 // Round 1: consider low-priority cookies only: evict least-recently 1870 // cookies with low-priority. Then, if we still need to remove cookies,
1908 // accessed, while protecting quota[0] of these from deletion. 1871 // bump the quota and remove low- and medium-priority. Then, if we
1909 // Round 2: consider {low, medium}-priority cookies, evict least-recently 1872 // _still_ need to remove cookies, bump the quota and remove cookies
1910 // accessed, while protecting quota[0] + quota[1]. 1873 // with any priority.
1911 // Round 3: consider all cookies, evict least-recently accessed. 1874 size_t quotas[3] = {kDomainCookiesQuotaLow, kDomainCookiesQuotaMedium,
1912 size_t accumulated_quota = 0; 1875 kDomainCookiesQuotaHigh};
1913 CookieItVector::iterator it_purge_begin = it_bdd[0]; 1876 size_t quota = 0;
1914 for (int i = 0; i < 3 && purge_goal > 0; ++i) { 1877 for (size_t i = 0; i < arraysize(quotas) && purge_goal; i++) {
1915 accumulated_quota += quota[i]; 1878 quota += quotas[i];
1879 size_t just_deleted =
1880 PurgeLeastRecentMatches(cookie_its, static_cast<CookiePriority>(i),
1881 quota, purge_goal, safe_date);
1882 purge_goal -= just_deleted;
1883 num_deleted += just_deleted;
1884 }
1916 1885
1917 size_t num_considered = it_bdd[i + 1] - it_purge_begin;
1918 if (num_considered <= accumulated_quota)
1919 continue;
1920
1921 // Number of cookies that will be purged in this round.
1922 size_t round_goal =
1923 std::min(purge_goal, num_considered - accumulated_quota);
1924 purge_goal -= round_goal;
1925
1926 SortLeastRecentlyAccessed(it_purge_begin, it_bdd[i + 1], round_goal);
1927 // Cookies accessed on or after |safe_date| would have been safe from
1928 // global purge, and we want to keep track of this.
1929 CookieItVector::iterator it_purge_end = it_purge_begin + round_goal;
1930 CookieItVector::iterator it_purge_middle =
1931 LowerBoundAccessDate(it_purge_begin, it_purge_end, safe_date);
1932 // Delete cookies accessed before |safe_date|.
1933 num_deleted += GarbageCollectDeleteRange(
1934 current, DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE, it_purge_begin,
1935 it_purge_middle);
1936 // Delete cookies accessed on or after |safe_date|.
1937 num_deleted += GarbageCollectDeleteRange(
1938 current, DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE, it_purge_middle,
1939 it_purge_end);
1940 it_purge_begin = it_purge_end;
1941 }
1942 DCHECK_EQ(0U, purge_goal); 1886 DCHECK_EQ(0U, purge_goal);
1943 } 1887 }
1944 } 1888 }
1945 1889
1946 // Collect garbage for everything. With firefox style we want to preserve 1890 // Collect garbage for everything. With firefox style we want to preserve
1947 // cookies accessed in kSafeFromGlobalPurgeDays, otherwise evict. 1891 // cookies accessed in kSafeFromGlobalPurgeDays, otherwise evict.
1948 if (cookies_.size() > kMaxCookies && earliest_access_time_ < safe_date) { 1892 if (cookies_.size() > kMaxCookies && earliest_access_time_ < safe_date) {
1949 VLOG(kVlogGarbageCollection) << "GarbageCollect() everything"; 1893 VLOG(kVlogGarbageCollection) << "GarbageCollect() everything";
1950 CookieItVector cookie_its; 1894 CookieItVector cookie_its;
1951 1895
(...skipping 27 matching lines...) Expand all
1979 } else { 1923 } else {
1980 num_deleted += GarbageCollectLeastRecentlyAccessed( 1924 num_deleted += GarbageCollectLeastRecentlyAccessed(
1981 current, safe_date, purge_goal, cookie_its); 1925 current, safe_date, purge_goal, cookie_its);
1982 } 1926 }
1983 } 1927 }
1984 } 1928 }
1985 1929
1986 return num_deleted; 1930 return num_deleted;
1987 } 1931 }
1988 1932
1933 size_t CookieMonster::PurgeLeastRecentMatches(CookieItVector* cookies,
mmenke 2016/03/04 16:17:57 Do we still need the CookieItVector, or could we j
mmenke 2016/03/04 16:20:19 If we take enum that indicates the secure value we
Mike West 2016/03/04 16:34:23 We'd need to scope it to the key involved, but we
Mike West 2016/03/07 10:22:28 Looking at this again, if we use `cookies_` we'll
1934 CookiePriority priority,
1935 size_t to_protect,
1936 size_t purge_goal,
1937 const base::Time& safe_date) {
1938 DCHECK(thread_checker_.CalledOnValidThread());
1939
1940 size_t matches = std::count_if(cookies->begin(), cookies->end(),
1941 [priority](const CookieMap::iterator& it) {
1942 return it->second->Priority() <= priority;
1943 });
1944 if (to_protect > matches)
1945 return 0;
1946
1947 size_t to_remove = std::min(purge_goal, matches - to_protect);
1948 size_t removed = 0;
1949 for (auto it = cookies->begin();
1950 it != cookies->end() && removed < to_remove;) {
1951 if ((*it)->second->Priority() <= priority) {
1952 InternalDeleteCookie(*it, true,
1953 (*it)->second->LastAccessDate() > safe_date
1954 ? DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE
1955 : DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE);
Mike West 2016/03/04 16:34:23 Is anyone looking at these metrics? If not (and I'
mmenke 2016/03/04 16:47:44 You mean the deletion cause? We pass that on to t
Mike West 2016/03/07 10:22:28 I was more specifically referring to the distincti
mmenke 2016/03/07 17:46:03 Ah, right, didn't realize we're pushing a simpler
Mike West 2016/03/08 08:58:28 https://codereview.chromium.org/1769023003
1956 it = cookies->erase(it);
1957 removed++;
1958 } else {
1959 it++;
1960 }
1961 }
1962 return removed;
mmenke 2016/03/04 16:17:57 I think this entire method can be simpler: for (a
Mike West 2016/03/04 16:34:23 We need to protect the X most-recently used cookie
mmenke 2016/03/04 16:40:51 Oh, right, I forgot about purge_goal...So we'd nee
Mike West 2016/03/04 16:46:28 Oh, that's clever. So we'd walk down to the |to_pr
mmenke 2016/03/04 16:48:29 Yes, that's exactly what I mean.
1963 }
1964
1989 size_t CookieMonster::GarbageCollectExpired(const Time& current, 1965 size_t CookieMonster::GarbageCollectExpired(const Time& current,
1990 const CookieMapItPair& itpair, 1966 const CookieMapItPair& itpair,
1991 CookieItVector* cookie_its) { 1967 CookieItVector* cookie_its) {
1992 DCHECK(thread_checker_.CalledOnValidThread()); 1968 DCHECK(thread_checker_.CalledOnValidThread());
1993 1969
1994 int num_deleted = 0; 1970 int num_deleted = 0;
1995 for (CookieMap::iterator it = itpair.first, end = itpair.second; it != end;) { 1971 for (CookieMap::iterator it = itpair.first, end = itpair.second; it != end;) {
1996 CookieMap::iterator curit = it; 1972 CookieMap::iterator curit = it;
1997 ++it; 1973 ++it;
1998 1974
(...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after
2318 it != hook_map_.end(); ++it) { 2294 it != hook_map_.end(); ++it) {
2319 std::pair<GURL, std::string> key = it->first; 2295 std::pair<GURL, std::string> key = it->first;
2320 if (cookie.IncludeForRequestURL(key.first, opts) && 2296 if (cookie.IncludeForRequestURL(key.first, opts) &&
2321 cookie.Name() == key.second) { 2297 cookie.Name() == key.second) {
2322 it->second->Notify(cookie, removed); 2298 it->second->Notify(cookie, removed);
2323 } 2299 }
2324 } 2300 }
2325 } 2301 }
2326 2302
2327 } // namespace net 2303 } // 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