| Index: net/cookies/cookie_monster.cc
|
| diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
|
| index c73e74aee7d2f4ae38e61053239b475930601e39..19a2d6ac7f81f99dca36e1ec8fc1f47e6c722b71 100644
|
| --- a/net/cookies/cookie_monster.cc
|
| +++ b/net/cookies/cookie_monster.cc
|
| @@ -162,13 +162,10 @@ bool CookieSorter(CanonicalCookie* cc1, CanonicalCookie* cc2) {
|
|
|
| bool LRACookieSorter(const CookieMonster::CookieMap::iterator& it1,
|
| const CookieMonster::CookieMap::iterator& it2) {
|
| - // Cookies accessed less recently should be deleted first.
|
| if (it1->second->LastAccessDate() != it2->second->LastAccessDate())
|
| return it1->second->LastAccessDate() < it2->second->LastAccessDate();
|
|
|
| - // In rare cases we might have two cookies with identical last access times.
|
| - // To preserve the stability of the sort, in these cases prefer to delete
|
| - // older cookies over newer ones. CreationDate() is guaranteed to be unique.
|
| + // Ensure stability for == last access times by falling back to creation.
|
| return it1->second->CreationDate() < it2->second->CreationDate();
|
| }
|
|
|
| @@ -250,29 +247,6 @@ void SplitCookieVectorIntoSecureAndNonSecure(
|
| }
|
| }
|
|
|
| -// Predicate to support PartitionCookieByPriority().
|
| -struct CookiePriorityEqualsTo {
|
| - explicit CookiePriorityEqualsTo(CookiePriority priority)
|
| - : priority_(priority) {}
|
| -
|
| - bool operator()(const CookieMonster::CookieMap::iterator it) const {
|
| - return it->second->Priority() == priority_;
|
| - }
|
| -
|
| - const CookiePriority priority_;
|
| -};
|
| -
|
| -// For a CookieItVector iterator range [|it_begin|, |it_end|),
|
| -// moves all cookies with a given |priority| to the beginning of the list.
|
| -// Returns: An iterator in [it_begin, it_end) to the first element with
|
| -// priority != |priority|, or |it_end| if all have priority == |priority|.
|
| -CookieMonster::CookieItVector::iterator PartitionCookieByPriority(
|
| - CookieMonster::CookieItVector::iterator it_begin,
|
| - CookieMonster::CookieItVector::iterator it_end,
|
| - CookiePriority priority) {
|
| - return std::partition(it_begin, it_end, CookiePriorityEqualsTo(priority));
|
| -}
|
| -
|
| bool LowerBoundAccessDateComparator(const CookieMonster::CookieMap::iterator it,
|
| const Time& access_date) {
|
| return it->second->LastAccessDate() < access_date;
|
| @@ -1898,6 +1872,7 @@ size_t CookieMonster::GarbageCollect(const Time& current,
|
| num_deleted +=
|
| GarbageCollectExpired(current, cookies_.equal_range(key), cookie_its);
|
|
|
| + // TODO(mkwst): Soften this.
|
| CookieItVector secure_cookie_its;
|
| if (enforce_strict_secure && cookie_its->size() > kDomainMaxCookies) {
|
| VLOG(kVlogGarbageCollection) << "Garbage collecting non-Secure cookies.";
|
| @@ -1912,56 +1887,28 @@ size_t CookieMonster::GarbageCollect(const Time& current,
|
| cookie_its->size() - (kDomainMaxCookies - kDomainPurgeCookies);
|
| DCHECK(purge_goal > kDomainPurgeCookies);
|
|
|
| - // Boundary iterators into |cookie_its| for different priorities.
|
| - CookieItVector::iterator it_bdd[4];
|
| - // Intialize |it_bdd| while sorting |cookie_its| by priorities.
|
| - // Schematic: [MLLHMHHLMM] => [LLL|MMMM|HHH], with 4 boundaries.
|
| - it_bdd[0] = cookie_its->begin();
|
| - it_bdd[3] = cookie_its->end();
|
| - it_bdd[1] =
|
| - PartitionCookieByPriority(it_bdd[0], it_bdd[3], COOKIE_PRIORITY_LOW);
|
| - it_bdd[2] = PartitionCookieByPriority(it_bdd[1], it_bdd[3],
|
| - COOKIE_PRIORITY_MEDIUM);
|
| - size_t quota[3] = {kDomainCookiesQuotaLow,
|
| - kDomainCookiesQuotaMedium,
|
| - kDomainCookiesQuotaHigh};
|
| -
|
| - // Purge domain cookies in 3 rounds.
|
| - // Round 1: consider low-priority cookies only: evict least-recently
|
| - // accessed, while protecting quota[0] of these from deletion.
|
| - // Round 2: consider {low, medium}-priority cookies, evict least-recently
|
| - // accessed, while protecting quota[0] + quota[1].
|
| - // Round 3: consider all cookies, evict least-recently accessed.
|
| - size_t accumulated_quota = 0;
|
| - CookieItVector::iterator it_purge_begin = it_bdd[0];
|
| - for (int i = 0; i < 3 && purge_goal > 0; ++i) {
|
| - accumulated_quota += quota[i];
|
| -
|
| - size_t num_considered = it_bdd[i + 1] - it_purge_begin;
|
| - if (num_considered <= accumulated_quota)
|
| - continue;
|
| -
|
| - // Number of cookies that will be purged in this round.
|
| - size_t round_goal =
|
| - std::min(purge_goal, num_considered - accumulated_quota);
|
| - purge_goal -= round_goal;
|
| -
|
| - SortLeastRecentlyAccessed(it_purge_begin, it_bdd[i + 1], round_goal);
|
| - // Cookies accessed on or after |safe_date| would have been safe from
|
| - // global purge, and we want to keep track of this.
|
| - CookieItVector::iterator it_purge_end = it_purge_begin + round_goal;
|
| - CookieItVector::iterator it_purge_middle =
|
| - LowerBoundAccessDate(it_purge_begin, it_purge_end, safe_date);
|
| - // Delete cookies accessed before |safe_date|.
|
| - num_deleted += GarbageCollectDeleteRange(
|
| - current, DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE, it_purge_begin,
|
| - it_purge_middle);
|
| - // Delete cookies accessed on or after |safe_date|.
|
| - num_deleted += GarbageCollectDeleteRange(
|
| - current, DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE, it_purge_middle,
|
| - it_purge_end);
|
| - it_purge_begin = it_purge_end;
|
| + // Sort the cookies by access date, from least-recent to most-recent.
|
| + std::sort(cookie_its->begin(), cookie_its->end(), LRACookieSorter);
|
| +
|
| + // Remove all but the kDomainCookiesQuotaLow most-recently accessed
|
| + // cookies with low-priority. Then, if cookies still need to be removed,
|
| + // bump the quota and remove low- and medium-priority. Then, if cookies
|
| + // _still_ need to be removed, bump the quota and remove cookies with
|
| + // any priority.
|
| + const size_t kQuotas[3] = {kDomainCookiesQuotaLow,
|
| + kDomainCookiesQuotaMedium,
|
| + kDomainCookiesQuotaHigh};
|
| + size_t quota = 0;
|
| + for (size_t i = 0; i < arraysize(kQuotas) && purge_goal > 0; i++) {
|
| + quota += kQuotas[i];
|
| + size_t just_deleted =
|
| + PurgeLeastRecentMatches(cookie_its, static_cast<CookiePriority>(i),
|
| + quota, purge_goal, safe_date);
|
| + DCHECK_LE(just_deleted, purge_goal);
|
| + purge_goal -= just_deleted;
|
| + num_deleted += just_deleted;
|
| }
|
| +
|
| DCHECK_EQ(0U, purge_goal);
|
| }
|
| }
|
| @@ -2009,6 +1956,49 @@ size_t CookieMonster::GarbageCollect(const Time& current,
|
| return num_deleted;
|
| }
|
|
|
| +size_t CookieMonster::PurgeLeastRecentMatches(CookieItVector* cookies,
|
| + CookiePriority priority,
|
| + size_t to_protect,
|
| + size_t purge_goal,
|
| + const base::Time& safe_date) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + // Find the first protected cookie by walking down from the end of the list
|
| + // cookie list (most-recently accessed) until |to_protect| cookies that match
|
| + // |priority| are found.
|
| + size_t protection_boundary = cookies->size();
|
| + while (to_protect > 0 && protection_boundary > 0) {
|
| + protection_boundary--;
|
| + if (cookies->at(protection_boundary)->second->Priority() <= priority)
|
| + to_protect--;
|
| + }
|
| +
|
| + // Now, walk up from the beginning of the list (least-recently accessed) until
|
| + // |purge_goal| cookies are removed, or the iterator hits
|
| + // |protection_boundary|.
|
| + size_t removed = 0;
|
| + size_t current = 0;
|
| + while (removed < purge_goal && current < protection_boundary) {
|
| + if (cookies->at(current)->second->Priority() <= priority) {
|
| + InternalDeleteCookie(
|
| + cookies->at(current), true,
|
| + cookies->at(current)->second->LastAccessDate() > safe_date
|
| + ? DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE
|
| + : DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE);
|
| + cookies->erase(cookies->begin() + current);
|
| + removed++;
|
| +
|
| + // The call to 'erase' above shifts the contents of the vector, but
|
| + // doesn't shift |protection_boundary|. Decrement that here to ensure that
|
| + // the correct set of cookies is protected.
|
| + protection_boundary--;
|
| + } else {
|
| + current++;
|
| + }
|
| + }
|
| + return removed;
|
| +}
|
| +
|
| size_t CookieMonster::GarbageCollectExpired(const Time& current,
|
| const CookieMapItPair& itpair,
|
| CookieItVector* cookie_its) {
|
|
|