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 1580 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1867 if (cookies_.count(key) > kDomainMaxCookies) { | 1840 if (cookies_.count(key) > kDomainMaxCookies) { |
1868 VLOG(kVlogGarbageCollection) << "GarbageCollect() key: " << key; | 1841 VLOG(kVlogGarbageCollection) << "GarbageCollect() key: " << key; |
1869 | 1842 |
1870 CookieItVector* cookie_its; | 1843 CookieItVector* cookie_its; |
1871 | 1844 |
1872 CookieItVector non_expired_cookie_its; | 1845 CookieItVector non_expired_cookie_its; |
1873 cookie_its = &non_expired_cookie_its; | 1846 cookie_its = &non_expired_cookie_its; |
1874 num_deleted += | 1847 num_deleted += |
1875 GarbageCollectExpired(current, cookies_.equal_range(key), cookie_its); | 1848 GarbageCollectExpired(current, cookies_.equal_range(key), cookie_its); |
1876 | 1849 |
1850 // TODO(mkwst): Soften this. | |
1877 CookieItVector secure_cookie_its; | 1851 CookieItVector secure_cookie_its; |
1878 if (enforce_strict_secure && cookie_its->size() > kDomainMaxCookies) { | 1852 if (enforce_strict_secure && cookie_its->size() > kDomainMaxCookies) { |
1879 VLOG(kVlogGarbageCollection) << "Garbage collecting non-Secure cookies."; | 1853 VLOG(kVlogGarbageCollection) << "Garbage collecting non-Secure cookies."; |
1880 num_deleted += | 1854 num_deleted += |
1881 GarbageCollectNonSecure(non_expired_cookie_its, &secure_cookie_its); | 1855 GarbageCollectNonSecure(non_expired_cookie_its, &secure_cookie_its); |
1882 cookie_its = &secure_cookie_its; | 1856 cookie_its = &secure_cookie_its; |
1883 } | 1857 } |
1884 | 1858 |
1885 if (cookie_its->size() > kDomainMaxCookies) { | 1859 if (cookie_its->size() > kDomainMaxCookies) { |
1886 VLOG(kVlogGarbageCollection) << "Deep Garbage Collect domain."; | 1860 VLOG(kVlogGarbageCollection) << "Deep Garbage Collect domain."; |
1887 size_t purge_goal = | 1861 size_t purge_goal = |
1888 cookie_its->size() - (kDomainMaxCookies - kDomainPurgeCookies); | 1862 cookie_its->size() - (kDomainMaxCookies - kDomainPurgeCookies); |
1889 DCHECK(purge_goal > kDomainPurgeCookies); | 1863 DCHECK(purge_goal > kDomainPurgeCookies); |
1890 | 1864 |
1891 // Boundary iterators into |cookie_its| for different priorities. | 1865 // Sort the cookies by access date, from least-recent to most-recent. |
1892 CookieItVector::iterator it_bdd[4]; | 1866 std::sort(cookie_its->begin(), cookie_its->end(), LRACookieSorter); |
1893 // Intialize |it_bdd| while sorting |cookie_its| by priorities. | |
1894 // Schematic: [MLLHMHHLMM] => [LLL|MMMM|HHH], with 4 boundaries. | |
1895 it_bdd[0] = cookie_its->begin(); | |
1896 it_bdd[3] = cookie_its->end(); | |
1897 it_bdd[1] = | |
1898 PartitionCookieByPriority(it_bdd[0], it_bdd[3], COOKIE_PRIORITY_LOW); | |
1899 it_bdd[2] = PartitionCookieByPriority(it_bdd[1], it_bdd[3], | |
1900 COOKIE_PRIORITY_MEDIUM); | |
1901 size_t quota[3] = {kDomainCookiesQuotaLow, | |
1902 kDomainCookiesQuotaMedium, | |
1903 kDomainCookiesQuotaHigh}; | |
1904 | 1867 |
1905 // Purge domain cookies in 3 rounds. | 1868 // Remove all but the kDomainCookiesQuotaLow most-recently accessed |
1906 // Round 1: consider low-priority cookies only: evict least-recently | 1869 // cookies with low-priority. Then, if we still need to remove cookies, |
mmenke
2016/03/07 17:46:03
nit: Avoid we in comments (x2)
Mike West
2016/03/08 08:44:56
Done.
| |
1907 // accessed, while protecting quota[0] of these from deletion. | 1870 // bump the quota and remove low- and medium-priority. Then, if we |
1908 // Round 2: consider {low, medium}-priority cookies, evict least-recently | 1871 // _still_ need to remove cookies, bump the quota and remove cookies |
1909 // accessed, while protecting quota[0] + quota[1]. | 1872 // with any priority. |
1910 // Round 3: consider all cookies, evict least-recently accessed. | 1873 size_t quotas[3] = {kDomainCookiesQuotaLow, kDomainCookiesQuotaMedium, |
1911 size_t accumulated_quota = 0; | 1874 kDomainCookiesQuotaHigh}; |
1912 CookieItVector::iterator it_purge_begin = it_bdd[0]; | 1875 size_t quota = 0; |
1913 for (int i = 0; i < 3 && purge_goal > 0; ++i) { | 1876 for (size_t i = 0; i < arraysize(quotas) && purge_goal; i++) { |
1914 accumulated_quota += quota[i]; | 1877 quota += quotas[i]; |
1878 size_t just_deleted = | |
1879 PurgeLeastRecentMatches(cookie_its, static_cast<CookiePriority>(i), | |
1880 quota, purge_goal, safe_date); | |
1881 purge_goal -= just_deleted; | |
1882 num_deleted += just_deleted; | |
1883 } | |
1915 | 1884 |
1916 size_t num_considered = it_bdd[i + 1] - it_purge_begin; | |
1917 if (num_considered <= accumulated_quota) | |
1918 continue; | |
1919 | |
1920 // Number of cookies that will be purged in this round. | |
1921 size_t round_goal = | |
1922 std::min(purge_goal, num_considered - accumulated_quota); | |
1923 purge_goal -= round_goal; | |
1924 | |
1925 SortLeastRecentlyAccessed(it_purge_begin, it_bdd[i + 1], round_goal); | |
1926 // Cookies accessed on or after |safe_date| would have been safe from | |
1927 // global purge, and we want to keep track of this. | |
1928 CookieItVector::iterator it_purge_end = it_purge_begin + round_goal; | |
1929 CookieItVector::iterator it_purge_middle = | |
1930 LowerBoundAccessDate(it_purge_begin, it_purge_end, safe_date); | |
1931 // Delete cookies accessed before |safe_date|. | |
1932 num_deleted += GarbageCollectDeleteRange( | |
1933 current, DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE, it_purge_begin, | |
1934 it_purge_middle); | |
1935 // Delete cookies accessed on or after |safe_date|. | |
1936 num_deleted += GarbageCollectDeleteRange( | |
1937 current, DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE, it_purge_middle, | |
1938 it_purge_end); | |
1939 it_purge_begin = it_purge_end; | |
1940 } | |
1941 DCHECK_EQ(0U, purge_goal); | 1885 DCHECK_EQ(0U, purge_goal); |
1942 } | 1886 } |
1943 } | 1887 } |
1944 | 1888 |
1945 // Collect garbage for everything. With firefox style we want to preserve | 1889 // Collect garbage for everything. With firefox style we want to preserve |
1946 // cookies accessed in kSafeFromGlobalPurgeDays, otherwise evict. | 1890 // cookies accessed in kSafeFromGlobalPurgeDays, otherwise evict. |
1947 if (cookies_.size() > kMaxCookies && earliest_access_time_ < safe_date) { | 1891 if (cookies_.size() > kMaxCookies && earliest_access_time_ < safe_date) { |
1948 VLOG(kVlogGarbageCollection) << "GarbageCollect() everything"; | 1892 VLOG(kVlogGarbageCollection) << "GarbageCollect() everything"; |
1949 CookieItVector cookie_its; | 1893 CookieItVector cookie_its; |
1950 | 1894 |
(...skipping 27 matching lines...) Expand all Loading... | |
1978 } else { | 1922 } else { |
1979 num_deleted += GarbageCollectLeastRecentlyAccessed( | 1923 num_deleted += GarbageCollectLeastRecentlyAccessed( |
1980 current, safe_date, purge_goal, cookie_its); | 1924 current, safe_date, purge_goal, cookie_its); |
1981 } | 1925 } |
1982 } | 1926 } |
1983 } | 1927 } |
1984 | 1928 |
1985 return num_deleted; | 1929 return num_deleted; |
1986 } | 1930 } |
1987 | 1931 |
1932 size_t CookieMonster::PurgeLeastRecentMatches(CookieItVector* cookies, | |
1933 CookiePriority priority, | |
1934 size_t to_protect, | |
1935 size_t purge_goal, | |
1936 const base::Time& safe_date) { | |
1937 DCHECK(thread_checker_.CalledOnValidThread()); | |
1938 | |
1939 // Find the first protected cookie by walking down from the end of the list | |
1940 // cookie list (most-recently accessed) until |to_protect| cookies that match | |
1941 // |priority| are found. | |
1942 CookieItVector::iterator protection_boundary = cookies->end(); | |
1943 while (to_protect && protection_boundary > cookies->begin()) { | |
mmenke
2016/03/07 17:46:03
comparing iterators with ">" instead of != seems w
mmenke
2016/03/07 17:46:03
Suggest to_protect -> to_protect > 0. They're equ
Mike West
2016/03/08 08:44:56
Dropped iterators to the extent possible, as below
| |
1944 protection_boundary--; | |
1945 if ((*protection_boundary)->second->Priority() <= priority) | |
1946 to_protect--; | |
1947 } | |
1948 | |
1949 // Now, walk up from the beginning of the list (least-recently accessed) until | |
1950 // |purge_goal| cookies are removed, or the iterator hits | |
1951 // |protection_boundary|. | |
1952 size_t removed = 0; | |
1953 CookieItVector::iterator current = cookies->begin(); | |
1954 while (removed < purge_goal && current < protection_boundary) { | |
1955 if ((*current)->second->Priority() <= priority) { | |
1956 InternalDeleteCookie(*current, true, | |
1957 (*current)->second->LastAccessDate() > safe_date | |
1958 ? DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE | |
1959 : DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE); | |
1960 current = cookies->erase(current); | |
1961 removed++; | |
1962 | |
1963 // The call to 'erase' above shifts the contents of the vector, but | |
1964 // doesn't shift |protection_boundary|. Decrement that here to ensure that | |
1965 // the correct set of cookies is protected. | |
1966 protection_boundary--; | |
mmenke
2016/03/07 17:46:03
Is this guaranteed to be correct? Can we just tra
Mike West
2016/03/08 08:44:56
I was pretty sure it was correct until you asked m
| |
1967 } else { | |
1968 current++; | |
1969 } | |
1970 } | |
1971 return removed; | |
1972 } | |
1973 | |
1988 size_t CookieMonster::GarbageCollectExpired(const Time& current, | 1974 size_t CookieMonster::GarbageCollectExpired(const Time& current, |
1989 const CookieMapItPair& itpair, | 1975 const CookieMapItPair& itpair, |
1990 CookieItVector* cookie_its) { | 1976 CookieItVector* cookie_its) { |
1991 DCHECK(thread_checker_.CalledOnValidThread()); | 1977 DCHECK(thread_checker_.CalledOnValidThread()); |
1992 | 1978 |
1993 int num_deleted = 0; | 1979 int num_deleted = 0; |
1994 for (CookieMap::iterator it = itpair.first, end = itpair.second; it != end;) { | 1980 for (CookieMap::iterator it = itpair.first, end = itpair.second; it != end;) { |
1995 CookieMap::iterator curit = it; | 1981 CookieMap::iterator curit = it; |
1996 ++it; | 1982 ++it; |
1997 | 1983 |
(...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2317 it != hook_map_.end(); ++it) { | 2303 it != hook_map_.end(); ++it) { |
2318 std::pair<GURL, std::string> key = it->first; | 2304 std::pair<GURL, std::string> key = it->first; |
2319 if (cookie.IncludeForRequestURL(key.first, opts) && | 2305 if (cookie.IncludeForRequestURL(key.first, opts) && |
2320 cookie.Name() == key.second) { | 2306 cookie.Name() == key.second) { |
2321 it->second->Notify(cookie, removed); | 2307 it->second->Notify(cookie, removed); |
2322 } | 2308 } |
2323 } | 2309 } |
2324 } | 2310 } |
2325 | 2311 |
2326 } // namespace net | 2312 } // namespace net |
OLD | NEW |