diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-11-20 10:33:36 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-11-22 11:45:12 +0000 |
commit | be59a35641616a4cf23c4a13fa0632624b021c1b (patch) | |
tree | 9da183258bdf9cc413f7562079d25ace6955467f /chromium/net/cookies | |
parent | d702e4b6a64574e97fc7df8fe3238cde70242080 (diff) | |
download | qtwebengine-chromium-be59a35641616a4cf23c4a13fa0632624b021c1b.tar.gz |
BASELINE: Update Chromium to 62.0.3202.101
Change-Id: I2d5eca8117600df6d331f6166ab24d943d9814ac
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/net/cookies')
-rw-r--r-- | chromium/net/cookies/OWNERS | 2 | ||||
-rw-r--r-- | chromium/net/cookies/canonical_cookie.cc | 3 | ||||
-rw-r--r-- | chromium/net/cookies/canonical_cookie_unittest.cc | 34 | ||||
-rw-r--r-- | chromium/net/cookies/cookie_constants.h | 3 | ||||
-rw-r--r-- | chromium/net/cookies/cookie_monster.cc | 67 | ||||
-rw-r--r-- | chromium/net/cookies/cookie_monster.h | 82 | ||||
-rw-r--r-- | chromium/net/cookies/cookie_monster_perftest.cc | 12 | ||||
-rw-r--r-- | chromium/net/cookies/cookie_monster_store_test.cc | 28 | ||||
-rw-r--r-- | chromium/net/cookies/cookie_monster_store_test.h | 27 | ||||
-rw-r--r-- | chromium/net/cookies/cookie_monster_unittest.cc | 288 | ||||
-rw-r--r-- | chromium/net/cookies/cookie_options.cc | 1 | ||||
-rw-r--r-- | chromium/net/cookies/cookie_options.h | 1 | ||||
-rw-r--r-- | chromium/net/cookies/cookie_store.h | 16 | ||||
-rw-r--r-- | chromium/net/cookies/cookie_store_test_helpers.cc | 7 | ||||
-rw-r--r-- | chromium/net/cookies/cookie_store_test_helpers.h | 3 | ||||
-rw-r--r-- | chromium/net/cookies/cookie_store_unittest.h | 257 |
16 files changed, 513 insertions, 318 deletions
diff --git a/chromium/net/cookies/OWNERS b/chromium/net/cookies/OWNERS index c97305e856e..ff5707f758f 100644 --- a/chromium/net/cookies/OWNERS +++ b/chromium/net/cookies/OWNERS @@ -1,4 +1,4 @@ -jww@chromium.org +estark@chromium.org mkwst@chromium.org # COMPONENT: Internals>Network>Cookies diff --git a/chromium/net/cookies/canonical_cookie.cc b/chromium/net/cookies/canonical_cookie.cc index b5fea34dcaf..ce5bf291c62 100644 --- a/chromium/net/cookies/canonical_cookie.cc +++ b/chromium/net/cookies/canonical_cookie.cc @@ -92,6 +92,7 @@ int PartialCookieOrdering(const CanonicalCookie& a, const CanonicalCookie& b) { } // namespace +// Keep defaults here in sync with content/public/common/cookie_manager.mojom. CanonicalCookie::CanonicalCookie() : secure_(false), httponly_(false), @@ -241,7 +242,7 @@ std::unique_ptr<CanonicalCookie> CanonicalCookie::Create( return nullptr; } - std::unique_ptr<CanonicalCookie> cc(base::MakeUnique<CanonicalCookie>( + std::unique_ptr<CanonicalCookie> cc(std::make_unique<CanonicalCookie>( parsed_cookie.Name(), parsed_cookie.Value(), cookie_domain, cookie_path, creation_time, cookie_expires, creation_time, parsed_cookie.IsSecure(), parsed_cookie.IsHttpOnly(), parsed_cookie.SameSite(), diff --git a/chromium/net/cookies/canonical_cookie_unittest.cc b/chromium/net/cookies/canonical_cookie_unittest.cc index ecbe8a90de8..9f1017bd315 100644 --- a/chromium/net/cookies/canonical_cookie_unittest.cc +++ b/chromium/net/cookies/canonical_cookie_unittest.cc @@ -19,7 +19,7 @@ TEST(CanonicalCookieTest, Constructor) { GURL url("http://www.example.com/test"); base::Time current_time = base::Time::Now(); - std::unique_ptr<CanonicalCookie> cookie(base::MakeUnique<CanonicalCookie>( + std::unique_ptr<CanonicalCookie> cookie(std::make_unique<CanonicalCookie>( "A", "2", "www.example.com", "/test", current_time, base::Time(), base::Time(), false, false, CookieSameSite::DEFAULT_MODE, COOKIE_PRIORITY_DEFAULT)); @@ -31,7 +31,7 @@ TEST(CanonicalCookieTest, Constructor) { EXPECT_FALSE(cookie->IsHttpOnly()); EXPECT_EQ(CookieSameSite::NO_RESTRICTION, cookie->SameSite()); - std::unique_ptr<CanonicalCookie> cookie2(base::MakeUnique<CanonicalCookie>( + std::unique_ptr<CanonicalCookie> cookie2(std::make_unique<CanonicalCookie>( "A", "2", ".www.example.com", "/", current_time, base::Time(), base::Time(), false, false, CookieSameSite::DEFAULT_MODE, COOKIE_PRIORITY_DEFAULT)); @@ -112,7 +112,7 @@ TEST(CanonicalCookieTest, Create) { // Test the creating cookies using specific parameter instead of a cookie // string. - cookie = base::MakeUnique<CanonicalCookie>( + cookie = std::make_unique<CanonicalCookie>( "A", "2", ".www.example.com", "/test", creation_time, base::Time(), base::Time(), false, false, CookieSameSite::DEFAULT_MODE, COOKIE_PRIORITY_DEFAULT); @@ -124,7 +124,7 @@ TEST(CanonicalCookieTest, Create) { EXPECT_FALSE(cookie->IsHttpOnly()); EXPECT_EQ(CookieSameSite::NO_RESTRICTION, cookie->SameSite()); - cookie = base::MakeUnique<CanonicalCookie>( + cookie = std::make_unique<CanonicalCookie>( "A", "2", ".www.example.com", "/test", creation_time, base::Time(), base::Time(), false, false, CookieSameSite::DEFAULT_MODE, COOKIE_PRIORITY_DEFAULT); @@ -198,7 +198,7 @@ TEST(CanonicalCookieTest, IsEquivalent) { CookieSameSite same_site(CookieSameSite::NO_RESTRICTION); // Test that a cookie is equivalent to itself. - std::unique_ptr<CanonicalCookie> cookie(base::MakeUnique<CanonicalCookie>( + std::unique_ptr<CanonicalCookie> cookie(std::make_unique<CanonicalCookie>( cookie_name, cookie_value, cookie_domain, cookie_path, creation_time, expiration_time, base::Time(), secure, httponly, same_site, COOKIE_PRIORITY_MEDIUM)); @@ -207,7 +207,7 @@ TEST(CanonicalCookieTest, IsEquivalent) { // Test that two identical cookies are equivalent. std::unique_ptr<CanonicalCookie> other_cookie( - base::MakeUnique<CanonicalCookie>( + std::make_unique<CanonicalCookie>( cookie_name, cookie_value, cookie_domain, cookie_path, creation_time, expiration_time, base::Time(), secure, httponly, same_site, COOKIE_PRIORITY_MEDIUM)); @@ -216,7 +216,7 @@ TEST(CanonicalCookieTest, IsEquivalent) { // Tests that use different variations of attribute values that // DON'T affect cookie equivalence. - other_cookie = base::MakeUnique<CanonicalCookie>( + other_cookie = std::make_unique<CanonicalCookie>( cookie_name, "2", cookie_domain, cookie_path, creation_time, expiration_time, base::Time(), secure, httponly, same_site, COOKIE_PRIORITY_HIGH); @@ -226,7 +226,7 @@ TEST(CanonicalCookieTest, IsEquivalent) { base::Time other_creation_time = creation_time + base::TimeDelta::FromMinutes(2); - other_cookie = base::MakeUnique<CanonicalCookie>( + other_cookie = std::make_unique<CanonicalCookie>( cookie_name, "2", cookie_domain, cookie_path, other_creation_time, expiration_time, base::Time(), secure, httponly, same_site, COOKIE_PRIORITY_MEDIUM); @@ -234,7 +234,7 @@ TEST(CanonicalCookieTest, IsEquivalent) { EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie)); EXPECT_TRUE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie)); - other_cookie = base::MakeUnique<CanonicalCookie>( + other_cookie = std::make_unique<CanonicalCookie>( cookie_name, cookie_name, cookie_domain, cookie_path, creation_time, expiration_time, base::Time(), true, httponly, same_site, COOKIE_PRIORITY_LOW); @@ -242,7 +242,7 @@ TEST(CanonicalCookieTest, IsEquivalent) { EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie)); EXPECT_TRUE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie)); - other_cookie = base::MakeUnique<CanonicalCookie>( + other_cookie = std::make_unique<CanonicalCookie>( cookie_name, cookie_name, cookie_domain, cookie_path, creation_time, expiration_time, base::Time(), secure, true, same_site, COOKIE_PRIORITY_LOW); @@ -250,7 +250,7 @@ TEST(CanonicalCookieTest, IsEquivalent) { EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie)); EXPECT_TRUE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie)); - other_cookie = base::MakeUnique<CanonicalCookie>( + other_cookie = std::make_unique<CanonicalCookie>( cookie_name, cookie_name, cookie_domain, cookie_path, creation_time, expiration_time, base::Time(), secure, httponly, CookieSameSite::STRICT_MODE, COOKIE_PRIORITY_LOW); @@ -259,7 +259,7 @@ TEST(CanonicalCookieTest, IsEquivalent) { EXPECT_TRUE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie)); // Cookies whose names mismatch are not equivalent. - other_cookie = base::MakeUnique<CanonicalCookie>( + other_cookie = std::make_unique<CanonicalCookie>( "B", cookie_value, cookie_domain, cookie_path, creation_time, expiration_time, base::Time(), secure, httponly, same_site, COOKIE_PRIORITY_MEDIUM); @@ -270,7 +270,7 @@ TEST(CanonicalCookieTest, IsEquivalent) { // A domain cookie at 'www.example.com' is not equivalent to a host cookie // at the same domain. These are, however, equivalent according to the laxer // rules of 'IsEquivalentForSecureCookieMatching'. - other_cookie = base::MakeUnique<CanonicalCookie>( + other_cookie = std::make_unique<CanonicalCookie>( cookie_name, cookie_value, "www.example.com", cookie_path, creation_time, expiration_time, base::Time(), secure, httponly, same_site, COOKIE_PRIORITY_MEDIUM); @@ -282,7 +282,7 @@ TEST(CanonicalCookieTest, IsEquivalent) { // Likewise, a cookie on 'example.com' is not equivalent to a cookie on // 'www.example.com', but they are equivalent for secure cookie matching. - other_cookie = base::MakeUnique<CanonicalCookie>( + other_cookie = std::make_unique<CanonicalCookie>( cookie_name, cookie_value, ".example.com", cookie_path, creation_time, expiration_time, base::Time(), secure, httponly, same_site, COOKIE_PRIORITY_MEDIUM); @@ -295,7 +295,7 @@ TEST(CanonicalCookieTest, IsEquivalent) { // That is, |cookie| set on '/path' is not equivalent in either way to // |other_cookie| set on '/test' or '/path/subpath'. It is, however, // equivalent for secure cookie matching to |other_cookie| set on '/'. - other_cookie = base::MakeUnique<CanonicalCookie>( + other_cookie = std::make_unique<CanonicalCookie>( cookie_name, cookie_value, cookie_domain, "/test", creation_time, expiration_time, base::Time(), secure, httponly, same_site, COOKIE_PRIORITY_MEDIUM); @@ -303,7 +303,7 @@ TEST(CanonicalCookieTest, IsEquivalent) { EXPECT_FALSE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie)); EXPECT_FALSE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie)); - other_cookie = base::MakeUnique<CanonicalCookie>( + other_cookie = std::make_unique<CanonicalCookie>( cookie_name, cookie_value, cookie_domain, cookie_path + "/subpath", creation_time, expiration_time, base::Time(), secure, httponly, same_site, COOKIE_PRIORITY_MEDIUM); @@ -311,7 +311,7 @@ TEST(CanonicalCookieTest, IsEquivalent) { EXPECT_FALSE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie)); EXPECT_TRUE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie)); - other_cookie = base::MakeUnique<CanonicalCookie>( + other_cookie = std::make_unique<CanonicalCookie>( cookie_name, cookie_value, cookie_domain, "/", creation_time, expiration_time, base::Time(), secure, httponly, same_site, COOKIE_PRIORITY_MEDIUM); diff --git a/chromium/net/cookies/cookie_constants.h b/chromium/net/cookies/cookie_constants.h index 49dafbdb3a1..61e1c0a0c0c 100644 --- a/chromium/net/cookies/cookie_constants.h +++ b/chromium/net/cookies/cookie_constants.h @@ -18,6 +18,9 @@ enum CookiePriority { COOKIE_PRIORITY_DEFAULT = COOKIE_PRIORITY_MEDIUM }; +// See https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00 +// and https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis for +// information about same site cookie restrictions. enum class CookieSameSite { NO_RESTRICTION = 0, LAX_MODE = 1, diff --git a/chromium/net/cookies/cookie_monster.cc b/chromium/net/cookies/cookie_monster.cc index 47785f6e758..bd9455ff578 100644 --- a/chromium/net/cookies/cookie_monster.cc +++ b/chromium/net/cookies/cookie_monster.cc @@ -353,30 +353,24 @@ size_t CountCookiesForPossibleDeletion( } // namespace -CookieMonster::CookieMonster(PersistentCookieStore* store, - CookieMonsterDelegate* delegate) +CookieMonster::CookieMonster(PersistentCookieStore* store) : CookieMonster( store, - delegate, nullptr, base::TimeDelta::FromSeconds(kDefaultAccessUpdateThresholdSeconds)) {} CookieMonster::CookieMonster(PersistentCookieStore* store, - CookieMonsterDelegate* delegate, ChannelIDService* channel_id_service) : CookieMonster( store, - delegate, channel_id_service, base::TimeDelta::FromSeconds(kDefaultAccessUpdateThresholdSeconds)) {} CookieMonster::CookieMonster(PersistentCookieStore* store, - CookieMonsterDelegate* delegate, base::TimeDelta last_access_threshold) - : CookieMonster(store, delegate, nullptr, last_access_threshold) {} + : CookieMonster(store, nullptr, last_access_threshold) {} CookieMonster::CookieMonster(PersistentCookieStore* store, - CookieMonsterDelegate* delegate, ChannelIDService* channel_id_service, base::TimeDelta last_access_threshold) : initialized_(false), @@ -386,15 +380,26 @@ CookieMonster::CookieMonster(PersistentCookieStore* store, seen_global_task_(false), store_(store), last_access_threshold_(last_access_threshold), - delegate_(delegate), channel_id_service_(channel_id_service), last_statistic_record_time_(base::Time::Now()), persist_session_cookies_(false), + global_hook_map_(base::MakeUnique<CookieChangedCallbackList>()), weak_ptr_factory_(this) { InitializeHistograms(); cookieable_schemes_.insert( cookieable_schemes_.begin(), kDefaultCookieableSchemes, kDefaultCookieableSchemes + kDefaultCookieableSchemesCount); + if (channel_id_service_ && store_) { + // |store_| can outlive this CookieMonster, but there are no guarantees + // about the lifetime of |channel_id_service_| relative to |store_|. The + // only guarantee is that |channel_id_service_| will outlive this + // CookieMonster. To avoid the PersistentCookieStore retaining a pointer to + // the ChannelIDStore via this callback after this CookieMonster is + // destroyed, CookieMonster's d'tor sets the callback to a null callback. + store_->SetBeforeFlushCallback( + base::Bind(&ChannelIDStore::Flush, + base::Unretained(channel_id_service_->GetChannelIDStore()))); + } } // Asynchronous CookieMonster API @@ -428,9 +433,6 @@ void CookieMonster::FlushStore(base::OnceClosure callback) { DCHECK(thread_checker_.CalledOnValidThread()); if (initialized_ && store_.get()) { - if (channel_id_service_) { - channel_id_service_->GetChannelIDStore()->Flush(); - } store_->Flush(std::move(callback)); } else if (callback) { base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, @@ -626,11 +628,19 @@ CookieMonster::AddCallbackForCookie(const GURL& gurl, std::pair<GURL, std::string> key(gurl, name); if (hook_map_.count(key) == 0) - hook_map_[key] = base::MakeUnique<CookieChangedCallbackList>(); + hook_map_[key] = std::make_unique<CookieChangedCallbackList>(); return hook_map_[key]->Add( base::Bind(&RunAsync, base::ThreadTaskRunnerHandle::Get(), callback)); } +std::unique_ptr<CookieStore::CookieChangedSubscription> +CookieMonster::AddCallbackForAllChanges(const CookieChangedCallback& callback) { + DCHECK(thread_checker_.CalledOnValidThread()); + + return global_hook_map_->Add( + base::Bind(&RunAsync, base::ThreadTaskRunnerHandle::Get(), callback)); +} + bool CookieMonster::IsEphemeral() { return store_.get() == nullptr; } @@ -638,7 +648,11 @@ bool CookieMonster::IsEphemeral() { CookieMonster::~CookieMonster() { DCHECK(thread_checker_.CalledOnValidThread()); - // TODO(mmenke): Does it really make sense to run |delegate_| and + if (channel_id_service_ && store_) { + store_->SetBeforeFlushCallback(base::Closure()); + } + + // TODO(mmenke): Does it really make sense to run // CookieChanged callbacks when the CookieStore is destroyed? for (CookieMap::iterator cookie_it = cookies_.begin(); cookie_it != cookies_.end();) { @@ -699,7 +713,7 @@ void CookieMonster::SetCookieWithDetails(const GURL& url, cookie_path = std::string(canon_path.data() + canon_path_component.begin, canon_path_component.len); - std::unique_ptr<CanonicalCookie> cc(base::MakeUnique<CanonicalCookie>( + std::unique_ptr<CanonicalCookie> cc(std::make_unique<CanonicalCookie>( name, value, cookie_domain, cookie_path, creation_time, expiration_time, last_access_time, secure, http_only, same_site, priority)); @@ -1319,6 +1333,10 @@ bool CookieMonster::DeleteAnyEquivalentCookie(const std::string& key, } else { histogram_cookie_delete_equivalent_->Add( COOKIE_DELETE_EQUIVALENT_FOUND); + if (cc->Value() == ecc.Value()) { + histogram_cookie_delete_equivalent_->Add( + COOKIE_DELETE_EQUIVALENT_FOUND_WITH_SAME_VALUE); + } InternalDeleteCookie(curit, true, already_expired ? DELETE_COOKIE_EXPIRED_OVERWRITE : DELETE_COOKIE_OVERWRITE); @@ -1341,10 +1359,6 @@ CookieMonster::CookieMap::iterator CookieMonster::InternalInsertCookie( store_->AddCookie(*cc_ptr); CookieMap::iterator inserted = cookies_.insert(CookieMap::value_type(key, std::move(cc))); - if (delegate_.get()) { - delegate_->OnCookieChanged(*cc_ptr, false, - CookieStore::ChangeCause::INSERTED); - } // See InitializeHistograms() for details. int32_t type_sample = cc_ptr->SameSite() != CookieSameSite::NO_RESTRICTION @@ -1354,7 +1368,7 @@ CookieMonster::CookieMap::iterator CookieMonster::InternalInsertCookie( type_sample |= cc_ptr->IsSecure() ? 1 << COOKIE_TYPE_SECURE : 0; histogram_cookie_type_->Add(type_sample); - RunCookieChangedCallbacks(*cc_ptr, CookieStore::ChangeCause::INSERTED); + RunCookieChangedCallbacks(*cc_ptr, true, CookieStore::ChangeCause::INSERTED); return inserted; } @@ -1393,7 +1407,8 @@ void CookieMonster::SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc, SetCookiesCallback callback) { DCHECK(thread_checker_.CalledOnValidThread()); - if (cc->IsSecure() && !secure_source) { + if ((cc->IsSecure() && !secure_source) || + (cc->IsHttpOnly() && !modify_http_only)) { MaybeRunCookieCallback(std::move(callback), false); return; } @@ -1488,7 +1503,7 @@ void CookieMonster::SetAllCookies(CookieList list, (cookie.ExpiryDate() - creation_time).InMinutes()); } - InternalInsertCookie(key, base::MakeUnique<CanonicalCookie>(cookie), true); + InternalInsertCookie(key, std::make_unique<CanonicalCookie>(cookie), true); GarbageCollect(creation_time, key); } @@ -1537,9 +1552,7 @@ void CookieMonster::InternalDeleteCookie(CookieMap::iterator it, sync_to_store) store_->DeleteCookie(*cc); ChangeCausePair mapping = kChangeCauseMapping[deletion_cause]; - if (delegate_.get() && mapping.notify) - delegate_->OnCookieChanged(*cc, true, mapping.cause); - RunCookieChangedCallbacks(*cc, mapping.cause); + RunCookieChangedCallbacks(*cc, mapping.notify, mapping.cause); cookies_.erase(it); } @@ -2014,6 +2027,7 @@ void CookieMonster::DoCookieCallbackForURL(base::OnceClosure callback, } void CookieMonster::RunCookieChangedCallbacks(const CanonicalCookie& cookie, + bool notify_global_hooks, ChangeCause cause) { DCHECK(thread_checker_.CalledOnValidThread()); @@ -2033,6 +2047,9 @@ void CookieMonster::RunCookieChangedCallbacks(const CanonicalCookie& cookie, it->second->Notify(cookie, cause); } } + + if (notify_global_hooks) + global_hook_map_->Notify(cookie, cause); } } // namespace net diff --git a/chromium/net/cookies/cookie_monster.h b/chromium/net/cookies/cookie_monster.h index 717059e75ce..cf51b6c4165 100644 --- a/chromium/net/cookies/cookie_monster.h +++ b/chromium/net/cookies/cookie_monster.h @@ -39,7 +39,6 @@ class HistogramBase; namespace net { class ChannelIDService; -class CookieMonsterDelegate; // The cookie monster is the system for storing and retrieving cookies. It has // an in-memory list of all cookies, and synchronizes non-session cookies to an @@ -131,20 +130,17 @@ class NET_EXPORT CookieMonster : public CookieStore { // class will take care of initializing it. The backing store is NOT owned by // this class, but it must remain valid for the duration of the cookie // monster's existence. If |store| is NULL, then no backing store will be - // updated. If |delegate| is non-NULL, it will be notified on - // creation/deletion of cookies. - CookieMonster(PersistentCookieStore* store, CookieMonsterDelegate* delegate); + // updated. + explicit CookieMonster(PersistentCookieStore* store); // Like above, but includes a non-owning pointer |channel_id_service| for the // corresponding ChannelIDService used with this CookieStore. The // |channel_id_service| must outlive the CookieMonster. CookieMonster(PersistentCookieStore* store, - CookieMonsterDelegate* delegate, ChannelIDService* channel_id_service); // Only used during unit testing. CookieMonster(PersistentCookieStore* store, - CookieMonsterDelegate* delegate, base::TimeDelta last_access_threshold); ~CookieMonster() override; @@ -226,6 +222,9 @@ class NET_EXPORT CookieMonster : public CookieStore { const std::string& name, const CookieChangedCallback& callback) override; + std::unique_ptr<CookieChangedSubscription> AddCallbackForAllChanges( + const CookieChangedCallback& callback) override; + bool IsEphemeral() override; void SetCookieWithCreationTimeForTesting(const GURL& url, @@ -235,7 +234,6 @@ class NET_EXPORT CookieMonster : public CookieStore { private: CookieMonster(PersistentCookieStore* store, - CookieMonsterDelegate* delegate, ChannelIDService* channel_id_service, base::TimeDelta last_access_threshold); @@ -354,21 +352,39 @@ class NET_EXPORT CookieMonster : public CookieStore { }; // Used to populate a histogram for cookie setting in the "delete equivalent" - // step. Measures total attempts to delete an equivalent cookie as well as if - // a cookie is found to delete, if a cookie is skipped because it is secure, - // and if it is skipped for being secure but would have been deleted - // otherwise. The last two are only possible if strict secure cookies is - // turned on and if an insecure origin attempts to a set a cookie where a - // cookie with the same name and secure attribute already exists. + // step. Measures total attempts to delete an equivalent cookie, and + // categorizes the outcome. + // + // * COOKIE_DELETE_EQUIVALENT_ATTEMPT is incremented each time a cookie is + // set, causing the equivalent deletion algorithm to execute. + // + // * COOKIE_DELETE_EQUIVALENT_SKIPPING_SECURE is incremented when a non-secure + // cookie is ignored because an equivalent, but secure, cookie already + // exists. + // + // * COOKIE_DELETE_EQUIVALENT_WOULD_HAVE_DELETED is incremented when a cookie + // is skipped due to `secure` rules (e.g. whenever + // COOKIE_DELETE_EQUIVALENT_SKIPPING_SECURE is incremented), but would have + // caused a deletion without those rules. + // + // TODO(mkwst): Now that we've shipped strict secure cookie checks, we don't + // need this value anymore. + // + // * COOKIE_DELETE_EQUIVALENT_FOUND is incremented each time an equivalent + // cookie is found (and deleted). + // + // * COOKIE_DELETE_EQUIVALENT_FOUND_WITH_SAME_VALUE is incremented each time + // an equivalent cookie that also shared the same value with the new cookie + // is found (and deleted). // - // Enum for UMA. Do no reorder or remove entries. New entries must be place - // directly before COOKIE_DELETE_EQUIVALENT_LAST_ENTRY and histograms.xml must - // be updated accordingly. + // Please do not reorder or remove entries. New entries must be added to the + // end of the list, just before COOKIE_DELETE_EQUIVALENT_LAST_ENTRY. enum CookieDeleteEquivalent { COOKIE_DELETE_EQUIVALENT_ATTEMPT = 0, COOKIE_DELETE_EQUIVALENT_FOUND, COOKIE_DELETE_EQUIVALENT_SKIPPING_SECURE, COOKIE_DELETE_EQUIVALENT_WOULD_HAVE_DELETED, + COOKIE_DELETE_EQUIVALENT_FOUND_WITH_SAME_VALUE, COOKIE_DELETE_EQUIVALENT_LAST_ENTRY }; @@ -636,8 +652,10 @@ class NET_EXPORT CookieMonster : public CookieStore { void DoCookieCallbackForURL(base::OnceClosure callback, const GURL& url); // Run all cookie changed callbacks that are monitoring |cookie|. - // |removed| is true if the cookie was deleted. + // |notify_global_hooks| is true if the function should run the + // global hooks in addition to the per-cookie hooks. void RunCookieChangedCallbacks(const CanonicalCookie& cookie, + bool notify_global_hooks, CookieStore::ChangeCause cause); // Histogram variables; see CookieMonster::InitializeHistograms() in @@ -707,7 +725,6 @@ class NET_EXPORT CookieMonster : public CookieStore { std::vector<std::string> cookieable_schemes_; - scoped_refptr<CookieMonsterDelegate> delegate_; ChannelIDService* channel_id_service_; base::Time last_statistic_record_time_; @@ -718,6 +735,7 @@ class NET_EXPORT CookieMonster : public CookieStore { std::map<std::pair<GURL, std::string>, std::unique_ptr<CookieChangedCallbackList>>; CookieChangedHookMap hook_map_; + std::unique_ptr<CookieChangedCallbackList> global_hook_map_; base::ThreadChecker thread_checker_; @@ -726,29 +744,6 @@ class NET_EXPORT CookieMonster : public CookieStore { DISALLOW_COPY_AND_ASSIGN(CookieMonster); }; -class NET_EXPORT CookieMonsterDelegate - : public base::RefCountedThreadSafe<CookieMonsterDelegate> { - public: - // Will be called when a cookie is added or removed. The function is passed - // the respective |cookie| which was added to or removed from the cookies. - // If |removed| is true, the cookie was deleted, and |cause| will be set - // to the reason for its removal. If |removed| is false, the cookie was - // added, and |cause| will be set to ChangeCause::EXPLICIT. - // - // As a special case, note that updating a cookie's properties is implemented - // as a two step process: the cookie to be updated is first removed entirely, - // generating a notification with cause ChangeCause::OVERWRITE. Afterwards, - // a new cookie is written with the updated values, generating a notification - // with cause ChangeCause::EXPLICIT. - virtual void OnCookieChanged(const CanonicalCookie& cookie, - bool removed, - CookieStore::ChangeCause cause) = 0; - - protected: - friend class base::RefCountedThreadSafe<CookieMonsterDelegate>; - virtual ~CookieMonsterDelegate() {} -}; - typedef base::RefCountedThreadSafe<CookieMonster::PersistentCookieStore> RefcountedPersistentCookieStore; @@ -786,6 +781,11 @@ class NET_EXPORT CookieMonster::PersistentCookieStore // Instructs the store to not discard session only cookies on shutdown. virtual void SetForceKeepSessionState() = 0; + // Sets a callback that will be run before the store flushes. If |callback| + // performs any async operations, the store will not wait for those to finish + // before flushing. + virtual void SetBeforeFlushCallback(base::RepeatingClosure callback) = 0; + // Flushes the store and posts |callback| when complete. |callback| may be // NULL. virtual void Flush(base::OnceClosure callback) = 0; diff --git a/chromium/net/cookies/cookie_monster_perftest.cc b/chromium/net/cookies/cookie_monster_perftest.cc index f7230710b84..05cfafdd163 100644 --- a/chromium/net/cookies/cookie_monster_perftest.cc +++ b/chromium/net/cookies/cookie_monster_perftest.cc @@ -139,7 +139,7 @@ TEST(ParsedCookieTest, TestParseBigCookies) { } TEST_F(CookieMonsterTest, TestAddCookiesOnSingleHost) { - std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr)); std::vector<std::string> cookies; for (int i = 0; i < kNumCookies; i++) { cookies.push_back(base::StringPrintf("a%03d=b", i)); @@ -172,7 +172,7 @@ TEST_F(CookieMonsterTest, TestAddCookiesOnSingleHost) { } TEST_F(CookieMonsterTest, TestAddCookieOnManyHosts) { - std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr)); std::string cookie(kCookieLine); std::vector<GURL> gurls; // just wanna have ffffuunnn for (int i = 0; i < kNumCookies; ++i) { @@ -205,7 +205,7 @@ TEST_F(CookieMonsterTest, TestAddCookieOnManyHosts) { } TEST_F(CookieMonsterTest, TestDomainTree) { - std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr)); GetCookiesCallback getCookiesCallback; SetCookieCallback setCookieCallback; const char domain_cookie_format_tree[] = "a=b; domain=%s"; @@ -260,7 +260,7 @@ TEST_F(CookieMonsterTest, TestDomainTree) { } TEST_F(CookieMonsterTest, TestDomainLine) { - std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr)); SetCookieCallback setCookieCallback; GetCookiesCallback getCookiesCallback; std::vector<std::string> domain_list; @@ -321,7 +321,7 @@ TEST_F(CookieMonsterTest, TestImport) { store->SetLoadExpectation(true, std::move(initial_cookies)); - std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get())); // Import will happen on first access. GURL gurl("www.foo.com"); @@ -335,7 +335,7 @@ TEST_F(CookieMonsterTest, TestImport) { } TEST_F(CookieMonsterTest, TestGetKey) { - std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr)); base::PerfTimeLogger timer("Cookie_monster_get_key"); for (int i = 0; i < kNumCookies; i++) cm->GetKey("www.foo.com"); diff --git a/chromium/net/cookies/cookie_monster_store_test.cc b/chromium/net/cookies/cookie_monster_store_test.cc index 0f60e4105f5..3e24ca45af8 100644 --- a/chromium/net/cookies/cookie_monster_store_test.cc +++ b/chromium/net/cookies/cookie_monster_store_test.cc @@ -87,6 +87,9 @@ void MockPersistentCookieStore::DeleteCookie(const CanonicalCookie& cookie) { commands_.push_back(CookieStoreCommand(CookieStoreCommand::REMOVE, cookie)); } +void MockPersistentCookieStore::SetBeforeFlushCallback( + base::RepeatingClosure callback) {} + void MockPersistentCookieStore::Flush(base::OnceClosure callback) { if (!callback.is_null()) base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, @@ -99,20 +102,6 @@ void MockPersistentCookieStore::SetForceKeepSessionState() { MockPersistentCookieStore::~MockPersistentCookieStore() { } -MockCookieMonsterDelegate::MockCookieMonsterDelegate() { -} - -void MockCookieMonsterDelegate::OnCookieChanged( - const CanonicalCookie& cookie, - bool removed, - CookieStore::ChangeCause cause) { - CookieNotification notification(cookie, removed); - changes_.push_back(notification); -} - -MockCookieMonsterDelegate::~MockCookieMonsterDelegate() { -} - std::unique_ptr<CanonicalCookie> BuildCanonicalCookie( const GURL& url, const std::string& cookie_line, @@ -131,7 +120,7 @@ std::unique_ptr<CanonicalCookie> BuildCanonicalCookie( : base::Time(); std::string cookie_path = pc.Path(); - return base::MakeUnique<CanonicalCookie>( + return std::make_unique<CanonicalCookie>( pc.Name(), pc.Value(), "." + url.host(), cookie_path, creation_time, cookie_expires, base::Time(), pc.IsSecure(), pc.IsHttpOnly(), pc.SameSite(), pc.Priority()); @@ -156,7 +145,7 @@ void MockSimplePersistentCookieStore::Load( std::vector<std::unique_ptr<CanonicalCookie>> out_cookies; for (auto it = cookies_.begin(); it != cookies_.end(); it++) - out_cookies.push_back(base::MakeUnique<CanonicalCookie>(it->second)); + out_cookies.push_back(std::make_unique<CanonicalCookie>(it->second)); base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(loaded_callback, base::Passed(&out_cookies))); @@ -196,6 +185,9 @@ void MockSimplePersistentCookieStore::DeleteCookie( cookies_.erase(it); } +void MockSimplePersistentCookieStore::SetBeforeFlushCallback( + base::RepeatingClosure callback) {} + void MockSimplePersistentCookieStore::Flush(base::OnceClosure callback) { if (!callback.is_null()) base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, @@ -240,7 +232,7 @@ std::unique_ptr<CookieMonster> CreateMonsterFromStoreForGC( // The URL must be HTTPS since |secure| can be true or false, and because // strict secure cookies are enforced, the cookie will fail to be created if // |secure| is true but the URL is an insecure scheme. - std::unique_ptr<CanonicalCookie> cc(base::MakeUnique<CanonicalCookie>( + std::unique_ptr<CanonicalCookie> cc(std::make_unique<CanonicalCookie>( "a", "1", base::StringPrintf("h%05d.izzle", i), "/path", creation_time, expiration_time, base::Time(), secure, false, CookieSameSite::DEFAULT_MODE, COOKIE_PRIORITY_DEFAULT)); @@ -248,7 +240,7 @@ std::unique_ptr<CookieMonster> CreateMonsterFromStoreForGC( store->AddCookie(*cc); } - return base::MakeUnique<CookieMonster>(store.get(), nullptr); + return std::make_unique<CookieMonster>(store.get()); } MockSimplePersistentCookieStore::~MockSimplePersistentCookieStore() { diff --git a/chromium/net/cookies/cookie_monster_store_test.h b/chromium/net/cookies/cookie_monster_store_test.h index 816077b74ad..6d8a8335a4b 100644 --- a/chromium/net/cookies/cookie_monster_store_test.h +++ b/chromium/net/cookies/cookie_monster_store_test.h @@ -99,6 +99,8 @@ class MockPersistentCookieStore : public CookieMonster::PersistentCookieStore { void DeleteCookie(const CanonicalCookie& cookie) override; + void SetBeforeFlushCallback(base::RepeatingClosure callback) override; + void Flush(base::OnceClosure callback) override; void SetForceKeepSessionState() override; @@ -121,29 +123,6 @@ class MockPersistentCookieStore : public CookieMonster::PersistentCookieStore { DISALLOW_COPY_AND_ASSIGN(MockPersistentCookieStore); }; -// Mock for CookieMonsterDelegate -class MockCookieMonsterDelegate : public CookieMonsterDelegate { - public: - typedef std::pair<CanonicalCookie, bool> CookieNotification; - - MockCookieMonsterDelegate(); - - const std::vector<CookieNotification>& changes() const { return changes_; } - - void reset() { changes_.clear(); } - - void OnCookieChanged(const CanonicalCookie& cookie, - bool removed, - CookieStore::ChangeCause cause) override; - - private: - ~MockCookieMonsterDelegate() override; - - std::vector<CookieNotification> changes_; - - DISALLOW_COPY_AND_ASSIGN(MockCookieMonsterDelegate); -}; - // Helper to build a single CanonicalCookie. std::unique_ptr<CanonicalCookie> BuildCanonicalCookie( const GURL& url, @@ -174,6 +153,8 @@ class MockSimplePersistentCookieStore void DeleteCookie(const CanonicalCookie& cookie) override; + void SetBeforeFlushCallback(base::RepeatingClosure callback) override; + void Flush(base::OnceClosure callback) override; void SetForceKeepSessionState() override; diff --git a/chromium/net/cookies/cookie_monster_unittest.cc b/chromium/net/cookies/cookie_monster_unittest.cc index 7ec0ad22b3c..c921d50643b 100644 --- a/chromium/net/cookies/cookie_monster_unittest.cc +++ b/chromium/net/cookies/cookie_monster_unittest.cc @@ -61,6 +61,7 @@ class NewMockPersistentCookieStore MOCK_METHOD1(AddCookie, void(const CanonicalCookie& cc)); MOCK_METHOD1(UpdateCookieAccessTime, void(const CanonicalCookie& cc)); MOCK_METHOD1(DeleteCookie, void(const CanonicalCookie& cc)); + MOCK_METHOD1(SetBeforeFlushCallback, void(base::RepeatingClosure)); virtual void Flush(base::OnceClosure callback) { if (!callback.is_null()) base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, @@ -104,7 +105,7 @@ bool CookieValuePredicate(const std::string& true_value, struct CookieMonsterTestTraits { static std::unique_ptr<CookieStore> Create() { - return base::MakeUnique<CookieMonster>(nullptr, nullptr); + return std::make_unique<CookieMonster>(nullptr); } static const bool supports_http_only = true; @@ -113,6 +114,7 @@ struct CookieMonsterTestTraits { static const bool filters_schemes = true; static const bool has_path_prefix_bug = false; static const bool forbids_setting_empty_name = false; + static const bool supports_global_cookie_tracking = true; static const int creation_time_granularity_in_ms = 0; }; @@ -327,7 +329,7 @@ class CookieMonsterTestBase : public CookieStoreTest<T> { (domain_max_cookies + domain_purge_cookies) * 2; // Add a bunch of cookies on a single host, should purge them. { - std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr)); for (int i = 0; i < more_than_enough_cookies; ++i) { std::string cookie = base::StringPrintf("a%03d=b", i); EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), cookie)); @@ -344,7 +346,7 @@ class CookieMonsterTestBase : public CookieStoreTest<T> { // between them. We shouldn't go above kDomainMaxCookies for both together. GURL url_google_specific(http_www_foo_.Format("http://www.gmail.%D")); { - std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr)); for (int i = 0; i < more_than_enough_cookies; ++i) { std::string cookie_general = base::StringPrintf("a%03d=b", i); EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), cookie_general)); @@ -522,7 +524,7 @@ class CookieMonsterTestBase : public CookieStoreTest<T> { std::unique_ptr<CookieMonster> cm; if (alt_host_entries == nullptr) { - cm.reset(new CookieMonster(nullptr, nullptr)); + cm.reset(new CookieMonster(nullptr)); } else { // When generating all of these cookies on alternate hosts, they need to // be all older than the max "safe" date for GC, which is currently 30 @@ -567,7 +569,7 @@ class CookieMonsterTestBase : public CookieStoreTest<T> { DCHECK_EQ(150U, CookieMonster::kDomainMaxCookies - CookieMonster::kDomainPurgeCookies); - std::unique_ptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(NULL)); // Each test case adds 181 cookies, so 31 cookies are evicted. // Cookie same priority, repeated for each priority. @@ -630,7 +632,7 @@ class CookieMonsterTestBase : public CookieStoreTest<T> { DCHECK_EQ(150U, CookieMonster::kDomainMaxCookies - CookieMonster::kDomainPurgeCookies); - std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr)); // Each test case adds 181 cookies, so 31 cookies are evicted. // Cookie same priority, repeated for each priority. @@ -687,7 +689,7 @@ class CookieMonsterTestBase : public CookieStoreTest<T> { DCHECK_EQ(150U, CookieMonster::kDomainMaxCookies - CookieMonster::kDomainPurgeCookies); - std::unique_ptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(NULL)); // Each test case adds 180 secure cookies, and some non-secure cookie. The // secure cookies take priority, so the non-secure cookie is removed, along @@ -793,7 +795,7 @@ class CookieMonsterTestBase : public CookieStoreTest<T> { // Function for creating a CM with a number of cookies in it, // no store (and hence no ability to affect access time). CookieMonster* CreateMonsterForGC(int num_cookies) { - CookieMonster* cm(new CookieMonster(NULL, NULL)); + CookieMonster* cm(new CookieMonster(NULL)); for (int i = 0; i < num_cookies; i++) { SetCookie(cm, GURL(base::StringPrintf("http://h%05d.izzle", i)), "a=1"); } @@ -931,7 +933,7 @@ class DeferredCookieTaskTest : public CookieMonsterTest { protected: DeferredCookieTaskTest() : expect_load_called_(false) { persistent_store_ = new NewMockPersistentCookieStore(); - cookie_monster_.reset(new CookieMonster(persistent_store_.get(), nullptr)); + cookie_monster_.reset(new CookieMonster(persistent_store_.get())); } // Defines a cookie to be returned from PersistentCookieStore::Load @@ -1361,7 +1363,7 @@ TEST_F(DeferredCookieTaskTest, DeferredTaskOrder) { TEST_F(CookieMonsterTest, TestCookieDeleteAll) { scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore); - std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get())); CookieOptions options; options.set_include_httponly(); @@ -1392,7 +1394,7 @@ TEST_F(CookieMonsterTest, TestCookieDeleteAll) { } TEST_F(CookieMonsterTest, TestCookieDeleteAllCreatedBetweenTimestamps) { - std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr)); Time now = Time::Now(); // Nothing has been added so nothing should be deleted. @@ -1437,7 +1439,7 @@ TEST_F(CookieMonsterTest, TestCookieDeleteAllCreatedBetweenTimestamps) { TEST_F(CookieMonsterTest, TestCookieDeleteAllCreatedBetweenTimestampsWithPredicate) { - std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr)); Time now = Time::Now(); CanonicalCookie test_cookie; @@ -1530,7 +1532,7 @@ static const base::TimeDelta kAccessDelay = TEST_F(CookieMonsterTest, TestLastAccess) { std::unique_ptr<CookieMonster> cm( - new CookieMonster(nullptr, nullptr, kLastAccessThreshold)); + new CookieMonster(nullptr, kLastAccessThreshold)); EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "A=B")); const Time last_access_date(GetFirstCookieAccessDate(cm.get())); @@ -1584,8 +1586,8 @@ TEST_F(CookieMonsterTest, TestPriorityAwareGarbageCollectionMixed) { } TEST_F(CookieMonsterTest, SetCookieableSchemes) { - std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, nullptr)); - std::unique_ptr<CookieMonster> cm_foo(new CookieMonster(nullptr, nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr)); + std::unique_ptr<CookieMonster> cm_foo(new CookieMonster(nullptr)); // Only cm_foo should allow foo:// cookies. std::vector<std::string> schemes; @@ -1603,7 +1605,7 @@ TEST_F(CookieMonsterTest, SetCookieableSchemes) { TEST_F(CookieMonsterTest, GetAllCookiesForURL) { std::unique_ptr<CookieMonster> cm( - new CookieMonster(nullptr, nullptr, kLastAccessThreshold)); + new CookieMonster(nullptr, kLastAccessThreshold)); // Create an httponly cookie. CookieOptions options; @@ -1670,7 +1672,7 @@ TEST_F(CookieMonsterTest, GetAllCookiesForURL) { } TEST_F(CookieMonsterTest, GetAllCookiesForURLPathMatching) { - std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr)); CookieOptions options; EXPECT_TRUE(SetCookieWithOptions(cm.get(), www_foo_foo_.url(), @@ -1708,7 +1710,7 @@ TEST_F(CookieMonsterTest, GetAllCookiesForURLPathMatching) { } TEST_F(CookieMonsterTest, CookieSorting) { - std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr)); EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "B=B1; path=/")); EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "B=B2; path=/foo")); @@ -1735,7 +1737,7 @@ TEST_F(CookieMonsterTest, CookieSorting) { } TEST_F(CookieMonsterTest, DeleteCookieByName) { - std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr)); EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "A=A1; path=/")); EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "A=A2; path=/foo")); @@ -1811,7 +1813,7 @@ TEST_F(CookieMonsterTest, DontImportDuplicateCookies) { // Inject our initial cookies into the mock PersistentCookieStore. store->SetLoadExpectation(true, std::move(initial_cookies)); - std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get())); // Verify that duplicates were not imported for path "/". // (If this had failed, GetCookies() would have also returned X=1, X=2, X=4). @@ -1867,7 +1869,7 @@ TEST_F(CookieMonsterTest, DontImportDuplicateCreationTimes) { // Inject our initial cookies into the mock PersistentCookieStore. store->SetLoadExpectation(true, std::move(initial_cookies)); - std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get())); CookieList list(GetAllCookies(cm.get())); EXPECT_EQ(2U, list.size()); @@ -1879,84 +1881,9 @@ TEST_F(CookieMonsterTest, DontImportDuplicateCreationTimes) { EXPECT_NE(name1, name2); } -TEST_F(CookieMonsterTest, CookieMonsterDelegate) { - scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore); - scoped_refptr<MockCookieMonsterDelegate> delegate( - new MockCookieMonsterDelegate); - std::unique_ptr<CookieMonster> cm( - new CookieMonster(store.get(), delegate.get())); - - EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "A=B")); - EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "C=D")); - EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "E=F")); - EXPECT_EQ("A=B; C=D; E=F", GetCookies(cm.get(), http_www_foo_.url())); - ASSERT_EQ(3u, delegate->changes().size()); - EXPECT_FALSE(delegate->changes()[0].second); - EXPECT_EQ(http_www_foo_.url().host(), delegate->changes()[0].first.Domain()); - EXPECT_EQ("A", delegate->changes()[0].first.Name()); - EXPECT_EQ("B", delegate->changes()[0].first.Value()); - EXPECT_EQ(http_www_foo_.url().host(), delegate->changes()[1].first.Domain()); - EXPECT_FALSE(delegate->changes()[1].second); - EXPECT_EQ("C", delegate->changes()[1].first.Name()); - EXPECT_EQ("D", delegate->changes()[1].first.Value()); - EXPECT_EQ(http_www_foo_.url().host(), delegate->changes()[2].first.Domain()); - EXPECT_FALSE(delegate->changes()[2].second); - EXPECT_EQ("E", delegate->changes()[2].first.Name()); - EXPECT_EQ("F", delegate->changes()[2].first.Value()); - delegate->reset(); - - EXPECT_TRUE(FindAndDeleteCookie(cm.get(), http_www_foo_.url().host(), "C")); - EXPECT_EQ("A=B; E=F", GetCookies(cm.get(), http_www_foo_.url())); - ASSERT_EQ(1u, delegate->changes().size()); - EXPECT_EQ(http_www_foo_.url().host(), delegate->changes()[0].first.Domain()); - EXPECT_TRUE(delegate->changes()[0].second); - EXPECT_EQ("C", delegate->changes()[0].first.Name()); - EXPECT_EQ("D", delegate->changes()[0].first.Value()); - delegate->reset(); - - EXPECT_FALSE(FindAndDeleteCookie(cm.get(), "random.host", "E")); - EXPECT_EQ("A=B; E=F", GetCookies(cm.get(), http_www_foo_.url())); - EXPECT_EQ(0u, delegate->changes().size()); - - // Insert a cookie "a" for path "/path1" - EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), - "a=val1; path=/path1; " - "expires=Mon, 18-Apr-22 22:50:13 GMT")); - ASSERT_EQ(1u, store->commands().size()); - EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[0].type); - ASSERT_EQ(1u, delegate->changes().size()); - EXPECT_FALSE(delegate->changes()[0].second); - EXPECT_EQ(http_www_foo_.url().host(), delegate->changes()[0].first.Domain()); - EXPECT_EQ("a", delegate->changes()[0].first.Name()); - EXPECT_EQ("val1", delegate->changes()[0].first.Value()); - delegate->reset(); - - // Insert a cookie "a" for path "/path1", that is httponly. This should - // overwrite the non-http-only version. - CookieOptions allow_httponly; - allow_httponly.set_include_httponly(); - EXPECT_TRUE(SetCookieWithOptions(cm.get(), http_www_foo_.url(), - "a=val2; path=/path1; httponly; " - "expires=Mon, 18-Apr-22 22:50:14 GMT", - allow_httponly)); - ASSERT_EQ(3u, store->commands().size()); - EXPECT_EQ(CookieStoreCommand::REMOVE, store->commands()[1].type); - EXPECT_EQ(CookieStoreCommand::ADD, store->commands()[2].type); - ASSERT_EQ(2u, delegate->changes().size()); - EXPECT_EQ(http_www_foo_.url().host(), delegate->changes()[0].first.Domain()); - EXPECT_TRUE(delegate->changes()[0].second); - EXPECT_EQ("a", delegate->changes()[0].first.Name()); - EXPECT_EQ("val1", delegate->changes()[0].first.Value()); - EXPECT_EQ(http_www_foo_.url().host(), delegate->changes()[1].first.Domain()); - EXPECT_FALSE(delegate->changes()[1].second); - EXPECT_EQ("a", delegate->changes()[1].first.Name()); - EXPECT_EQ("val2", delegate->changes()[1].first.Value()); - delegate->reset(); -} - TEST_F(CookieMonsterTest, PredicateSeesAllCookies) { const std::string kTrueValue = "A"; - std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr)); // We test that we can see all cookies with our predicated. This includes // host, http_only, host secure, and all domain cookies. CookiePredicate value_matcher = base::Bind(&CookieValuePredicate, kTrueValue); @@ -1976,7 +1903,7 @@ TEST_F(CookieMonsterTest, PredicateSeesAllCookies) { } TEST_F(CookieMonsterTest, UniqueCreationTime) { - std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr)); CookieOptions options; // Add in three cookies through every public interface to the @@ -2039,7 +1966,7 @@ TEST_F(CookieMonsterTest, UniqueCreationTime) { // Mainly a test of GetEffectiveDomain, or more specifically, of the // expected behavior of GetEffectiveDomain within the CookieMonster. TEST_F(CookieMonsterTest, GetKey) { - std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr)); // This test is really only interesting if GetKey() actually does something. EXPECT_EQ("foo.com", cm->GetKey("www.foo.com")); @@ -2083,8 +2010,7 @@ TEST_F(CookieMonsterTest, BackingStoreCommunication) { // Create new cookies and flush them to the store. { - std::unique_ptr<CookieMonster> cmout( - new CookieMonster(store.get(), nullptr)); + std::unique_ptr<CookieMonster> cmout(new CookieMonster(store.get())); for (const CookiesInputInfo* p = input_info; p < &input_info[arraysize(input_info)]; p++) { EXPECT_TRUE(SetCookieWithDetails( @@ -2100,8 +2026,7 @@ TEST_F(CookieMonsterTest, BackingStoreCommunication) { // Create a new cookie monster and make sure that everything is correct { - std::unique_ptr<CookieMonster> cmin( - new CookieMonster(store.get(), nullptr)); + std::unique_ptr<CookieMonster> cmin(new CookieMonster(store.get())); CookieList cookies(GetAllCookies(cmin.get())); ASSERT_EQ(2u, cookies.size()); // Ordering is path length, then creation time. So second cookie @@ -2131,7 +2056,7 @@ TEST_F(CookieMonsterTest, BackingStoreCommunication) { TEST_F(CookieMonsterTest, CookieListOrdering) { // Put a random set of cookies into a monster and make sure // they're returned in the right order. - std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr)); EXPECT_TRUE( SetCookie(cm.get(), GURL("http://d.c.b.a.foo.com/aa/x.html"), "c=1")); EXPECT_TRUE(SetCookie(cm.get(), GURL("http://b.a.foo.com/aa/bb/cc/x.html"), @@ -2269,7 +2194,7 @@ TEST_F(CookieMonsterTest, WhileLoadingLoadCompletesBeforeKeyLoadCompletes) { scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore); store->set_store_load_commands(true); - std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get())); // Get all cookies task that queues a task to set a cookie when executed. ResultSavingCookieCallback<bool> set_cookie_callback; @@ -2323,7 +2248,7 @@ TEST_F(CookieMonsterTest, WhileLoadingDeleteAllGetForURL) { scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore); store->set_store_load_commands(true); - std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get())); ResultSavingCookieCallback<uint32_t> delete_callback; cm->DeleteAllAsync(base::Bind(&ResultSavingCookieCallback<uint32_t>::Run, @@ -2363,7 +2288,7 @@ TEST_F(CookieMonsterTest, WhileLoadingGetAllSetGetAll) { scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore); store->set_store_load_commands(true); - std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get())); GetCookieListCallback get_cookie_list_callback1; cm->GetAllCookiesAsync( @@ -2416,7 +2341,7 @@ TEST_F(CookieMonsterTest, CheckOrderOfCookieTaskQueueWhenLoadingCompletes) { scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore); store->set_store_load_commands(true); - std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get())); // Get all cookies task that queues a task to set a cookie when executed. ResultSavingCookieCallback<bool> set_cookie_callback; @@ -2480,6 +2405,7 @@ class FlushablePersistentStore : public CookieMonster::PersistentCookieStore { void UpdateCookieAccessTime(const CanonicalCookie&) override {} void DeleteCookie(const CanonicalCookie&) override {} void SetForceKeepSessionState() override {} + void SetBeforeFlushCallback(base::RepeatingClosure callback) override {} void Flush(base::OnceClosure callback) override { ++flush_count_; @@ -2511,26 +2437,13 @@ class CallbackCounter : public base::RefCountedThreadSafe<CallbackCounter> { volatile int callback_count_; }; -class FlushCountingChannelIDStore : public DefaultChannelIDStore { - public: - FlushCountingChannelIDStore() - : DefaultChannelIDStore(nullptr), flush_count_(0) {} - - void Flush() override { flush_count_++; } - - int flush_count() { return flush_count_; } - - private: - int flush_count_; -}; - } // namespace // Test that FlushStore() is forwarded to the store and callbacks are posted. TEST_F(CookieMonsterTest, FlushStore) { scoped_refptr<CallbackCounter> counter(new CallbackCounter()); scoped_refptr<FlushablePersistentStore> store(new FlushablePersistentStore()); - std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get())); ASSERT_EQ(0, store->flush_count()); ASSERT_EQ(0, counter->callback_count()); @@ -2565,7 +2478,7 @@ TEST_F(CookieMonsterTest, FlushStore) { ASSERT_EQ(2, counter->callback_count()); // If there's no backing store, FlushStore() is always a safe no-op. - cm.reset(new CookieMonster(nullptr, nullptr)); + cm.reset(new CookieMonster(nullptr)); GetAllCookies(cm.get()); // Force init. cm->FlushStore(base::Closure()); base::RunLoop().RunUntilIdle(); @@ -2578,44 +2491,23 @@ TEST_F(CookieMonsterTest, FlushStore) { ASSERT_EQ(3, counter->callback_count()); } -TEST_F(CookieMonsterTest, FlushChannelIDs) { - // |channel_id_service| owns |channel_id_store|. - FlushCountingChannelIDStore* channel_id_store = - new FlushCountingChannelIDStore(); +TEST_F(CookieMonsterTest, SetBeforeFlushCallbackIsCalled) { std::unique_ptr<ChannelIDService> channel_id_service( - new ChannelIDService(channel_id_store)); - - scoped_refptr<FlushablePersistentStore> store(new FlushablePersistentStore()); - std::unique_ptr<CookieMonster> cm( - new CookieMonster(store.get(), nullptr, channel_id_service.get())); - EXPECT_EQ(0, channel_id_store->flush_count()); + new ChannelIDService(nullptr)); - // Before initialization, FlushStore() doesn't propagate to the - // ChannelIDStore. - cm->FlushStore(base::Closure()); - base::RunLoop().RunUntilIdle(); + scoped_refptr<NewMockPersistentCookieStore> store( + new NewMockPersistentCookieStore()); - EXPECT_EQ(0, channel_id_store->flush_count()); + // SetBeforeFlushCallback should be called in both the c'tor and d'tor. + EXPECT_CALL(*store, SetBeforeFlushCallback(testing::_)).Times(2); - // After initialization, FlushStore() propagates to the ChannelIDStore. - GetAllCookies(cm.get()); // Force init. - cm->FlushStore(base::Closure()); - base::RunLoop().RunUntilIdle(); - - EXPECT_EQ(1, channel_id_store->flush_count()); - - // If there is no persistent store, then a ChannelIDStore won't be notified. - cm.reset(new CookieMonster(nullptr, nullptr, channel_id_service.get())); - GetAllCookies(cm.get()); // Force init. - cm->FlushStore(base::Closure()); - base::RunLoop().RunUntilIdle(); - - EXPECT_EQ(1, channel_id_store->flush_count()); + std::unique_ptr<CookieMonster> cm( + new CookieMonster(store.get(), channel_id_service.get())); } TEST_F(CookieMonsterTest, SetAllCookies) { scoped_refptr<FlushablePersistentStore> store(new FlushablePersistentStore()); - std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get())); cm->SetPersistSessionCookies(true); EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "U=V; path=/")); @@ -2664,7 +2556,7 @@ TEST_F(CookieMonsterTest, SetAllCookies) { // works). TEST_F(CookieMonsterTest, DeleteAll) { scoped_refptr<FlushablePersistentStore> store(new FlushablePersistentStore()); - std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get())); cm->SetPersistSessionCookies(true); EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "X=Y; path=/")); @@ -2675,7 +2567,7 @@ TEST_F(CookieMonsterTest, DeleteAll) { } TEST_F(CookieMonsterTest, HistogramCheck) { - std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr)); // Should match call in InitializeHistograms, but doesn't really matter // since the histogram should have been initialized by the CM construction // above. @@ -2714,7 +2606,7 @@ TEST_F(CookieMonsterTest, InvalidExpiryTime) { // CookieStore if the "persist session cookies" option is on. TEST_F(CookieMonsterTest, PersistSessionCookies) { scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore); - std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get())); cm->SetPersistSessionCookies(true); // All cookies set with SetCookie are session cookies. @@ -2750,7 +2642,7 @@ TEST_F(CookieMonsterTest, PersistSessionCookies) { // Test the commands sent to the persistent cookie store. TEST_F(CookieMonsterTest, PersisentCookieStorageTest) { scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore); - std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get())); // Add a cookie. EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), @@ -2806,7 +2698,7 @@ TEST_F(CookieMonsterTest, ControlCharacterPurge) { // We have to manually build this cookie because it contains a control // character, and our cookie line parser rejects control characters. - std::unique_ptr<CanonicalCookie> cc = base::MakeUnique<CanonicalCookie>( + std::unique_ptr<CanonicalCookie> cc = std::make_unique<CanonicalCookie>( "baz", "\x05" "boo", @@ -2819,7 +2711,7 @@ TEST_F(CookieMonsterTest, ControlCharacterPurge) { // Inject our initial cookies into the mock PersistentCookieStore. store->SetLoadExpectation(true, std::move(initial_cookies)); - std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get())); EXPECT_EQ("foo=bar; hello=world", GetCookies(cm.get(), url)); } @@ -2830,7 +2722,7 @@ TEST_F(CookieMonsterTest, CookieSourceHistogram) { const std::string cookie_source_histogram = "Cookie.CookieSourceScheme"; scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore); - std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get())); histograms.ExpectTotalCount(cookie_source_histogram, 0); @@ -2892,7 +2784,7 @@ TEST_F(CookieMonsterTest, CookieDeleteEquivalentHistogramTest) { const std::string cookie_source_histogram = "Cookie.CookieDeleteEquivalent"; scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore); - std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get())); // Set a secure cookie from a secure origin EXPECT_TRUE(SetCookie(cm.get(), https_www_foo_.url(), "A=B; Secure")); @@ -2955,6 +2847,9 @@ TEST_F(CookieMonsterTest, CookieDeleteEquivalentHistogramTest) { histograms.ExpectBucketCount(cookie_source_histogram, CookieMonster::COOKIE_DELETE_EQUIVALENT_FOUND, 1); + histograms.ExpectBucketCount( + cookie_source_histogram, + CookieMonster::COOKIE_DELETE_EQUIVALENT_FOUND_WITH_SAME_VALUE, 0); // Set a secure cookie from a secure origin that matches the name of an // already existing cookie and is not equivalent. @@ -2964,10 +2859,24 @@ TEST_F(CookieMonsterTest, CookieDeleteEquivalentHistogramTest) { histograms.ExpectBucketCount(cookie_source_histogram, CookieMonster::COOKIE_DELETE_EQUIVALENT_ATTEMPT, 7); + + // Set a cookie that matches both the name and value of an already existing + // cookie. + EXPECT_TRUE(SetCookie(cm.get(), https_www_foo_.url(), "A=D; secure")); + histograms.ExpectTotalCount(cookie_source_histogram, 14); + histograms.ExpectBucketCount(cookie_source_histogram, + CookieMonster::COOKIE_DELETE_EQUIVALENT_ATTEMPT, + 8); + histograms.ExpectBucketCount(cookie_source_histogram, + CookieMonster::COOKIE_DELETE_EQUIVALENT_FOUND, + 2); + histograms.ExpectBucketCount( + cookie_source_histogram, + CookieMonster::COOKIE_DELETE_EQUIVALENT_FOUND_WITH_SAME_VALUE, 1); } TEST_F(CookieMonsterTest, SetSecureCookies) { - std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr)); GURL http_url("http://www.foo.com"); GURL http_superdomain_url("http://foo.com"); GURL https_url("https://www.foo.com"); @@ -3170,7 +3079,7 @@ TEST_F(CookieMonsterTest, EvictSecureCookies) { // Tests that strict secure cookies doesn't trip equivalent cookie checks // accidentally. Regression test for https://crbug.com/569943. TEST_F(CookieMonsterTest, EquivalentCookies) { - std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, nullptr)); + std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr)); GURL http_url("http://www.foo.com"); GURL http_superdomain_url("http://foo.com"); GURL https_url("https://www.foo.com"); @@ -3193,7 +3102,7 @@ class CookieMonsterNotificationTest : public CookieMonsterTest { CookieMonsterNotificationTest() : test_url_("http://www.foo.com/foo"), store_(new MockPersistentCookieStore), - monster_(new CookieMonster(store_.get(), nullptr)) {} + monster_(new CookieMonster(store_.get())) {} ~CookieMonsterNotificationTest() override {} @@ -3341,7 +3250,56 @@ TEST_F(CookieMonsterNotificationTest, MultipleSameNotifies) { SetCookie(monster(), test_url_, "abc=def"); base::RunLoop().RunUntilIdle(); EXPECT_EQ(1U, cookies0.size()); - EXPECT_EQ(1U, cookies0.size()); + EXPECT_EQ(1U, cookies1.size()); +} + +TEST_F(CookieMonsterNotificationTest, GlobalNotBroadcast) { + // Create a persistent store that will not synchronously satisfy the + // loading requirement. + scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore); + store->set_store_load_commands(true); + + // Bind it to a CookieMonster + std::unique_ptr<CookieMonster> monster( + base::MakeUnique<CookieMonster>(store.get())); + + // Trigger load dispatch and confirm it. + monster->GetAllCookiesAsync(CookieStore::GetCookieListCallback()); + EXPECT_EQ(1u, store->commands().size()); + EXPECT_EQ(CookieStoreCommand::LOAD, store->commands()[0].type); + + // Attach a change subscription. + std::vector<CanonicalCookie> cookies; + std::vector<CookieStore::ChangeCause> causes; + std::unique_ptr<CookieStore::CookieChangedSubscription> sub( + monster->AddCallbackForAllChanges( + base::Bind(&RecordCookieChanges, &cookies, &causes))); + + // Set up a set of cookies with a duplicate. + std::vector<std::unique_ptr<CanonicalCookie>> initial_cookies; + AddCookieToList(GURL("http://www.foo.com"), + "X=1; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT", + base::Time::Now() + base::TimeDelta::FromDays(3), + &initial_cookies); + + AddCookieToList(GURL("http://www.foo.com"), + "X=2; path=/; expires=Mon, 18-Apr-22 22:50:14 GMT", + base::Time::Now() + base::TimeDelta::FromDays(1), + &initial_cookies); + + // Execute the load + store->commands()[0].loaded_callback.Run(std::move(initial_cookies)); + base::RunLoop().RunUntilIdle(); + + // We should see two insertions, no deletions, and only one cookie in the + // monster. + // TODO(rdsmith): Why yes, this is an internally inconsistent interface. + EXPECT_EQ(2U, cookies.size()); + EXPECT_EQ("X", cookies[0].Name()); + EXPECT_EQ(CookieStore::ChangeCause::INSERTED, causes[0]); + EXPECT_EQ("X", cookies[1].Name()); + EXPECT_EQ(CookieStore::ChangeCause::INSERTED, causes[1]); + EXPECT_EQ(1u, this->GetAllCookies(monster.get()).size()); } } // namespace net diff --git a/chromium/net/cookies/cookie_options.cc b/chromium/net/cookies/cookie_options.cc index 3a4e584ec62..1b97f8545cd 100644 --- a/chromium/net/cookies/cookie_options.cc +++ b/chromium/net/cookies/cookie_options.cc @@ -8,6 +8,7 @@ namespace net { +// Keep default values in sync with content/public/common/cookie_manager.mojom. CookieOptions::CookieOptions() : exclude_httponly_(true), same_site_cookie_mode_(SameSiteCookieMode::DO_NOT_INCLUDE), diff --git a/chromium/net/cookies/cookie_options.h b/chromium/net/cookies/cookie_options.h index 53a4d0f0c0e..0e312b04014 100644 --- a/chromium/net/cookies/cookie_options.h +++ b/chromium/net/cookies/cookie_options.h @@ -59,6 +59,7 @@ class NET_EXPORT CookieOptions { bool has_server_time() const { return !server_time_.is_null(); } base::Time server_time() const { return server_time_; } + void set_update_access_time() { update_access_time_ = true; } void set_do_not_update_access_time() { update_access_time_ = false; } bool update_access_time() const { return update_access_time_; } diff --git a/chromium/net/cookies/cookie_store.h b/chromium/net/cookies/cookie_store.h index 1a4d3d47ed5..e9bf8cbfae5 100644 --- a/chromium/net/cookies/cookie_store.h +++ b/chromium/net/cookies/cookie_store.h @@ -42,7 +42,7 @@ class NET_EXPORT CookieStore { // The following four values have the same meaning as EXPLICIT, but are // being used to track down where a bug is coming from. // TODO(nharper): Remove the following four values once the one of interest - // has been found. + // has been found. See http://crbug.com/548423. EXPLICIT_DELETE_BETWEEN, EXPLICIT_DELETE_PREDICATE, EXPLICIT_DELETE_SINGLE, @@ -202,9 +202,11 @@ class NET_EXPORT CookieStore { // Deletes all of the cookies that match the given predicate and that have a // creation_date greater than or equal to |delete_begin| and smaller than - // |delete_end|. This includes all http_only and secure cookies. Avoid - // deleting cookies that could leave websites with a partial set of visible - // cookies. + // |delete_end|. Null times do not cap their ranges (i.e. + // |delete_end.is_null()| would mean that there is no time after which + // cookies are not deleted). This includes all http_only and secure + // cookies. Avoid deleting cookies that could leave websites with a + // partial set of visible cookies. // Calls |callback| with the number of cookies deleted. virtual void DeleteAllCreatedBetweenWithPredicateAsync( const base::Time& delete_begin, @@ -249,6 +251,12 @@ class NET_EXPORT CookieStore { const std::string& name, const CookieChangedCallback& callback) = 0; + // Add a callback to be notified on all cookie changes (with a few + // bookkeeping exceptions; see kChangeCauseMapping in + // cookie_monster.cc). + virtual std::unique_ptr<CookieChangedSubscription> AddCallbackForAllChanges( + const CookieChangedCallback& callback) = 0; + // Returns true if this cookie store is ephemeral, and false if it is backed // by some sort of persistence layer. // TODO(nharper): Remove this method once crbug.com/548423 has been closed. diff --git a/chromium/net/cookies/cookie_store_test_helpers.cc b/chromium/net/cookies/cookie_store_test_helpers.cc index 3a1f3492f9f..cf846b89187 100644 --- a/chromium/net/cookies/cookie_store_test_helpers.cc +++ b/chromium/net/cookies/cookie_store_test_helpers.cc @@ -222,6 +222,13 @@ DelayedCookieMonster::AddCallbackForCookie( return std::unique_ptr<CookieStore::CookieChangedSubscription>(); } +std::unique_ptr<CookieStore::CookieChangedSubscription> +DelayedCookieMonster::AddCallbackForAllChanges( + const CookieChangedCallback& callback) { + ADD_FAILURE(); + return std::unique_ptr<CookieStore::CookieChangedSubscription>(); +} + bool DelayedCookieMonster::IsEphemeral() { return true; } diff --git a/chromium/net/cookies/cookie_store_test_helpers.h b/chromium/net/cookies/cookie_store_test_helpers.h index bd55a3de6f0..5004b7a86e1 100644 --- a/chromium/net/cookies/cookie_store_test_helpers.h +++ b/chromium/net/cookies/cookie_store_test_helpers.h @@ -97,6 +97,9 @@ class DelayedCookieMonster : public CookieStore { const std::string& name, const CookieChangedCallback& callback) override; + std::unique_ptr<CookieStore::CookieChangedSubscription> + AddCallbackForAllChanges(const CookieChangedCallback& callback) override; + bool IsEphemeral() override; private: diff --git a/chromium/net/cookies/cookie_store_unittest.h b/chromium/net/cookies/cookie_store_unittest.h index 56ee4248410..58599b0f60c 100644 --- a/chromium/net/cookies/cookie_store_unittest.h +++ b/chromium/net/cookies/cookie_store_unittest.h @@ -64,6 +64,13 @@ const char kValidCookieLine[] = "A=B; path=/"; // // another. // static const bool has_path_prefix_bug; // +// // The cookie store forbids setting a cookie with an empty name. +// static const bool forbids_setting_empty_name; +// +// // The cookie store supports global tracking of cookie changes (i.e. +// // calls to CookieStore::AddCallbackForAllChanges()). +// static const bool supports_global_cookie_tracking; +// // // Time to wait between two cookie insertions to ensure that cookies have // // different creation times. // static const int creation_time_granularity_in_ms; @@ -286,6 +293,17 @@ class CookieStoreTest : public testing::Test { return callback.result(); } + bool FindAndDeleteCookie(CookieStore* cs, + const std::string& domain, + const std::string& name) { + for (auto& cookie : this->GetAllCookies(cs)) { + if (cookie.Domain() == domain && cookie.Name() == name) + return this->DeleteCanonicalCookie(cs, cookie); + } + + return false; + } + // Returns the CookieStore for the test - each test only uses one CookieStore. CookieStore* GetCookieStore() { if (!cookie_store_) @@ -495,47 +513,86 @@ TYPED_TEST_P(CookieStoreTest, SetCanonicalCookieTest) { EXPECT_TRUE(this->SetCanonicalCookie( cs, - base::MakeUnique<CanonicalCookie>( + std::make_unique<CanonicalCookie>( "A", "B", foo_foo_host, "/foo", one_hour_ago, one_hour_from_now, - base::Time(), false, false, CookieSameSite::DEFAULT_MODE, - COOKIE_PRIORITY_DEFAULT), - false, true)); + base::Time(), false /* secure */, false /* httponly */, + CookieSameSite::DEFAULT_MODE, COOKIE_PRIORITY_DEFAULT), + false /* secure_source */, true)); // Note that for the creation time to be set exactly, without modification, // it must be different from the one set by the line above. EXPECT_TRUE(this->SetCanonicalCookie( cs, - base::MakeUnique<CanonicalCookie>( + std::make_unique<CanonicalCookie>( "C", "D", "." + foo_bar_domain, "/bar", two_hours_ago, base::Time(), one_hour_ago, false, true, CookieSameSite::DEFAULT_MODE, COOKIE_PRIORITY_DEFAULT), - false, true)); + false /* secure_source */, true)); // A secure source is required for creating secure cookies. EXPECT_FALSE(this->SetCanonicalCookie( cs, - base::MakeUnique<CanonicalCookie>( + std::make_unique<CanonicalCookie>( "E", "F", http_foo_host, "/", base::Time(), base::Time(), base::Time(), true, false, CookieSameSite::DEFAULT_MODE, COOKIE_PRIORITY_DEFAULT), - false, true)); + false /* secure_source */, true)); // A secure source is also required for overwriting secure cookies. Writing // a secure cookie then overwriting it from a non-secure source should fail. EXPECT_TRUE(this->SetCanonicalCookie( cs, - base::MakeUnique<CanonicalCookie>( + std::make_unique<CanonicalCookie>( "E", "F", http_foo_host, "/", base::Time(), base::Time(), - base::Time(), true, false, CookieSameSite::DEFAULT_MODE, - COOKIE_PRIORITY_DEFAULT), - true, true)); + base::Time(), true /* secure */, false /* httponly */, + CookieSameSite::DEFAULT_MODE, COOKIE_PRIORITY_DEFAULT), + true /* secure_source */, true /* modify_http_only */)); EXPECT_FALSE(this->SetCanonicalCookie( cs, - base::MakeUnique<CanonicalCookie>( + std::make_unique<CanonicalCookie>( "E", "F", http_foo_host, "/", base::Time(), base::Time(), - base::Time(), true, false, CookieSameSite::DEFAULT_MODE, - COOKIE_PRIORITY_DEFAULT), - false, true)); + base::Time(), true /* secure */, false /* httponly */, + CookieSameSite::DEFAULT_MODE, COOKIE_PRIORITY_DEFAULT), + false /* secure_source */, true /* modify_http_only */)); + + if (TypeParam::supports_http_only) { + // Permission to modify http only cookies is required to create an + // httponly cookie. + EXPECT_FALSE(this->SetCanonicalCookie( + cs, + std::make_unique<CanonicalCookie>( + "G", "H", http_foo_host, "/unique", base::Time(), base::Time(), + base::Time(), false /* secure */, true /* httponly */, + CookieSameSite::DEFAULT_MODE, COOKIE_PRIORITY_DEFAULT), + false /* secure_source */, false /* modify_http_only */)); + + // Permission to modify httponly cookies is also required to overwrite + // an httponly cookie. + EXPECT_TRUE(this->SetCanonicalCookie( + cs, + std::make_unique<CanonicalCookie>( + "G", "H", http_foo_host, "/unique", base::Time(), base::Time(), + base::Time(), false /* secure */, true /* httponly */, + CookieSameSite::DEFAULT_MODE, COOKIE_PRIORITY_DEFAULT), + false /* secure_source */, true /* modify_http_only */)); + + EXPECT_FALSE(this->SetCanonicalCookie( + cs, + std::make_unique<CanonicalCookie>( + "G", "H", http_foo_host, "/unique", base::Time(), base::Time(), + base::Time(), false /* secure */, true /* httponly */, + CookieSameSite::DEFAULT_MODE, COOKIE_PRIORITY_DEFAULT), + false /* secure_source */, false /* modify_http_only */)); + } else { + // Leave store in same state as if the above tests had been run. + EXPECT_TRUE(this->SetCanonicalCookie( + cs, + std::make_unique<CanonicalCookie>( + "G", "H", http_foo_host, "/unique", base::Time(), base::Time(), + base::Time(), false /* secure */, true /* httponly */, + CookieSameSite::DEFAULT_MODE, COOKIE_PRIORITY_DEFAULT), + false /* secure_source */, true /* modify_http_only */)); + } // Get all the cookies for a given URL, regardless of properties. This 'get()' // operation shouldn't update the access time, as the test checks that the @@ -1615,6 +1672,168 @@ TYPED_TEST_P(CookieStoreTest, DeleteSessionCookie) { EXPECT_EQ("C=D", this->GetCookies(cs, this->http_www_foo_.url())); } +namespace { + +typedef std::pair<CanonicalCookie, CookieStore::ChangeCause> CookieNotification; + +void OnCookieChanged(std::vector<CookieNotification>* changes, + const CanonicalCookie& cookie, + CookieStore::ChangeCause cause) { + CookieNotification notification(cookie, cause); + changes->push_back(notification); +} + +} // namespace + +TYPED_TEST_P(CookieStoreTest, GlobalChangeTracking_Insert) { + if (!TypeParam::supports_global_cookie_tracking) + return; + + CookieStore* cs = this->GetCookieStore(); + std::vector<CookieNotification> cookie_changes; + std::unique_ptr<CookieStore::CookieChangedSubscription> subscription( + cs->AddCallbackForAllChanges( + base::Bind(&OnCookieChanged, base::Unretained(&cookie_changes)))); + EXPECT_TRUE(this->SetCookie(cs, this->http_www_foo_.url(), "A=B")); + EXPECT_TRUE(this->SetCookie(cs, this->http_www_foo_.url(), "C=D")); + EXPECT_TRUE(this->SetCookie(cs, this->http_www_foo_.url(), "E=F")); + EXPECT_EQ("A=B; C=D; E=F", this->GetCookies(cs, this->http_www_foo_.url())); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(3u, cookie_changes.size()); + EXPECT_EQ(CookieStore::ChangeCause::INSERTED, cookie_changes[0].second); + EXPECT_EQ(this->http_www_foo_.url().host(), cookie_changes[0].first.Domain()); + EXPECT_EQ("A", cookie_changes[0].first.Name()); + EXPECT_EQ("B", cookie_changes[0].first.Value()); + EXPECT_EQ(this->http_www_foo_.url().host(), cookie_changes[1].first.Domain()); + EXPECT_EQ(CookieStore::ChangeCause::INSERTED, cookie_changes[1].second); + EXPECT_EQ("C", cookie_changes[1].first.Name()); + EXPECT_EQ("D", cookie_changes[1].first.Value()); + EXPECT_EQ(this->http_www_foo_.url().host(), cookie_changes[2].first.Domain()); + EXPECT_EQ(CookieStore::ChangeCause::INSERTED, cookie_changes[2].second); + EXPECT_EQ("E", cookie_changes[2].first.Name()); + EXPECT_EQ("F", cookie_changes[2].first.Value()); +} + +TYPED_TEST_P(CookieStoreTest, GlobalChangeTracking_Delete) { + if (!TypeParam::supports_global_cookie_tracking) + return; + + CookieStore* cs = this->GetCookieStore(); + std::vector<CookieNotification> cookie_changes; + EXPECT_TRUE(this->SetCookie(cs, this->http_www_foo_.url(), "A=B")); + EXPECT_TRUE(this->SetCookie(cs, this->http_www_foo_.url(), "C=D")); + EXPECT_TRUE(this->SetCookie(cs, this->http_www_foo_.url(), "E=F")); + + std::unique_ptr<CookieStore::CookieChangedSubscription> subscription( + cs->AddCallbackForAllChanges( + base::Bind(&OnCookieChanged, base::Unretained(&cookie_changes)))); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(0u, cookie_changes.size()); + + EXPECT_TRUE( + this->FindAndDeleteCookie(cs, this->http_www_foo_.url().host(), "C")); + EXPECT_EQ("A=B; E=F", this->GetCookies(cs, this->http_www_foo_.url())); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(1u, cookie_changes.size()); + EXPECT_EQ(this->http_www_foo_.url().host(), cookie_changes[0].first.Domain()); + EXPECT_EQ(CookieStore::ChangeCause::EXPLICIT_DELETE_CANONICAL, + cookie_changes[0].second); + EXPECT_EQ("C", cookie_changes[0].first.Name()); + EXPECT_EQ("D", cookie_changes[0].first.Value()); +} + +TYPED_TEST_P(CookieStoreTest, GlobalChangeTracking_Overwrite) { + if (!TypeParam::supports_global_cookie_tracking) + return; + + // Insert a cookie "a" for path "/path1" + CookieStore* cs = this->GetCookieStore(); + std::vector<CookieNotification> cookie_changes; + std::unique_ptr<CookieStore::CookieChangedSubscription> subscription( + cs->AddCallbackForAllChanges( + base::Bind(&OnCookieChanged, base::Unretained(&cookie_changes)))); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(0u, cookie_changes.size()); + + EXPECT_TRUE(this->SetCookie(cs, this->http_www_foo_.url(), + "a=val1; path=/path1; " + "expires=Mon, 18-Apr-22 22:50:13 GMT")); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(1u, cookie_changes.size()); + EXPECT_EQ(CookieStore::ChangeCause::INSERTED, cookie_changes[0].second); + EXPECT_EQ(this->http_www_foo_.url().host(), cookie_changes[0].first.Domain()); + EXPECT_EQ("a", cookie_changes[0].first.Name()); + EXPECT_EQ("val1", cookie_changes[0].first.Value()); + cookie_changes.clear(); + + // Insert a cookie "a" for path "/path1", that is httponly. This should + // overwrite the non-http-only version. + CookieOptions allow_httponly; + allow_httponly.set_include_httponly(); + EXPECT_TRUE(this->SetCookieWithOptions(cs, this->http_www_foo_.url(), + "a=val2; path=/path1; httponly; " + "expires=Mon, 18-Apr-22 22:50:14 GMT", + allow_httponly)); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(2u, cookie_changes.size()); + EXPECT_EQ(this->http_www_foo_.url().host(), cookie_changes[0].first.Domain()); + EXPECT_EQ(CookieStore::ChangeCause::OVERWRITE, cookie_changes[0].second); + EXPECT_EQ("a", cookie_changes[0].first.Name()); + EXPECT_EQ("val1", cookie_changes[0].first.Value()); + EXPECT_EQ(this->http_www_foo_.url().host(), cookie_changes[1].first.Domain()); + EXPECT_EQ(CookieStore::ChangeCause::INSERTED, cookie_changes[1].second); + EXPECT_EQ("a", cookie_changes[1].first.Name()); + EXPECT_EQ("val2", cookie_changes[1].first.Value()); +} + +TYPED_TEST_P(CookieStoreTest, GlobalChangeTracking_Deregister) { + if (!TypeParam::supports_global_cookie_tracking) + return; + + CookieStore* cs = this->GetCookieStore(); + + // Register two notifiers. + std::vector<CookieNotification> cookie_changes_1; + std::unique_ptr<CookieStore::CookieChangedSubscription> subscription1( + cs->AddCallbackForAllChanges( + base::Bind(&OnCookieChanged, base::Unretained(&cookie_changes_1)))); + + std::vector<CookieNotification> cookie_changes_2; + std::unique_ptr<CookieStore::CookieChangedSubscription> subscription2( + cs->AddCallbackForAllChanges( + base::Bind(&OnCookieChanged, base::Unretained(&cookie_changes_2)))); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(0u, cookie_changes_1.size()); + ASSERT_EQ(0u, cookie_changes_2.size()); + + // Insert a cookie and make sure both see it. + EXPECT_TRUE(this->SetCookie(cs, this->http_www_foo_.url(), "A=B")); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(1u, cookie_changes_1.size()); + EXPECT_EQ("A", cookie_changes_1[0].first.Name()); + EXPECT_EQ("B", cookie_changes_1[0].first.Value()); + cookie_changes_1.clear(); + + ASSERT_EQ(1u, cookie_changes_2.size()); + EXPECT_EQ("A", cookie_changes_2[0].first.Name()); + EXPECT_EQ("B", cookie_changes_2[0].first.Value()); + cookie_changes_2.clear(); + + // De-register the second registration. + subscription2.reset(); + + // Insert a second cookie and make sure that it's only visible in one + // change array. + EXPECT_TRUE(this->SetCookie(cs, this->http_www_foo_.url(), "C=D")); + base::RunLoop().RunUntilIdle(); + ASSERT_EQ(1u, cookie_changes_1.size()); + EXPECT_EQ("C", cookie_changes_1[0].first.Name()); + EXPECT_EQ("D", cookie_changes_1[0].first.Value()); + cookie_changes_1.clear(); + + ASSERT_EQ(0u, cookie_changes_2.size()); +} + REGISTER_TYPED_TEST_CASE_P(CookieStoreTest, SetCookieWithDetailsAsync, SetCanonicalCookieTest, @@ -1655,7 +1874,11 @@ REGISTER_TYPED_TEST_CASE_P(CookieStoreTest, GetAllCookiesAsync, DeleteCookieAsync, DeleteCanonicalCookieAsync, - DeleteSessionCookie); + DeleteSessionCookie, + GlobalChangeTracking_Insert, + GlobalChangeTracking_Delete, + GlobalChangeTracking_Overwrite, + GlobalChangeTracking_Deregister); } // namespace net |