// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/cookies/canonical_cookie.h" #include "base/optional.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "build/build_config.h" #include "net/base/features.h" #include "net/cookies/cookie_constants.h" #include "net/cookies/cookie_options.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" namespace net { namespace { // Helper for testing BuildCookieLine void MatchCookieLineToVector( const std::string& line, const std::vector>& cookies) { std::vector list; for (const auto& cookie : cookies) list.push_back(*cookie); EXPECT_EQ(line, CanonicalCookie::BuildCookieLine(list)); } } // namespace TEST(CanonicalCookieTest, Constructor) { GURL url("http://www.example.com/test"); base::Time current_time = base::Time::Now(); std::unique_ptr cookie1(std::make_unique( "A", "2", "www.example.com", "/test", current_time, base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT, CookieSourceScheme::kSecure)); EXPECT_EQ("A", cookie1->Name()); EXPECT_EQ("2", cookie1->Value()); EXPECT_EQ("www.example.com", cookie1->Domain()); EXPECT_EQ("/test", cookie1->Path()); EXPECT_FALSE(cookie1->IsSecure()); EXPECT_FALSE(cookie1->IsHttpOnly()); EXPECT_EQ(CookieSameSite::NO_RESTRICTION, cookie1->SameSite()); EXPECT_EQ(cookie1->SourceScheme(), CookieSourceScheme::kSecure); std::unique_ptr cookie2(std::make_unique( "A", "2", ".www.example.com", "/", current_time, base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT, CookieSourceScheme::kNonSecure)); EXPECT_EQ("A", cookie2->Name()); EXPECT_EQ("2", cookie2->Value()); EXPECT_EQ(".www.example.com", cookie2->Domain()); EXPECT_EQ("/", cookie2->Path()); EXPECT_FALSE(cookie2->IsSecure()); EXPECT_FALSE(cookie2->IsHttpOnly()); EXPECT_EQ(CookieSameSite::NO_RESTRICTION, cookie2->SameSite()); EXPECT_EQ(cookie2->SourceScheme(), CookieSourceScheme::kNonSecure); // Set Secure to true but don't specify is_source_scheme_secure auto cookie3 = std::make_unique( "A", "2", ".www.example.com", "/", current_time, base::Time(), base::Time(), true /* secure */, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT); EXPECT_TRUE(cookie3->IsSecure()); EXPECT_EQ(cookie3->SourceScheme(), CookieSourceScheme::kUnset); auto cookie4 = std::make_unique( "A", "2", ".www.example.com", "/test", current_time, base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT); EXPECT_EQ("A", cookie4->Name()); EXPECT_EQ("2", cookie4->Value()); EXPECT_EQ(".www.example.com", cookie4->Domain()); EXPECT_EQ("/test", cookie4->Path()); EXPECT_FALSE(cookie4->IsSecure()); EXPECT_FALSE(cookie4->IsHttpOnly()); EXPECT_EQ(CookieSameSite::NO_RESTRICTION, cookie4->SameSite()); } TEST(CanonicalCookie, CreationCornerCases) { base::Time creation_time = base::Time::Now(); std::unique_ptr cookie; base::Optional server_time = base::nullopt; // Space in name. cookie = CanonicalCookie::Create(GURL("http://www.example.com/test/foo.html"), "A C=2", creation_time, server_time); EXPECT_TRUE(cookie.get()); EXPECT_EQ("A C", cookie->Name()); // Semicolon in path. cookie = CanonicalCookie::Create(GURL("http://fool/;/"), "*", creation_time, server_time); EXPECT_TRUE(cookie.get()); } TEST(CanonicalCookieTest, Create) { // Test creating cookies from a cookie string. GURL url("http://www.example.com/test/foo.html"); GURL https_url("https://www.example.com/test/foo.html"); base::Time creation_time = base::Time::Now(); base::Optional server_time = base::nullopt; std::unique_ptr cookie( CanonicalCookie::Create(url, "A=2", creation_time, server_time)); EXPECT_EQ("A", cookie->Name()); EXPECT_EQ("2", cookie->Value()); EXPECT_EQ("www.example.com", cookie->Domain()); EXPECT_EQ("/test", cookie->Path()); EXPECT_FALSE(cookie->IsSecure()); EXPECT_EQ(cookie->SourceScheme(), CookieSourceScheme::kNonSecure); GURL url2("http://www.foo.com"); cookie = CanonicalCookie::Create(url2, "B=1", creation_time, server_time); EXPECT_EQ("B", cookie->Name()); EXPECT_EQ("1", cookie->Value()); EXPECT_EQ("www.foo.com", cookie->Domain()); EXPECT_EQ("/", cookie->Path()); EXPECT_FALSE(cookie->IsSecure()); EXPECT_EQ(cookie->SourceScheme(), CookieSourceScheme::kNonSecure); // Test creating secure cookies. Secure scheme is not checked upon creation, // so a URL of any scheme can create a Secure cookie. CanonicalCookie::CookieInclusionStatus status; cookie = CanonicalCookie::Create(url, "A=2; Secure", creation_time, server_time, &status); EXPECT_TRUE(cookie->IsSecure()); cookie = CanonicalCookie::Create(https_url, "A=2; Secure", creation_time, server_time, &status); EXPECT_TRUE(cookie->IsSecure()); GURL url3("https://www.foo.com"); cookie = CanonicalCookie::Create(url3, "A=2; Secure", creation_time, server_time, &status); EXPECT_TRUE(cookie->IsSecure()); EXPECT_EQ(cookie->SourceScheme(), CookieSourceScheme::kSecure); cookie = CanonicalCookie::Create(url3, "A=2", creation_time, server_time, &status); EXPECT_FALSE(cookie->IsSecure()); EXPECT_EQ(cookie->SourceScheme(), CookieSourceScheme::kSecure); // Test creating http only cookies. HttpOnly is not checked upon creation. cookie = CanonicalCookie::Create(url, "A=2; HttpOnly", creation_time, server_time, &status); EXPECT_TRUE(cookie->IsHttpOnly()); cookie = CanonicalCookie::Create(url, "A=2; HttpOnly", creation_time, server_time); EXPECT_TRUE(cookie->IsHttpOnly()); // Test creating SameSite cookies. SameSite is not checked upon creation. cookie = CanonicalCookie::Create(url, "A=2; SameSite=Strict", creation_time, server_time); ASSERT_TRUE(cookie.get()); EXPECT_EQ(CookieSameSite::STRICT_MODE, cookie->SameSite()); cookie = CanonicalCookie::Create(url, "A=2; SameSite=Lax", creation_time, server_time); ASSERT_TRUE(cookie.get()); EXPECT_EQ(CookieSameSite::LAX_MODE, cookie->SameSite()); cookie = CanonicalCookie::Create(url, "A=2; SameSite=Extended", creation_time, server_time); ASSERT_TRUE(cookie.get()); EXPECT_EQ(CookieSameSite::UNSPECIFIED, cookie->SameSite()); cookie = CanonicalCookie::Create(url, "A=2; SameSite=None", creation_time, server_time); ASSERT_TRUE(cookie.get()); EXPECT_EQ(CookieSameSite::NO_RESTRICTION, cookie->SameSite()); cookie = CanonicalCookie::Create(url, "A=2", creation_time, server_time); ASSERT_TRUE(cookie.get()); EXPECT_EQ(CookieSameSite::UNSPECIFIED, cookie->SameSite()); } TEST(CanonicalCookieTest, CreateNonStandardSameSite) { GURL url("http://www.example.com/test/foo.html"); base::Time now = base::Time::Now(); std::unique_ptr cookie; base::Optional server_time = base::nullopt; // Non-standard value for the SameSite attribute. cookie = CanonicalCookie::Create(url, "A=2; SameSite=NonStandard", now, server_time); EXPECT_TRUE(cookie.get()); EXPECT_EQ(CookieSameSite::UNSPECIFIED, cookie->SameSite()); // Omit value for the SameSite attribute. cookie = CanonicalCookie::Create(url, "A=2; SameSite", now, server_time); EXPECT_TRUE(cookie.get()); EXPECT_EQ(CookieSameSite::UNSPECIFIED, cookie->SameSite()); } TEST(CanonicalCookieTest, CreateSameSiteInCrossSiteContexts) { GURL url("http://www.example.com/test/foo.html"); base::Time now = base::Time::Now(); std::unique_ptr cookie; base::Optional server_time = base::nullopt; // A cookie can be created from any SameSiteContext regardless of SameSite // value (it is upon setting the cookie that the SameSiteContext comes into // effect). cookie = CanonicalCookie::Create(url, "A=2; SameSite=Strict", now, server_time); EXPECT_TRUE(cookie.get()); cookie = CanonicalCookie::Create(url, "A=2; SameSite=Lax", now, server_time); EXPECT_TRUE(cookie.get()); cookie = CanonicalCookie::Create(url, "A=2; SameSite=None", now, server_time); EXPECT_TRUE(cookie.get()); cookie = CanonicalCookie::Create(url, "A=2;", now, server_time); EXPECT_TRUE(cookie.get()); } TEST(CanonicalCookieTest, CreateHttpOnly) { GURL url("http://www.example.com/test/foo.html"); base::Time now = base::Time::Now(); base::Optional server_time = base::nullopt; CanonicalCookie::CookieInclusionStatus status; // An HttpOnly cookie can be created. std::unique_ptr cookie = CanonicalCookie::Create(url, "A=2; HttpOnly", now, server_time, &status); EXPECT_TRUE(cookie->IsHttpOnly()); EXPECT_TRUE(status.IsInclude()); } TEST(CanonicalCookieTest, CreateWithInvalidDomain) { GURL url("http://www.example.com/test/foo.html"); base::Time now = base::Time::Now(); base::Optional server_time = base::nullopt; CanonicalCookie::CookieInclusionStatus status; std::unique_ptr cookie = CanonicalCookie::Create( url, "A=2; Domain=wrongdomain.com", now, server_time, &status); EXPECT_EQ(nullptr, cookie.get()); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN})); } TEST(CanonicalCookieTest, EmptyExpiry) { GURL url("http://www7.ipdl.inpit.go.jp/Tokujitu/tjkta.ipdl?N0000=108"); base::Time creation_time = base::Time::Now(); base::Optional server_time = base::nullopt; std::string cookie_line = "ACSTM=20130308043820420042; path=/; domain=ipdl.inpit.go.jp; Expires="; std::unique_ptr cookie( CanonicalCookie::Create(url, cookie_line, creation_time, server_time)); EXPECT_TRUE(cookie.get()); EXPECT_FALSE(cookie->IsPersistent()); EXPECT_FALSE(cookie->IsExpired(creation_time)); EXPECT_EQ(base::Time(), cookie->ExpiryDate()); // With a stale server time server_time = creation_time - base::TimeDelta::FromHours(1); cookie = CanonicalCookie::Create(url, cookie_line, creation_time, server_time); EXPECT_TRUE(cookie.get()); EXPECT_FALSE(cookie->IsPersistent()); EXPECT_FALSE(cookie->IsExpired(creation_time)); EXPECT_EQ(base::Time(), cookie->ExpiryDate()); // With a future server time server_time = creation_time + base::TimeDelta::FromHours(1); cookie = CanonicalCookie::Create(url, cookie_line, creation_time, server_time); EXPECT_TRUE(cookie.get()); EXPECT_FALSE(cookie->IsPersistent()); EXPECT_FALSE(cookie->IsExpired(creation_time)); EXPECT_EQ(base::Time(), cookie->ExpiryDate()); } TEST(CanonicalCookieTest, IsEquivalent) { GURL url("https://www.example.com/"); std::string cookie_name = "A"; std::string cookie_value = "2EDA-EF"; std::string cookie_domain = ".www.example.com"; std::string cookie_path = "/path"; base::Time creation_time = base::Time::Now(); base::Time expiration_time = creation_time + base::TimeDelta::FromDays(2); bool secure(false); bool httponly(false); CookieSameSite same_site(CookieSameSite::NO_RESTRICTION); // Test that a cookie is equivalent to itself. std::unique_ptr cookie(std::make_unique( cookie_name, cookie_value, cookie_domain, cookie_path, creation_time, expiration_time, base::Time(), secure, httponly, same_site, COOKIE_PRIORITY_MEDIUM)); EXPECT_TRUE(cookie->IsEquivalent(*cookie)); EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*cookie)); // Test that two identical cookies are equivalent. std::unique_ptr other_cookie( std::make_unique( cookie_name, cookie_value, cookie_domain, cookie_path, creation_time, expiration_time, base::Time(), secure, httponly, same_site, COOKIE_PRIORITY_MEDIUM)); EXPECT_TRUE(cookie->IsEquivalent(*other_cookie)); EXPECT_TRUE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie)); // Tests that use different variations of attribute values that // DON'T affect cookie equivalence. other_cookie = std::make_unique( cookie_name, "2", cookie_domain, cookie_path, creation_time, expiration_time, base::Time(), secure, httponly, same_site, COOKIE_PRIORITY_HIGH); EXPECT_TRUE(cookie->IsEquivalent(*other_cookie)); EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie)); EXPECT_TRUE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie)); base::Time other_creation_time = creation_time + base::TimeDelta::FromMinutes(2); other_cookie = std::make_unique( cookie_name, "2", cookie_domain, cookie_path, other_creation_time, expiration_time, base::Time(), secure, httponly, same_site, COOKIE_PRIORITY_MEDIUM); EXPECT_TRUE(cookie->IsEquivalent(*other_cookie)); EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie)); EXPECT_TRUE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie)); other_cookie = std::make_unique( cookie_name, cookie_name, cookie_domain, cookie_path, creation_time, expiration_time, base::Time(), true, httponly, same_site, COOKIE_PRIORITY_LOW); EXPECT_TRUE(cookie->IsEquivalent(*other_cookie)); EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie)); EXPECT_TRUE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie)); other_cookie = std::make_unique( cookie_name, cookie_name, cookie_domain, cookie_path, creation_time, expiration_time, base::Time(), secure, true, same_site, COOKIE_PRIORITY_LOW); EXPECT_TRUE(cookie->IsEquivalent(*other_cookie)); EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie)); EXPECT_TRUE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie)); other_cookie = std::make_unique( cookie_name, cookie_name, cookie_domain, cookie_path, creation_time, expiration_time, base::Time(), secure, httponly, CookieSameSite::STRICT_MODE, COOKIE_PRIORITY_LOW); EXPECT_TRUE(cookie->IsEquivalent(*other_cookie)); EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie)); EXPECT_TRUE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie)); // Cookies whose names mismatch are not equivalent. other_cookie = std::make_unique( "B", cookie_value, cookie_domain, cookie_path, creation_time, expiration_time, base::Time(), secure, httponly, same_site, COOKIE_PRIORITY_MEDIUM); EXPECT_FALSE(cookie->IsEquivalent(*other_cookie)); EXPECT_FALSE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie)); EXPECT_FALSE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie)); // 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 = std::make_unique( cookie_name, cookie_value, "www.example.com", cookie_path, creation_time, expiration_time, base::Time(), secure, httponly, same_site, COOKIE_PRIORITY_MEDIUM); EXPECT_TRUE(cookie->IsDomainCookie()); EXPECT_FALSE(other_cookie->IsDomainCookie()); EXPECT_FALSE(cookie->IsEquivalent(*other_cookie)); EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie)); EXPECT_TRUE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie)); // 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 = std::make_unique( cookie_name, cookie_value, ".example.com", cookie_path, creation_time, expiration_time, base::Time(), secure, httponly, same_site, COOKIE_PRIORITY_MEDIUM); EXPECT_FALSE(cookie->IsEquivalent(*other_cookie)); EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie)); EXPECT_TRUE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie)); // Paths are a bit more complicated. 'IsEquivalent' requires an exact path // match, while secure cookie matching uses a more relaxed 'IsOnPath' check. // 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 = std::make_unique( cookie_name, cookie_value, cookie_domain, "/test", creation_time, expiration_time, base::Time(), secure, httponly, same_site, COOKIE_PRIORITY_MEDIUM); EXPECT_FALSE(cookie->IsEquivalent(*other_cookie)); EXPECT_FALSE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie)); EXPECT_FALSE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie)); other_cookie = std::make_unique( cookie_name, cookie_value, cookie_domain, cookie_path + "/subpath", creation_time, expiration_time, base::Time(), secure, httponly, same_site, COOKIE_PRIORITY_MEDIUM); EXPECT_FALSE(cookie->IsEquivalent(*other_cookie)); EXPECT_FALSE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie)); EXPECT_TRUE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie)); other_cookie = std::make_unique( cookie_name, cookie_value, cookie_domain, "/", creation_time, expiration_time, base::Time(), secure, httponly, same_site, COOKIE_PRIORITY_MEDIUM); EXPECT_FALSE(cookie->IsEquivalent(*other_cookie)); EXPECT_TRUE(cookie->IsEquivalentForSecureCookieMatching(*other_cookie)); EXPECT_FALSE(other_cookie->IsEquivalentForSecureCookieMatching(*cookie)); } TEST(CanonicalCookieTest, IsDomainMatch) { GURL url("http://www.example.com/test/foo.html"); base::Time creation_time = base::Time::Now(); base::Optional server_time = base::nullopt; std::unique_ptr cookie( CanonicalCookie::Create(url, "A=2", creation_time, server_time)); EXPECT_TRUE(cookie->IsHostCookie()); EXPECT_TRUE(cookie->IsDomainMatch("www.example.com")); EXPECT_TRUE(cookie->IsDomainMatch("www.example.com")); EXPECT_FALSE(cookie->IsDomainMatch("foo.www.example.com")); EXPECT_FALSE(cookie->IsDomainMatch("www0.example.com")); EXPECT_FALSE(cookie->IsDomainMatch("example.com")); cookie = CanonicalCookie::Create(url, "A=2; Domain=www.example.com", creation_time, server_time); EXPECT_TRUE(cookie->IsDomainCookie()); EXPECT_TRUE(cookie->IsDomainMatch("www.example.com")); EXPECT_TRUE(cookie->IsDomainMatch("www.example.com")); EXPECT_TRUE(cookie->IsDomainMatch("foo.www.example.com")); EXPECT_FALSE(cookie->IsDomainMatch("www0.example.com")); EXPECT_FALSE(cookie->IsDomainMatch("example.com")); cookie = CanonicalCookie::Create(url, "A=2; Domain=.www.example.com", creation_time, server_time); EXPECT_TRUE(cookie->IsDomainMatch("www.example.com")); EXPECT_TRUE(cookie->IsDomainMatch("www.example.com")); EXPECT_TRUE(cookie->IsDomainMatch("foo.www.example.com")); EXPECT_FALSE(cookie->IsDomainMatch("www0.example.com")); EXPECT_FALSE(cookie->IsDomainMatch("example.com")); } TEST(CanonicalCookieTest, IsOnPath) { base::Time creation_time = base::Time::Now(); base::Optional server_time = base::nullopt; std::unique_ptr cookie(CanonicalCookie::Create( GURL("http://www.example.com"), "A=2", creation_time, server_time)); EXPECT_TRUE(cookie->IsOnPath("/")); EXPECT_TRUE(cookie->IsOnPath("/test")); EXPECT_TRUE(cookie->IsOnPath("/test/bar.html")); // Test the empty string edge case. EXPECT_FALSE(cookie->IsOnPath(std::string())); cookie = CanonicalCookie::Create(GURL("http://www.example.com/test/foo.html"), "A=2", creation_time, server_time); EXPECT_FALSE(cookie->IsOnPath("/")); EXPECT_TRUE(cookie->IsOnPath("/test")); EXPECT_TRUE(cookie->IsOnPath("/test/bar.html")); EXPECT_TRUE(cookie->IsOnPath("/test/sample/bar.html")); } struct EffectiveSameSiteTestCase { CookieSameSite same_site; CookieEffectiveSameSite effective_same_site; CookieAccessSemantics access_semantics; }; void VerifyEffectiveSameSiteTestCases( base::Time creation_time, base::Time expiry_time, bool is_samesite_by_default_enabled, std::vector test_cases) { base::test::ScopedFeatureList feature_list; if (is_samesite_by_default_enabled) { feature_list.InitAndEnableFeature(features::kSameSiteByDefaultCookies); } else { feature_list.InitAndDisableFeature(features::kSameSiteByDefaultCookies); } for (const auto& test_case : test_cases) { CanonicalCookie cookie("A", "2", "example.test", "/", creation_time, expiry_time, base::Time(), true /* secure */, false /* httponly */, test_case.same_site, COOKIE_PRIORITY_DEFAULT); EXPECT_EQ( test_case.effective_same_site, cookie.GetEffectiveSameSiteForTesting(test_case.access_semantics)); } } TEST(CanonicalCookieTest, GetEffectiveSameSite) { // Test cases that are always the same, regardless of time or // SameSite-by-default feature status. const std::vector common_test_cases = { // Explicitly specified SameSite always has the same effective SameSite // regardless of the access semantics. {CookieSameSite::NO_RESTRICTION, CookieEffectiveSameSite::NO_RESTRICTION, CookieAccessSemantics::UNKNOWN}, {CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, CookieAccessSemantics::UNKNOWN}, {CookieSameSite::STRICT_MODE, CookieEffectiveSameSite::STRICT_MODE, CookieAccessSemantics::UNKNOWN}, {CookieSameSite::NO_RESTRICTION, CookieEffectiveSameSite::NO_RESTRICTION, CookieAccessSemantics::LEGACY}, {CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, CookieAccessSemantics::LEGACY}, {CookieSameSite::STRICT_MODE, CookieEffectiveSameSite::STRICT_MODE, CookieAccessSemantics::LEGACY}, {CookieSameSite::NO_RESTRICTION, CookieEffectiveSameSite::NO_RESTRICTION, CookieAccessSemantics::NONLEGACY}, {CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, CookieAccessSemantics::NONLEGACY}, {CookieSameSite::STRICT_MODE, CookieEffectiveSameSite::STRICT_MODE, CookieAccessSemantics::NONLEGACY}, // UNSPECIFIED always maps to NO_RESTRICTION if LEGACY access semantics. {CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::NO_RESTRICTION, CookieAccessSemantics::LEGACY}}; // Test cases that differ based on access semantics, feature status, and // whether cookie is recently created: std::vector enabled_recent_test_cases = { {CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, CookieAccessSemantics::UNKNOWN}, {CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, CookieAccessSemantics::NONLEGACY}}; std::vector enabled_not_recent_test_cases = { {CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE, CookieAccessSemantics::UNKNOWN}, {CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE, CookieAccessSemantics::NONLEGACY}}; std::vector disabled_recent_test_cases = { {CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::NO_RESTRICTION, CookieAccessSemantics::UNKNOWN}, {CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, CookieAccessSemantics::NONLEGACY}}; std::vector disabled_not_recent_test_cases = { {CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::NO_RESTRICTION, CookieAccessSemantics::UNKNOWN}, {CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE, CookieAccessSemantics::NONLEGACY}}; // Test GetEffectiveSameSite for recently created cookies // Session cookie created less than kLaxAllowUnsafeMaxAge ago. base::Time now = base::Time::Now(); base::Time creation_time = now - (kLaxAllowUnsafeMaxAge / 4); VerifyEffectiveSameSiteTestCases(creation_time, base::Time(), false, common_test_cases); VerifyEffectiveSameSiteTestCases(creation_time, base::Time(), false, disabled_recent_test_cases); VerifyEffectiveSameSiteTestCases(creation_time, base::Time(), true, common_test_cases); VerifyEffectiveSameSiteTestCases(creation_time, base::Time(), true, enabled_recent_test_cases); // Persistent cookie with max age less than kLaxAllowUnsafeMaxAge. base::Time expiry_time = creation_time + (kLaxAllowUnsafeMaxAge / 4); VerifyEffectiveSameSiteTestCases(creation_time, expiry_time, false, common_test_cases); VerifyEffectiveSameSiteTestCases(creation_time, expiry_time, false, disabled_recent_test_cases); VerifyEffectiveSameSiteTestCases(creation_time, expiry_time, true, common_test_cases); VerifyEffectiveSameSiteTestCases(creation_time, expiry_time, true, enabled_recent_test_cases); // Test GetEffectiveSameSite for not-recently-created cookies: // Session cookie created more than kLaxAllowUnsafeMaxAge ago. creation_time = now - (kLaxAllowUnsafeMaxAge * 4); VerifyEffectiveSameSiteTestCases(creation_time, base::Time(), false, common_test_cases); VerifyEffectiveSameSiteTestCases(creation_time, base::Time(), false, disabled_not_recent_test_cases); VerifyEffectiveSameSiteTestCases(creation_time, base::Time(), true, common_test_cases); VerifyEffectiveSameSiteTestCases(creation_time, base::Time(), true, enabled_not_recent_test_cases); // Persistent cookie with max age more than kLaxAllowUnsafeMaxAge, created // more than kLaxAllowUnsafeMaxAge ago. expiry_time = creation_time + (kLaxAllowUnsafeMaxAge * 8); VerifyEffectiveSameSiteTestCases(creation_time, expiry_time, false, common_test_cases); VerifyEffectiveSameSiteTestCases(creation_time, expiry_time, false, disabled_not_recent_test_cases); VerifyEffectiveSameSiteTestCases(creation_time, expiry_time, true, common_test_cases); VerifyEffectiveSameSiteTestCases(creation_time, expiry_time, true, enabled_not_recent_test_cases); } TEST(CanonicalCookieTest, IncludeForRequestURL) { GURL url("http://www.example.com"); base::Time creation_time = base::Time::Now(); CookieOptions options = CookieOptions::MakeAllInclusive(); base::Optional server_time = base::nullopt; std::unique_ptr cookie( CanonicalCookie::Create(url, "A=2", creation_time, server_time)); EXPECT_TRUE(cookie->IncludeForRequestURL(url, options).IsInclude()); EXPECT_TRUE(cookie ->IncludeForRequestURL(GURL("http://www.example.com/foo/bar"), options) .IsInclude()); EXPECT_TRUE(cookie ->IncludeForRequestURL( GURL("https://www.example.com/foo/bar"), options) .IsInclude()); EXPECT_TRUE( cookie->IncludeForRequestURL(GURL("https://sub.example.com"), options) .HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus:: EXCLUDE_DOMAIN_MISMATCH})); EXPECT_TRUE( cookie->IncludeForRequestURL(GURL("https://sub.www.example.com"), options) .HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus:: EXCLUDE_DOMAIN_MISMATCH})); // Test that cookie with a cookie path that does not match the url path are // not included. cookie = CanonicalCookie::Create(url, "A=2; Path=/foo/bar", creation_time, server_time); EXPECT_TRUE( cookie->IncludeForRequestURL(url, options) .HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus::EXCLUDE_NOT_ON_PATH})); EXPECT_TRUE( cookie ->IncludeForRequestURL( GURL("http://www.example.com/foo/bar/index.html"), options) .IsInclude()); // Test that a secure cookie is not included for a non secure URL. GURL secure_url("https://www.example.com"); cookie = CanonicalCookie::Create(secure_url, "A=2; Secure", creation_time, server_time); EXPECT_TRUE(cookie->IsSecure()); EXPECT_TRUE(cookie->IncludeForRequestURL(secure_url, options).IsInclude()); EXPECT_TRUE( cookie->IncludeForRequestURL(url, options) .HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY})); // Test that http only cookies are only included if the include httponly flag // is set on the cookie options. options.set_include_httponly(); cookie = CanonicalCookie::Create(url, "A=2; HttpOnly", creation_time, server_time); EXPECT_TRUE(cookie->IsHttpOnly()); EXPECT_TRUE(cookie->IncludeForRequestURL(url, options).IsInclude()); options.set_exclude_httponly(); EXPECT_TRUE( cookie->IncludeForRequestURL(url, options) .HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY})); } struct IncludeForRequestURLTestCase { std::string cookie_line; CookieSameSite expected_samesite; CookieEffectiveSameSite expected_effective_samesite; CookieOptions::SameSiteCookieContext request_options_samesite_context; CanonicalCookie::CookieInclusionStatus expected_inclusion_status; base::TimeDelta creation_time_delta = base::TimeDelta(); }; void VerifyIncludeForRequestURLTestCases( bool is_samesite_by_default_enabled, CookieAccessSemantics access_semantics, std::vector test_cases) { GURL url("https://example.test"); for (const auto& test : test_cases) { base::test::ScopedFeatureList feature_list; if (is_samesite_by_default_enabled) { feature_list.InitAndEnableFeature(features::kSameSiteByDefaultCookies); } else { feature_list.InitAndDisableFeature(features::kSameSiteByDefaultCookies); } base::Time creation_time = base::Time::Now() - test.creation_time_delta; std::unique_ptr cookie = CanonicalCookie::Create( url, test.cookie_line, creation_time, base::nullopt /* server_time */); EXPECT_EQ(test.expected_samesite, cookie->SameSite()); EXPECT_EQ(test.expected_effective_samesite, cookie->GetEffectiveSameSiteForTesting(access_semantics)); CookieOptions request_options; request_options.set_same_site_cookie_context( test.request_options_samesite_context); EXPECT_EQ( test.expected_inclusion_status, cookie->IncludeForRequestURL(url, request_options, access_semantics)); } } TEST(CanonicalCookieTest, IncludeForRequestURLSameSite) { const base::TimeDelta kLongAge = kLaxAllowUnsafeMaxAge * 4; const base::TimeDelta kShortAge = kLaxAllowUnsafeMaxAge / 4; // Test cases that are the same regardless of feature status or access // semantics: std::vector common_test_cases = { // Strict cookies: {"A=2; SameSite=Strict", CookieSameSite::STRICT_MODE, CookieEffectiveSameSite::STRICT_MODE, CookieOptions::SameSiteCookieContext::CROSS_SITE, CanonicalCookie::CookieInclusionStatus( CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT)}, {"A=2; SameSite=Strict", CookieSameSite::STRICT_MODE, CookieEffectiveSameSite::STRICT_MODE, CookieOptions::SameSiteCookieContext::SAME_SITE_LAX_METHOD_UNSAFE, CanonicalCookie::CookieInclusionStatus( CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT)}, {"A=2; SameSite=Strict", CookieSameSite::STRICT_MODE, CookieEffectiveSameSite::STRICT_MODE, CookieOptions::SameSiteCookieContext::SAME_SITE_LAX, CanonicalCookie::CookieInclusionStatus( CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT)}, {"A=2; SameSite=Strict", CookieSameSite::STRICT_MODE, CookieEffectiveSameSite::STRICT_MODE, CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT, CanonicalCookie::CookieInclusionStatus()}, {"A=2; SameSite=Strict", CookieSameSite::STRICT_MODE, CookieEffectiveSameSite::STRICT_MODE, CookieOptions::SameSiteCookieContext:: SAME_SITE_STRICT_CROSS_SCHEME_SECURE_URL, CanonicalCookie::CookieInclusionStatus()}, {"A=2; SameSite=Strict", CookieSameSite::STRICT_MODE, CookieEffectiveSameSite::STRICT_MODE, CookieOptions::SameSiteCookieContext:: SAME_SITE_STRICT_CROSS_SCHEME_INSECURE_URL, CanonicalCookie::CookieInclusionStatus()}, // Lax cookies: {"A=2; SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, CookieOptions::SameSiteCookieContext::CROSS_SITE, CanonicalCookie::CookieInclusionStatus( CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX)}, {"A=2; SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, CookieOptions::SameSiteCookieContext::SAME_SITE_LAX_METHOD_UNSAFE, CanonicalCookie::CookieInclusionStatus( CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX)}, {"A=2; SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, CookieOptions::SameSiteCookieContext::SAME_SITE_LAX, CanonicalCookie::CookieInclusionStatus()}, {"A=2; SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT, CanonicalCookie::CookieInclusionStatus()}, {"A=2; SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, CookieOptions::SameSiteCookieContext:: SAME_SITE_LAX_CROSS_SCHEME_SECURE_URL, CanonicalCookie::CookieInclusionStatus()}, {"A=2; SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, CookieOptions::SameSiteCookieContext:: SAME_SITE_STRICT_CROSS_SCHEME_SECURE_URL, CanonicalCookie::CookieInclusionStatus()}, {"A=2; SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, CookieOptions::SameSiteCookieContext:: SAME_SITE_LAX_CROSS_SCHEME_INSECURE_URL, CanonicalCookie::CookieInclusionStatus()}, {"A=2; SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, CookieOptions::SameSiteCookieContext:: SAME_SITE_STRICT_CROSS_SCHEME_INSECURE_URL, CanonicalCookie::CookieInclusionStatus()}, // None and Secure cookies: {"A=2; SameSite=None; Secure", CookieSameSite::NO_RESTRICTION, CookieEffectiveSameSite::NO_RESTRICTION, CookieOptions::SameSiteCookieContext::CROSS_SITE, CanonicalCookie::CookieInclusionStatus()}, {"A=2; SameSite=None; Secure", CookieSameSite::NO_RESTRICTION, CookieEffectiveSameSite::NO_RESTRICTION, CookieOptions::SameSiteCookieContext::SAME_SITE_LAX_METHOD_UNSAFE, CanonicalCookie::CookieInclusionStatus()}, {"A=2; SameSite=None; Secure", CookieSameSite::NO_RESTRICTION, CookieEffectiveSameSite::NO_RESTRICTION, CookieOptions::SameSiteCookieContext::SAME_SITE_LAX, CanonicalCookie::CookieInclusionStatus()}, {"A=2; SameSite=None; Secure", CookieSameSite::NO_RESTRICTION, CookieEffectiveSameSite::NO_RESTRICTION, CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT, CanonicalCookie::CookieInclusionStatus()}, {"A=2; SameSite=None; Secure", CookieSameSite::NO_RESTRICTION, CookieEffectiveSameSite::NO_RESTRICTION, CookieOptions::SameSiteCookieContext:: SAME_SITE_LAX_CROSS_SCHEME_SECURE_URL, CanonicalCookie::CookieInclusionStatus()}, {"A=2; SameSite=None; Secure", CookieSameSite::NO_RESTRICTION, CookieEffectiveSameSite::NO_RESTRICTION, CookieOptions::SameSiteCookieContext:: SAME_SITE_STRICT_CROSS_SCHEME_SECURE_URL, CanonicalCookie::CookieInclusionStatus()}, {"A=2; SameSite=None; Secure", CookieSameSite::NO_RESTRICTION, CookieEffectiveSameSite::NO_RESTRICTION, CookieOptions::SameSiteCookieContext:: SAME_SITE_LAX_CROSS_SCHEME_INSECURE_URL, CanonicalCookie::CookieInclusionStatus()}, {"A=2; SameSite=None; Secure", CookieSameSite::NO_RESTRICTION, CookieEffectiveSameSite::NO_RESTRICTION, CookieOptions::SameSiteCookieContext:: SAME_SITE_STRICT_CROSS_SCHEME_INSECURE_URL, CanonicalCookie::CookieInclusionStatus()}}; // Test cases where the default is None (either access semantics is LEGACY, or // semantics is UNKNOWN and feature is enabled): std::vector default_none_test_cases = { // Unspecified cookies (without SameSite-by-default): {"A=2", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::NO_RESTRICTION, CookieOptions::SameSiteCookieContext::CROSS_SITE, CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting( std::vector< CanonicalCookie::CookieInclusionStatus::ExclusionReason>(), CanonicalCookie::CookieInclusionStatus:: WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT)}, {"A=2", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::NO_RESTRICTION, CookieOptions::SameSiteCookieContext::SAME_SITE_LAX_METHOD_UNSAFE, CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting( std::vector< CanonicalCookie::CookieInclusionStatus::ExclusionReason>(), CanonicalCookie::CookieInclusionStatus:: WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT)}, {"A=2", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::NO_RESTRICTION, CookieOptions::SameSiteCookieContext::SAME_SITE_LAX, CanonicalCookie::CookieInclusionStatus()}, {"A=2", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::NO_RESTRICTION, CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT, CanonicalCookie::CookieInclusionStatus()}}; // Test cases where the default is Lax (either access semantics is NONLEGACY, // or access semantics is UNKNOWN and feature is enabled): std::vector default_lax_test_cases = { // Unspecified recently-created cookies (with SameSite-by-default): {"A=2", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, CookieOptions::SameSiteCookieContext::CROSS_SITE, CanonicalCookie::CookieInclusionStatus( CanonicalCookie::CookieInclusionStatus:: EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX, CanonicalCookie::CookieInclusionStatus:: WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT), kShortAge}, {"A=2", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, CookieOptions::SameSiteCookieContext::SAME_SITE_LAX_METHOD_UNSAFE, CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting( std::vector< CanonicalCookie::CookieInclusionStatus::ExclusionReason>(), CanonicalCookie::CookieInclusionStatus:: WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE), kShortAge}, {"A=2", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, CookieOptions::SameSiteCookieContext::SAME_SITE_LAX, CanonicalCookie::CookieInclusionStatus(), kShortAge}, {"A=2", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT, CanonicalCookie::CookieInclusionStatus(), kShortAge}, // Unspecified not-recently-created cookies (with SameSite-by-default): {"A=2", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE, CookieOptions::SameSiteCookieContext::CROSS_SITE, CanonicalCookie::CookieInclusionStatus( CanonicalCookie::CookieInclusionStatus:: EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX, CanonicalCookie::CookieInclusionStatus:: WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT), kLongAge}, {"A=2", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE, CookieOptions::SameSiteCookieContext::SAME_SITE_LAX_METHOD_UNSAFE, CanonicalCookie::CookieInclusionStatus( CanonicalCookie::CookieInclusionStatus:: EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX, CanonicalCookie::CookieInclusionStatus:: WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT), kLongAge}, {"A=2", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE, CookieOptions::SameSiteCookieContext::SAME_SITE_LAX, CanonicalCookie::CookieInclusionStatus(), kLongAge}, {"A=2", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE, CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT, CanonicalCookie::CookieInclusionStatus(), kLongAge}, }; VerifyIncludeForRequestURLTestCases(true, CookieAccessSemantics::UNKNOWN, common_test_cases); VerifyIncludeForRequestURLTestCases(true, CookieAccessSemantics::UNKNOWN, default_lax_test_cases); VerifyIncludeForRequestURLTestCases(true, CookieAccessSemantics::LEGACY, common_test_cases); VerifyIncludeForRequestURLTestCases(true, CookieAccessSemantics::LEGACY, default_none_test_cases); VerifyIncludeForRequestURLTestCases(true, CookieAccessSemantics::NONLEGACY, common_test_cases); VerifyIncludeForRequestURLTestCases(true, CookieAccessSemantics::NONLEGACY, default_lax_test_cases); VerifyIncludeForRequestURLTestCases(false, CookieAccessSemantics::UNKNOWN, common_test_cases); VerifyIncludeForRequestURLTestCases(false, CookieAccessSemantics::UNKNOWN, default_none_test_cases); VerifyIncludeForRequestURLTestCases(false, CookieAccessSemantics::LEGACY, common_test_cases); VerifyIncludeForRequestURLTestCases(false, CookieAccessSemantics::LEGACY, default_none_test_cases); VerifyIncludeForRequestURLTestCases(false, CookieAccessSemantics::NONLEGACY, common_test_cases); VerifyIncludeForRequestURLTestCases(false, CookieAccessSemantics::NONLEGACY, default_lax_test_cases); } // Test that non-SameSite, insecure cookies are excluded if both // SameSiteByDefaultCookies and CookiesWithoutSameSiteMustBeSecure are enabled. TEST(CanonicalCookieTest, IncludeCookiesWithoutSameSiteMustBeSecure) { GURL url("https://www.example.com"); base::Time creation_time = base::Time::Now(); base::Optional server_time = base::nullopt; CookieOptions options; std::unique_ptr cookie; // Create the cookie without the experimental options enabled. cookie = CanonicalCookie::Create(url, "A=2; SameSite=None", creation_time, server_time); ASSERT_TRUE(cookie.get()); EXPECT_FALSE(cookie->IsSecure()); EXPECT_EQ(CookieSameSite::NO_RESTRICTION, cookie->SameSite()); EXPECT_EQ(CookieEffectiveSameSite::NO_RESTRICTION, cookie->GetEffectiveSameSiteForTesting()); // Test SameSite=None must be Secure. // Features on: { base::test::ScopedFeatureList feature_list; feature_list.InitWithFeatures( {features::kSameSiteByDefaultCookies, features::kCookiesWithoutSameSiteMustBeSecure} /* enabled_features */, {} /* disabled_features */); EXPECT_TRUE( cookie ->IncludeForRequestURL(url, options, CookieAccessSemantics::UNKNOWN) .HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus:: EXCLUDE_SAMESITE_NONE_INSECURE})); EXPECT_TRUE( cookie ->IncludeForRequestURL(url, options, CookieAccessSemantics::LEGACY) .IsInclude()); EXPECT_TRUE(cookie ->IncludeForRequestURL(url, options, CookieAccessSemantics::NONLEGACY) .HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus:: EXCLUDE_SAMESITE_NONE_INSECURE})); } // Features off: { base::test::ScopedFeatureList feature_list; feature_list.InitWithFeatures( {} /* enabled_features */, {features::kSameSiteByDefaultCookies, features:: kCookiesWithoutSameSiteMustBeSecure} /* disabled_features */); EXPECT_TRUE( cookie ->IncludeForRequestURL(url, options, CookieAccessSemantics::UNKNOWN) .IsInclude()); EXPECT_TRUE( cookie ->IncludeForRequestURL(url, options, CookieAccessSemantics::LEGACY) .IsInclude()); // If the semantics is Nonlegacy, only reject the cookie if the // SameSite=None-must-be-Secure feature is enabled. EXPECT_TRUE(cookie ->IncludeForRequestURL(url, options, CookieAccessSemantics::NONLEGACY) .IsInclude()); } } TEST(CanonicalCookieTest, MultipleExclusionReasons) { GURL url("http://www.not-secure.com/foo"); base::Time creation_time = base::Time::Now(); base::Optional server_time = base::nullopt; CookieOptions options; options.set_exclude_httponly(); options.set_same_site_cookie_context( CookieOptions::SameSiteCookieContext::CROSS_SITE); // Test IncludeForRequestURL() // Note: This is a cookie that should never exist normally, because Create() // would weed it out. CanonicalCookie cookie1 = CanonicalCookie( "name", "value", "other-domain.com", "/bar", creation_time, base::Time(), base::Time(), true /* secure */, true /* httponly */, CookieSameSite::STRICT_MODE, COOKIE_PRIORITY_DEFAULT); EXPECT_TRUE( cookie1.IncludeForRequestURL(url, options) .HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY, CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY, CanonicalCookie::CookieInclusionStatus::EXCLUDE_DOMAIN_MISMATCH, CanonicalCookie::CookieInclusionStatus::EXCLUDE_NOT_ON_PATH, CanonicalCookie::CookieInclusionStatus:: EXCLUDE_SAMESITE_STRICT})); // Test Create() CanonicalCookie::CookieInclusionStatus create_status; auto cookie2 = CanonicalCookie::Create( url, "__Secure-notactuallysecure=value;Domain=some-other-domain.com", creation_time, server_time, &create_status); ASSERT_FALSE(cookie2); EXPECT_TRUE(create_status.HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX, CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN})); // Test IsSetPermittedInContext() auto cookie3 = CanonicalCookie::Create( url, "name=value;HttpOnly;SameSite=Lax", creation_time, server_time); ASSERT_TRUE(cookie3); EXPECT_TRUE( cookie3->IsSetPermittedInContext(options) .HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY, CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX})); } TEST(CanonicalCookieTest, PartialCompare) { GURL url("http://www.example.com"); base::Time creation_time = base::Time::Now(); base::Optional server_time = base::nullopt; std::unique_ptr cookie( CanonicalCookie::Create(url, "a=b", creation_time, server_time)); std::unique_ptr cookie_different_path( CanonicalCookie::Create(url, "a=b; path=/foo", creation_time, server_time)); std::unique_ptr cookie_different_value( CanonicalCookie::Create(url, "a=c", creation_time, server_time)); // Cookie is equivalent to itself. EXPECT_FALSE(cookie->PartialCompare(*cookie)); // Changing the path affects the ordering. EXPECT_TRUE(cookie->PartialCompare(*cookie_different_path)); EXPECT_FALSE(cookie_different_path->PartialCompare(*cookie)); // Changing the value does not affect the ordering. EXPECT_FALSE(cookie->PartialCompare(*cookie_different_value)); EXPECT_FALSE(cookie_different_value->PartialCompare(*cookie)); // Cookies identical for PartialCompare() are equivalent. EXPECT_TRUE(cookie->IsEquivalent(*cookie_different_value)); EXPECT_TRUE(cookie->IsEquivalent(*cookie)); } TEST(CanonicalCookieTest, SecureCookiePrefix) { GURL https_url("https://www.example.test"); GURL http_url("http://www.example.test"); base::Time creation_time = base::Time::Now(); base::Optional server_time = base::nullopt; CanonicalCookie::CookieInclusionStatus status; // A __Secure- cookie must be Secure. EXPECT_FALSE(CanonicalCookie::Create(https_url, "__Secure-A=B", creation_time, server_time, &status)); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); EXPECT_FALSE(CanonicalCookie::Create(https_url, "__Secure-A=B; httponly", creation_time, server_time, &status)); // (EXCLUDE_HTTP_ONLY would be fine, too) EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); // A typoed prefix does not have to be Secure. EXPECT_TRUE(CanonicalCookie::Create(https_url, "__secure-A=B; Secure", creation_time, server_time)); EXPECT_TRUE(CanonicalCookie::Create(https_url, "__secure-A=C;", creation_time, server_time)); EXPECT_TRUE(CanonicalCookie::Create(https_url, "__SecureA=B; Secure", creation_time, server_time)); EXPECT_TRUE(CanonicalCookie::Create(https_url, "__SecureA=C;", creation_time, server_time)); // A __Secure- cookie can't be set on a non-secure origin. EXPECT_FALSE(CanonicalCookie::Create(http_url, "__Secure-A=B; Secure", creation_time, server_time, &status)); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); } TEST(CanonicalCookieTest, HostCookiePrefix) { GURL https_url("https://www.example.test"); GURL http_url("http://www.example.test"); base::Time creation_time = base::Time::Now(); base::Optional server_time = base::nullopt; std::string domain = https_url.host(); CanonicalCookie::CookieInclusionStatus status; // A __Host- cookie must be Secure. EXPECT_FALSE(CanonicalCookie::Create(https_url, "__Host-A=B;", creation_time, server_time, &status)); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); EXPECT_FALSE(CanonicalCookie::Create( https_url, "__Host-A=B; Domain=" + domain + "; Path=/;", creation_time, server_time, &status)); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); EXPECT_TRUE(CanonicalCookie::Create(https_url, "__Host-A=B; Path=/; Secure;", creation_time, server_time)); // A __Host- cookie must be set from a secure scheme. EXPECT_FALSE(CanonicalCookie::Create( http_url, "__Host-A=B; Domain=" + domain + "; Path=/; Secure;", creation_time, server_time, &status)); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); EXPECT_TRUE(CanonicalCookie::Create(https_url, "__Host-A=B; Path=/; Secure;", creation_time, server_time)); // A __Host- cookie can't have a Domain. EXPECT_FALSE(CanonicalCookie::Create( https_url, "__Host-A=B; Domain=" + domain + "; Path=/; Secure;", creation_time, server_time, &status)); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); EXPECT_FALSE(CanonicalCookie::Create( https_url, "__Host-A=B; Domain=" + domain + "; Secure;", creation_time, server_time, &status)); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); // A __Host- cookie may have a domain if it's an IP address that matches the // URL. EXPECT_TRUE( CanonicalCookie::Create(GURL("https://127.0.0.1"), "__Host-A=B; Domain=127.0.0.1; Path=/; Secure;", creation_time, server_time, &status)); // A __Host- cookie with an IP address domain does not need the domain // attribute specified explicitly (just like a normal domain). EXPECT_TRUE(CanonicalCookie::Create(GURL("https://127.0.0.1"), "__Host-A=B; Domain=; Path=/; Secure;", creation_time, server_time, &status)); // A __Host- cookie must have a Path of "/". EXPECT_FALSE(CanonicalCookie::Create(https_url, "__Host-A=B; Path=/foo; Secure;", creation_time, server_time, &status)); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); EXPECT_FALSE(CanonicalCookie::Create(https_url, "__Host-A=B; Secure;", creation_time, server_time, &status)); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); EXPECT_TRUE(CanonicalCookie::Create(https_url, "__Host-A=B; Secure; Path=/;", creation_time, server_time)); // Rules don't apply for a typoed prefix. EXPECT_TRUE(CanonicalCookie::Create( http_url, "__host-A=B; Domain=" + domain + "; Path=/;", creation_time, server_time)); EXPECT_TRUE(CanonicalCookie::Create( https_url, "__HostA=B; Domain=" + domain + "; Secure;", creation_time, server_time)); } TEST(CanonicalCookieTest, CanCreateSecureCookiesFromAnyScheme) { GURL http_url("http://www.example.com"); GURL https_url("https://www.example.com"); base::Time creation_time = base::Time::Now(); base::Optional server_time = base::nullopt; std::unique_ptr http_cookie_no_secure( CanonicalCookie::Create(http_url, "a=b", creation_time, server_time)); std::unique_ptr http_cookie_secure(CanonicalCookie::Create( http_url, "a=b; Secure", creation_time, server_time)); std::unique_ptr https_cookie_no_secure( CanonicalCookie::Create(https_url, "a=b", creation_time, server_time)); std::unique_ptr https_cookie_secure(CanonicalCookie::Create( https_url, "a=b; Secure", creation_time, server_time)); EXPECT_TRUE(http_cookie_no_secure.get()); EXPECT_TRUE(http_cookie_secure.get()); EXPECT_TRUE(https_cookie_no_secure.get()); EXPECT_TRUE(https_cookie_secure.get()); } TEST(CanonicalCookieTest, IsCanonical) { // Base correct template. EXPECT_TRUE(CanonicalCookie("A", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Newline in name. EXPECT_FALSE(CanonicalCookie("A\n", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Carriage return in name. EXPECT_FALSE(CanonicalCookie("A\r", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Null character in name. EXPECT_FALSE(CanonicalCookie(std::string("A\0Z", 3), "B", "x.y", "/path", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Name begins with whitespace. EXPECT_FALSE(CanonicalCookie(" A", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Name ends with whitespace. EXPECT_FALSE(CanonicalCookie("A ", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Empty name. (Note this is against the spec but compatible with other // browsers.) EXPECT_TRUE(CanonicalCookie("", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Space in name EXPECT_TRUE(CanonicalCookie("A C", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Extra space suffixing name. EXPECT_FALSE(CanonicalCookie("A ", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // '=' character in name. EXPECT_FALSE(CanonicalCookie("A=", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Separator in name. EXPECT_FALSE(CanonicalCookie("A;", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // '=' character in value. EXPECT_TRUE(CanonicalCookie("A", "B=", "x.y", "/path", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Separator in value. EXPECT_FALSE(CanonicalCookie("A", "B;", "x.y", "/path", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Separator in domain. EXPECT_FALSE(CanonicalCookie("A", "B", ";x.y", "/path", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Garbage in domain. EXPECT_FALSE(CanonicalCookie("A", "B", "@:&", "/path", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Space in domain. EXPECT_FALSE(CanonicalCookie("A", "B", "x.y ", "/path", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Empty domain. (This is against cookie spec, but needed for Chrome's // out-of-spec use of cookies for extensions; see http://crbug.com/730633. EXPECT_TRUE(CanonicalCookie("A", "B", "", "/path", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Path does not start with a "/". EXPECT_FALSE(CanonicalCookie("A", "B", "x.y", "path", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Empty path. EXPECT_FALSE(CanonicalCookie("A", "B", "x.y", "", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Simple IPv4 address as domain. EXPECT_TRUE(CanonicalCookie("A", "B", "1.2.3.4", "/path", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // NOn-canonical IPv4 address as domain. EXPECT_FALSE(CanonicalCookie("A", "B", "01.2.03.4", "/path", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Null IPv6 address as domain. EXPECT_TRUE(CanonicalCookie("A", "B", "[::]", "/path", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Localhost IPv6 address as domain. EXPECT_TRUE(CanonicalCookie("A", "B", "[::1]", "/path", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Fully speced IPv6 address as domain. EXPECT_FALSE(CanonicalCookie( "A", "B", "[2001:0DB8:AC10:FE01:0000:0000:0000:0000]", "/path", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Zero abbreviated IPv6 address as domain. Not canonical because of leading // zeros & uppercase hex letters. EXPECT_FALSE(CanonicalCookie("A", "B", "[2001:0DB8:AC10:FE01::]", "/path", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Zero prefixes removed IPv6 address as domain. Not canoncial because of // uppercase hex letters. EXPECT_FALSE(CanonicalCookie("A", "B", "[2001:DB8:AC10:FE01::]", "/path", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Lowercased hex IPv6 address as domain. EXPECT_TRUE(CanonicalCookie("A", "B", "[2001:db8:ac10:fe01::]", "/path", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Properly formatted host cookie. EXPECT_TRUE(CanonicalCookie("__Host-A", "B", "x.y", "/", base::Time(), base::Time(), base::Time(), true, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Insecure host cookie. EXPECT_FALSE(CanonicalCookie("__Host-A", "B", "x.y", "/", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Host cookie with non-null path. EXPECT_FALSE(CanonicalCookie("__Host-A", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(), true, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Host cookie with empty domain. EXPECT_FALSE(CanonicalCookie("__Host-A", "B", "", "/", base::Time(), base::Time(), base::Time(), true, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Host cookie with period prefixed domain. EXPECT_FALSE(CanonicalCookie("__Host-A", "B", ".x.y", "/", base::Time(), base::Time(), base::Time(), true, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Properly formatted secure cookie. EXPECT_TRUE(CanonicalCookie("__Secure-A", "B", "x.y", "/", base::Time(), base::Time(), base::Time(), true, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); // Insecure secure cookie. EXPECT_FALSE(CanonicalCookie("__Secure-A", "B", "x.y", "/", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW) .IsCanonical()); } TEST(CanonicalCookieTest, TestSetCreationDate) { CanonicalCookie cookie("A", "B", "x.y", "/path", base::Time(), base::Time(), base::Time(), false, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW); EXPECT_TRUE(cookie.CreationDate().is_null()); base::Time now(base::Time::Now()); cookie.SetCreationDate(now); EXPECT_EQ(now, cookie.CreationDate()); } TEST(CanonicalCookieTest, TestPrefixHistograms) { base::HistogramTester histograms; const char kCookiePrefixHistogram[] = "Cookie.CookiePrefix"; const char kCookiePrefixBlockedHistogram[] = "Cookie.CookiePrefixBlocked"; GURL https_url("https://www.example.test"); base::Time creation_time = base::Time::Now(); base::Optional server_time = base::nullopt; EXPECT_FALSE(CanonicalCookie::Create(https_url, "__Host-A=B;", creation_time, server_time)); histograms.ExpectBucketCount(kCookiePrefixHistogram, CanonicalCookie::COOKIE_PREFIX_HOST, 1); histograms.ExpectBucketCount(kCookiePrefixBlockedHistogram, CanonicalCookie::COOKIE_PREFIX_HOST, 1); EXPECT_TRUE(CanonicalCookie::Create(https_url, "__Host-A=B; Path=/; Secure", creation_time, server_time)); histograms.ExpectBucketCount(kCookiePrefixHistogram, CanonicalCookie::COOKIE_PREFIX_HOST, 2); histograms.ExpectBucketCount(kCookiePrefixBlockedHistogram, CanonicalCookie::COOKIE_PREFIX_HOST, 1); EXPECT_TRUE(CanonicalCookie::Create(https_url, "__HostA=B; Path=/; Secure", creation_time, server_time)); histograms.ExpectBucketCount(kCookiePrefixHistogram, CanonicalCookie::COOKIE_PREFIX_HOST, 2); histograms.ExpectBucketCount(kCookiePrefixBlockedHistogram, CanonicalCookie::COOKIE_PREFIX_HOST, 1); EXPECT_FALSE(CanonicalCookie::Create(https_url, "__Secure-A=B;", creation_time, server_time)); histograms.ExpectBucketCount(kCookiePrefixHistogram, CanonicalCookie::COOKIE_PREFIX_SECURE, 1); histograms.ExpectBucketCount(kCookiePrefixBlockedHistogram, CanonicalCookie::COOKIE_PREFIX_SECURE, 1); EXPECT_TRUE(CanonicalCookie::Create(https_url, "__Secure-A=B; Path=/; Secure", creation_time, server_time)); histograms.ExpectBucketCount(kCookiePrefixHistogram, CanonicalCookie::COOKIE_PREFIX_SECURE, 2); histograms.ExpectBucketCount(kCookiePrefixBlockedHistogram, CanonicalCookie::COOKIE_PREFIX_SECURE, 1); EXPECT_TRUE(CanonicalCookie::Create(https_url, "__SecureA=B; Path=/; Secure", creation_time, server_time)); histograms.ExpectBucketCount(kCookiePrefixHistogram, CanonicalCookie::COOKIE_PREFIX_SECURE, 2); histograms.ExpectBucketCount(kCookiePrefixBlockedHistogram, CanonicalCookie::COOKIE_PREFIX_SECURE, 1); } TEST(CanonicalCookieTest, BuildCookieLine) { std::vector> cookies; GURL url("https://example.com/"); base::Time now = base::Time::Now(); base::Optional server_time = base::nullopt; MatchCookieLineToVector("", cookies); cookies.push_back(CanonicalCookie::Create(url, "A=B", now, server_time)); MatchCookieLineToVector("A=B", cookies); // Nameless cookies are sent back without a prefixed '='. cookies.push_back(CanonicalCookie::Create(url, "C", now, server_time)); MatchCookieLineToVector("A=B; C", cookies); // Cookies separated by ';'. cookies.push_back(CanonicalCookie::Create(url, "D=E", now, server_time)); MatchCookieLineToVector("A=B; C; D=E", cookies); // BuildCookieLine doesn't reorder the list, it relies on the caller to do so. cookies.push_back(CanonicalCookie::Create( url, "F=G", now - base::TimeDelta::FromSeconds(1), server_time)); MatchCookieLineToVector("A=B; C; D=E; F=G", cookies); // BuildCookieLine doesn't deduplicate. cookies.push_back(CanonicalCookie::Create( url, "D=E", now - base::TimeDelta::FromSeconds(2), server_time)); MatchCookieLineToVector("A=B; C; D=E; F=G; D=E", cookies); } // Confirm that input arguments are reflected in the output cookie. TEST(CanonicalCookieTest, CreateSanitizedCookie_Inputs) { base::Time two_hours_ago = base::Time::Now() - base::TimeDelta::FromHours(2); base::Time one_hour_ago = base::Time::Now() - base::TimeDelta::FromHours(1); base::Time one_hour_from_now = base::Time::Now() + base::TimeDelta::FromHours(1); std::unique_ptr cc; cc = CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "A", "B", std::string(), "/foo", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT); EXPECT_TRUE(cc); EXPECT_EQ("A", cc->Name()); EXPECT_EQ("B", cc->Value()); EXPECT_EQ("www.foo.com", cc->Domain()); EXPECT_EQ("/foo", cc->Path()); EXPECT_EQ(base::Time(), cc->CreationDate()); EXPECT_EQ(base::Time(), cc->LastAccessDate()); EXPECT_EQ(base::Time(), cc->ExpiryDate()); EXPECT_FALSE(cc->IsSecure()); EXPECT_FALSE(cc->IsHttpOnly()); EXPECT_EQ(CookieSameSite::NO_RESTRICTION, cc->SameSite()); EXPECT_EQ(COOKIE_PRIORITY_MEDIUM, cc->Priority()); EXPECT_FALSE(cc->IsDomainCookie()); // Creation date cc = CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "A", "B", std::string(), "/foo", two_hours_ago, base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT); EXPECT_TRUE(cc); EXPECT_EQ(two_hours_ago, cc->CreationDate()); // Last access date cc = CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "A", "B", std::string(), "/foo", two_hours_ago, base::Time(), one_hour_ago, false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT); EXPECT_TRUE(cc); EXPECT_EQ(one_hour_ago, cc->LastAccessDate()); // Expiry cc = CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "A", "B", std::string(), "/foo", base::Time(), one_hour_from_now, base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT); EXPECT_TRUE(cc); EXPECT_EQ(one_hour_from_now, cc->ExpiryDate()); // Secure cc = CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "A", "B", std::string(), "/foo", base::Time(), base::Time(), base::Time(), true /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT); EXPECT_TRUE(cc); EXPECT_TRUE(cc->IsSecure()); // Httponly cc = CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "A", "B", std::string(), "/foo", base::Time(), base::Time(), base::Time(), false /*secure*/, true /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT); EXPECT_TRUE(cc); EXPECT_TRUE(cc->IsHttpOnly()); // Same site cc = CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "A", "B", std::string(), "/foo", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::LAX_MODE, COOKIE_PRIORITY_DEFAULT); EXPECT_TRUE(cc); EXPECT_EQ(CookieSameSite::LAX_MODE, cc->SameSite()); // Priority cc = CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "A", "B", std::string(), "/foo", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW); EXPECT_TRUE(cc); EXPECT_EQ(COOKIE_PRIORITY_LOW, cc->Priority()); // Domain cookie cc = CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "A", "B", "www.foo.com", "/foo", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT); EXPECT_TRUE(cc); EXPECT_TRUE(cc->IsDomainCookie()); } // Make sure sanitization and blocking of cookies works correctly. TEST(CanonicalCookieTest, CreateSanitizedCookie_Logic) { base::Time two_hours_ago = base::Time::Now() - base::TimeDelta::FromHours(2); base::Time one_hour_ago = base::Time::Now() - base::TimeDelta::FromHours(1); base::Time one_hour_from_now = base::Time::Now() + base::TimeDelta::FromHours(1); // Simple path and domain variations. EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com/foo"), "A", "B", std::string(), "/foo", one_hour_ago, one_hour_from_now, base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT)); EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com/bar"), "C", "D", "www.foo.com", "/", two_hours_ago, base::Time(), one_hour_ago, false /*secure*/, true /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT)); EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "E", "F", std::string(), std::string(), base::Time(), base::Time(), base::Time(), true /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT)); // Test the file:// protocol. EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("file:///"), "A", "B", std::string(), "/foo", one_hour_ago, one_hour_from_now, base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT)); EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("file:///home/user/foo.txt"), "A", "B", std::string(), "/foo", one_hour_ago, one_hour_from_now, base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT)); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("file:///home/user/foo.txt"), "A", "B", "home", "/foo", one_hour_ago, one_hour_from_now, base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT)); // Test that malformed attributes fail to set the cookie. EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com/foo"), " A", "B", std::string(), "/foo", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT)); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com/foo"), "A;", "B", std::string(), "/foo", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT)); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com/foo"), "A=", "B", std::string(), "/foo", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT)); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com/foo"), "A\x07", "B", std::string(), "/foo", one_hour_ago, one_hour_from_now, base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT)); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com"), "A", " B", std::string(), "/foo", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT)); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com"), "A", "\x0fZ", std::string(), "/foo", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT)); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com"), "A", "B", "www.foo.com ", "/foo", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT)); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com/foo"), "A", "B", "foo.ozzzzzzle", "/foo", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT)); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com/foo"), "A", "B", std::string(), "foo", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT)); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com"), "A", "B", std::string(), "/foo ", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT)); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com/foo"), "A", "B", "%2Efoo.com", "/foo", one_hour_ago, one_hour_from_now, base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT)); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://domaintest.%E3%81%BF%E3%82%93%E3%81%AA"), "A", "B", "domaintest.%E3%81%BF%E3%82%93%E3%81%AA", "/foo", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT)); std::unique_ptr cc; // Confirm that setting domain cookies with or without leading periods, // or on domains different from the URL's, functions correctly. cc = CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com/foo"), "A", "B", "www.foo.com", "/foo", one_hour_ago, one_hour_from_now, base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT); ASSERT_TRUE(cc); EXPECT_TRUE(cc->IsDomainCookie()); EXPECT_EQ(".www.foo.com", cc->Domain()); cc = CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com/foo"), "A", "B", ".www.foo.com", "/foo", one_hour_ago, one_hour_from_now, base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT); ASSERT_TRUE(cc); EXPECT_TRUE(cc->IsDomainCookie()); EXPECT_EQ(".www.foo.com", cc->Domain()); cc = CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com/foo"), "A", "B", ".foo.com", "/foo", one_hour_ago, one_hour_from_now, base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT); ASSERT_TRUE(cc); EXPECT_TRUE(cc->IsDomainCookie()); EXPECT_EQ(".foo.com", cc->Domain()); cc = CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com/foo"), "A", "B", ".www2.www.foo.com", "/foo", one_hour_ago, one_hour_from_now, base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT); EXPECT_FALSE(cc); // Secure/URL Scheme mismatch. EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com"), "A", "B", std::string(), "/foo ", base::Time(), base::Time(), base::Time(), true /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT)); // Null creation date/non-null last access date conflict. EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com"), "A", "B", std::string(), "/foo", base::Time(), base::Time(), base::Time::Now(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT)); // Domain doesn't match URL EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com"), "A", "B", "www.bar.com", "/", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT)); // Path with unusual characters escaped. cc = CanonicalCookie::CreateSanitizedCookie( GURL("http://www.foo.com"), "A", "B", std::string(), "/foo", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT); ASSERT_TRUE(cc); EXPECT_EQ("/foo%7F", cc->Path()); // A __Secure- cookie must be Secure. EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "__Secure-A", "B", ".www.foo.com", "/", two_hours_ago, one_hour_from_now, one_hour_ago, true, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT)); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "__Secure-A", "B", ".www.foo.com", "/", two_hours_ago, one_hour_from_now, one_hour_ago, false, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT)); // A __Host- cookie must be Secure. EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "__Host-A", "B", std::string(), "/", two_hours_ago, one_hour_from_now, one_hour_ago, true, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT)); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "__Host-A", "B", std::string(), "/", two_hours_ago, one_hour_from_now, one_hour_ago, false, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT)); // A __Host- cookie must have path "/". EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "__Host-A", "B", std::string(), "/", two_hours_ago, one_hour_from_now, one_hour_ago, true, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT)); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "__Host-A", "B", std::string(), "/foo", two_hours_ago, one_hour_from_now, one_hour_ago, true, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT)); // A __Host- cookie must not specify a domain. EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "__Host-A", "B", std::string(), "/", two_hours_ago, one_hour_from_now, one_hour_ago, true, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT)); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "__Host-A", "B", ".www.foo.com", "/", two_hours_ago, one_hour_from_now, one_hour_ago, true, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT)); // Without __Host- prefix, this is a valid host cookie because it does not // specify a domain. EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "A", "B", std::string(), "/", two_hours_ago, one_hour_from_now, one_hour_ago, true, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT)); // Without __Host- prefix, this is a valid domain (not host) cookie. EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("https://www.foo.com"), "A", "B", ".www.foo.com", "/", two_hours_ago, one_hour_from_now, one_hour_ago, true, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT)); // The __Host- prefix should not prevent otherwise-valid host cookies from // being accepted. EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("https://127.0.0.1"), "A", "B", std::string(), "/", two_hours_ago, one_hour_from_now, one_hour_ago, true, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT)); EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("https://127.0.0.1"), "__Host-A", "B", std::string(), "/", two_hours_ago, one_hour_from_now, one_hour_ago, true, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT)); // Host cookies should not specify domain unless it is an IP address that // matches the URL. EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("https://127.0.0.1"), "A", "B", "127.0.0.1", "/", two_hours_ago, one_hour_from_now, one_hour_ago, true, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT)); EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("https://127.0.0.1"), "__Host-A", "B", "127.0.0.1", "/", two_hours_ago, one_hour_from_now, one_hour_ago, true, false, CookieSameSite::NO_RESTRICTION, CookiePriority::COOKIE_PRIORITY_DEFAULT)); // Check that CreateSanitizedCookie can gracefully fail on inputs that would // crash cookie_util::GetCookieDomainWithString due to failing // DCHECKs. Specifically, GetCookieDomainWithString requires that if the // domain is empty or the URL's host matches the domain, then the URL's host // must pass DomainIsHostOnly; it must not begin with a period. EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://..."), "A", "B", "...", "/", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT)); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://."), "A", "B", std::string(), "/", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT)); EXPECT_FALSE(CanonicalCookie::CreateSanitizedCookie( GURL("http://.chromium.org"), "A", "B", ".chromium.org", "/", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT)); // Check that a file URL with an IPv6 host, and matching IPv6 domain, are // valid. EXPECT_TRUE(CanonicalCookie::CreateSanitizedCookie( GURL("file://[A::]"), std::string(), std::string(), "[A::]", "", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT)); // On Windows, URLs beginning with two backslashes are considered file // URLs. On other platforms, they are invalid. auto double_backslash_ipv6_cookie = CanonicalCookie::CreateSanitizedCookie( GURL("\\\\[A::]"), std::string(), std::string(), "[A::]", "", base::Time(), base::Time(), base::Time(), false /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT); #if defined(OS_WIN) EXPECT_TRUE(double_backslash_ipv6_cookie); EXPECT_TRUE(double_backslash_ipv6_cookie->IsCanonical()); #else EXPECT_FALSE(double_backslash_ipv6_cookie); #endif } TEST(CanonicalCookieTest, IsSetPermittedInContext) { GURL url("http://www.example.com/test"); base::Time current_time = base::Time::Now(); CanonicalCookie cookie_scriptable( "A", "2", "www.example.com", "/test", current_time, base::Time(), base::Time(), true /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT); CanonicalCookie cookie_httponly( "A", "2", "www.example.com", "/test", current_time, base::Time(), base::Time(), true /*secure*/, true /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT); CookieOptions context_script; CookieOptions context_network; context_network.set_include_httponly(); EXPECT_TRUE( cookie_scriptable.IsSetPermittedInContext(context_network).IsInclude()); EXPECT_TRUE( cookie_scriptable.IsSetPermittedInContext(context_script).IsInclude()); EXPECT_TRUE( cookie_httponly.IsSetPermittedInContext(context_network).IsInclude()); EXPECT_TRUE( cookie_httponly.IsSetPermittedInContext(context_script) .HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY})); CookieOptions context_cross_site; CookieOptions context_same_site_lax; context_same_site_lax.set_same_site_cookie_context( net::CookieOptions::SameSiteCookieContext::SAME_SITE_LAX); CookieOptions context_same_site_strict; context_same_site_strict.set_same_site_cookie_context( net::CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT); CookieOptions context_same_site_lax_to_secure; context_same_site_lax_to_secure.set_same_site_cookie_context( net::CookieOptions::SameSiteCookieContext:: SAME_SITE_LAX_CROSS_SCHEME_SECURE_URL); CookieOptions context_same_site_strict_to_secure; context_same_site_strict_to_secure.set_same_site_cookie_context( net::CookieOptions::SameSiteCookieContext:: SAME_SITE_STRICT_CROSS_SCHEME_SECURE_URL); CookieOptions context_same_site_lax_to_insecure; context_same_site_lax_to_insecure.set_same_site_cookie_context( net::CookieOptions::SameSiteCookieContext:: SAME_SITE_LAX_CROSS_SCHEME_INSECURE_URL); CookieOptions context_same_site_strict_to_insecure; context_same_site_strict_to_insecure.set_same_site_cookie_context( net::CookieOptions::SameSiteCookieContext:: SAME_SITE_STRICT_CROSS_SCHEME_INSECURE_URL); { CanonicalCookie cookie_same_site_unrestricted( "A", "2", "www.example.com", "/test", current_time, base::Time(), base::Time(), true /*secure*/, false /*httponly*/, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT); EXPECT_TRUE(cookie_same_site_unrestricted .IsSetPermittedInContext(context_cross_site) .IsInclude()); EXPECT_TRUE(cookie_same_site_unrestricted .IsSetPermittedInContext(context_same_site_lax) .IsInclude()); EXPECT_TRUE(cookie_same_site_unrestricted .IsSetPermittedInContext(context_same_site_strict) .IsInclude()); EXPECT_TRUE(cookie_same_site_unrestricted .IsSetPermittedInContext(context_same_site_lax_to_secure) .IsInclude()); EXPECT_TRUE(cookie_same_site_unrestricted .IsSetPermittedInContext(context_same_site_strict_to_secure) .IsInclude()); EXPECT_TRUE(cookie_same_site_unrestricted .IsSetPermittedInContext(context_same_site_lax_to_insecure) .IsInclude()); EXPECT_TRUE( cookie_same_site_unrestricted .IsSetPermittedInContext(context_same_site_strict_to_insecure) .IsInclude()); } { CanonicalCookie cookie_same_site_lax( "A", "2", "www.example.com", "/test", current_time, base::Time(), base::Time(), true /*secure*/, false /*httponly*/, CookieSameSite::LAX_MODE, COOKIE_PRIORITY_DEFAULT); EXPECT_TRUE(cookie_same_site_lax.IsSetPermittedInContext(context_cross_site) .HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus:: EXCLUDE_SAMESITE_LAX})); EXPECT_TRUE( cookie_same_site_lax.IsSetPermittedInContext(context_same_site_lax) .IsInclude()); EXPECT_TRUE( cookie_same_site_lax.IsSetPermittedInContext(context_same_site_strict) .IsInclude()); EXPECT_TRUE(cookie_same_site_lax .IsSetPermittedInContext(context_same_site_lax_to_secure) .IsInclude()); EXPECT_TRUE(cookie_same_site_lax .IsSetPermittedInContext(context_same_site_strict_to_secure) .IsInclude()); EXPECT_TRUE(cookie_same_site_lax .IsSetPermittedInContext(context_same_site_lax_to_insecure) .IsInclude()); EXPECT_TRUE( cookie_same_site_lax .IsSetPermittedInContext(context_same_site_strict_to_insecure) .IsInclude()); } { CanonicalCookie cookie_same_site_strict( "A", "2", "www.example.com", "/test", current_time, base::Time(), base::Time(), true /*secure*/, false /*httponly*/, CookieSameSite::STRICT_MODE, COOKIE_PRIORITY_DEFAULT); // TODO(morlovich): Do compatibility testing on whether set of strict in lax // context really should be accepted. EXPECT_TRUE( cookie_same_site_strict.IsSetPermittedInContext(context_cross_site) .HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus:: EXCLUDE_SAMESITE_STRICT})); EXPECT_TRUE( cookie_same_site_strict.IsSetPermittedInContext(context_same_site_lax) .IsInclude()); EXPECT_TRUE(cookie_same_site_strict .IsSetPermittedInContext(context_same_site_strict) .IsInclude()); EXPECT_TRUE(cookie_same_site_strict .IsSetPermittedInContext(context_same_site_lax_to_secure) .IsInclude()); EXPECT_TRUE(cookie_same_site_strict .IsSetPermittedInContext(context_same_site_strict_to_secure) .IsInclude()); EXPECT_TRUE(cookie_same_site_strict .IsSetPermittedInContext(context_same_site_lax_to_insecure) .IsInclude()); EXPECT_TRUE( cookie_same_site_strict .IsSetPermittedInContext(context_same_site_strict_to_insecure) .IsInclude()); } // Behavior of UNSPECIFIED depends on an experiment and CookieAccessSemantics. CanonicalCookie cookie_same_site_unspecified( "A", "2", "www.example.com", "/test", current_time, base::Time(), base::Time(), true /*secure*/, false /*httponly*/, CookieSameSite::UNSPECIFIED, COOKIE_PRIORITY_DEFAULT); { base::test::ScopedFeatureList feature_list; feature_list.InitAndDisableFeature(features::kSameSiteByDefaultCookies); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_cross_site, CookieAccessSemantics::UNKNOWN) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax, CookieAccessSemantics::UNKNOWN) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_strict, CookieAccessSemantics::UNKNOWN) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax_to_secure, CookieAccessSemantics::UNKNOWN) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_strict_to_secure, CookieAccessSemantics::UNKNOWN) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax_to_insecure, CookieAccessSemantics::UNKNOWN) .IsInclude()); EXPECT_TRUE( cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_strict_to_insecure, CookieAccessSemantics::UNKNOWN) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_cross_site, CookieAccessSemantics::LEGACY) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax, CookieAccessSemantics::LEGACY) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_strict, CookieAccessSemantics::LEGACY) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax_to_secure, CookieAccessSemantics::LEGACY) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_strict_to_secure, CookieAccessSemantics::LEGACY) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax_to_insecure, CookieAccessSemantics::LEGACY) .IsInclude()); EXPECT_TRUE( cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_strict_to_insecure, CookieAccessSemantics::LEGACY) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_cross_site, CookieAccessSemantics::NONLEGACY) .HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus:: EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX})); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax, CookieAccessSemantics::NONLEGACY) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_strict, CookieAccessSemantics::NONLEGACY) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax_to_secure, CookieAccessSemantics::NONLEGACY) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_strict_to_secure, CookieAccessSemantics::NONLEGACY) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax_to_insecure, CookieAccessSemantics::NONLEGACY) .IsInclude()); EXPECT_TRUE( cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_strict_to_insecure, CookieAccessSemantics::NONLEGACY) .IsInclude()); } { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature(features::kSameSiteByDefaultCookies); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_cross_site, CookieAccessSemantics::UNKNOWN) .HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus:: EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX})); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax, CookieAccessSemantics::UNKNOWN) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_strict, CookieAccessSemantics::UNKNOWN) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax_to_secure, CookieAccessSemantics::UNKNOWN) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_strict_to_secure, CookieAccessSemantics::UNKNOWN) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax_to_insecure, CookieAccessSemantics::UNKNOWN) .IsInclude()); EXPECT_TRUE( cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_strict_to_insecure, CookieAccessSemantics::UNKNOWN) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_cross_site, CookieAccessSemantics::LEGACY) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax, CookieAccessSemantics::LEGACY) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_strict, CookieAccessSemantics::LEGACY) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax_to_secure, CookieAccessSemantics::LEGACY) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_strict_to_secure, CookieAccessSemantics::LEGACY) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax_to_insecure, CookieAccessSemantics::LEGACY) .IsInclude()); EXPECT_TRUE( cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_strict_to_insecure, CookieAccessSemantics::LEGACY) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_cross_site, CookieAccessSemantics::NONLEGACY) .HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus:: EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX})); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax, CookieAccessSemantics::NONLEGACY) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_strict, CookieAccessSemantics::NONLEGACY) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax_to_secure, CookieAccessSemantics::NONLEGACY) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_strict_to_secure, CookieAccessSemantics::NONLEGACY) .IsInclude()); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax_to_insecure, CookieAccessSemantics::NONLEGACY) .IsInclude()); EXPECT_TRUE( cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_strict_to_insecure, CookieAccessSemantics::NONLEGACY) .IsInclude()); } } TEST(CookieInclusionStatusTest, IncludeStatus) { int num_exclusion_reasons = static_cast( CanonicalCookie::CookieInclusionStatus::NUM_EXCLUSION_REASONS); // Zero-argument constructor CanonicalCookie::CookieInclusionStatus status; EXPECT_TRUE(status.IsValid()); EXPECT_TRUE(status.IsInclude()); for (int i = 0; i < num_exclusion_reasons; ++i) { EXPECT_FALSE(status.HasExclusionReason( static_cast( i))); } EXPECT_FALSE(status.HasExclusionReason( CanonicalCookie::CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR)); } TEST(CookieInclusionStatusTest, ExcludeStatus) { int num_exclusion_reasons = static_cast( CanonicalCookie::CookieInclusionStatus::NUM_EXCLUSION_REASONS); for (int i = 0; i < num_exclusion_reasons; ++i) { auto reason = static_cast(i); CanonicalCookie::CookieInclusionStatus status(reason); EXPECT_TRUE(status.IsValid()); EXPECT_FALSE(status.IsInclude()); EXPECT_TRUE(status.HasExclusionReason(reason)); for (int j = 0; j < num_exclusion_reasons; ++j) { if (i == j) continue; EXPECT_FALSE(status.HasExclusionReason( static_cast( j))); } } } TEST(CookieInclusionStatusTest, NotValid) { CanonicalCookie::CookieInclusionStatus status; int num_exclusion_reasons = static_cast( CanonicalCookie::CookieInclusionStatus::NUM_EXCLUSION_REASONS); status.set_exclusion_reasons(1 << num_exclusion_reasons); EXPECT_FALSE(status.IsInclude()); EXPECT_FALSE(status.IsValid()); status.set_exclusion_reasons(~0u); EXPECT_FALSE(status.IsInclude()); EXPECT_FALSE(status.IsValid()); } TEST(CookieInclusionStatusTest, AddExclusionReason) { CanonicalCookie::CookieInclusionStatus status; status.set_warning(CanonicalCookie::CookieInclusionStatus:: WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE); status.AddExclusionReason( CanonicalCookie::CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR); EXPECT_TRUE(status.IsValid()); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR})); // Adding an exclusion reason other than // EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX or // EXCLUDE_SAMESITE_NONE_INSECURE should clear any SameSite warning. EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::DO_NOT_WARN, status.warning()); status = CanonicalCookie::CookieInclusionStatus(); status.set_warning(CanonicalCookie::CookieInclusionStatus:: WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); status.AddExclusionReason(CanonicalCookie::CookieInclusionStatus:: EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX); EXPECT_TRUE(status.IsValid()); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( {CanonicalCookie::CookieInclusionStatus:: EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX})); EXPECT_EQ(CanonicalCookie::CookieInclusionStatus:: WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT, status.warning()); } TEST(CookieInclusionStatusTest, RemoveExclusionReason) { CanonicalCookie::CookieInclusionStatus status( CanonicalCookie::CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR); EXPECT_TRUE(status.IsValid()); ASSERT_TRUE(status.HasExclusionReason( CanonicalCookie::CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR)); status.RemoveExclusionReason( CanonicalCookie::CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR); EXPECT_TRUE(status.IsValid()); EXPECT_FALSE(status.HasExclusionReason( CanonicalCookie::CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR)); // Removing a nonexistent exclusion reason doesn't do anything. ASSERT_FALSE(status.HasExclusionReason( CanonicalCookie::CookieInclusionStatus::NUM_EXCLUSION_REASONS)); status.RemoveExclusionReason( CanonicalCookie::CookieInclusionStatus::NUM_EXCLUSION_REASONS); EXPECT_TRUE(status.IsValid()); EXPECT_FALSE(status.HasExclusionReason( CanonicalCookie::CookieInclusionStatus::NUM_EXCLUSION_REASONS)); } } // namespace net