summaryrefslogtreecommitdiff
path: root/chromium/net/cookies/cookie_monster.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/net/cookies/cookie_monster.cc')
-rw-r--r--chromium/net/cookies/cookie_monster.cc281
1 files changed, 184 insertions, 97 deletions
diff --git a/chromium/net/cookies/cookie_monster.cc b/chromium/net/cookies/cookie_monster.cc
index 75c62667dda..3d7124d502e 100644
--- a/chromium/net/cookies/cookie_monster.cc
+++ b/chromium/net/cookies/cookie_monster.cc
@@ -46,6 +46,7 @@
#include <algorithm>
#include <functional>
+#include <memory>
#include <set>
#include "base/bind.h"
@@ -53,14 +54,14 @@
#include "base/location.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
+#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
#include "base/profiler/scoped_tracker.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
-#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "net/cookies/canonical_cookie.h"
#include "net/cookies/cookie_util.h"
@@ -308,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,
@@ -592,37 +642,38 @@ int CookieMonster::DeleteAllCreatedBetweenTask::RunDeleteTask() {
delete_end_);
}
-// Task class for DeleteAllCreatedBetweenForHost call.
-class CookieMonster::DeleteAllCreatedBetweenForHostTask
+// Task class for DeleteAllCreatedBetweenWithPredicate call.
+class CookieMonster::DeleteAllCreatedBetweenWithPredicateTask
: public DeleteTask<int> {
public:
- DeleteAllCreatedBetweenForHostTask(CookieMonster* cookie_monster,
- Time delete_begin,
- Time delete_end,
- const GURL& url,
- const DeleteCallback& callback)
+ DeleteAllCreatedBetweenWithPredicateTask(
+ CookieMonster* cookie_monster,
+ Time delete_begin,
+ Time delete_end,
+ base::Callback<bool(const CanonicalCookie&)> predicate,
+ const DeleteCallback& callback)
: DeleteTask<int>(cookie_monster, callback),
delete_begin_(delete_begin),
delete_end_(delete_end),
- url_(url) {}
+ predicate_(predicate) {}
// DeleteTask:
int RunDeleteTask() override;
protected:
- ~DeleteAllCreatedBetweenForHostTask() override {}
+ ~DeleteAllCreatedBetweenWithPredicateTask() override {}
private:
Time delete_begin_;
Time delete_end_;
- GURL url_;
+ base::Callback<bool(const CanonicalCookie&)> predicate_;
- DISALLOW_COPY_AND_ASSIGN(DeleteAllCreatedBetweenForHostTask);
+ DISALLOW_COPY_AND_ASSIGN(DeleteAllCreatedBetweenWithPredicateTask);
};
-int CookieMonster::DeleteAllCreatedBetweenForHostTask::RunDeleteTask() {
- return this->cookie_monster()->DeleteAllCreatedBetweenForHost(
- delete_begin_, delete_end_, url_);
+int CookieMonster::DeleteAllCreatedBetweenWithPredicateTask::RunDeleteTask() {
+ return this->cookie_monster()->DeleteAllCreatedBetweenWithPredicate(
+ delete_begin_, delete_end_, predicate_);
}
// Task class for DeleteCanonicalCookie call.
@@ -923,16 +974,19 @@ void CookieMonster::DeleteAllCreatedBetweenAsync(
DoCookieTask(task);
}
-void CookieMonster::DeleteAllCreatedBetweenForHostAsync(
- const Time delete_begin,
- const Time delete_end,
- const GURL& url,
+void CookieMonster::DeleteAllCreatedBetweenWithPredicateAsync(
+ const Time& delete_begin,
+ const Time& delete_end,
+ const base::Callback<bool(const CanonicalCookie&)>& predicate,
const DeleteCallback& callback) {
- scoped_refptr<DeleteAllCreatedBetweenForHostTask> task =
- new DeleteAllCreatedBetweenForHostTask(this, delete_begin, delete_end,
- url, callback);
-
- DoCookieTaskForURL(task, url);
+ if (predicate.is_null()) {
+ callback.Run(0);
+ return;
+ }
+ scoped_refptr<DeleteAllCreatedBetweenWithPredicateTask> task =
+ new DeleteAllCreatedBetweenWithPredicateTask(
+ this, delete_begin, delete_end, predicate, callback);
+ DoCookieTask(task);
}
void CookieMonster::DeleteSessionCookiesAsync(
@@ -974,7 +1028,7 @@ const char* const CookieMonster::kDefaultCookieableSchemes[] = {"http", "https",
const int CookieMonster::kDefaultCookieableSchemesCount =
arraysize(kDefaultCookieableSchemes);
-scoped_ptr<CookieStore::CookieChangedSubscription>
+std::unique_ptr<CookieStore::CookieChangedSubscription>
CookieMonster::AddCallbackForCookie(const GURL& gurl,
const std::string& name,
const CookieChangedCallback& callback) {
@@ -1033,7 +1087,7 @@ bool CookieMonster::SetCookieWithDetails(const GURL& url,
last_time_seen_ = actual_creation_time;
}
- scoped_ptr<CanonicalCookie> cc(CanonicalCookie::Create(
+ std::unique_ptr<CanonicalCookie> cc(CanonicalCookie::Create(
url, name, value, domain, path, actual_creation_time, expiration_time,
secure, http_only, same_site, enforce_strict_secure, priority));
@@ -1125,42 +1179,30 @@ int CookieMonster::DeleteAllCreatedBetween(const Time& delete_begin,
return num_deleted;
}
-int CookieMonster::DeleteAllCreatedBetweenForHost(const Time delete_begin,
- const Time delete_end,
- const GURL& url) {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- if (!HasCookieableScheme(url))
- return 0;
-
- const std::string host(url.host());
-
- // We store host cookies in the store by their canonical host name;
- // domain cookies are stored with a leading ".". So this is a pretty
- // simple lookup and per-cookie delete.
+int CookieMonster::DeleteAllCreatedBetweenWithPredicate(
+ const base::Time& delete_begin,
+ const base::Time& delete_end,
+ const base::Callback<bool(const CanonicalCookie&)>& predicate) {
int num_deleted = 0;
- for (CookieMapItPair its = cookies_.equal_range(GetKey(host));
- its.first != its.second;) {
- CookieMap::iterator curit = its.first;
- ++its.first;
-
- const CanonicalCookie* const cc = curit->second;
+ for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) {
+ CookieMap::iterator curit = it;
+ CanonicalCookie* cc = curit->second;
+ ++it;
- // Delete only on a match as a host cookie.
- if (cc->IsHostCookie() && cc->IsDomainMatch(host) &&
- cc->CreationDate() >= delete_begin &&
+ if (cc->CreationDate() >= delete_begin &&
// The assumption that null |delete_end| is equivalent to
// Time::Max() is confusing.
- (delete_end.is_null() || cc->CreationDate() < delete_end)) {
- num_deleted++;
-
- InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPLICIT);
+ (delete_end.is_null() || cc->CreationDate() < delete_end) &&
+ predicate.Run(*cc)) {
+ InternalDeleteCookie(curit, true, /*sync_to_store*/
+ DELETE_COOKIE_EXPLICIT);
+ ++num_deleted;
}
}
+
return num_deleted;
}
-
bool CookieMonster::SetCookieWithOptions(const GURL& url,
const std::string& cookie_line,
const CookieOptions& options) {
@@ -1727,7 +1769,7 @@ bool CookieMonster::SetCookieWithCreationTimeAndOptions(
last_time_seen_ = creation_time;
}
- scoped_ptr<CanonicalCookie> cc(
+ std::unique_ptr<CanonicalCookie> cc(
CanonicalCookie::Create(url, cookie_line, creation_time, options));
if (!cc.get()) {
@@ -1737,7 +1779,7 @@ bool CookieMonster::SetCookieWithCreationTimeAndOptions(
return SetCanonicalCookie(std::move(cc), options);
}
-bool CookieMonster::SetCanonicalCookie(scoped_ptr<CanonicalCookie> cc,
+bool CookieMonster::SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc,
const CookieOptions& options) {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -1795,7 +1837,7 @@ bool CookieMonster::SetCanonicalCookies(const CookieList& list) {
options.set_include_httponly();
for (const auto& cookie : list) {
- if (!SetCanonicalCookie(make_scoped_ptr(new CanonicalCookie(cookie)),
+ if (!SetCanonicalCookie(base::WrapUnique(new CanonicalCookie(cookie)),
options)) {
return false;
}
@@ -1877,15 +1919,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 =
@@ -1895,25 +1928,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);
}
}
@@ -1963,12 +2054,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--;
@@ -1982,7 +2082,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);
@@ -2020,24 +2125,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,