Commit 2b0d5b18 authored by Maks Orlovich's avatar Maks Orlovich Committed by Commit Bot

CookieMonster: don't enforce ctime uniqueness on load.

This used to be a requirement, but isn't any more, and doing this may cause
us to lose some cookies, which is rude.

Bug: 825222
Change-Id: I221693e72742e0b520f6f70ba5f0d5f716785c18
Reviewed-on: https://chromium-review.googlesource.com/978384
Commit-Queue: Maks Orlovich <morlovich@chromium.org>
Reviewed-by: default avatarMatt Menke <mmenke@chromium.org>
Reviewed-by: default avatarVictor Costan <pwnall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#549614}
parent 14a3782d
...@@ -924,28 +924,17 @@ void CookieMonster::StoreLoadedCookies( ...@@ -924,28 +924,17 @@ void CookieMonster::StoreLoadedCookies(
CookieItVector cookies_with_control_chars; CookieItVector cookies_with_control_chars;
for (auto& cookie : cookies) { for (auto& cookie : cookies) {
int64_t cookie_creation_time = cookie->CreationDate().ToInternalValue(); CanonicalCookie* cookie_ptr = cookie.get();
CookieMap::iterator inserted = InternalInsertCookie(
if (creation_times_.insert(cookie_creation_time).second) { GetKey(cookie_ptr->Domain()), std::move(cookie), false);
CanonicalCookie* cookie_ptr = cookie.get(); const Time cookie_access_time(cookie_ptr->LastAccessDate());
CookieMap::iterator inserted = InternalInsertCookie( if (earliest_access_time_.is_null() ||
GetKey(cookie_ptr->Domain()), std::move(cookie), false); cookie_access_time < earliest_access_time_)
const Time cookie_access_time(cookie_ptr->LastAccessDate()); earliest_access_time_ = cookie_access_time;
if (earliest_access_time_.is_null() ||
cookie_access_time < earliest_access_time_) if (ContainsControlCharacter(cookie_ptr->Name()) ||
earliest_access_time_ = cookie_access_time; ContainsControlCharacter(cookie_ptr->Value())) {
cookies_with_control_chars.push_back(inserted);
if (ContainsControlCharacter(cookie_ptr->Name()) ||
ContainsControlCharacter(cookie_ptr->Value())) {
cookies_with_control_chars.push_back(inserted);
}
} else {
LOG(ERROR) << base::StringPrintf(
"Found cookies with duplicate creation "
"times in backing store: "
"{name='%s', domain='%s', path='%s'}",
cookie->Name().c_str(), cookie->Domain().c_str(),
cookie->Path().c_str());
} }
} }
...@@ -995,7 +984,6 @@ void CookieMonster::InvokeQueue() { ...@@ -995,7 +984,6 @@ void CookieMonster::InvokeQueue() {
DCHECK(tasks_pending_for_key_.empty()); DCHECK(tasks_pending_for_key_.empty());
finished_fetching_all_cookies_ = true; finished_fetching_all_cookies_ = true;
creation_times_.clear();
keys_loaded_.clear(); keys_loaded_.clear();
} }
...@@ -1021,7 +1009,7 @@ void CookieMonster::TrimDuplicateCookiesForKey(const std::string& key, ...@@ -1021,7 +1009,7 @@ void CookieMonster::TrimDuplicateCookiesForKey(const std::string& key,
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
// Set of cookies ordered by creation time. // Set of cookies ordered by creation time.
typedef std::set<CookieMap::iterator, OrderByCreationTimeDesc> CookieSet; typedef std::multiset<CookieMap::iterator, OrderByCreationTimeDesc> CookieSet;
// Helper map we populate to find the duplicates. // Helper map we populate to find the duplicates.
typedef std::map<CookieSignature, CookieSet> EquivalenceMap; typedef std::map<CookieSignature, CookieSet> EquivalenceMap;
...@@ -1045,9 +1033,7 @@ void CookieMonster::TrimDuplicateCookiesForKey(const std::string& key, ...@@ -1045,9 +1033,7 @@ void CookieMonster::TrimDuplicateCookiesForKey(const std::string& key,
// We save the iterator into |cookies_| rather than the actual cookie // We save the iterator into |cookies_| rather than the actual cookie
// pointer, since we may need to delete it later. // pointer, since we may need to delete it later.
bool insert_success = set.insert(it).second; set.insert(it);
DCHECK(insert_success)
<< "Duplicate creation times found in duplicate cookie name scan.";
} }
// If there were no duplicates, we are done! // If there were no duplicates, we are done!
...@@ -1068,8 +1054,9 @@ void CookieMonster::TrimDuplicateCookiesForKey(const std::string& key, ...@@ -1068,8 +1054,9 @@ void CookieMonster::TrimDuplicateCookiesForKey(const std::string& key,
continue; // This cookiename/path has no duplicates. continue; // This cookiename/path has no duplicates.
num_duplicates_found += dupes.size() - 1; num_duplicates_found += dupes.size() - 1;
// Since |dups| is sorted by creation time (descending), the first cookie // Since |dupes| is sorted by creation time (descending), the first cookie
// is the most recent one, so we will keep it. The rest are duplicates. // is the most recent one (or tied for it), so we will keep it. The rest are
// duplicates.
dupes.erase(dupes.begin()); dupes.erase(dupes.begin());
LOG(ERROR) << base::StringPrintf( LOG(ERROR) << base::StringPrintf(
......
...@@ -643,12 +643,6 @@ class NET_EXPORT CookieMonster : public CookieStore { ...@@ -643,12 +643,6 @@ class NET_EXPORT CookieMonster : public CookieStore {
// wanted. Thus this value is not initialized. // wanted. Thus this value is not initialized.
base::Time earliest_access_time_; base::Time earliest_access_time_;
// During loading, holds the set of all loaded cookie creation times. Used to
// avoid ever letting cookies with duplicate creation times into the store;
// that way we don't have to worry about what sections of code are safe
// to call while it's in that state.
std::set<int64_t> creation_times_;
std::vector<std::string> cookieable_schemes_; std::vector<std::string> cookieable_schemes_;
ChannelIDService* channel_id_service_; ChannelIDService* channel_id_service_;
......
...@@ -137,6 +137,7 @@ void AddCookieToList(const GURL& url, ...@@ -137,6 +137,7 @@ void AddCookieToList(const GURL& url,
// Just act like a backing database. Keep cookie information from // Just act like a backing database. Keep cookie information from
// Add/Update/Delete and regurgitate it when Load is called. // Add/Update/Delete and regurgitate it when Load is called.
// TODO(morlovich): This still assumes that creation times are unique.
class MockSimplePersistentCookieStore class MockSimplePersistentCookieStore
: public CookieMonster::PersistentCookieStore { : public CookieMonster::PersistentCookieStore {
public: public:
......
...@@ -1865,11 +1865,11 @@ TEST_F(CookieMonsterTest, DontImportDuplicateCookies) { ...@@ -1865,11 +1865,11 @@ TEST_F(CookieMonsterTest, DontImportDuplicateCookies) {
} }
// Tests importing from a persistent cookie store that contains cookies // Tests importing from a persistent cookie store that contains cookies
// with duplicate creation times. This situation should be handled by // with duplicate creation times. This is OK now, but it still interacts
// dropping the cookies before insertion/visibility to user. // with the de-duplication algorithm.
// //
// This is a regression test for: http://crbug.com/43188. // This is a regression test for: http://crbug.com/43188.
TEST_F(CookieMonsterTest, DontImportDuplicateCreationTimes) { TEST_F(CookieMonsterTest, ImportDuplicateCreationTimes) {
scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore); scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore);
Time now(Time::Now()); Time now(Time::Now());
...@@ -2075,6 +2075,41 @@ TEST_F(CookieMonsterTest, BackingStoreCommunication) { ...@@ -2075,6 +2075,41 @@ TEST_F(CookieMonsterTest, BackingStoreCommunication) {
} }
} }
TEST_F(CookieMonsterTest, RestoreDifferentCookieSameCreationTime) {
// Test that we can restore different cookies with duplicate creation times.
base::Time current(base::Time::Now());
scoped_refptr<MockPersistentCookieStore> store =
base::MakeRefCounted<MockPersistentCookieStore>();
{
CookieMonster cmout(store.get());
GURL url("http://www.example.com/");
EXPECT_TRUE(
SetCookieWithCreationTime(&cmout, url, "A=1; max-age=600", current));
EXPECT_TRUE(
SetCookieWithCreationTime(&cmout, url, "B=2; max-age=600", current));
}
// Play back the cookies into store 2.
scoped_refptr<MockPersistentCookieStore> store2 =
base::MakeRefCounted<MockPersistentCookieStore>();
std::vector<std::unique_ptr<CanonicalCookie>> load_expectation;
EXPECT_EQ(2u, store->commands().size());
for (const CookieStoreCommand& command : store->commands()) {
ASSERT_EQ(command.type, CookieStoreCommand::ADD);
load_expectation.push_back(
std::make_unique<CanonicalCookie>(command.cookie));
}
store2->SetLoadExpectation(true, std::move(load_expectation));
// Now read them in. Should get two cookies, not one.
{
CookieMonster cmin(store2.get());
CookieList cookies(GetAllCookies(&cmin));
ASSERT_EQ(2u, cookies.size());
}
}
TEST_F(CookieMonsterTest, CookieListOrdering) { TEST_F(CookieMonsterTest, CookieListOrdering) {
// Put a random set of cookies into a monster and make sure // Put a random set of cookies into a monster and make sure
// they're returned in the right order. // they're returned in the right order.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment