Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |