diff options
Diffstat (limited to 'net/base')
-rw-r--r-- | net/base/cookie_monster.cc | 158 | ||||
-rw-r--r-- | net/base/cookie_monster.h | 38 |
2 files changed, 111 insertions, 85 deletions
diff --git a/net/base/cookie_monster.cc b/net/base/cookie_monster.cc index 136f38e..7a56831 100644 --- a/net/base/cookie_monster.cc +++ b/net/base/cookie_monster.cc @@ -302,7 +302,7 @@ static std::string CanonPath(const GURL& url, // How would this work for a cookie on /? We will include it then. const std::string& url_path = url.path(); - std::string::size_type idx = url_path.find_last_of('/'); + size_t idx = url_path.find_last_of('/'); // The cookie path was invalid or a single '/'. if (idx == 0 || idx == std::string::npos) @@ -406,9 +406,7 @@ bool CookieMonster::SetCookieWithCreationTime(const GURL& url, return false; } - // We should have only purged at most one matching cookie. - int num_deleted = DeleteEquivalentCookies(cookie_domain, *cc); - DCHECK(num_deleted <= 1); + DeleteAnyEquivalentCookie(cookie_domain, *cc); COOKIE_DLOG(INFO) << "SetCookie() cc: " << cc->DebugString(); @@ -452,30 +450,59 @@ void CookieMonster::InternalDeleteCookie(CookieMap::iterator it, delete cc; } -int CookieMonster::DeleteEquivalentCookies(const std::string& key, - const CanonicalCookie& ecc) { - int num_deleted = 0; +void CookieMonster::DeleteAnyEquivalentCookie(const std::string& key, + const CanonicalCookie& ecc) { + bool found_equivalent_cookie = false; for (CookieMapItPair its = cookies_.equal_range(key); its.first != its.second; ) { CookieMap::iterator curit = its.first; CanonicalCookie* cc = curit->second; ++its.first; - // TODO while we're here, we might as well purge expired cookies too. - if (ecc.IsEquivalent(*cc)) { + // We should never have more than one equivalent cookie, since they should + // overwrite each other. + DCHECK(!found_equivalent_cookie) << + "Duplicate equivalent cookies found, cookie store is corrupted."; InternalDeleteCookie(curit, true); - ++num_deleted; + found_equivalent_cookie = true; #ifdef NDEBUG - // We should only ever find a single equivalent cookie + // Speed optimization: No point looping through the rest of the cookies + // since we're only doing it as a consistency check. break; #endif } } +} + +int CookieMonster::GarbageCollect(const Time& current, + const std::string& key) { + // Based off of the Mozilla defaults. + // It might seem scary to have a high purge value, but really it's not. You + // just make sure that you increase the max to cover the increase in purge, + // and we would have been purging the same amount of cookies. We're just + // going through the garbage collection process less often. + static const size_t kNumCookiesPerHost = 70; // ~50 cookies + static const size_t kNumCookiesPerHostPurge = 20; + static const size_t kNumCookiesTotal = 1100; // ~1000 cookies + static const size_t kNumCookiesTotalPurge = 100; - // Our internal state should be consistent, we should never have more - // than one equivalent cookie, since they should overwrite each other. - DCHECK(num_deleted <= 1); + int num_deleted = 0; + + // Collect garbage for this key. + if (cookies_.count(key) > kNumCookiesPerHost) { + COOKIE_DLOG(INFO) << "GarbageCollect() key: " << key; + num_deleted += GarbageCollectRange(current, cookies_.equal_range(key), + kNumCookiesPerHost, kNumCookiesPerHostPurge); + } + + // Collect garbage for everything. + if (cookies_.size() > kNumCookiesTotal) { + COOKIE_DLOG(INFO) << "GarbageCollect() everything"; + num_deleted += GarbageCollectRange(current, + CookieMapItPair(cookies_.begin(), cookies_.end()), kNumCookiesTotal, + kNumCookiesTotalPurge); + } return num_deleted; } @@ -487,75 +514,47 @@ static bool OldestCookieSorter(const CookieMonster::CookieMap::iterator& it1, return it1->second->CreationDate() < it2->second->CreationDate(); } -// is vector::size_type always going to be size_t? int CookieMonster::GarbageCollectRange(const Time& current, const CookieMapItPair& itpair, - size_t num_max, size_t num_purge) { - int num_deleted = 0; - - // First, walk through and delete anything that's expired. - // Save a list of iterators to the ones that weren't expired + size_t num_max, + size_t num_purge) { + // First, delete anything that's expired. std::vector<CookieMap::iterator> cookie_its; - for (CookieMap::iterator it = itpair.first, end = itpair.second; it != end;) { - CookieMap::iterator curit = it; - CanonicalCookie* cc = curit->second; - ++it; - - if (cc->IsExpired(current)) { - InternalDeleteCookie(curit, true); - ++num_deleted; - } else { - cookie_its.push_back(curit); - } - } + int num_deleted = GarbageCollectExpired(current, itpair, &cookie_its); + // If the range still has too many cookies, delete the oldest. if (cookie_its.size() > num_max) { COOKIE_DLOG(INFO) << "GarbageCollectRange() Deep Garbage Collect."; + // Purge down to (|num_max| - |num_purge|) total cookies. + DCHECK(num_purge <= num_max); num_purge += cookie_its.size() - num_max; - // Sort the top N we want to purge. + std::partial_sort(cookie_its.begin(), cookie_its.begin() + num_purge, cookie_its.end(), OldestCookieSorter); - - // TODO should probably use an iterator and not an index. - for (size_t i = 0; i < num_purge; ++i) { + for (size_t i = 0; i < num_purge; ++i) InternalDeleteCookie(cookie_its[i], true); - ++num_deleted; - } + + num_deleted += num_purge; } return num_deleted; } -// TODO Whenever we delete, check last_cur_utc_... -int CookieMonster::GarbageCollect(const Time& current, - const std::string& key) { - // Based off of the Mozilla defaults - // It might seem scary to have a high purge value, but really it's not. You - // just make sure that you increase the max to cover the increase in purge, - // and we would have been purging the same amount of cookies. We're just - // going through the garbage collection process less often. - static const size_t kNumCookiesPerHost = 70; // ~50 cookies - static const size_t kNumCookiesPerHostPurge = 20; - static const size_t kNumCookiesTotal = 1100; // ~1000 cookies - static const size_t kNumCookiesTotalPurge = 100; - +int CookieMonster::GarbageCollectExpired( + const Time& current, + const CookieMapItPair& itpair, + std::vector<CookieMap::iterator>* cookie_its) { int num_deleted = 0; + for (CookieMap::iterator it = itpair.first, end = itpair.second; it != end;) { + CookieMap::iterator curit = it; + ++it; - // Collect garbage for this key. - if (cookies_.count(key) > kNumCookiesPerHost) { - COOKIE_DLOG(INFO) << "GarbageCollect() key: " << key; - num_deleted += GarbageCollectRange(current, cookies_.equal_range(key), - kNumCookiesPerHost, - kNumCookiesPerHostPurge); - } - - // Collect garbage for everything. - if (cookies_.size() > kNumCookiesTotal) { - COOKIE_DLOG(INFO) << "GarbageCollect() everything"; - num_deleted += GarbageCollectRange(current, - CookieMapItPair(cookies_.begin(), - cookies_.end()), - kNumCookiesTotal, kNumCookiesTotalPurge); + if (curit->second->IsExpired(current)) { + InternalDeleteCookie(curit, true); + ++num_deleted; + } else if (cookie_its) { + cookie_its->push_back(curit); + } } return num_deleted; @@ -676,22 +675,25 @@ std::string CookieMonster::GetCookiesWithOptions(const GURL& url, return cookie_line; } -// TODO(deanm): We could have expired cookies that haven't been purged yet, -// and exporting these would be inaccurate, for example in the cookie manager -// it might show cookies that are actually expired already. We should do -// a full garbage collection before ... There actually isn't a way to do -// this right now (a forceful full GC), so we'll have to live with the -// possibility of showing the user expired cookies. This shouldn't be very -// common since most persistent cookies have a long lifetime. CookieMonster::CookieList CookieMonster::GetAllCookies() { AutoLock autolock(lock_); InitIfNecessary(); - CookieList cookie_list; + // This function is being called to scrape the cookie list for management UI + // or similar. We shouldn't show expired cookies in this list since it will + // just be confusing to users, and this function is called rarely enough (and + // is already slow enough) that it's OK to take the time to garbage collect + // the expired cookies now. + // + // Note that this does not prune cookies to be below our limits (if we've + // exceeded them) the way that calling GarbageCollect() would. + GarbageCollectExpired(Time::Now(), + CookieMapItPair(cookies_.begin(), cookies_.end()), + NULL); - for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end(); ++it) { + CookieList cookie_list; + for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end(); ++it) cookie_list.push_back(CookieListPair(it->first, *it->second)); - } return cookie_list; } @@ -836,8 +838,8 @@ void CookieMonster::ParsedCookie::ParseTokenValuePairs( // TODO Make sure we're stripping \r\n in the network code. Then we // can log any unexpected terminators. - std::string::size_type term_pos = cookie_line.find_first_of( - std::string(kTerminator, kTerminatorLen)); + size_t term_pos = + cookie_line.find_first_of(std::string(kTerminator, kTerminatorLen)); if (term_pos != std::string::npos) { // We found a character we should treat as an end of string. end = start + term_pos; diff --git a/net/base/cookie_monster.h b/net/base/cookie_monster.h index 11491ff..6db774a 100644 --- a/net/base/cookie_monster.h +++ b/net/base/cookie_monster.h @@ -142,8 +142,8 @@ class CookieMonster { const base::Time& current, std::vector<CanonicalCookie*>* cookies); - int DeleteEquivalentCookies(const std::string& key, - const CanonicalCookie& ecc); + void DeleteAnyEquivalentCookie(const std::string& key, + const CanonicalCookie& ecc); void InternalInsertCookie(const std::string& key, CanonicalCookie* cc, @@ -151,13 +151,33 @@ class CookieMonster { void InternalDeleteCookie(CookieMap::iterator it, bool sync_to_store); - // Enforce cookie maximum limits, purging expired and old cookies if needed + // If the number of cookies for host |key|, or globally, are over preset + // maximums, garbage collects, first for the host and then globally, as + // described by GarbageCollectRange(). The limits can be found as constants + // at the top of the function body. + // + // Returns the number of cookies deleted (useful for debugging). int GarbageCollect(const base::Time& current, const std::string& key); + + // Deletes all expired cookies in |itpair|; + // then, if the number of remaining cookies is greater than |num_max|, + // collects the oldest cookies until (|num_max| - |num_purge|) cookies remain. + // + // Returns the number of cookies deleted. int GarbageCollectRange(const base::Time& current, const CookieMapItPair& itpair, size_t num_max, size_t num_purge); + // Helper for GarbageCollectRange(); can be called directly as well. Deletes + // all expired cookies in |itpair|. If |cookie_its| is non-NULL, it is + // populated with all the non-expired cookies from |itpair|. + // + // Returns the number of cookies deleted. + int GarbageCollectExpired(const base::Time& current, + const CookieMapItPair& itpair, + std::vector<CookieMap::iterator>* cookie_its); + CookieMap cookies_; // Indicates whether the cookie store has been initialized. This happens @@ -235,10 +255,14 @@ class CookieMonster::ParsedCookie { class CookieMonster::CanonicalCookie { public: - CanonicalCookie(const std::string& name, const std::string& value, - const std::string& path, bool secure, - bool httponly, const base::Time& creation, - bool has_expires, const base::Time& expires) + CanonicalCookie(const std::string& name, + const std::string& value, + const std::string& path, + bool secure, + bool httponly, + const base::Time& creation, + bool has_expires, + const base::Time& expires) : name_(name), value_(value), path_(path), |