| Index: net/cookies/cookie_monster.cc
|
| diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
|
| index e208d332882e58ecfd09c6d0c88baa6916168a88..fd97ab5c67e2bf489d4a1517ead6c2f3d117cf7d 100644
|
| --- a/net/cookies/cookie_monster.cc
|
| +++ b/net/cookies/cookie_monster.cc
|
| @@ -309,6 +309,55 @@ void RunAsync(scoped_refptr<base::TaskRunner> proxy,
|
| proxy->PostTask(FROM_HERE, base::Bind(callback, cookie, removed));
|
| }
|
|
|
| +size_t CountProtectedSecureCookiesAtPriority(
|
| + CookiePriority priority,
|
| + CookieMonster::CookieItVector* cookies) {
|
| + size_t num_protected_secure_cookies = 0;
|
| + for (const auto& cookie : *cookies) {
|
| + if (!cookie->second->IsSecure())
|
| + continue;
|
| + // 1) At low-priority, only low-priority secure cookies are protected as
|
| + // part of the quota.
|
| + // 2) At medium-priority, only medium-priority secure cookies are protected
|
| + // as part of the quota (low-priority secure cookies may be deleted).
|
| + // 3) At high-priority, medium-priority and high-priority secure cookies are
|
| + // protected as part of the quota (low-priority secure cookies may be
|
| + // deleted).
|
| + CookiePriority cookie_priority = cookie->second->Priority();
|
| + switch (cookie_priority) {
|
| + case COOKIE_PRIORITY_LOW:
|
| + if (priority == COOKIE_PRIORITY_LOW)
|
| + num_protected_secure_cookies++;
|
| + break;
|
| + case COOKIE_PRIORITY_MEDIUM:
|
| + case COOKIE_PRIORITY_HIGH:
|
| + if (cookie_priority <= priority)
|
| + num_protected_secure_cookies++;
|
| + break;
|
| + }
|
| + }
|
| +
|
| + return num_protected_secure_cookies;
|
| +}
|
| +
|
| +bool IsCookieEligibleForEviction(CookiePriority current_priority_level,
|
| + bool protect_secure_cookies,
|
| + const CanonicalCookie* cookie) {
|
| + if (!cookie->IsSecure() || !protect_secure_cookies)
|
| + return cookie->Priority() <= current_priority_level;
|
| +
|
| + // Special consideration has to be given for low-priority secure cookies since
|
| + // they are given lower prority than non-secure medium-priority and non-secure
|
| + // high-priority cookies. Thus, low-priority secure cookies may be evicted at
|
| + // a medium and high value of |current_priority_level|. Put another way,
|
| + // low-priority secure cookies are only protected when the current priority
|
| + // level is low.
|
| + if (current_priority_level == COOKIE_PRIORITY_LOW)
|
| + return false;
|
| +
|
| + return cookie->Priority() == COOKIE_PRIORITY_LOW;
|
| +}
|
| +
|
| } // namespace
|
|
|
| CookieMonster::CookieMonster(PersistentCookieStore* store,
|
| @@ -1869,15 +1918,6 @@ 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.";
|
| - num_deleted +=
|
| - GarbageCollectNonSecure(non_expired_cookie_its, &secure_cookie_its);
|
| - cookie_its = &secure_cookie_its;
|
| - }
|
| -
|
| if (cookie_its->size() > kDomainMaxCookies) {
|
| VLOG(kVlogGarbageCollection) << "Deep Garbage Collect domain.";
|
| size_t purge_goal =
|
| @@ -1887,25 +1927,83 @@ size_t CookieMonster::GarbageCollect(const Time& current,
|
| // Sort the cookies by access date, from least-recent to most-recent.
|
| std::sort(cookie_its->begin(), cookie_its->end(), LRACookieSorter);
|
|
|
| + size_t additional_quota_low = kDomainCookiesQuotaLow;
|
| + size_t additional_quota_medium = kDomainCookiesQuotaMedium;
|
| + size_t additional_quota_high = kDomainCookiesQuotaHigh;
|
| +
|
| // 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};
|
| + //
|
| + // 1. Low-priority non-secure cookies.
|
| + // 2. Low-priority secure cookies.
|
| + // 3. Medium-priority non-secure cookies.
|
| + // 4. High-priority non-secure cookies.
|
| + // 5. Medium-priority secure cookies.
|
| + // 6. High-priority secure cookies.
|
| + const static struct {
|
| + CookiePriority priority;
|
| + bool protect_secure_cookies;
|
| + } purge_rounds[] = {
|
| + // 1. Low-priority non-secure cookies.
|
| + {COOKIE_PRIORITY_LOW, true},
|
| + // 2. Low-priority secure cookies.
|
| + {COOKIE_PRIORITY_LOW, false},
|
| + // 3. Medium-priority non-secure cookies.
|
| + {COOKIE_PRIORITY_MEDIUM, true},
|
| + // 4. High-priority non-secure cookies.
|
| + {COOKIE_PRIORITY_HIGH, true},
|
| + // 5. Medium-priority secure cookies.
|
| + {COOKIE_PRIORITY_MEDIUM, false},
|
| + // 6. High-priority secure cookies.
|
| + {COOKIE_PRIORITY_HIGH, false},
|
| + };
|
| +
|
| 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);
|
| - DCHECK_LE(just_deleted, purge_goal);
|
| - purge_goal -= just_deleted;
|
| - num_deleted += just_deleted;
|
| + for (const auto& purge_round : purge_rounds) {
|
| + // Only observe the non-secure purge rounds if strict secure cookies is
|
| + // enabled.
|
| + if (!enforce_strict_secure && purge_round.protect_secure_cookies)
|
| + continue;
|
| +
|
| + // Only adjust the quota if the round is executing, otherwise it is
|
| + // necesary to delay quota adjustments until a later round. This is
|
| + // because if the high priority, non-secure round is skipped, its quota
|
| + // should not count until the later high priority, full round later.
|
| + size_t* additional_quota = nullptr;
|
| + switch (purge_round.priority) {
|
| + case COOKIE_PRIORITY_LOW:
|
| + additional_quota = &additional_quota_low;
|
| + break;
|
| + case COOKIE_PRIORITY_MEDIUM:
|
| + additional_quota = &additional_quota_medium;
|
| + break;
|
| + case COOKIE_PRIORITY_HIGH:
|
| + additional_quota = &additional_quota_high;
|
| + break;
|
| + }
|
| + quota += *additional_quota;
|
| + *additional_quota = 0u;
|
| + size_t just_deleted = 0u;
|
| +
|
| + // Purge up to |purge_goal| for all cookies at the given priority. This
|
| + // path will always execute if strict secure cookies is disabled since
|
| + // |purge_goal| must be positive because of the for-loop guard. If
|
| + // strict secure cookies is enabled, this path will be taken only if the
|
| + // initial non-secure purge did not evict enough cookies.
|
| + if (purge_goal > 0) {
|
| + just_deleted = PurgeLeastRecentMatches(
|
| + cookie_its, purge_round.priority, quota, purge_goal,
|
| + purge_round.protect_secure_cookies);
|
| + DCHECK_LE(just_deleted, purge_goal);
|
| + purge_goal -= just_deleted;
|
| + num_deleted += just_deleted;
|
| + }
|
| }
|
|
|
| - DCHECK_EQ(0U, purge_goal);
|
| + DCHECK_EQ(0u, purge_goal);
|
| }
|
| }
|
|
|
| @@ -1955,12 +2053,21 @@ size_t CookieMonster::GarbageCollect(const Time& current,
|
| size_t CookieMonster::PurgeLeastRecentMatches(CookieItVector* cookies,
|
| CookiePriority priority,
|
| size_t to_protect,
|
| - size_t purge_goal) {
|
| + size_t purge_goal,
|
| + bool protect_secure_cookies) {
|
| 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.
|
| + //
|
| + // If |protect_secure_cookies| is true, do a first pass that counts eligible
|
| + // secure cookies at the specified priority as protected.
|
| + if (protect_secure_cookies) {
|
| + to_protect -= std::min(
|
| + to_protect, CountProtectedSecureCookiesAtPriority(priority, cookies));
|
| + }
|
| +
|
| size_t protection_boundary = cookies->size();
|
| while (to_protect > 0 && protection_boundary > 0) {
|
| protection_boundary--;
|
| @@ -1974,7 +2081,12 @@ size_t CookieMonster::PurgeLeastRecentMatches(CookieItVector* cookies,
|
| size_t removed = 0;
|
| size_t current = 0;
|
| while (removed < purge_goal && current < protection_boundary) {
|
| - if (cookies->at(current)->second->Priority() <= priority) {
|
| + const CanonicalCookie* current_cookie = cookies->at(current)->second;
|
| + // Only delete the current cookie if the priority is less than or equal to
|
| + // the current level. If it is equal to the current level, and secure
|
| + // cookies are protected, only delete it if it is not secure.
|
| + if (IsCookieEligibleForEviction(priority, protect_secure_cookies,
|
| + current_cookie)) {
|
| InternalDeleteCookie(cookies->at(current), true,
|
| DELETE_COOKIE_EVICTED_DOMAIN);
|
| cookies->erase(cookies->begin() + current);
|
| @@ -2012,24 +2124,6 @@ size_t CookieMonster::GarbageCollectExpired(const Time& current,
|
| return num_deleted;
|
| }
|
|
|
| -size_t CookieMonster::GarbageCollectNonSecure(
|
| - const CookieItVector& valid_cookies,
|
| - CookieItVector* cookie_its) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - size_t num_deleted = 0;
|
| - for (const auto& curr_cookie_it : valid_cookies) {
|
| - if (!curr_cookie_it->second->IsSecure()) {
|
| - InternalDeleteCookie(curr_cookie_it, true, DELETE_COOKIE_NON_SECURE);
|
| - ++num_deleted;
|
| - } else if (cookie_its) {
|
| - cookie_its->push_back(curr_cookie_it);
|
| - }
|
| - }
|
| -
|
| - return num_deleted;
|
| -}
|
| -
|
| size_t CookieMonster::GarbageCollectDeleteRange(
|
| const Time& current,
|
| DeletionCause cause,
|
|
|