diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-12 14:27:29 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-13 09:35:20 +0000 |
commit | c30a6232df03e1efbd9f3b226777b07e087a1122 (patch) | |
tree | e992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/net/cookies | |
parent | 7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff) | |
download | qtwebengine-chromium-85-based.tar.gz |
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/net/cookies')
23 files changed, 1657 insertions, 1258 deletions
diff --git a/chromium/net/cookies/canonical_cookie.cc b/chromium/net/cookies/canonical_cookie.cc index e87937435d9..68fa41779bb 100644 --- a/chromium/net/cookies/canonical_cookie.cc +++ b/chromium/net/cookies/canonical_cookie.cc @@ -105,16 +105,6 @@ void AppendCookieLineEntry(const CanonicalCookie& cookie, *cookie_line += cookie.Value(); } -uint32_t GetExclusionBitmask( - CanonicalCookie::CookieInclusionStatus::ExclusionReason reason) { - return 1u << static_cast<uint32_t>(reason); -} - -uint32_t GetWarningBitmask( - CanonicalCookie::CookieInclusionStatus::WarningReason reason) { - return 1u << static_cast<uint32_t>(reason); -} - // Captures Strict -> Lax context downgrade with Strict cookie bool IsBreakingStrictToLaxDowngrade( CookieOptions::SameSiteCookieContext::ContextType context, @@ -198,13 +188,13 @@ void ApplySameSiteCookieWarningToStatus( CookieEffectiveSameSite effective_samesite, bool is_secure, CookieOptions::SameSiteCookieContext same_site_context, - CanonicalCookie::CookieInclusionStatus* status, + CookieInclusionStatus* status, bool is_cookie_being_set) { if (samesite == CookieSameSite::UNSPECIFIED && same_site_context.GetContextForCookieInclusion() < CookieOptions::SameSiteCookieContext::ContextType::SAME_SITE_LAX) { - status->AddWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); + status->AddWarningReason( + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); } if (effective_samesite == CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE && same_site_context.GetContextForCookieInclusion() == @@ -213,14 +203,13 @@ void ApplySameSiteCookieWarningToStatus( // This warning is more specific so remove the previous, more general, // warning. status->RemoveWarningReason( - CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); - status->AddWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE); + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); + status->AddWarningReason( + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE); } if (samesite == CookieSameSite::NO_RESTRICTION && !is_secure) { status->AddWarningReason( - CanonicalCookie::CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE); + CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE); } // Add a warning if the cookie would be accessible in @@ -229,19 +218,19 @@ void ApplySameSiteCookieWarningToStatus( if (IsBreakingStrictToLaxDowngrade(same_site_context.context(), same_site_context.schemeful_context(), effective_samesite, is_cookie_being_set)) { - status->AddWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE); + status->AddWarningReason( + CookieInclusionStatus::WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE); } else if (IsBreakingStrictToCrossDowngrade( same_site_context.context(), same_site_context.schemeful_context(), effective_samesite)) { // Which warning to apply depends on the SameSite value. if (effective_samesite == CookieEffectiveSameSite::STRICT_MODE) { - status->AddWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE); + status->AddWarningReason( + CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE); } else { // LAX_MODE or LAX_MODE_ALLOW_UNSAFE. - status->AddWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE); + status->AddWarningReason( + CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE); } } else if (IsBreakingLaxToCrossDowngrade( @@ -250,13 +239,13 @@ void ApplySameSiteCookieWarningToStatus( is_cookie_being_set)) { // Which warning to apply depends on the SameSite value. if (effective_samesite == CookieEffectiveSameSite::STRICT_MODE) { - status->AddWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE); + status->AddWarningReason( + CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE); } else { // LAX_MODE or LAX_MODE_ALLOW_UNSAFE. // This warning applies to both set/send. - status->AddWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE); + status->AddWarningReason( + CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE); } } @@ -581,11 +570,10 @@ bool CanonicalCookie::IsDomainMatch(const std::string& host) const { return cookie_util::IsDomainMatch(domain_, host); } -CanonicalCookie::CookieInclusionStatus CanonicalCookie::IncludeForRequestURL( +CookieAccessResult CanonicalCookie::IncludeForRequestURL( const GURL& url, const CookieOptions& options, CookieAccessSemantics access_semantics) const { - base::TimeDelta cookie_age = base::Time::Now() - CreationDate(); CookieInclusionStatus status; // Filter out HttpOnly cookies, per options. if (options.exclude_httponly() && IsHttpOnly()) @@ -627,17 +615,6 @@ CanonicalCookie::CookieInclusionStatus CanonicalCookie::IncludeForRequestURL( case CookieEffectiveSameSite::LAX_MODE: if (options.same_site_cookie_context().GetContextForCookieInclusion() < CookieOptions::SameSiteCookieContext::ContextType::SAME_SITE_LAX) { - // Log metrics for a cookie that would have been included under the - // "Lax-allow-unsafe" intervention, had it been new enough. - if (SameSite() == CookieSameSite::UNSPECIFIED && - options.same_site_cookie_context().GetContextForCookieInclusion() == - CookieOptions::SameSiteCookieContext::ContextType:: - SAME_SITE_LAX_METHOD_UNSAFE) { - UMA_HISTOGRAM_CUSTOM_TIMES( - "Cookie.SameSiteUnspecifiedTooOldToAllowUnsafe", cookie_age, - base::TimeDelta::FromMinutes(1), base::TimeDelta::FromDays(5), - 100); - } status.AddExclusionReason( (SameSite() == CookieSameSite::UNSPECIFIED) ? CookieInclusionStatus:: @@ -654,15 +631,6 @@ CanonicalCookie::CookieInclusionStatus CanonicalCookie::IncludeForRequestURL( // TODO(chlily): Do we need a separate CookieInclusionStatus for this? status.AddExclusionReason( CookieInclusionStatus::EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX); - } else if (options.same_site_cookie_context() - .GetContextForCookieInclusion() == - CookieOptions::SameSiteCookieContext::ContextType:: - SAME_SITE_LAX_METHOD_UNSAFE) { - // Log metrics for cookies that activate the "Lax-allow-unsafe" - // intervention. This histogram macro allows up to 3 minutes, which is - // enough for the current threshold of 2 minutes. - UMA_HISTOGRAM_MEDIUM_TIMES("Cookie.LaxAllowUnsafeCookieIncludedAge", - cookie_age); } break; default: @@ -700,10 +668,10 @@ CanonicalCookie::CookieInclusionStatus CanonicalCookie::IncludeForRequestURL( } // TODO(chlily): Log metrics. - return status; + return CookieAccessResult(effective_same_site, status); } -CanonicalCookie::CookieInclusionStatus CanonicalCookie::IsSetPermittedInContext( +CookieInclusionStatus CanonicalCookie::IsSetPermittedInContext( const CookieOptions& options, CookieAccessSemantics access_semantics) const { CookieInclusionStatus status; @@ -730,7 +698,7 @@ void CanonicalCookie::IsSetPermittedInContext( DVLOG(net::cookie_util::kVlogSetCookies) << "SetCookie() rejecting insecure cookie with SameSite=None."; status->AddExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE); + CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE); } // Log whether a SameSite=None cookie is Secure or not. if (SameSite() == CookieSameSite::NO_RESTRICTION) { @@ -867,10 +835,10 @@ std::string CanonicalCookie::BuildCookieLine(const CookieList& cookies) { // static std::string CanonicalCookie::BuildCookieLine( - const CookieStatusList& cookie_status_list) { + const CookieAccessResultList& cookie_access_result_list) { std::string cookie_line; - for (const auto& cookie_with_status : cookie_status_list) { - const CanonicalCookie& cookie = cookie_with_status.cookie; + for (const auto& cookie_with_access_result : cookie_access_result_list) { + const CanonicalCookie& cookie = cookie_with_access_result.cookie; AppendCookieLineEntry(cookie, &cookie_line); } return cookie_line; @@ -973,289 +941,12 @@ bool CanonicalCookie::IsRecentlyCreated(base::TimeDelta age_threshold) const { return (base::Time::Now() - creation_date_) <= age_threshold; } -CanonicalCookie::CookieInclusionStatus::CookieInclusionStatus() - : exclusion_reasons_(0u), warning_reasons_(0u) {} - -CanonicalCookie::CookieInclusionStatus::CookieInclusionStatus( - ExclusionReason reason) - : exclusion_reasons_(GetExclusionBitmask(reason)) {} - -CanonicalCookie::CookieInclusionStatus::CookieInclusionStatus( - ExclusionReason reason, - WarningReason warning) - : exclusion_reasons_(GetExclusionBitmask(reason)), - warning_reasons_(GetWarningBitmask(warning)) {} - -bool CanonicalCookie::CookieInclusionStatus::operator==( - const CookieInclusionStatus& other) const { - return exclusion_reasons_ == other.exclusion_reasons_ && - warning_reasons_ == other.warning_reasons_; -} - -bool CanonicalCookie::CookieInclusionStatus::operator!=( - const CookieInclusionStatus& other) const { - return !operator==(other); -} - -bool CanonicalCookie::CookieInclusionStatus::IsInclude() const { - return exclusion_reasons_ == 0u; -} - -bool CanonicalCookie::CookieInclusionStatus::HasExclusionReason( - ExclusionReason reason) const { - return exclusion_reasons_ & GetExclusionBitmask(reason); -} - -void CanonicalCookie::CookieInclusionStatus::AddExclusionReason( - ExclusionReason reason) { - exclusion_reasons_ |= GetExclusionBitmask(reason); - // If the cookie would be excluded for reasons other than the new SameSite - // rules, don't bother warning about it. - MaybeClearSameSiteWarning(); -} - -void CanonicalCookie::CookieInclusionStatus::RemoveExclusionReason( - ExclusionReason reason) { - exclusion_reasons_ &= ~(GetExclusionBitmask(reason)); -} - -void CanonicalCookie::CookieInclusionStatus::MaybeClearSameSiteWarning() { - uint32_t samesite_reasons_mask = - GetExclusionBitmask(EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX) | - GetExclusionBitmask(EXCLUDE_SAMESITE_NONE_INSECURE); - if (exclusion_reasons_ & ~samesite_reasons_mask) { - RemoveWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); - RemoveWarningReason( - CanonicalCookie::CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE); - RemoveWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE); - } - - uint32_t context_reasons_mask = - GetExclusionBitmask(EXCLUDE_SAMESITE_STRICT) | - GetExclusionBitmask(EXCLUDE_SAMESITE_LAX) | - GetExclusionBitmask(EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX); - if (exclusion_reasons_ & ~context_reasons_mask) { - RemoveWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE); - RemoveWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE); - RemoveWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE); - RemoveWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE); - RemoveWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE); - } -} - -bool CanonicalCookie::CookieInclusionStatus::ShouldRecordDowngradeMetrics() - const { - uint32_t context_reasons_mask = - GetExclusionBitmask(EXCLUDE_SAMESITE_STRICT) | - GetExclusionBitmask(EXCLUDE_SAMESITE_LAX) | - GetExclusionBitmask(EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX); - - return (exclusion_reasons_ & ~context_reasons_mask) == 0u; -} - -bool CanonicalCookie::CookieInclusionStatus::ShouldWarn() const { - return warning_reasons_ != 0u; -} - -bool CanonicalCookie::CookieInclusionStatus::HasWarningReason( - WarningReason reason) const { - return warning_reasons_ & GetWarningBitmask(reason); -} - -bool net::CanonicalCookie::CookieInclusionStatus::HasDowngradeWarning( - CookieInclusionStatus::WarningReason* reason) const { - if (!ShouldWarn()) - return false; - - const CookieInclusionStatus::WarningReason kDowngradeWarnings[] = { - WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE, - WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE, - WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE, - WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE, - WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE, - }; - - for (auto warning : kDowngradeWarnings) { - if (!HasWarningReason(warning)) - continue; - - if (reason) - *reason = warning; - - return true; - } - - return false; -} - -void CanonicalCookie::CookieInclusionStatus::AddWarningReason( - WarningReason reason) { - warning_reasons_ |= GetWarningBitmask(reason); -} - -void CanonicalCookie::CookieInclusionStatus::RemoveWarningReason( - WarningReason reason) { - warning_reasons_ &= ~(GetWarningBitmask(reason)); -} - -CanonicalCookie::CookieInclusionStatus::ContextDowngradeMetricValues -CanonicalCookie::CookieInclusionStatus::GetBreakingDowngradeMetricsEnumValue( - const GURL& url) const { - bool url_is_secure = url.SchemeIsCryptographic(); - - // Start the |reason| as something other than the downgrade warnings. - WarningReason reason = WarningReason::NUM_WARNING_REASONS; - - // Don't bother checking the return value because the default switch case - // will handle if no reason was found. - HasDowngradeWarning(&reason); - - switch (reason) { - case WarningReason::WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE: - return url_is_secure - ? ContextDowngradeMetricValues::STRICT_LAX_STRICT_SECURE - : ContextDowngradeMetricValues::STRICT_LAX_STRICT_INSECURE; - case WarningReason::WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE: - return url_is_secure - ? ContextDowngradeMetricValues::STRICT_CROSS_STRICT_SECURE - : ContextDowngradeMetricValues::STRICT_CROSS_STRICT_INSECURE; - case WarningReason::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE: - return url_is_secure - ? ContextDowngradeMetricValues::STRICT_CROSS_LAX_SECURE - : ContextDowngradeMetricValues::STRICT_CROSS_LAX_INSECURE; - case WarningReason::WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE: - return url_is_secure - ? ContextDowngradeMetricValues::LAX_CROSS_STRICT_SECURE - : ContextDowngradeMetricValues::LAX_CROSS_STRICT_INSECURE; - case WarningReason::WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE: - return url_is_secure - ? ContextDowngradeMetricValues::LAX_CROSS_LAX_SECURE - : ContextDowngradeMetricValues::LAX_CROSS_LAX_INSECURE; - default: - return url_is_secure - ? ContextDowngradeMetricValues::NO_DOWNGRADE_SECURE - : ContextDowngradeMetricValues::NO_DOWNGRADE_INSECURE; - } -} - -std::string CanonicalCookie::CookieInclusionStatus::GetDebugString() const { - std::string out; - - // Inclusion/exclusion - if (IsInclude()) - base::StrAppend(&out, {"INCLUDE, "}); - if (HasExclusionReason(EXCLUDE_UNKNOWN_ERROR)) - base::StrAppend(&out, {"EXCLUDE_UNKNOWN_ERROR, "}); - if (HasExclusionReason(EXCLUDE_HTTP_ONLY)) - base::StrAppend(&out, {"EXCLUDE_HTTP_ONLY, "}); - if (HasExclusionReason(EXCLUDE_SECURE_ONLY)) - base::StrAppend(&out, {"EXCLUDE_SECURE_ONLY, "}); - if (HasExclusionReason(EXCLUDE_DOMAIN_MISMATCH)) - base::StrAppend(&out, {"EXCLUDE_DOMAIN_MISMATCH, "}); - if (HasExclusionReason(EXCLUDE_NOT_ON_PATH)) - base::StrAppend(&out, {"EXCLUDE_NOT_ON_PATH, "}); - if (HasExclusionReason(EXCLUDE_SAMESITE_STRICT)) - base::StrAppend(&out, {"EXCLUDE_SAMESITE_STRICT, "}); - if (HasExclusionReason(EXCLUDE_SAMESITE_LAX)) - base::StrAppend(&out, {"EXCLUDE_SAMESITE_LAX, "}); - if (HasExclusionReason(EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX)) - base::StrAppend(&out, {"EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX, "}); - if (HasExclusionReason(EXCLUDE_SAMESITE_NONE_INSECURE)) - base::StrAppend(&out, {"EXCLUDE_SAMESITE_NONE_INSECURE, "}); - if (HasExclusionReason(EXCLUDE_USER_PREFERENCES)) - base::StrAppend(&out, {"EXCLUDE_USER_PREFERENCES, "}); - if (HasExclusionReason(EXCLUDE_FAILURE_TO_STORE)) - base::StrAppend(&out, {"EXCLUDE_FAILURE_TO_STORE, "}); - if (HasExclusionReason(EXCLUDE_NONCOOKIEABLE_SCHEME)) - base::StrAppend(&out, {"EXCLUDE_NONCOOKIEABLE_SCHEME, "}); - if (HasExclusionReason(EXCLUDE_OVERWRITE_SECURE)) - base::StrAppend(&out, {"EXCLUDE_OVERWRITE_SECURE, "}); - if (HasExclusionReason(EXCLUDE_OVERWRITE_HTTP_ONLY)) - base::StrAppend(&out, {"EXCLUDE_OVERWRITE_HTTP_ONLY, "}); - if (HasExclusionReason(EXCLUDE_INVALID_DOMAIN)) - base::StrAppend(&out, {"EXCLUDE_INVALID_DOMAIN, "}); - if (HasExclusionReason(EXCLUDE_INVALID_PREFIX)) - base::StrAppend(&out, {"EXCLUDE_INVALID_PREFIX, "}); - - // Add warning - if (!ShouldWarn()) { - base::StrAppend(&out, {"DO_NOT_WARN"}); - return out; - } - - if (HasWarningReason(WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT)) - base::StrAppend(&out, {"WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT, "}); - if (HasWarningReason(WARN_SAMESITE_NONE_INSECURE)) - base::StrAppend(&out, {"WARN_SAMESITE_NONE_INSECURE, "}); - if (HasWarningReason(WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE)) - base::StrAppend(&out, {"WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE, "}); - if (HasWarningReason(WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE)) - base::StrAppend(&out, {"WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE, "}); - if (HasWarningReason(WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE)) - base::StrAppend(&out, {"WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE, "}); - if (HasWarningReason(WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE)) - base::StrAppend(&out, {"WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE, "}); - if (HasWarningReason(WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE)) - base::StrAppend(&out, {"WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE, "}); - if (HasWarningReason(WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE)) - base::StrAppend(&out, {"WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE, "}); - - // Strip trailing comma and space. - out.erase(out.end() - 2, out.end()); - - return out; -} - -bool CanonicalCookie::CookieInclusionStatus::IsValid() const { - // Bit positions where there should not be any true bits. - uint32_t exclusion_mask = ~0u << static_cast<int>(NUM_EXCLUSION_REASONS); - uint32_t warning_mask = ~0u << static_cast<int>(NUM_WARNING_REASONS); - return (exclusion_mask & exclusion_reasons_) == 0u && - (warning_mask & warning_reasons_) == 0u; -} - -bool CanonicalCookie::CookieInclusionStatus:: - HasExactlyExclusionReasonsForTesting( - std::vector<CanonicalCookie::CookieInclusionStatus::ExclusionReason> - reasons) const { - CookieInclusionStatus expected = MakeFromReasonsForTesting(reasons); - return expected.exclusion_reasons_ == exclusion_reasons_; -} - -bool CanonicalCookie::CookieInclusionStatus::HasExactlyWarningReasonsForTesting( - std::vector<WarningReason> reasons) const { - CookieInclusionStatus expected = MakeFromReasonsForTesting({}, reasons); - return expected.warning_reasons_ == warning_reasons_; -} - -// static -CanonicalCookie::CookieInclusionStatus -CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting( - std::vector<ExclusionReason> reasons, - std::vector<WarningReason> warnings) { - CookieInclusionStatus status; - for (ExclusionReason reason : reasons) { - status.AddExclusionReason(reason); - } - for (WarningReason warning : warnings) { - status.AddWarningReason(warning); - } - return status; -} - CookieAndLineWithStatus::CookieAndLineWithStatus() = default; CookieAndLineWithStatus::CookieAndLineWithStatus( base::Optional<CanonicalCookie> cookie, std::string cookie_string, - CanonicalCookie::CookieInclusionStatus status) + CookieInclusionStatus status) : cookie(std::move(cookie)), cookie_string(std::move(cookie_string)), status(status) {} diff --git a/chromium/net/cookies/canonical_cookie.h b/chromium/net/cookies/canonical_cookie.h index 10b66c661b2..aa538085ac8 100644 --- a/chromium/net/cookies/canonical_cookie.h +++ b/chromium/net/cookies/canonical_cookie.h @@ -14,7 +14,9 @@ #include "base/optional.h" #include "base/time/time.h" #include "net/base/net_export.h" +#include "net/cookies/cookie_access_result.h" #include "net/cookies/cookie_constants.h" +#include "net/cookies/cookie_inclusion_status.h" #include "net/cookies/cookie_options.h" class GURL; @@ -25,15 +27,16 @@ class ParsedCookie; class CanonicalCookie; struct CookieWithStatus; +struct CookieWithAccessResult; struct CookieAndLineWithStatus; using CookieList = std::vector<CanonicalCookie>; using CookieStatusList = std::vector<CookieWithStatus>; using CookieAndLineStatusList = std::vector<CookieAndLineWithStatus>; +using CookieAccessResultList = std::vector<CookieWithAccessResult>; class NET_EXPORT CanonicalCookie { public: - class CookieInclusionStatus; using UniqueCookieKey = std::tuple<std::string, std::string, std::string>; CanonicalCookie(); @@ -228,7 +231,7 @@ class NET_EXPORT CanonicalCookie { // request |url| using the CookieInclusionStatus enum. HTTP only cookies can // be filter by using appropriate cookie |options|. PLEASE NOTE that this // method does not check whether a cookie is expired or not! - CookieInclusionStatus IncludeForRequestURL( + CookieAccessResult IncludeForRequestURL( const GURL& url, const CookieOptions& options, CookieAccessSemantics access_semantics = @@ -294,8 +297,9 @@ class NET_EXPORT CanonicalCookie { // by |cookies|. The string is built in the same order as the given list. static std::string BuildCookieLine(const CookieList& cookies); - // Same as above but takes a CookieStatusList (ignores the statuses). - static std::string BuildCookieLine(const CookieStatusList& cookies); + // Same as above but takes a CookieAccessResultList + // (ignores the access result). + static std::string BuildCookieLine(const CookieAccessResultList& cookies); private: FRIEND_TEST_ALL_PREFIXES(CanonicalCookieTest, TestPrefixHistograms); @@ -358,250 +362,11 @@ class NET_EXPORT CanonicalCookie { CookieSourceScheme source_scheme_; }; -// This class represents if a cookie was included or excluded in a cookie get or -// set operation, and if excluded why. It holds a vector of reasons for -// exclusion, where cookie inclusion is represented by the absence of any -// exclusion reasons. Also marks whether a cookie should be warned about, e.g. -// for deprecation or intervention reasons. -// TODO(chlily): Rename/move this to just net::CookieInclusionStatus. -class NET_EXPORT CanonicalCookie::CookieInclusionStatus { - public: - // Types of reasons why a cookie might be excluded. - // If adding a ExclusionReason, please also update the GetDebugString() - // method. - enum ExclusionReason { - EXCLUDE_UNKNOWN_ERROR = 0, - - EXCLUDE_HTTP_ONLY = 1, - EXCLUDE_SECURE_ONLY = 2, - EXCLUDE_DOMAIN_MISMATCH = 3, - EXCLUDE_NOT_ON_PATH = 4, - EXCLUDE_SAMESITE_STRICT = 5, - EXCLUDE_SAMESITE_LAX = 6, - - // The following two are used for the SameSiteByDefaultCookies experiment, - // where if the SameSite attribute is not specified, it will be treated as - // SameSite=Lax by default. - EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX = 7, - // This is used if SameSite=None is specified, but the cookie is not - // Secure. - EXCLUDE_SAMESITE_NONE_INSECURE = 8, - EXCLUDE_USER_PREFERENCES = 9, - - // Statuses specific to setting cookies - EXCLUDE_FAILURE_TO_STORE = 10, - EXCLUDE_NONCOOKIEABLE_SCHEME = 11, - EXCLUDE_OVERWRITE_SECURE = 12, - EXCLUDE_OVERWRITE_HTTP_ONLY = 13, - EXCLUDE_INVALID_DOMAIN = 14, - EXCLUDE_INVALID_PREFIX = 15, - - // This should be kept last. - NUM_EXCLUSION_REASONS - }; - - // Reason to warn about a cookie. If you add one, please update - // GetDebugString(). - enum WarningReason { - // Of the following 3 SameSite warnings, there will be, at most, a single - // active one. - - // Warn if a cookie with unspecified SameSite attribute is used in a - // cross-site context. - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT = 0, - // Warn if a cookie with SameSite=None is not Secure. - WARN_SAMESITE_NONE_INSECURE = 1, - // Warn if a cookie with unspecified SameSite attribute is defaulted into - // Lax and is sent on a request with unsafe method, only because it is new - // enough to activate the Lax-allow-unsafe intervention. - WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE = 2, - - // The following warnings indicate that an included cookie with an effective - // SameSite is experiencing a SameSiteCookieContext::|context| -> - // SameSiteCookieContext::|schemeful_context| downgrade that will prevent - // its access schemefully. - // This situation means that a cookie is accessible when the - // SchemefulSameSite feature is disabled but not when it's enabled, - // indicating changed behavior and potential breakage. - // - // For example, a Strict to Lax downgrade for an effective SameSite=Strict - // cookie: - // This cookie would be accessible in the Strict context as its SameSite - // value is Strict. However its context for schemeful same-site becomes Lax. - // A strict cookie cannot be accessed in a Lax context and therefore the - // behavior has changed. - // As a counterexample, a Strict to Lax downgrade for an effective - // SameSite=Lax cookie: A Lax cookie can be accessed in both Strict and Lax - // contexts so there is no behavior change (and we don't warn about it). - // - // The warnings are in the following format: - // WARN_{context}_{schemeful_context}_DOWNGRADE_{samesite_value}_SAMESITE - // - // Of the following 5 SameSite warnings, there will be, at most, a single - // active one. - - // Strict to Lax downgrade for an effective SameSite=Strict cookie. - // This warning is only applicable for cookies being sent because a Strict - // cookie will be set in both Strict and Lax Contexts so the downgrade will - // not affect it. - WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE = 3, - // Strict to Cross-site downgrade for an effective SameSite=Strict cookie. - // This also applies to Strict to Lax Unsafe downgrades due to Lax Unsafe - // behaving like Cross-site. - WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE = 4, - // Strict to Cross-site downgrade for an effective SameSite=Lax cookie. - // This also applies to Strict to Lax Unsafe downgrades due to Lax Unsafe - // behaving like Cross-site. - WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE = 5, - // Lax to Cross-site downgrade for an effective SameSite=Strict cookie. - // This warning is only applicable for cookies being set because a Strict - // cookie will not be sent in a Lax context so the downgrade would not - // affect it. - WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE = 6, - // Lax to Cross-site downgrade for an effective SameSite=Lax cookie. - WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE = 7, - - // This should be kept last. - NUM_WARNING_REASONS - }; - - // These enums encode the context downgrade warnings + the secureness of the - // url sending/setting the cookie. They're used for metrics only. The format - // is {context}_{schemeful_context}_{samesite_value}_{securness}. - // NO_DOWNGRADE_{securness} indicates that a cookie didn't have a breaking - // context downgrade and was A) included B) excluded only due to insufficient - // same-site context. I.e. the cookie wasn't excluded due to other reasons - // such as third-party cookie blocking. Keep this in line with - // SameSiteCookieContextBreakingDowngradeWithSecureness in enums.xml. - enum ContextDowngradeMetricValues { - NO_DOWNGRADE_INSECURE = 0, - NO_DOWNGRADE_SECURE = 1, - - STRICT_LAX_STRICT_INSECURE = 2, - STRICT_CROSS_STRICT_INSECURE = 3, - STRICT_CROSS_LAX_INSECURE = 4, - LAX_CROSS_STRICT_INSECURE = 5, - LAX_CROSS_LAX_INSECURE = 6, - - STRICT_LAX_STRICT_SECURE = 7, - STRICT_CROSS_STRICT_SECURE = 8, - STRICT_CROSS_LAX_SECURE = 9, - LAX_CROSS_STRICT_SECURE = 10, - LAX_CROSS_LAX_SECURE = 11, - - // Keep last. - kMaxValue = LAX_CROSS_LAX_SECURE - }; - // Makes a status that says include and should not warn. - CookieInclusionStatus(); - - // Make a status that contains the given exclusion reason. - explicit CookieInclusionStatus(ExclusionReason reason); - // Makes a status that contains the given exclusion reason and warning. - CookieInclusionStatus(ExclusionReason reason, WarningReason warning); - - bool operator==(const CookieInclusionStatus& other) const; - bool operator!=(const CookieInclusionStatus& other) const; - - // Whether the status is to include the cookie, and has no other reasons for - // exclusion. - bool IsInclude() const; - - // Whether the given reason for exclusion is present. - bool HasExclusionReason(ExclusionReason status_type) const; - - // Add an exclusion reason. - void AddExclusionReason(ExclusionReason status_type); - - // Remove an exclusion reason. - void RemoveExclusionReason(ExclusionReason reason); - - // If the cookie would have been excluded for reasons other than - // SAMESITE_UNSPECIFIED_TREATED_AS_LAX or SAMESITE_NONE_INSECURE, don't bother - // warning about it (clear the warning). - void MaybeClearSameSiteWarning(); - - // Whether to record the breaking downgrade metrics if the cookie is included - // or if it's only excluded because of insufficient same-site context. - bool ShouldRecordDowngradeMetrics() const; - - // Whether the cookie should be warned about. - bool ShouldWarn() const; - - // Whether the given reason for warning is present. - bool HasWarningReason(WarningReason reason) const; - - // Whether a schemeful downgrade warning is present. - // A schemeful downgrade means that an included cookie with an effective - // SameSite is experiencing a SameSiteCookieContext::|context| -> - // SameSiteCookieContext::|schemeful_context| downgrade that will prevent its - // access schemefully. If the function returns true and |reason| is valid then - // |reason| will contain which warning was found. - bool HasDowngradeWarning( - CookieInclusionStatus::WarningReason* reason = nullptr) const; - - // Add an warning reason. - void AddWarningReason(WarningReason reason); - - // Remove an warning reason. - void RemoveWarningReason(WarningReason reason); - - // Used for serialization/deserialization. - uint32_t exclusion_reasons() const { return exclusion_reasons_; } - void set_exclusion_reasons(uint32_t exclusion_reasons) { - exclusion_reasons_ = exclusion_reasons; - } - - uint32_t warning_reasons() const { return warning_reasons_; } - void set_warning_reasons(uint32_t warning_reasons) { - warning_reasons_ = warning_reasons; - } - - ContextDowngradeMetricValues GetBreakingDowngradeMetricsEnumValue( - const GURL& url) const; - - // Get exclusion reason(s) and warning in string format. - std::string GetDebugString() const; - - // Checks that the underlying bit vector representation doesn't contain any - // extraneous bits that are not mapped to any enum values. Does not check - // for reasons which semantically cannot coexist. - bool IsValid() const; - - // Checks whether the exclusion reasons are exactly the set of exclusion - // reasons in the vector. (Ignores warnings.) - bool HasExactlyExclusionReasonsForTesting( - std::vector<ExclusionReason> reasons) const; - - // Checks whether the warning reasons are exactly the set of warning - // reasons in the vector. (Ignores exclusions.) - bool HasExactlyWarningReasonsForTesting( - std::vector<WarningReason> reasons) const; - - // Makes a status that contains the given exclusion reasons and warning. - static CookieInclusionStatus MakeFromReasonsForTesting( - std::vector<ExclusionReason> reasons, - std::vector<WarningReason> warnings = std::vector<WarningReason>()); - - private: - // A bit vector of the applicable exclusion reasons. - uint32_t exclusion_reasons_ = 0u; - - // A bit vector of the applicable warning reasons. - uint32_t warning_reasons_ = 0u; -}; - -NET_EXPORT inline std::ostream& operator<<( - std::ostream& os, - const CanonicalCookie::CookieInclusionStatus status) { - return os << status.GetDebugString(); -} - // These enable us to pass along a list of excluded cookie with the reason they // were excluded struct CookieWithStatus { CanonicalCookie cookie; - CanonicalCookie::CookieInclusionStatus status; + CookieInclusionStatus status; }; // Used to pass excluded cookie information when it's possible that the @@ -610,7 +375,7 @@ struct NET_EXPORT CookieAndLineWithStatus { CookieAndLineWithStatus(); CookieAndLineWithStatus(base::Optional<CanonicalCookie> cookie, std::string cookie_string, - CanonicalCookie::CookieInclusionStatus status); + CookieInclusionStatus status); CookieAndLineWithStatus( const CookieAndLineWithStatus& cookie_and_line_with_status); @@ -624,7 +389,12 @@ struct NET_EXPORT CookieAndLineWithStatus { base::Optional<CanonicalCookie> cookie; std::string cookie_string; - CanonicalCookie::CookieInclusionStatus status; + CookieInclusionStatus status; +}; + +struct CookieWithAccessResult { + CanonicalCookie cookie; + CookieAccessResult access_result; }; } // namespace net diff --git a/chromium/net/cookies/canonical_cookie_unittest.cc b/chromium/net/cookies/canonical_cookie_unittest.cc index 68548deed97..77465c83b92 100644 --- a/chromium/net/cookies/canonical_cookie_unittest.cc +++ b/chromium/net/cookies/canonical_cookie_unittest.cc @@ -125,7 +125,7 @@ TEST(CanonicalCookieTest, Create) { // 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; + CookieInclusionStatus status; cookie = CanonicalCookie::Create(url, "A=2; Secure", creation_time, server_time, &status); EXPECT_TRUE(cookie->IsSecure()); @@ -218,7 +218,7 @@ TEST(CanonicalCookieTest, CreateHttpOnly) { GURL url("http://www.example.com/test/foo.html"); base::Time now = base::Time::Now(); base::Optional<base::Time> server_time = base::nullopt; - CanonicalCookie::CookieInclusionStatus status; + CookieInclusionStatus status; // An HttpOnly cookie can be created. std::unique_ptr<CanonicalCookie> cookie = @@ -231,13 +231,13 @@ TEST(CanonicalCookieTest, CreateWithInvalidDomain) { GURL url("http://www.example.com/test/foo.html"); base::Time now = base::Time::Now(); base::Optional<base::Time> server_time = base::nullopt; - CanonicalCookie::CookieInclusionStatus status; + CookieInclusionStatus status; std::unique_ptr<CanonicalCookie> 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})); + {CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN})); } TEST(CanonicalCookieTest, EmptyExpiry) { @@ -656,50 +656,47 @@ TEST(CanonicalCookieTest, IncludeForRequestURL) { std::unique_ptr<CanonicalCookie> cookie( CanonicalCookie::Create(url, "A=2", creation_time, server_time)); - EXPECT_TRUE(cookie->IncludeForRequestURL(url, options).IsInclude()); + EXPECT_TRUE(cookie->IncludeForRequestURL(url, options).status.IsInclude()); EXPECT_TRUE(cookie ->IncludeForRequestURL(GURL("http://www.example.com/foo/bar"), options) - .IsInclude()); + .status.IsInclude()); EXPECT_TRUE(cookie ->IncludeForRequestURL( GURL("https://www.example.com/foo/bar"), options) - .IsInclude()); + .status.IsInclude()); EXPECT_TRUE( cookie->IncludeForRequestURL(GURL("https://sub.example.com"), options) - .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_DOMAIN_MISMATCH})); + .status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_DOMAIN_MISMATCH})); EXPECT_TRUE( cookie->IncludeForRequestURL(GURL("https://sub.www.example.com"), options) - .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_DOMAIN_MISMATCH})); + .status.HasExactlyExclusionReasonsForTesting( + {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(url, options) + .status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_NOT_ON_PATH})); EXPECT_TRUE( cookie ->IncludeForRequestURL( GURL("http://www.example.com/foo/bar/index.html"), options) - .IsInclude()); + .status.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})); + cookie->IncludeForRequestURL(secure_url, options).status.IsInclude()); + EXPECT_TRUE(cookie->IncludeForRequestURL(url, options) + .status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_SECURE_ONLY})); // Test that http only cookies are only included if the include httponly flag // is set on the cookie options. @@ -707,12 +704,11 @@ TEST(CanonicalCookieTest, IncludeForRequestURL) { cookie = CanonicalCookie::Create(url, "A=2; HttpOnly", creation_time, server_time); EXPECT_TRUE(cookie->IsHttpOnly()); - EXPECT_TRUE(cookie->IncludeForRequestURL(url, options).IsInclude()); + EXPECT_TRUE(cookie->IncludeForRequestURL(url, options).status.IsInclude()); options.set_exclude_httponly(); - EXPECT_TRUE( - cookie->IncludeForRequestURL(url, options) - .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY})); + EXPECT_TRUE(cookie->IncludeForRequestURL(url, options) + .status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_HTTP_ONLY})); } struct IncludeForRequestURLTestCase { @@ -720,7 +716,7 @@ struct IncludeForRequestURLTestCase { CookieSameSite expected_samesite; CookieEffectiveSameSite expected_effective_samesite; CookieOptions::SameSiteCookieContext request_options_samesite_context; - CanonicalCookie::CookieInclusionStatus expected_inclusion_status; + CookieInclusionStatus expected_inclusion_status; base::TimeDelta creation_time_delta = base::TimeDelta(); }; @@ -742,16 +738,16 @@ void VerifyIncludeForRequestURLTestCases( std::unique_ptr<CanonicalCookie> 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); + net::CookieAccessResult access_result = + cookie->IncludeForRequestURL(url, request_options, access_semantics); - EXPECT_EQ( - test.expected_inclusion_status, - cookie->IncludeForRequestURL(url, request_options, access_semantics)); + EXPECT_EQ(test.expected_inclusion_status, access_result.status); + EXPECT_EQ(test.expected_effective_samesite, + access_result.effective_same_site); } } @@ -770,131 +766,116 @@ TEST(CanonicalCookieTest, IncludeForRequestURLSameSite) { {"Common=1;SameSite=Strict", CookieSameSite::STRICT_MODE, CookieEffectiveSameSite::STRICT_MODE, SameSiteCookieContext(SameSiteCookieContext::ContextType::CROSS_SITE), - CanonicalCookie::CookieInclusionStatus( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT)}, + CookieInclusionStatus(CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT)}, {"Common=2;SameSite=Strict", CookieSameSite::STRICT_MODE, CookieEffectiveSameSite::STRICT_MODE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_LAX_METHOD_UNSAFE), - CanonicalCookie::CookieInclusionStatus( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT)}, + CookieInclusionStatus(CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT)}, {"Common=3;SameSite=Strict", CookieSameSite::STRICT_MODE, CookieEffectiveSameSite::STRICT_MODE, SameSiteCookieContext(SameSiteCookieContext::ContextType::SAME_SITE_LAX), - CanonicalCookie::CookieInclusionStatus( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT)}, + CookieInclusionStatus(CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT)}, {"Common=4;SameSite=Strict", CookieSameSite::STRICT_MODE, CookieEffectiveSameSite::STRICT_MODE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_STRICT), - CanonicalCookie::CookieInclusionStatus()}, + CookieInclusionStatus()}, // Strict cookies with downgrade: {"Common=5;SameSite=Strict", CookieSameSite::STRICT_MODE, CookieEffectiveSameSite::STRICT_MODE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_STRICT, SameSiteCookieContext::ContextType::SAME_SITE_LAX), - CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting( - std::vector< - CanonicalCookie::CookieInclusionStatus::ExclusionReason>(), - {CanonicalCookie::CookieInclusionStatus:: - WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE})}, + CookieInclusionStatus::MakeFromReasonsForTesting( + std::vector<CookieInclusionStatus::ExclusionReason>(), + {CookieInclusionStatus::WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE})}, {"Common=6;SameSite=Strict", CookieSameSite::STRICT_MODE, CookieEffectiveSameSite::STRICT_MODE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_STRICT, SameSiteCookieContext::ContextType::SAME_SITE_LAX_METHOD_UNSAFE), - CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting( - std::vector< - CanonicalCookie::CookieInclusionStatus::ExclusionReason>(), - {CanonicalCookie::CookieInclusionStatus:: + CookieInclusionStatus::MakeFromReasonsForTesting( + std::vector<CookieInclusionStatus::ExclusionReason>(), + {CookieInclusionStatus:: WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE})}, {"Common=7;SameSite=Strict", CookieSameSite::STRICT_MODE, CookieEffectiveSameSite::STRICT_MODE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_STRICT, SameSiteCookieContext::ContextType::CROSS_SITE), - CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting( - std::vector< - CanonicalCookie::CookieInclusionStatus::ExclusionReason>(), - {CanonicalCookie::CookieInclusionStatus:: + CookieInclusionStatus::MakeFromReasonsForTesting( + std::vector<CookieInclusionStatus::ExclusionReason>(), + {CookieInclusionStatus:: WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE})}, // Lax cookies: {"Common=8;SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext(SameSiteCookieContext::ContextType::CROSS_SITE), - CanonicalCookie::CookieInclusionStatus( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX)}, + CookieInclusionStatus(CookieInclusionStatus::EXCLUDE_SAMESITE_LAX)}, {"Common=9;SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_LAX_METHOD_UNSAFE), - CanonicalCookie::CookieInclusionStatus( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX)}, + CookieInclusionStatus(CookieInclusionStatus::EXCLUDE_SAMESITE_LAX)}, {"Common=10;SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext(SameSiteCookieContext::ContextType::SAME_SITE_LAX), - CanonicalCookie::CookieInclusionStatus()}, + CookieInclusionStatus()}, {"Common=11;SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_STRICT), - CanonicalCookie::CookieInclusionStatus()}, + CookieInclusionStatus()}, // Lax cookies with downgrade: {"Common=12;SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_STRICT, SameSiteCookieContext::ContextType::SAME_SITE_LAX), - CanonicalCookie::CookieInclusionStatus()}, + CookieInclusionStatus()}, {"Common=13;SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_STRICT, SameSiteCookieContext::ContextType::SAME_SITE_LAX_METHOD_UNSAFE), - CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting( - std::vector< - CanonicalCookie::CookieInclusionStatus::ExclusionReason>(), - {CanonicalCookie::CookieInclusionStatus:: - WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE})}, + CookieInclusionStatus::MakeFromReasonsForTesting( + std::vector<CookieInclusionStatus::ExclusionReason>(), + {CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE})}, {"Common=14;SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_STRICT, SameSiteCookieContext::ContextType::CROSS_SITE), - CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting( - std::vector< - CanonicalCookie::CookieInclusionStatus::ExclusionReason>(), - {CanonicalCookie::CookieInclusionStatus:: - WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE})}, + CookieInclusionStatus::MakeFromReasonsForTesting( + std::vector<CookieInclusionStatus::ExclusionReason>(), + {CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE})}, {"Common=15;SameSite=Lax", CookieSameSite::LAX_MODE, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext(SameSiteCookieContext::ContextType::SAME_SITE_LAX, SameSiteCookieContext::ContextType::CROSS_SITE), - CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting( - std::vector< - CanonicalCookie::CookieInclusionStatus::ExclusionReason>(), - {CanonicalCookie::CookieInclusionStatus:: - WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE})}, + CookieInclusionStatus::MakeFromReasonsForTesting( + std::vector<CookieInclusionStatus::ExclusionReason>(), + {CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE})}, // None and Secure cookies: {"Common=16;SameSite=None;Secure", CookieSameSite::NO_RESTRICTION, CookieEffectiveSameSite::NO_RESTRICTION, SameSiteCookieContext(SameSiteCookieContext::ContextType::CROSS_SITE), - CanonicalCookie::CookieInclusionStatus()}, + CookieInclusionStatus()}, {"Common=17;SameSite=None;Secure", CookieSameSite::NO_RESTRICTION, CookieEffectiveSameSite::NO_RESTRICTION, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_LAX_METHOD_UNSAFE), - CanonicalCookie::CookieInclusionStatus()}, + CookieInclusionStatus()}, {"Common=18;SameSite=None;Secure", CookieSameSite::NO_RESTRICTION, CookieEffectiveSameSite::NO_RESTRICTION, SameSiteCookieContext(SameSiteCookieContext::ContextType::SAME_SITE_LAX), - CanonicalCookie::CookieInclusionStatus()}, + CookieInclusionStatus()}, {"Common=19;SameSite=None;Secure", CookieSameSite::NO_RESTRICTION, CookieEffectiveSameSite::NO_RESTRICTION, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_STRICT), - CanonicalCookie::CookieInclusionStatus()}}; + CookieInclusionStatus()}}; // Test cases where the default is None (either access semantics is LEGACY, or // semantics is UNKNOWN and feature is enabled): @@ -903,29 +884,27 @@ TEST(CanonicalCookieTest, IncludeForRequestURLSameSite) { {"DefaultNone=1", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::NO_RESTRICTION, SameSiteCookieContext(SameSiteCookieContext::ContextType::CROSS_SITE), - CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting( - std::vector< - CanonicalCookie::CookieInclusionStatus::ExclusionReason>(), - {CanonicalCookie::CookieInclusionStatus:: + CookieInclusionStatus::MakeFromReasonsForTesting( + std::vector<CookieInclusionStatus::ExclusionReason>(), + {CookieInclusionStatus:: WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT})}, {"DefaultNone=2", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::NO_RESTRICTION, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_LAX_METHOD_UNSAFE), - CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting( - std::vector< - CanonicalCookie::CookieInclusionStatus::ExclusionReason>(), - {CanonicalCookie::CookieInclusionStatus:: + CookieInclusionStatus::MakeFromReasonsForTesting( + std::vector<CookieInclusionStatus::ExclusionReason>(), + {CookieInclusionStatus:: WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT})}, {"DefaultNone=3", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::NO_RESTRICTION, SameSiteCookieContext(SameSiteCookieContext::ContextType::SAME_SITE_LAX), - CanonicalCookie::CookieInclusionStatus()}, + CookieInclusionStatus()}, {"DefaultNone=4", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::NO_RESTRICTION, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_STRICT), - CanonicalCookie::CookieInclusionStatus()}}; + CookieInclusionStatus()}}; // Test cases where the default is Lax (either access semantics is NONLEGACY, // or access semantics is UNKNOWN and feature is enabled): @@ -934,60 +913,52 @@ TEST(CanonicalCookieTest, IncludeForRequestURLSameSite) { {"DefaultLax=1", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, SameSiteCookieContext(SameSiteCookieContext::ContextType::CROSS_SITE), - CanonicalCookie::CookieInclusionStatus( - CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX, - CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT), + CookieInclusionStatus( + CookieInclusionStatus::EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX, + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT), kShortAge}, {"DefaultLax=2", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_LAX_METHOD_UNSAFE), - CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting( - std::vector< - CanonicalCookie::CookieInclusionStatus::ExclusionReason>(), - {CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE}), + CookieInclusionStatus::MakeFromReasonsForTesting( + std::vector<CookieInclusionStatus::ExclusionReason>(), + {CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE}), kShortAge}, {"DefaultLax=3", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, SameSiteCookieContext(SameSiteCookieContext::ContextType::SAME_SITE_LAX), - CanonicalCookie::CookieInclusionStatus(), kShortAge}, + CookieInclusionStatus(), kShortAge}, {"DefaultLax=4", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_STRICT), - CanonicalCookie::CookieInclusionStatus(), kShortAge}, + CookieInclusionStatus(), kShortAge}, // Unspecified not-recently-created cookies (with SameSite-by-default): {"DefaultLax=5", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext(SameSiteCookieContext::ContextType::CROSS_SITE), - CanonicalCookie::CookieInclusionStatus( - CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX, - CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT), + CookieInclusionStatus( + CookieInclusionStatus::EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX, + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT), kLongAge}, {"DefaultLax=6", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_LAX_METHOD_UNSAFE), - CanonicalCookie::CookieInclusionStatus( - CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX, - CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT), + CookieInclusionStatus( + CookieInclusionStatus::EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX, + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT), kLongAge}, {"DefaultLax=7", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext(SameSiteCookieContext::ContextType::SAME_SITE_LAX), - CanonicalCookie::CookieInclusionStatus(), kLongAge}, + CookieInclusionStatus(), kLongAge}, {"DefaultLax=8", CookieSameSite::UNSPECIFIED, CookieEffectiveSameSite::LAX_MODE, SameSiteCookieContext( SameSiteCookieContext::ContextType::SAME_SITE_STRICT), - CanonicalCookie::CookieInclusionStatus(), kLongAge}, + CookieInclusionStatus(), kLongAge}, }; VerifyIncludeForRequestURLTestCases(true, CookieAccessSemantics::UNKNOWN, @@ -1046,19 +1017,18 @@ TEST(CanonicalCookieTest, IncludeCookiesWithoutSameSiteMustBeSecure) { EXPECT_TRUE( cookie ->IncludeForRequestURL(url, options, CookieAccessSemantics::UNKNOWN) - .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_SAMESITE_NONE_INSECURE})); + .status.HasExactlyExclusionReasonsForTesting( + {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})); + .status.IsInclude()); + EXPECT_TRUE( + cookie + ->IncludeForRequestURL(url, options, + CookieAccessSemantics::NONLEGACY) + .status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE})); } // Features off: { @@ -1072,17 +1042,17 @@ TEST(CanonicalCookieTest, IncludeCookiesWithoutSameSiteMustBeSecure) { EXPECT_TRUE( cookie ->IncludeForRequestURL(url, options, CookieAccessSemantics::UNKNOWN) - .IsInclude()); + .status.IsInclude()); EXPECT_TRUE( cookie ->IncludeForRequestURL(url, options, CookieAccessSemantics::LEGACY) - .IsInclude()); + .status.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()); + .status.IsInclude()); } } @@ -1102,35 +1072,32 @@ TEST(CanonicalCookieTest, MultipleExclusionReasons) { "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})); + EXPECT_TRUE(cookie1.IncludeForRequestURL(url, options) + .status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_HTTP_ONLY, + CookieInclusionStatus::EXCLUDE_SECURE_ONLY, + CookieInclusionStatus::EXCLUDE_DOMAIN_MISMATCH, + CookieInclusionStatus::EXCLUDE_NOT_ON_PATH, + CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT})); // Test Create() - CanonicalCookie::CookieInclusionStatus create_status; + 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})); + {CookieInclusionStatus::EXCLUDE_INVALID_PREFIX, + 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})); + EXPECT_TRUE(cookie3->IsSetPermittedInContext(options) + .HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_HTTP_ONLY, + CookieInclusionStatus::EXCLUDE_SAMESITE_LAX})); } TEST(CanonicalCookieTest, PartialCompare) { @@ -1166,18 +1133,18 @@ TEST(CanonicalCookieTest, SecureCookiePrefix) { GURL http_url("http://www.example.test"); base::Time creation_time = base::Time::Now(); base::Optional<base::Time> server_time = base::nullopt; - CanonicalCookie::CookieInclusionStatus status; + 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})); + {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})); + {CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); // A typoed prefix does not have to be Secure. EXPECT_TRUE(CanonicalCookie::Create(https_url, "__secure-A=B; Secure", @@ -1193,7 +1160,7 @@ TEST(CanonicalCookieTest, SecureCookiePrefix) { EXPECT_FALSE(CanonicalCookie::Create(http_url, "__Secure-A=B; Secure", creation_time, server_time, &status)); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); + {CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); } TEST(CanonicalCookieTest, HostCookiePrefix) { @@ -1202,18 +1169,18 @@ TEST(CanonicalCookieTest, HostCookiePrefix) { base::Time creation_time = base::Time::Now(); base::Optional<base::Time> server_time = base::nullopt; std::string domain = https_url.host(); - CanonicalCookie::CookieInclusionStatus status; + 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})); + {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})); + {CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); EXPECT_TRUE(CanonicalCookie::Create(https_url, "__Host-A=B; Path=/; Secure;", creation_time, server_time)); @@ -1222,7 +1189,7 @@ TEST(CanonicalCookieTest, HostCookiePrefix) { http_url, "__Host-A=B; Domain=" + domain + "; Path=/; Secure;", creation_time, server_time, &status)); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); + {CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); EXPECT_TRUE(CanonicalCookie::Create(https_url, "__Host-A=B; Path=/; Secure;", creation_time, server_time)); @@ -1231,12 +1198,12 @@ TEST(CanonicalCookieTest, HostCookiePrefix) { https_url, "__Host-A=B; Domain=" + domain + "; Path=/; Secure;", creation_time, server_time, &status)); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); + {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})); + {CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); // A __Host- cookie may have a domain if it's an IP address that matches the // URL. @@ -1255,11 +1222,11 @@ TEST(CanonicalCookieTest, HostCookiePrefix) { "__Host-A=B; Path=/foo; Secure;", creation_time, server_time, &status)); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); + {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})); + {CookieInclusionStatus::EXCLUDE_INVALID_PREFIX})); EXPECT_TRUE(CanonicalCookie::Create(https_url, "__Host-A=B; Secure; Path=/;", creation_time, server_time)); @@ -2030,10 +1997,9 @@ TEST(CanonicalCookieTest, IsSetPermittedInContext) { EXPECT_TRUE( cookie_httponly.IsSetPermittedInContext(context_network).IsInclude()); - EXPECT_TRUE( - cookie_httponly.IsSetPermittedInContext(context_script) - .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY})); + EXPECT_TRUE(cookie_httponly.IsSetPermittedInContext(context_script) + .HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_HTTP_ONLY})); CookieOptions context_cross_site; CookieOptions context_same_site_lax; @@ -2079,17 +2045,17 @@ TEST(CanonicalCookieTest, IsSetPermittedInContext) { .IsSetPermittedInContext(context_same_site_strict) .IsInclude()); - CanonicalCookie::CookieInclusionStatus status_strict_to_lax = + CookieInclusionStatus status_strict_to_lax = cookie_same_site_unrestricted.IsSetPermittedInContext( context_same_site_strict_to_lax); EXPECT_TRUE(status_strict_to_lax.IsInclude()); EXPECT_FALSE(status_strict_to_lax.HasDowngradeWarning()); - CanonicalCookie::CookieInclusionStatus status_strict_to_cross = + CookieInclusionStatus status_strict_to_cross = cookie_same_site_unrestricted.IsSetPermittedInContext( context_same_site_strict_to_cross); EXPECT_TRUE(status_strict_to_cross.IsInclude()); EXPECT_FALSE(status_strict_to_cross.HasDowngradeWarning()); - CanonicalCookie::CookieInclusionStatus status_lax_to_cross = + CookieInclusionStatus status_lax_to_cross = cookie_same_site_unrestricted.IsSetPermittedInContext( context_same_site_lax_to_cross); EXPECT_TRUE(status_lax_to_cross.IsInclude()); @@ -2104,8 +2070,7 @@ TEST(CanonicalCookieTest, IsSetPermittedInContext) { EXPECT_TRUE(cookie_same_site_lax.IsSetPermittedInContext(context_cross_site) .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_SAMESITE_LAX})); + {CookieInclusionStatus::EXCLUDE_SAMESITE_LAX})); EXPECT_TRUE( cookie_same_site_lax.IsSetPermittedInContext(context_same_site_lax) .IsInclude()); @@ -2113,25 +2078,23 @@ TEST(CanonicalCookieTest, IsSetPermittedInContext) { cookie_same_site_lax.IsSetPermittedInContext(context_same_site_strict) .IsInclude()); - CanonicalCookie::CookieInclusionStatus status_strict_to_lax = + CookieInclusionStatus status_strict_to_lax = cookie_same_site_lax.IsSetPermittedInContext( context_same_site_strict_to_lax); EXPECT_TRUE(status_strict_to_lax.IsInclude()); EXPECT_FALSE(status_strict_to_lax.HasDowngradeWarning()); - CanonicalCookie::CookieInclusionStatus status_strict_to_cross = + CookieInclusionStatus status_strict_to_cross = cookie_same_site_lax.IsSetPermittedInContext( context_same_site_strict_to_cross); EXPECT_TRUE(status_strict_to_cross.IsInclude()); EXPECT_TRUE(status_strict_to_cross.HasWarningReason( - CanonicalCookie::CookieInclusionStatus:: - WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE)); - CanonicalCookie::CookieInclusionStatus status_lax_to_cross = + CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE)); + CookieInclusionStatus status_lax_to_cross = cookie_same_site_lax.IsSetPermittedInContext( context_same_site_lax_to_cross); EXPECT_TRUE(status_lax_to_cross.IsInclude()); EXPECT_TRUE(status_lax_to_cross.HasWarningReason( - CanonicalCookie::CookieInclusionStatus:: - WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE)); + CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE)); } { @@ -2145,8 +2108,7 @@ TEST(CanonicalCookieTest, IsSetPermittedInContext) { EXPECT_TRUE( cookie_same_site_strict.IsSetPermittedInContext(context_cross_site) .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_SAMESITE_STRICT})); + {CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT})); EXPECT_TRUE( cookie_same_site_strict.IsSetPermittedInContext(context_same_site_lax) .IsInclude()); @@ -2154,25 +2116,23 @@ TEST(CanonicalCookieTest, IsSetPermittedInContext) { .IsSetPermittedInContext(context_same_site_strict) .IsInclude()); - CanonicalCookie::CookieInclusionStatus status_strict_to_lax = + CookieInclusionStatus status_strict_to_lax = cookie_same_site_strict.IsSetPermittedInContext( context_same_site_strict_to_lax); EXPECT_TRUE(status_strict_to_lax.IsInclude()); EXPECT_FALSE(status_strict_to_lax.HasDowngradeWarning()); - CanonicalCookie::CookieInclusionStatus status_strict_to_cross = + CookieInclusionStatus status_strict_to_cross = cookie_same_site_strict.IsSetPermittedInContext( context_same_site_strict_to_cross); EXPECT_TRUE(status_strict_to_cross.IsInclude()); EXPECT_TRUE(status_strict_to_cross.HasWarningReason( - CanonicalCookie::CookieInclusionStatus:: - WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE)); - CanonicalCookie::CookieInclusionStatus status_lax_to_cross = + CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE)); + CookieInclusionStatus status_lax_to_cross = cookie_same_site_strict.IsSetPermittedInContext( context_same_site_lax_to_cross); EXPECT_TRUE(status_lax_to_cross.IsInclude()); EXPECT_TRUE(status_lax_to_cross.HasWarningReason( - CanonicalCookie::CookieInclusionStatus:: - WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE)); + CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE)); } // Behavior of UNSPECIFIED depends on an experiment and CookieAccessSemantics. @@ -2213,7 +2173,7 @@ TEST(CanonicalCookieTest, IsSetPermittedInContext) { .IsSetPermittedInContext(context_cross_site, CookieAccessSemantics::NONLEGACY) .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: + {CookieInclusionStatus:: EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX})); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax, @@ -2233,7 +2193,7 @@ TEST(CanonicalCookieTest, IsSetPermittedInContext) { .IsSetPermittedInContext(context_cross_site, CookieAccessSemantics::UNKNOWN) .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: + {CookieInclusionStatus:: EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX})); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax, @@ -2259,7 +2219,7 @@ TEST(CanonicalCookieTest, IsSetPermittedInContext) { .IsSetPermittedInContext(context_cross_site, CookieAccessSemantics::NONLEGACY) .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: + {CookieInclusionStatus:: EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX})); EXPECT_TRUE(cookie_same_site_unspecified .IsSetPermittedInContext(context_same_site_lax, @@ -2272,213 +2232,4 @@ TEST(CanonicalCookieTest, IsSetPermittedInContext) { } } -TEST(CookieInclusionStatusTest, IncludeStatus) { - int num_exclusion_reasons = static_cast<int>( - CanonicalCookie::CookieInclusionStatus::NUM_EXCLUSION_REASONS); - int num_warning_reasons = static_cast<int>( - CanonicalCookie::CookieInclusionStatus::NUM_WARNING_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<CanonicalCookie::CookieInclusionStatus::ExclusionReason>( - i))); - } - for (int i = 0; i < num_warning_reasons; ++i) { - EXPECT_FALSE(status.HasWarningReason( - static_cast<CanonicalCookie::CookieInclusionStatus::WarningReason>(i))); - } - EXPECT_FALSE(status.HasExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR)); -} - -TEST(CookieInclusionStatusTest, ExcludeStatus) { - int num_exclusion_reasons = static_cast<int>( - CanonicalCookie::CookieInclusionStatus::NUM_EXCLUSION_REASONS); - for (int i = 0; i < num_exclusion_reasons; ++i) { - auto reason = - static_cast<CanonicalCookie::CookieInclusionStatus::ExclusionReason>(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<CanonicalCookie::CookieInclusionStatus::ExclusionReason>( - j))); - } - } -} - -TEST(CookieInclusionStatusTest, NotValid) { - CanonicalCookie::CookieInclusionStatus status; - int num_exclusion_reasons = static_cast<int>( - CanonicalCookie::CookieInclusionStatus::NUM_EXCLUSION_REASONS); - int num_warning_reasons = static_cast<int>( - CanonicalCookie::CookieInclusionStatus::NUM_WARNING_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()); - - status.set_warning_reasons(1 << num_warning_reasons); - EXPECT_FALSE(status.IsInclude()); - EXPECT_FALSE(status.IsValid()); - - status.set_warning_reasons(~0u); - EXPECT_FALSE(status.IsInclude()); - EXPECT_FALSE(status.IsValid()); - - status.set_exclusion_reasons(1 << num_exclusion_reasons); - status.set_warning_reasons(1 << num_warning_reasons); - EXPECT_FALSE(status.IsInclude()); - EXPECT_FALSE(status.IsValid()); -} - -TEST(CookieInclusionStatusTest, AddExclusionReason) { - CanonicalCookie::CookieInclusionStatus status; - status.AddWarningReason(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_FALSE(status.ShouldWarn()); - - status = CanonicalCookie::CookieInclusionStatus(); - status.AddWarningReason(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_TRUE(status.HasExactlyWarningReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT})); -} - -TEST(CookieInclusionStatusTest, CheckEachWarningReason) { - CanonicalCookie::CookieInclusionStatus status; - - int num_warning_reasons = static_cast<int>( - CanonicalCookie::CookieInclusionStatus::NUM_WARNING_REASONS); - EXPECT_FALSE(status.ShouldWarn()); - for (int i = 0; i < num_warning_reasons; ++i) { - auto reason = - static_cast<CanonicalCookie::CookieInclusionStatus::WarningReason>(i); - status.AddWarningReason(reason); - EXPECT_TRUE(status.IsValid()); - EXPECT_TRUE(status.IsInclude()); - EXPECT_TRUE(status.ShouldWarn()); - EXPECT_TRUE(status.HasWarningReason(reason)); - for (int j = 0; j < num_warning_reasons; ++j) { - if (i == j) - continue; - EXPECT_FALSE(status.HasWarningReason( - static_cast<CanonicalCookie::CookieInclusionStatus::WarningReason>( - j))); - } - status.RemoveWarningReason(reason); - EXPECT_FALSE(status.ShouldWarn()); - } -} - -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)); -} - -TEST(CookieInclusionStatusTest, RemoveWarningReason) { - CanonicalCookie::CookieInclusionStatus status( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR, - CanonicalCookie::CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE); - EXPECT_TRUE(status.IsValid()); - EXPECT_TRUE(status.ShouldWarn()); - ASSERT_TRUE(status.HasWarningReason( - CanonicalCookie::CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE)); - - status.RemoveWarningReason( - CanonicalCookie::CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE); - EXPECT_TRUE(status.IsValid()); - EXPECT_FALSE(status.ShouldWarn()); - EXPECT_FALSE(status.HasWarningReason( - CanonicalCookie::CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE)); - - // Removing a nonexistent warning reason doesn't do anything. - ASSERT_FALSE(status.HasWarningReason( - CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT)); - status.RemoveWarningReason(CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); - EXPECT_TRUE(status.IsValid()); - EXPECT_FALSE(status.ShouldWarn()); - EXPECT_FALSE(status.HasWarningReason( - CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT)); -} - -TEST(CookieInclusionStatusTest, HasDowngradeWarning) { - std::vector<CanonicalCookie::CookieInclusionStatus::WarningReason> - downgrade_warnings = { - CanonicalCookie::CookieInclusionStatus:: - WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE, - CanonicalCookie::CookieInclusionStatus:: - WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE, - CanonicalCookie::CookieInclusionStatus:: - WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE, - CanonicalCookie::CookieInclusionStatus:: - WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE, - CanonicalCookie::CookieInclusionStatus:: - WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE, - }; - - CanonicalCookie::CookieInclusionStatus empty_status; - EXPECT_FALSE(empty_status.HasDowngradeWarning()); - - CanonicalCookie::CookieInclusionStatus not_downgrade; - not_downgrade.AddWarningReason( - CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); - EXPECT_FALSE(not_downgrade.HasDowngradeWarning()); - - for (auto warning : downgrade_warnings) { - CanonicalCookie::CookieInclusionStatus status; - status.AddWarningReason(warning); - CanonicalCookie::CookieInclusionStatus::WarningReason reason; - - EXPECT_TRUE(status.HasDowngradeWarning(&reason)); - EXPECT_EQ(warning, reason); - } -} } // namespace net diff --git a/chromium/net/cookies/cookie_access_result.cc b/chromium/net/cookies/cookie_access_result.cc new file mode 100644 index 00000000000..182dc53f704 --- /dev/null +++ b/chromium/net/cookies/cookie_access_result.cc @@ -0,0 +1,25 @@ +// Copyright 2020 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/cookie_access_result.h" + +namespace net { + +CookieAccessResult::CookieAccessResult() = default; + +CookieAccessResult::CookieAccessResult( + CookieEffectiveSameSite effective_same_site, + CookieInclusionStatus status) + : effective_same_site(effective_same_site), status(status) {} + +CookieAccessResult::CookieAccessResult(const CookieAccessResult&) = default; + +CookieAccessResult& CookieAccessResult::operator=( + const CookieAccessResult& cookie_access_result) = default; + +CookieAccessResult::CookieAccessResult(CookieAccessResult&&) = default; + +CookieAccessResult::~CookieAccessResult() = default; + +} // namespace net diff --git a/chromium/net/cookies/cookie_access_result.h b/chromium/net/cookies/cookie_access_result.h new file mode 100644 index 00000000000..a21305bfe11 --- /dev/null +++ b/chromium/net/cookies/cookie_access_result.h @@ -0,0 +1,34 @@ +// Copyright 2020 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. + +#ifndef NET_COOKIES_COOKIE_ACCESS_RESULT_H_ +#define NET_COOKIES_COOKIE_ACCESS_RESULT_H_ + +#include "net/base/net_export.h" +#include "net/cookies/cookie_constants.h" +#include "net/cookies/cookie_inclusion_status.h" + +namespace net { + +struct NET_EXPORT CookieAccessResult { + CookieAccessResult(); + CookieAccessResult(CookieEffectiveSameSite effective_same_site, + CookieInclusionStatus status); + + CookieAccessResult(const CookieAccessResult& cookie_access_result); + + CookieAccessResult& operator=(const CookieAccessResult& cookie_access_result); + + CookieAccessResult(CookieAccessResult&& cookie_access_result); + + ~CookieAccessResult(); + + CookieEffectiveSameSite effective_same_site = + CookieEffectiveSameSite::LAX_MODE; + CookieInclusionStatus status; +}; + +} // namespace net + +#endif // NET_COOKIES_COOKIE_ACCESS_RESULT_H_ diff --git a/chromium/net/cookies/cookie_deletion_info.cc b/chromium/net/cookies/cookie_deletion_info.cc index b451dc2350f..6429510e83f 100644 --- a/chromium/net/cookies/cookie_deletion_info.cc +++ b/chromium/net/cookies/cookie_deletion_info.cc @@ -116,7 +116,7 @@ bool CookieDeletionInfo::Matches(const CanonicalCookie& cookie, !cookie .IncludeForRequestURL(url.value(), CookieOptions::MakeAllInclusive(), access_semantics) - .IsInclude()) { + .status.IsInclude()) { return false; } diff --git a/chromium/net/cookies/cookie_inclusion_status.cc b/chromium/net/cookies/cookie_inclusion_status.cc new file mode 100644 index 00000000000..8e13916ba13 --- /dev/null +++ b/chromium/net/cookies/cookie_inclusion_status.cc @@ -0,0 +1,290 @@ +// Copyright 2020 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/cookie_inclusion_status.h" + +#include "base/strings/strcat.h" +#include "url/gurl.h" + +namespace net { + +namespace { + +uint32_t GetExclusionBitmask(CookieInclusionStatus::ExclusionReason reason) { + return 1u << static_cast<uint32_t>(reason); +} + +uint32_t GetWarningBitmask(CookieInclusionStatus::WarningReason reason) { + return 1u << static_cast<uint32_t>(reason); +} + +} // namespace + +CookieInclusionStatus::CookieInclusionStatus() + : exclusion_reasons_(0u), warning_reasons_(0u) {} + +CookieInclusionStatus::CookieInclusionStatus(ExclusionReason reason) + : exclusion_reasons_(GetExclusionBitmask(reason)) {} + +CookieInclusionStatus::CookieInclusionStatus(ExclusionReason reason, + WarningReason warning) + : exclusion_reasons_(GetExclusionBitmask(reason)), + warning_reasons_(GetWarningBitmask(warning)) {} + +bool CookieInclusionStatus::operator==( + const CookieInclusionStatus& other) const { + return exclusion_reasons_ == other.exclusion_reasons_ && + warning_reasons_ == other.warning_reasons_; +} + +bool CookieInclusionStatus::operator!=( + const CookieInclusionStatus& other) const { + return !operator==(other); +} + +bool CookieInclusionStatus::IsInclude() const { + return exclusion_reasons_ == 0u; +} + +bool CookieInclusionStatus::HasExclusionReason(ExclusionReason reason) const { + return exclusion_reasons_ & GetExclusionBitmask(reason); +} + +void CookieInclusionStatus::AddExclusionReason(ExclusionReason reason) { + exclusion_reasons_ |= GetExclusionBitmask(reason); + // If the cookie would be excluded for reasons other than the new SameSite + // rules, don't bother warning about it. + MaybeClearSameSiteWarning(); +} + +void CookieInclusionStatus::RemoveExclusionReason(ExclusionReason reason) { + exclusion_reasons_ &= ~(GetExclusionBitmask(reason)); +} + +void CookieInclusionStatus::MaybeClearSameSiteWarning() { + uint32_t samesite_reasons_mask = + GetExclusionBitmask(EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX) | + GetExclusionBitmask(EXCLUDE_SAMESITE_NONE_INSECURE); + if (exclusion_reasons_ & ~samesite_reasons_mask) { + RemoveWarningReason( + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); + RemoveWarningReason(CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE); + RemoveWarningReason( + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE); + } + + uint32_t context_reasons_mask = + GetExclusionBitmask(EXCLUDE_SAMESITE_STRICT) | + GetExclusionBitmask(EXCLUDE_SAMESITE_LAX) | + GetExclusionBitmask(EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX); + if (exclusion_reasons_ & ~context_reasons_mask) { + RemoveWarningReason( + CookieInclusionStatus::WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE); + RemoveWarningReason( + CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE); + RemoveWarningReason( + CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE); + RemoveWarningReason( + CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE); + RemoveWarningReason( + CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE); + } +} + +bool CookieInclusionStatus::ShouldRecordDowngradeMetrics() const { + uint32_t context_reasons_mask = + GetExclusionBitmask(EXCLUDE_SAMESITE_STRICT) | + GetExclusionBitmask(EXCLUDE_SAMESITE_LAX) | + GetExclusionBitmask(EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX); + + return (exclusion_reasons_ & ~context_reasons_mask) == 0u; +} + +bool CookieInclusionStatus::ShouldWarn() const { + return warning_reasons_ != 0u; +} + +bool CookieInclusionStatus::HasWarningReason(WarningReason reason) const { + return warning_reasons_ & GetWarningBitmask(reason); +} + +bool CookieInclusionStatus::HasDowngradeWarning( + CookieInclusionStatus::WarningReason* reason) const { + if (!ShouldWarn()) + return false; + + const CookieInclusionStatus::WarningReason kDowngradeWarnings[] = { + WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE, + WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE, + WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE, + WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE, + WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE, + }; + + for (auto warning : kDowngradeWarnings) { + if (!HasWarningReason(warning)) + continue; + + if (reason) + *reason = warning; + + return true; + } + + return false; +} + +void CookieInclusionStatus::AddWarningReason(WarningReason reason) { + warning_reasons_ |= GetWarningBitmask(reason); +} + +void CookieInclusionStatus::RemoveWarningReason(WarningReason reason) { + warning_reasons_ &= ~(GetWarningBitmask(reason)); +} + +CookieInclusionStatus::ContextDowngradeMetricValues +CookieInclusionStatus::GetBreakingDowngradeMetricsEnumValue( + const GURL& url) const { + bool url_is_secure = url.SchemeIsCryptographic(); + + // Start the |reason| as something other than the downgrade warnings. + WarningReason reason = WarningReason::NUM_WARNING_REASONS; + + // Don't bother checking the return value because the default switch case + // will handle if no reason was found. + HasDowngradeWarning(&reason); + + switch (reason) { + case WarningReason::WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE: + return url_is_secure + ? ContextDowngradeMetricValues::STRICT_LAX_STRICT_SECURE + : ContextDowngradeMetricValues::STRICT_LAX_STRICT_INSECURE; + case WarningReason::WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE: + return url_is_secure + ? ContextDowngradeMetricValues::STRICT_CROSS_STRICT_SECURE + : ContextDowngradeMetricValues::STRICT_CROSS_STRICT_INSECURE; + case WarningReason::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE: + return url_is_secure + ? ContextDowngradeMetricValues::STRICT_CROSS_LAX_SECURE + : ContextDowngradeMetricValues::STRICT_CROSS_LAX_INSECURE; + case WarningReason::WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE: + return url_is_secure + ? ContextDowngradeMetricValues::LAX_CROSS_STRICT_SECURE + : ContextDowngradeMetricValues::LAX_CROSS_STRICT_INSECURE; + case WarningReason::WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE: + return url_is_secure + ? ContextDowngradeMetricValues::LAX_CROSS_LAX_SECURE + : ContextDowngradeMetricValues::LAX_CROSS_LAX_INSECURE; + default: + return url_is_secure + ? ContextDowngradeMetricValues::NO_DOWNGRADE_SECURE + : ContextDowngradeMetricValues::NO_DOWNGRADE_INSECURE; + } +} + +std::string CookieInclusionStatus::GetDebugString() const { + std::string out; + + // Inclusion/exclusion + if (IsInclude()) + base::StrAppend(&out, {"INCLUDE, "}); + if (HasExclusionReason(EXCLUDE_UNKNOWN_ERROR)) + base::StrAppend(&out, {"EXCLUDE_UNKNOWN_ERROR, "}); + if (HasExclusionReason(EXCLUDE_HTTP_ONLY)) + base::StrAppend(&out, {"EXCLUDE_HTTP_ONLY, "}); + if (HasExclusionReason(EXCLUDE_SECURE_ONLY)) + base::StrAppend(&out, {"EXCLUDE_SECURE_ONLY, "}); + if (HasExclusionReason(EXCLUDE_DOMAIN_MISMATCH)) + base::StrAppend(&out, {"EXCLUDE_DOMAIN_MISMATCH, "}); + if (HasExclusionReason(EXCLUDE_NOT_ON_PATH)) + base::StrAppend(&out, {"EXCLUDE_NOT_ON_PATH, "}); + if (HasExclusionReason(EXCLUDE_SAMESITE_STRICT)) + base::StrAppend(&out, {"EXCLUDE_SAMESITE_STRICT, "}); + if (HasExclusionReason(EXCLUDE_SAMESITE_LAX)) + base::StrAppend(&out, {"EXCLUDE_SAMESITE_LAX, "}); + if (HasExclusionReason(EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX)) + base::StrAppend(&out, {"EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX, "}); + if (HasExclusionReason(EXCLUDE_SAMESITE_NONE_INSECURE)) + base::StrAppend(&out, {"EXCLUDE_SAMESITE_NONE_INSECURE, "}); + if (HasExclusionReason(EXCLUDE_USER_PREFERENCES)) + base::StrAppend(&out, {"EXCLUDE_USER_PREFERENCES, "}); + if (HasExclusionReason(EXCLUDE_FAILURE_TO_STORE)) + base::StrAppend(&out, {"EXCLUDE_FAILURE_TO_STORE, "}); + if (HasExclusionReason(EXCLUDE_NONCOOKIEABLE_SCHEME)) + base::StrAppend(&out, {"EXCLUDE_NONCOOKIEABLE_SCHEME, "}); + if (HasExclusionReason(EXCLUDE_OVERWRITE_SECURE)) + base::StrAppend(&out, {"EXCLUDE_OVERWRITE_SECURE, "}); + if (HasExclusionReason(EXCLUDE_OVERWRITE_HTTP_ONLY)) + base::StrAppend(&out, {"EXCLUDE_OVERWRITE_HTTP_ONLY, "}); + if (HasExclusionReason(EXCLUDE_INVALID_DOMAIN)) + base::StrAppend(&out, {"EXCLUDE_INVALID_DOMAIN, "}); + if (HasExclusionReason(EXCLUDE_INVALID_PREFIX)) + base::StrAppend(&out, {"EXCLUDE_INVALID_PREFIX, "}); + + // Add warning + if (!ShouldWarn()) { + base::StrAppend(&out, {"DO_NOT_WARN"}); + return out; + } + + if (HasWarningReason(WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT)) + base::StrAppend(&out, {"WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT, "}); + if (HasWarningReason(WARN_SAMESITE_NONE_INSECURE)) + base::StrAppend(&out, {"WARN_SAMESITE_NONE_INSECURE, "}); + if (HasWarningReason(WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE)) + base::StrAppend(&out, {"WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE, "}); + if (HasWarningReason(WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE)) + base::StrAppend(&out, {"WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE, "}); + if (HasWarningReason(WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE)) + base::StrAppend(&out, {"WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE, "}); + if (HasWarningReason(WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE)) + base::StrAppend(&out, {"WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE, "}); + if (HasWarningReason(WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE)) + base::StrAppend(&out, {"WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE, "}); + if (HasWarningReason(WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE)) + base::StrAppend(&out, {"WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE, "}); + if (HasWarningReason(WARN_SAMESITE_COMPAT_PAIR)) + base::StrAppend(&out, {"WARN_SAMESITE_COMPAT_PAIR, "}); + + // Strip trailing comma and space. + out.erase(out.end() - 2, out.end()); + + return out; +} + +bool CookieInclusionStatus::IsValid() const { + // Bit positions where there should not be any true bits. + uint32_t exclusion_mask = ~0u << static_cast<int>(NUM_EXCLUSION_REASONS); + uint32_t warning_mask = ~0u << static_cast<int>(NUM_WARNING_REASONS); + return (exclusion_mask & exclusion_reasons_) == 0u && + (warning_mask & warning_reasons_) == 0u; +} + +bool CookieInclusionStatus::HasExactlyExclusionReasonsForTesting( + std::vector<CookieInclusionStatus::ExclusionReason> reasons) const { + CookieInclusionStatus expected = MakeFromReasonsForTesting(reasons); + return expected.exclusion_reasons_ == exclusion_reasons_; +} + +bool CookieInclusionStatus::HasExactlyWarningReasonsForTesting( + std::vector<WarningReason> reasons) const { + CookieInclusionStatus expected = MakeFromReasonsForTesting({}, reasons); + return expected.warning_reasons_ == warning_reasons_; +} + +// static +CookieInclusionStatus CookieInclusionStatus::MakeFromReasonsForTesting( + std::vector<ExclusionReason> reasons, + std::vector<WarningReason> warnings) { + CookieInclusionStatus status; + for (ExclusionReason reason : reasons) { + status.AddExclusionReason(reason); + } + for (WarningReason warning : warnings) { + status.AddWarningReason(warning); + } + return status; +} + +} // namespace net diff --git a/chromium/net/cookies/cookie_inclusion_status.h b/chromium/net/cookies/cookie_inclusion_status.h new file mode 100644 index 00000000000..3f38eddb39b --- /dev/null +++ b/chromium/net/cookies/cookie_inclusion_status.h @@ -0,0 +1,275 @@ +// Copyright 2020 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. + +#ifndef NET_COOKIES_COOKIE_INCLUSION_STATUS_H_ +#define NET_COOKIES_COOKIE_INCLUSION_STATUS_H_ + +#include <string> +#include <vector> + +#include "net/base/net_export.h" + +class GURL; + +namespace net { + +// This class represents if a cookie was included or excluded in a cookie get or +// set operation, and if excluded why. It holds a vector of reasons for +// exclusion, where cookie inclusion is represented by the absence of any +// exclusion reasons. Also marks whether a cookie should be warned about, e.g. +// for deprecation or intervention reasons. +class NET_EXPORT CookieInclusionStatus { + public: + // Types of reasons why a cookie might be excluded. + // If adding a ExclusionReason, please also update the GetDebugString() + // method. + enum ExclusionReason { + EXCLUDE_UNKNOWN_ERROR = 0, + + EXCLUDE_HTTP_ONLY = 1, + EXCLUDE_SECURE_ONLY = 2, + EXCLUDE_DOMAIN_MISMATCH = 3, + EXCLUDE_NOT_ON_PATH = 4, + EXCLUDE_SAMESITE_STRICT = 5, + EXCLUDE_SAMESITE_LAX = 6, + + // The following two are used for the SameSiteByDefaultCookies experiment, + // where if the SameSite attribute is not specified, it will be treated as + // SameSite=Lax by default. + EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX = 7, + // This is used if SameSite=None is specified, but the cookie is not + // Secure. + EXCLUDE_SAMESITE_NONE_INSECURE = 8, + EXCLUDE_USER_PREFERENCES = 9, + + // Statuses specific to setting cookies + EXCLUDE_FAILURE_TO_STORE = 10, + EXCLUDE_NONCOOKIEABLE_SCHEME = 11, + EXCLUDE_OVERWRITE_SECURE = 12, + EXCLUDE_OVERWRITE_HTTP_ONLY = 13, + EXCLUDE_INVALID_DOMAIN = 14, + EXCLUDE_INVALID_PREFIX = 15, + + // This should be kept last. + NUM_EXCLUSION_REASONS + }; + + // Reason to warn about a cookie. Any information contained in WarningReason + // of an included cookie may be passed to an untrusted renderer. + // If you add one, please update GetDebugString(). + enum WarningReason { + // Of the following 3 SameSite warnings, there will be, at most, a single + // active one. + + // Warn if a cookie with unspecified SameSite attribute is used in a + // cross-site context. + WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT = 0, + // Warn if a cookie with SameSite=None is not Secure. + WARN_SAMESITE_NONE_INSECURE = 1, + // Warn if a cookie with unspecified SameSite attribute is defaulted into + // Lax and is sent on a request with unsafe method, only because it is new + // enough to activate the Lax-allow-unsafe intervention. + WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE = 2, + + // The following warnings indicate that an included cookie with an effective + // SameSite is experiencing a SameSiteCookieContext::|context| -> + // SameSiteCookieContext::|schemeful_context| downgrade that will prevent + // its access schemefully. + // This situation means that a cookie is accessible when the + // SchemefulSameSite feature is disabled but not when it's enabled, + // indicating changed behavior and potential breakage. + // + // For example, a Strict to Lax downgrade for an effective SameSite=Strict + // cookie: + // This cookie would be accessible in the Strict context as its SameSite + // value is Strict. However its context for schemeful same-site becomes Lax. + // A strict cookie cannot be accessed in a Lax context and therefore the + // behavior has changed. + // As a counterexample, a Strict to Lax downgrade for an effective + // SameSite=Lax cookie: A Lax cookie can be accessed in both Strict and Lax + // contexts so there is no behavior change (and we don't warn about it). + // + // The warnings are in the following format: + // WARN_{context}_{schemeful_context}_DOWNGRADE_{samesite_value}_SAMESITE + // + // Of the following 5 SameSite warnings, there will be, at most, a single + // active one. + + // Strict to Lax downgrade for an effective SameSite=Strict cookie. + // This warning is only applicable for cookies being sent because a Strict + // cookie will be set in both Strict and Lax Contexts so the downgrade will + // not affect it. + WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE = 3, + // Strict to Cross-site downgrade for an effective SameSite=Strict cookie. + // This also applies to Strict to Lax Unsafe downgrades due to Lax Unsafe + // behaving like Cross-site. + WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE = 4, + // Strict to Cross-site downgrade for an effective SameSite=Lax cookie. + // This also applies to Strict to Lax Unsafe downgrades due to Lax Unsafe + // behaving like Cross-site. + WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE = 5, + // Lax to Cross-site downgrade for an effective SameSite=Strict cookie. + // This warning is only applicable for cookies being set because a Strict + // cookie will not be sent in a Lax context so the downgrade would not + // affect it. + WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE = 6, + // Lax to Cross-site downgrade for an effective SameSite=Lax cookie. + WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE = 7, + + // This is applied to a cookie that may be part of a "double cookie" pair + // used for compatibility reasons. These pairs consist of one cookie that + // has "SameSite=None; Secure" and a duplicate cookie that leaves SameSite + // unspecified to maintain compatibility with browsers that do not support + // the "SameSite=None" attribute. This warning is applied to both + // members of the pair. See cookie_util::IsSameSiteCompatPair(). + // + // If computing this for a cookie access attempt from a non-network context + // (i.e. script), this should not be applied if either member of the pair is + // HttpOnly, to avoid leaking information about the name and value of + // HttpOnly cookies to an untrusted renderer. + // + // This is only relevant if WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT is + // present on the same status or a status for a cookie accessed at the same + // time, so it may not be applied at other times (e.g. when the context is + // same-site). + WARN_SAMESITE_COMPAT_PAIR = 8, + + // This should be kept last. + NUM_WARNING_REASONS + }; + + // These enums encode the context downgrade warnings + the secureness of the + // url sending/setting the cookie. They're used for metrics only. The format + // is {context}_{schemeful_context}_{samesite_value}_{securness}. + // NO_DOWNGRADE_{securness} indicates that a cookie didn't have a breaking + // context downgrade and was A) included B) excluded only due to insufficient + // same-site context. I.e. the cookie wasn't excluded due to other reasons + // such as third-party cookie blocking. Keep this in line with + // SameSiteCookieContextBreakingDowngradeWithSecureness in enums.xml. + enum ContextDowngradeMetricValues { + NO_DOWNGRADE_INSECURE = 0, + NO_DOWNGRADE_SECURE = 1, + + STRICT_LAX_STRICT_INSECURE = 2, + STRICT_CROSS_STRICT_INSECURE = 3, + STRICT_CROSS_LAX_INSECURE = 4, + LAX_CROSS_STRICT_INSECURE = 5, + LAX_CROSS_LAX_INSECURE = 6, + + STRICT_LAX_STRICT_SECURE = 7, + STRICT_CROSS_STRICT_SECURE = 8, + STRICT_CROSS_LAX_SECURE = 9, + LAX_CROSS_STRICT_SECURE = 10, + LAX_CROSS_LAX_SECURE = 11, + + // Keep last. + kMaxValue = LAX_CROSS_LAX_SECURE + }; + // Makes a status that says include and should not warn. + CookieInclusionStatus(); + + // Make a status that contains the given exclusion reason. + explicit CookieInclusionStatus(ExclusionReason reason); + // Makes a status that contains the given exclusion reason and warning. + CookieInclusionStatus(ExclusionReason reason, WarningReason warning); + + bool operator==(const CookieInclusionStatus& other) const; + bool operator!=(const CookieInclusionStatus& other) const; + + // Whether the status is to include the cookie, and has no other reasons for + // exclusion. + bool IsInclude() const; + + // Whether the given reason for exclusion is present. + bool HasExclusionReason(ExclusionReason status_type) const; + + // Add an exclusion reason. + void AddExclusionReason(ExclusionReason status_type); + + // Remove an exclusion reason. + void RemoveExclusionReason(ExclusionReason reason); + + // If the cookie would have been excluded for reasons other than + // SAMESITE_UNSPECIFIED_TREATED_AS_LAX or SAMESITE_NONE_INSECURE, don't bother + // warning about it (clear the warning). + void MaybeClearSameSiteWarning(); + + // Whether to record the breaking downgrade metrics if the cookie is included + // or if it's only excluded because of insufficient same-site context. + bool ShouldRecordDowngradeMetrics() const; + + // Whether the cookie should be warned about. + bool ShouldWarn() const; + + // Whether the given reason for warning is present. + bool HasWarningReason(WarningReason reason) const; + + // Whether a schemeful downgrade warning is present. + // A schemeful downgrade means that an included cookie with an effective + // SameSite is experiencing a SameSiteCookieContext::|context| -> + // SameSiteCookieContext::|schemeful_context| downgrade that will prevent its + // access schemefully. If the function returns true and |reason| is valid then + // |reason| will contain which warning was found. + bool HasDowngradeWarning( + CookieInclusionStatus::WarningReason* reason = nullptr) const; + + // Add an warning reason. + void AddWarningReason(WarningReason reason); + + // Remove an warning reason. + void RemoveWarningReason(WarningReason reason); + + // Used for serialization/deserialization. + uint32_t exclusion_reasons() const { return exclusion_reasons_; } + void set_exclusion_reasons(uint32_t exclusion_reasons) { + exclusion_reasons_ = exclusion_reasons; + } + + uint32_t warning_reasons() const { return warning_reasons_; } + void set_warning_reasons(uint32_t warning_reasons) { + warning_reasons_ = warning_reasons; + } + + ContextDowngradeMetricValues GetBreakingDowngradeMetricsEnumValue( + const GURL& url) const; + + // Get exclusion reason(s) and warning in string format. + std::string GetDebugString() const; + + // Checks that the underlying bit vector representation doesn't contain any + // extraneous bits that are not mapped to any enum values. Does not check + // for reasons which semantically cannot coexist. + bool IsValid() const; + + // Checks whether the exclusion reasons are exactly the set of exclusion + // reasons in the vector. (Ignores warnings.) + bool HasExactlyExclusionReasonsForTesting( + std::vector<ExclusionReason> reasons) const; + + // Checks whether the warning reasons are exactly the set of warning + // reasons in the vector. (Ignores exclusions.) + bool HasExactlyWarningReasonsForTesting( + std::vector<WarningReason> reasons) const; + + // Makes a status that contains the given exclusion reasons and warning. + static CookieInclusionStatus MakeFromReasonsForTesting( + std::vector<ExclusionReason> reasons, + std::vector<WarningReason> warnings = std::vector<WarningReason>()); + + private: + // A bit vector of the applicable exclusion reasons. + uint32_t exclusion_reasons_ = 0u; + + // A bit vector of the applicable warning reasons. + uint32_t warning_reasons_ = 0u; +}; + +NET_EXPORT inline std::ostream& operator<<(std::ostream& os, + const CookieInclusionStatus status) { + return os << status.GetDebugString(); +} + +} // namespace net + +#endif // NET_COOKIES_COOKIE_INCLUSION_STATUS_H_ diff --git a/chromium/net/cookies/cookie_inclusion_status_unittest.cc b/chromium/net/cookies/cookie_inclusion_status_unittest.cc new file mode 100644 index 00000000000..bc5c7edaa39 --- /dev/null +++ b/chromium/net/cookies/cookie_inclusion_status_unittest.cc @@ -0,0 +1,200 @@ +// Copyright 2020 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/cookie_inclusion_status.h" + +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { + +TEST(CookieInclusionStatusTest, IncludeStatus) { + int num_exclusion_reasons = + static_cast<int>(CookieInclusionStatus::NUM_EXCLUSION_REASONS); + int num_warning_reasons = + static_cast<int>(CookieInclusionStatus::NUM_WARNING_REASONS); + // Zero-argument constructor + 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<CookieInclusionStatus::ExclusionReason>(i))); + } + for (int i = 0; i < num_warning_reasons; ++i) { + EXPECT_FALSE(status.HasWarningReason( + static_cast<CookieInclusionStatus::WarningReason>(i))); + } + EXPECT_FALSE( + status.HasExclusionReason(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR)); +} + +TEST(CookieInclusionStatusTest, ExcludeStatus) { + int num_exclusion_reasons = + static_cast<int>(CookieInclusionStatus::NUM_EXCLUSION_REASONS); + for (int i = 0; i < num_exclusion_reasons; ++i) { + auto reason = static_cast<CookieInclusionStatus::ExclusionReason>(i); + 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<CookieInclusionStatus::ExclusionReason>(j))); + } + } +} + +TEST(CookieInclusionStatusTest, NotValid) { + CookieInclusionStatus status; + int num_exclusion_reasons = + static_cast<int>(CookieInclusionStatus::NUM_EXCLUSION_REASONS); + int num_warning_reasons = + static_cast<int>(CookieInclusionStatus::NUM_WARNING_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()); + + status.set_warning_reasons(1 << num_warning_reasons); + EXPECT_FALSE(status.IsInclude()); + EXPECT_FALSE(status.IsValid()); + + status.set_warning_reasons(~0u); + EXPECT_FALSE(status.IsInclude()); + EXPECT_FALSE(status.IsValid()); + + status.set_exclusion_reasons(1 << num_exclusion_reasons); + status.set_warning_reasons(1 << num_warning_reasons); + EXPECT_FALSE(status.IsInclude()); + EXPECT_FALSE(status.IsValid()); +} + +TEST(CookieInclusionStatusTest, AddExclusionReason) { + CookieInclusionStatus status; + status.AddWarningReason( + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE); + status.AddExclusionReason(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR); + EXPECT_TRUE(status.IsValid()); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {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_FALSE(status.ShouldWarn()); + + status = CookieInclusionStatus(); + status.AddWarningReason( + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); + status.AddExclusionReason( + CookieInclusionStatus::EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX); + EXPECT_TRUE(status.IsValid()); + EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX})); + EXPECT_TRUE(status.HasExactlyWarningReasonsForTesting( + {CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT})); +} + +TEST(CookieInclusionStatusTest, CheckEachWarningReason) { + CookieInclusionStatus status; + + int num_warning_reasons = + static_cast<int>(CookieInclusionStatus::NUM_WARNING_REASONS); + EXPECT_FALSE(status.ShouldWarn()); + for (int i = 0; i < num_warning_reasons; ++i) { + auto reason = static_cast<CookieInclusionStatus::WarningReason>(i); + status.AddWarningReason(reason); + EXPECT_TRUE(status.IsValid()); + EXPECT_TRUE(status.IsInclude()); + EXPECT_TRUE(status.ShouldWarn()); + EXPECT_TRUE(status.HasWarningReason(reason)); + for (int j = 0; j < num_warning_reasons; ++j) { + if (i == j) + continue; + EXPECT_FALSE(status.HasWarningReason( + static_cast<CookieInclusionStatus::WarningReason>(j))); + } + status.RemoveWarningReason(reason); + EXPECT_FALSE(status.ShouldWarn()); + } +} + +TEST(CookieInclusionStatusTest, RemoveExclusionReason) { + CookieInclusionStatus status(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR); + EXPECT_TRUE(status.IsValid()); + ASSERT_TRUE( + status.HasExclusionReason(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR)); + + status.RemoveExclusionReason(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR); + EXPECT_TRUE(status.IsValid()); + EXPECT_FALSE( + status.HasExclusionReason(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR)); + + // Removing a nonexistent exclusion reason doesn't do anything. + ASSERT_FALSE( + status.HasExclusionReason(CookieInclusionStatus::NUM_EXCLUSION_REASONS)); + status.RemoveExclusionReason(CookieInclusionStatus::NUM_EXCLUSION_REASONS); + EXPECT_TRUE(status.IsValid()); + EXPECT_FALSE( + status.HasExclusionReason(CookieInclusionStatus::NUM_EXCLUSION_REASONS)); +} + +TEST(CookieInclusionStatusTest, RemoveWarningReason) { + CookieInclusionStatus status( + CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR, + CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE); + EXPECT_TRUE(status.IsValid()); + EXPECT_TRUE(status.ShouldWarn()); + ASSERT_TRUE(status.HasWarningReason( + CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE)); + + status.RemoveWarningReason( + CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE); + EXPECT_TRUE(status.IsValid()); + EXPECT_FALSE(status.ShouldWarn()); + EXPECT_FALSE(status.HasWarningReason( + CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE)); + + // Removing a nonexistent warning reason doesn't do anything. + ASSERT_FALSE(status.HasWarningReason( + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT)); + status.RemoveWarningReason( + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); + EXPECT_TRUE(status.IsValid()); + EXPECT_FALSE(status.ShouldWarn()); + EXPECT_FALSE(status.HasWarningReason( + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT)); +} + +TEST(CookieInclusionStatusTest, HasDowngradeWarning) { + std::vector<CookieInclusionStatus::WarningReason> downgrade_warnings = { + CookieInclusionStatus::WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE, + CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE, + CookieInclusionStatus::WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE, + CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE, + CookieInclusionStatus::WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE, + }; + + CookieInclusionStatus empty_status; + EXPECT_FALSE(empty_status.HasDowngradeWarning()); + + CookieInclusionStatus not_downgrade; + not_downgrade.AddWarningReason( + CookieInclusionStatus::WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT); + EXPECT_FALSE(not_downgrade.HasDowngradeWarning()); + + for (auto warning : downgrade_warnings) { + CookieInclusionStatus status; + status.AddWarningReason(warning); + CookieInclusionStatus::WarningReason reason; + + EXPECT_TRUE(status.HasDowngradeWarning(&reason)); + EXPECT_EQ(warning, reason); + } +} +} // namespace net diff --git a/chromium/net/cookies/cookie_monster.cc b/chromium/net/cookies/cookie_monster.cc index 533cc97ba71..477b47a7721 100644 --- a/chromium/net/cookies/cookie_monster.cc +++ b/chromium/net/cookies/cookie_monster.cc @@ -142,6 +142,8 @@ const size_t CookieMonster::kDomainPurgeCookies = 30; const size_t CookieMonster::kMaxCookies = 3300; const size_t CookieMonster::kPurgeCookies = 300; +const size_t CookieMonster::kMaxDomainPurgedKeys = 100; + const size_t CookieMonster::kDomainCookiesQuotaLow = 30; const size_t CookieMonster::kDomainCookiesQuotaMedium = 50; const size_t CookieMonster::kDomainCookiesQuotaHigh = @@ -319,7 +321,8 @@ CookieMonster::CookieMonster(scoped_refptr<PersistentCookieStore> store, CookieMonster::CookieMonster(scoped_refptr<PersistentCookieStore> store, base::TimeDelta last_access_threshold, NetLog* net_log) - : initialized_(false), + : num_keys_(0u), + initialized_(false), started_fetching_all_cookies_(false), finished_fetching_all_cookies_(false), seen_global_task_(false), @@ -578,8 +581,8 @@ void CookieMonster::GetCookieListWithOptions(const GURL& url, GetCookieListCallback callback) { DCHECK(thread_checker_.CalledOnValidThread()); - CookieStatusList included_cookies; - CookieStatusList excluded_cookies; + CookieAccessResultList included_cookies; + CookieAccessResultList excluded_cookies; if (HasCookieableScheme(url)) { std::vector<CanonicalCookie*> cookie_ptrs; FindCookiesForRegistryControlledHost(url, &cookie_ptrs); @@ -950,8 +953,8 @@ void CookieMonster::FilterCookiesWithOptions( const GURL url, const CookieOptions options, std::vector<CanonicalCookie*>* cookie_ptrs, - CookieStatusList* included_cookies, - CookieStatusList* excluded_cookies) { + CookieAccessResultList* included_cookies, + CookieAccessResultList* excluded_cookies) { DCHECK(thread_checker_.CalledOnValidThread()); // Probe to save statistics relatively frequently. We do it here rather @@ -965,12 +968,12 @@ void CookieMonster::FilterCookiesWithOptions( // Filter out cookies that should not be included for a request to the // given |url|. HTTP only cookies are filtered depending on the passed // cookie |options|. - CanonicalCookie::CookieInclusionStatus status = (*it)->IncludeForRequestURL( + CookieAccessResult access_result = (*it)->IncludeForRequestURL( url, options, GetAccessSemanticsForCookieGet(**it)); - if (!status.IsInclude()) { + if (!access_result.status.IsInclude()) { if (options.return_excluded_cookies()) - excluded_cookies->push_back({**it, status}); + excluded_cookies->push_back({**it, access_result}); continue; } @@ -979,7 +982,7 @@ void CookieMonster::FilterCookiesWithOptions( MaybeRecordCookieAccessWithOptions(**it, options, false); - included_cookies->push_back({**it, status}); + included_cookies->push_back({**it, access_result}); } } @@ -990,12 +993,12 @@ void CookieMonster::MaybeDeleteEquivalentCookieAndUpdateStatus( bool skip_httponly, bool already_expired, base::Time* creation_date_to_inherit, - CanonicalCookie::CookieInclusionStatus* status) { + CookieInclusionStatus* status) { DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(!status->HasExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE)); + CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE)); DCHECK(!status->HasExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY)); + CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY)); bool found_equivalent_cookie = false; CookieMap::iterator deletion_candidate_it = cookies_.end(); @@ -1030,7 +1033,7 @@ void CookieMonster::MaybeDeleteEquivalentCookieAndUpdateStatus( capture_mode); }); status->AddExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE); + CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE); } if (cookie_being_set.IsEquivalent(*cur_existing_cookie)) { @@ -1050,8 +1053,8 @@ void CookieMonster::MaybeDeleteEquivalentCookieAndUpdateStatus( return NetLogCookieMonsterCookieRejectedHttponly( cur_existing_cookie, &cookie_being_set, capture_mode); }); - status->AddExclusionReason(CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_HTTP_ONLY); + status->AddExclusionReason( + CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY); } else { deletion_candidate_it = cur_it; } @@ -1067,8 +1070,7 @@ void CookieMonster::MaybeDeleteEquivalentCookieAndUpdateStatus( already_expired ? DELETE_COOKIE_EXPIRED_OVERWRITE : DELETE_COOKIE_OVERWRITE); } else if (status->HasExclusionReason( - CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE)) { + CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE)) { // Log that we preserved a cookie that would have been deleted due to // Leave Secure Cookies Alone. This arbitrarily only logs the last // |skipped_secure_cookie| that we were left with after the for loop, even @@ -1145,6 +1147,15 @@ CookieMonster::CookieMap::iterator CookieMonster::InternalInsertCookie( CookieChangeCause::INSERTED), true); + // If this is the first cookie in |cookies_| with this key, increment the + // |num_keys_| counter. + bool different_prev = + inserted == cookies_.begin() || std::prev(inserted)->first != key; + bool different_next = + inserted == cookies_.end() || std::next(inserted)->first != key; + if (different_prev && different_next) + ++num_keys_; + return inserted; } @@ -1154,19 +1165,18 @@ void CookieMonster::SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc, SetCookiesCallback callback) { DCHECK(thread_checker_.CalledOnValidThread()); - CanonicalCookie::CookieInclusionStatus status; + CookieInclusionStatus status; bool secure_source = source_url.SchemeIsCryptographic(); cc->SetSourceScheme(secure_source ? CookieSourceScheme::kSecure : CookieSourceScheme::kNonSecure); if ((cc->IsSecure() && !secure_source)) { - status.AddExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY); + status.AddExclusionReason(CookieInclusionStatus::EXCLUDE_SECURE_ONLY); } if (!IsCookieableScheme(source_url.scheme())) { status.AddExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME); + CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME); } const std::string key(GetKey(cc->Domain())); @@ -1194,9 +1204,9 @@ void CookieMonster::SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc, &creation_date_to_inherit, &status); if (status.HasExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE) || - status.HasExclusionReason(CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_HTTP_ONLY)) { + CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE) || + status.HasExclusionReason( + CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY)) { DVLOG(net::cookie_util::kVlogSetCookies) << "SetCookie() not clobbering httponly cookie or secure cookie for " "insecure scheme"; @@ -1293,8 +1303,7 @@ void CookieMonster::SetAllCookies(CookieList list, // shouldn't have a return value. But it should also be deleted (see // https://codereview.chromium.org/2882063002/#msg64), which would // solve the return value problem. - MaybeRunCookieCallback(std::move(callback), - CanonicalCookie::CookieInclusionStatus()); + MaybeRunCookieCallback(std::move(callback), CookieInclusionStatus()); } void CookieMonster::InternalUpdateCookieAccessTime(CanonicalCookie* cc, @@ -1358,6 +1367,16 @@ void CookieMonster::InternalDeleteCookie(CookieMap::iterator it, GetAccessSemanticsForCookie(*cc, false /* legacy_access_granted */), mapping.cause), mapping.notify); + + // If this is the last cookie in |cookies_| with this key, decrement the + // |num_keys_| counter. + bool different_prev = + it == cookies_.begin() || std::prev(it)->first != it->first; + bool different_next = + it == cookies_.end() || std::next(it)->first != it->first; + if (different_prev && different_next) + --num_keys_; + cookies_.erase(it); } @@ -1385,6 +1404,10 @@ size_t CookieMonster::GarbageCollect(const Time& current, if (cookie_its->size() > kDomainMaxCookies) { DVLOG(net::cookie_util::kVlogGarbageCollection) << "Deep Garbage Collect domain."; + + if (domain_purged_keys_.size() < kMaxDomainPurgedKeys) + domain_purged_keys_.insert(key); + size_t purge_goal = cookie_its->size() - (kDomainMaxCookies - kDomainPurgeCookies); DCHECK(purge_goal > kDomainPurgeCookies); @@ -1801,11 +1824,25 @@ void CookieMonster::RecordPeriodicStats(const base::Time& current_time) { return; } + if (DoRecordPeriodicStats()) + last_statistic_record_time_ = current_time; +} + +bool CookieMonster::DoRecordPeriodicStats() { + // These values are all bogus if we have only partially loaded the cookies. + if (started_fetching_all_cookies_ && !finished_fetching_all_cookies_) + return false; + // See InitializeHistograms() for details. histogram_count_->Add(cookies_.size()); - // More detailed statistics on cookie counts at different granularities. - last_statistic_record_time_ = current_time; + // Can be up to kMaxDomainPurgedKeys. + UMA_HISTOGRAM_COUNTS_100("Cookie.NumDomainPurgedKeys", + domain_purged_keys_.size()); + // Can be up to kMaxCookies. + UMA_HISTOGRAM_COUNTS_10000("Cookie.NumKeys", num_keys_); + + return true; } // Initialize all histogram counter variables used in this class. diff --git a/chromium/net/cookies/cookie_monster.h b/chromium/net/cookies/cookie_monster.h index 46001bd4e4e..9908e6f8e7e 100644 --- a/chromium/net/cookies/cookie_monster.h +++ b/chromium/net/cookies/cookie_monster.h @@ -31,6 +31,7 @@ #include "net/cookies/canonical_cookie.h" #include "net/cookies/cookie_access_delegate.h" #include "net/cookies/cookie_constants.h" +#include "net/cookies/cookie_inclusion_status.h" #include "net/cookies/cookie_monster_change_dispatcher.h" #include "net/cookies/cookie_store.h" #include "net/log/net_log_with_source.h" @@ -123,6 +124,9 @@ class NET_EXPORT CookieMonster : public CookieStore { static const size_t kMaxCookies; static const size_t kPurgeCookies; + // Max number of keys to store for domains that have been purged. + static const size_t kMaxDomainPurgedKeys; + // Quota for cookies with {low, medium, high} priorities within a domain. static const size_t kDomainCookiesQuotaLow; static const size_t kDomainCookiesQuotaMedium; @@ -203,6 +207,10 @@ class NET_EXPORT CookieMonster : public CookieStore { // before the CookieMap typedef. static std::string GetKey(base::StringPiece domain); + // Triggers immediate recording of stats that are typically reported + // periodically. + bool DoRecordPeriodicStatsForTesting() { return DoRecordPeriodicStats(); } + private: // For garbage collection constants. FRIEND_TEST_ALL_PREFIXES(CookieMonsterTest, TestHostGarbageCollection); @@ -394,8 +402,8 @@ class NET_EXPORT CookieMonster : public CookieStore { void FilterCookiesWithOptions(const GURL url, const CookieOptions options, std::vector<CanonicalCookie*>* cookie_ptrs, - CookieStatusList* included_cookies, - CookieStatusList* excluded_cookies); + CookieAccessResultList* included_cookies, + CookieAccessResultList* excluded_cookies); // Possibly delete an existing cookie equivalent to |cookie_being_set| (same // path, domain, and name). @@ -428,7 +436,7 @@ class NET_EXPORT CookieMonster : public CookieStore { bool skip_httponly, bool already_expired, base::Time* creation_date_to_inherit, - CanonicalCookie::CookieInclusionStatus* status); + CookieInclusionStatus* status); // This is only used if the RecentCreationTimeGrantsLegacyCookieSemantics // feature is enabled. It finds an equivalent cookie (based on name, domain, @@ -562,7 +570,11 @@ class NET_EXPORT CookieMonster : public CookieStore { // statistics if a sufficient time period has passed. void RecordPeriodicStats(const base::Time& current_time); - // Initialize the above variables; should only be called from + // Records the aforementioned stats if we have already finished loading all + // cookies. Returns whether stats were recorded. + bool DoRecordPeriodicStats(); + + // Initialize the histogram_* variables below; should only be called from // the constructor. void InitializeHistograms(); @@ -588,6 +600,15 @@ class NET_EXPORT CookieMonster : public CookieStore { base::HistogramBase* histogram_cookie_source_scheme_; base::HistogramBase* histogram_time_blocked_on_load_; + // Set of keys (eTLD+1's) for which non-expired cookies have + // been evicted for hitting the per-domain max. The size of this set is + // histogrammed periodically. The size is limited to |kMaxDomainPurgedKeys|. + std::set<std::string> domain_purged_keys_; + + // The number of distinct keys (eTLD+1's) currently present in the |cookies_| + // multimap. This is histogrammed periodically. + size_t num_keys_; + CookieMap cookies_; CookieMonsterChangeDispatcher change_dispatcher_; diff --git a/chromium/net/cookies/cookie_monster_change_dispatcher.cc b/chromium/net/cookies/cookie_monster_change_dispatcher.cc index 28cfe347c58..6bd731f47ca 100644 --- a/chromium/net/cookies/cookie_monster_change_dispatcher.cc +++ b/chromium/net/cookies/cookie_monster_change_dispatcher.cc @@ -61,7 +61,7 @@ void CookieMonsterChangeDispatcher::Subscription::DispatchChange( !cookie .IncludeForRequestURL(url_, CookieOptions::MakeAllInclusive(), change.access_semantics) - .IsInclude()) { + .status.IsInclude()) { return; } diff --git a/chromium/net/cookies/cookie_monster_perftest.cc b/chromium/net/cookies/cookie_monster_perftest.cc index 6966a8a9e4b..96d16f545a6 100644 --- a/chromium/net/cookies/cookie_monster_perftest.cc +++ b/chromium/net/cookies/cookie_monster_perftest.cc @@ -105,7 +105,7 @@ class SetCookieCallback : public CookieTestCallback { } private: - void Run(CanonicalCookie::CookieInclusionStatus status) { + void Run(CookieInclusionStatus status) { EXPECT_TRUE(status.IsInclude()); CookieTestCallback::Run(); } @@ -123,9 +123,9 @@ class GetCookieListCallback : public CookieTestCallback { } private: - void Run(const CookieStatusList& cookie_list, - const CookieStatusList& excluded_cookies) { - cookie_list_ = cookie_util::StripStatuses(cookie_list); + void Run(const CookieAccessResultList& cookie_list, + const CookieAccessResultList& excluded_cookies) { + cookie_list_ = cookie_util::StripAccessResults(cookie_list); CookieTestCallback::Run(); } CookieList cookie_list_; diff --git a/chromium/net/cookies/cookie_monster_unittest.cc b/chromium/net/cookies/cookie_monster_unittest.cc index 82877bcb54b..fc83d6a6211 100644 --- a/chromium/net/cookies/cookie_monster_unittest.cc +++ b/chromium/net/cookies/cookie_monster_unittest.cc @@ -135,7 +135,7 @@ class CookieMonsterTestBase : public CookieStoreTest<T> { return callback.cookies(); } - CookieStatusList GetExcludedCookiesForURLWithOptions( + CookieAccessResultList GetExcludedCookiesForURLWithOptions( CookieMonster* cm, const GURL& url, const CookieOptions& options) { @@ -148,7 +148,7 @@ class CookieMonsterTestBase : public CookieStoreTest<T> { bool SetAllCookies(CookieMonster* cm, const CookieList& list) { DCHECK(cm); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieInclusionStatus> callback; cm->SetAllCookiesAsync(list, callback.MakeCallback()); callback.WaitUntilDone(); return callback.result().IsInclude(); @@ -160,7 +160,7 @@ class CookieMonsterTestBase : public CookieStoreTest<T> { base::Time creation_time) { DCHECK(cm); DCHECK(!creation_time.is_null()); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieInclusionStatus> callback; cm->SetCanonicalCookieAsync( CanonicalCookie::Create(url, cookie_line, creation_time, base::nullopt /* server_time */), @@ -310,10 +310,10 @@ class CookieMonsterTestBase : public CookieStoreTest<T> { } void TestHostGarbageCollectHelper() { + const char kHistogramName[] = "Cookie.NumDomainPurgedKeys"; int domain_max_cookies = CookieMonster::kDomainMaxCookies; int domain_purge_cookies = CookieMonster::kDomainPurgeCookies; - const int more_than_enough_cookies = - (domain_max_cookies + domain_purge_cookies) * 2; + const int more_than_enough_cookies = domain_max_cookies + 10; // Add a bunch of cookies on a single host, should purge them. { auto cm = std::make_unique<CookieMonster>(nullptr, &net_log_); @@ -326,6 +326,10 @@ class CookieMonsterTestBase : public CookieStoreTest<T> { // Count the number of cookies. EXPECT_LE(CountInString(cookies, '='), domain_max_cookies); } + base::HistogramTester histogram_tester; + EXPECT_TRUE(cm->DoRecordPeriodicStatsForTesting()); + histogram_tester.ExpectUniqueSample(kHistogramName, 1 /* sample */, + 1 /* count */); } // Add a bunch of cookies on multiple hosts within a single eTLD. @@ -359,6 +363,51 @@ class CookieMonsterTestBase : public CookieStoreTest<T> { CountInString(cookies_specific, '=')); EXPECT_GE(total_cookies, domain_max_cookies - domain_purge_cookies); EXPECT_LE(total_cookies, domain_max_cookies); + + base::HistogramTester histogram_tester; + EXPECT_TRUE(cm->DoRecordPeriodicStatsForTesting()); + histogram_tester.ExpectUniqueSample(kHistogramName, 1 /* sample */, + 1 /* count */); + } + + // Test histogram for the number of registrable domains affected by domain + // purge. + { + auto cm = std::make_unique<CookieMonster>(nullptr, &net_log_); + GURL url; + for (int domain_num = 0; domain_num < 3; ++domain_num) { + url = GURL(base::StringPrintf("http://domain%d.test", domain_num)); + for (int i = 0; i < more_than_enough_cookies; ++i) { + std::string cookie = base::StringPrintf("a%03d=b", i); + EXPECT_TRUE(SetCookie(cm.get(), url, cookie)); + std::string cookies = this->GetCookies(cm.get(), url); + // Make sure we find it in the cookies. + EXPECT_NE(cookies.find(cookie), std::string::npos); + // Count the number of cookies. + EXPECT_LE(CountInString(cookies, '='), domain_max_cookies); + } + base::HistogramTester histogram_tester; + EXPECT_TRUE(cm->DoRecordPeriodicStatsForTesting()); + histogram_tester.ExpectUniqueSample( + kHistogramName, domain_num + 1 /* sample */, 1 /* count */); + } + + // Triggering eviction again for a previously affected registrable domain + // does not increment the histogram. + for (int i = 0; i < domain_purge_cookies * 2; ++i) { + // Add some extra cookies (different names than before). + std::string cookie = base::StringPrintf("b%03d=b", i); + EXPECT_TRUE(SetCookie(cm.get(), url, cookie)); + std::string cookies = this->GetCookies(cm.get(), url); + // Make sure we find it in the cookies. + EXPECT_NE(cookies.find(cookie), std::string::npos); + // Count the number of cookies. + EXPECT_LE(CountInString(cookies, '='), domain_max_cookies); + } + base::HistogramTester histogram_tester; + EXPECT_TRUE(cm->DoRecordPeriodicStatsForTesting()); + histogram_tester.ExpectUniqueSample(kHistogramName, 3 /* sample */, + 1 /* count */); } } @@ -932,7 +981,7 @@ TEST_F(DeferredCookieTaskTest, DeferredSetCookie) { // Generate puts to store w/o needing a proper expiration. cookie_monster_->SetPersistSessionCookies(true); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> call1; + ResultSavingCookieCallback<CookieInclusionStatus> call1; cookie_monster_->SetCanonicalCookieAsync( CanonicalCookie::Create(http_www_foo_.url(), "A=B", base::Time::Now(), base::nullopt /* server_time */), @@ -946,7 +995,7 @@ TEST_F(DeferredCookieTaskTest, DeferredSetCookie) { EXPECT_TRUE(call1.result().IsInclude()); EXPECT_EQ("LOAD; LOAD_FOR_KEY:foo.com; ADD; ", TakeCommandSummary()); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> call2; + ResultSavingCookieCallback<CookieInclusionStatus> call2; cookie_monster_->SetCanonicalCookieAsync( CanonicalCookie::Create(http_www_foo_.url(), "X=Y", base::Time::Now(), base::nullopt /* server_time */), @@ -971,7 +1020,7 @@ TEST_F(DeferredCookieTaskTest, DeferredSetAllCookies) { false, true, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT)); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> call1; + ResultSavingCookieCallback<CookieInclusionStatus> call1; cookie_monster_->SetAllCookiesAsync(list, call1.MakeCallback()); base::RunLoop().RunUntilIdle(); EXPECT_FALSE(call1.was_run()); @@ -982,7 +1031,7 @@ TEST_F(DeferredCookieTaskTest, DeferredSetAllCookies) { EXPECT_EQ("LOAD; ADD; ADD; ", TakeCommandSummary()); // 2nd set doesn't need to read from store. It erases the old cookies, though. - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> call2; + ResultSavingCookieCallback<CookieInclusionStatus> call2; cookie_monster_->SetAllCookiesAsync(list, call2.MakeCallback()); ASSERT_TRUE(call2.was_run()); EXPECT_TRUE(call2.result().IsInclude()); @@ -1183,30 +1232,30 @@ TEST_F(DeferredCookieTaskTest, DeferredTaskOrder) { bool get_cookie_list_callback_was_run = false; GetCookieListCallback get_cookie_list_callback_deferred; - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> - set_cookies_callback; + ResultSavingCookieCallback<CookieInclusionStatus> set_cookies_callback; base::RunLoop run_loop; cookie_monster_->GetCookieListWithOptionsAsync( http_www_foo_.url(), CookieOptions::MakeAllInclusive(), - base::BindLambdaForTesting([&](const CookieStatusList& cookies, - const CookieStatusList& excluded_list) { - // This should complete before the set. - get_cookie_list_callback_was_run = true; - EXPECT_FALSE(set_cookies_callback.was_run()); - EXPECT_THAT(cookies, MatchesCookieLine("X=1")); - // Can't use TakeCommandSummary here since ExecuteLoads is walking - // through the data it takes. - EXPECT_EQ("LOAD; LOAD_FOR_KEY:foo.com; ", - CommandSummary(persistent_store_->commands())); - - // Queue up a second get. It should see the result of the set queued - // before it. - cookie_monster_->GetCookieListWithOptionsAsync( - http_www_foo_.url(), CookieOptions::MakeAllInclusive(), - get_cookie_list_callback_deferred.MakeCallback()); - - run_loop.Quit(); - })); + base::BindLambdaForTesting( + [&](const CookieAccessResultList& cookies, + const CookieAccessResultList& excluded_list) { + // This should complete before the set. + get_cookie_list_callback_was_run = true; + EXPECT_FALSE(set_cookies_callback.was_run()); + EXPECT_THAT(cookies, MatchesCookieLine("X=1")); + // Can't use TakeCommandSummary here since ExecuteLoads is walking + // through the data it takes. + EXPECT_EQ("LOAD; LOAD_FOR_KEY:foo.com; ", + CommandSummary(persistent_store_->commands())); + + // Queue up a second get. It should see the result of the set queued + // before it. + cookie_monster_->GetCookieListWithOptionsAsync( + http_www_foo_.url(), CookieOptions::MakeAllInclusive(), + get_cookie_list_callback_deferred.MakeCallback()); + + run_loop.Quit(); + })); cookie_monster_->SetCanonicalCookieAsync( CanonicalCookie::Create(http_www_foo_.url(), "A=B", base::Time::Now(), @@ -1446,15 +1495,13 @@ TEST_F(CookieMonsterTest, SetCookieableSchemes) { EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), foo_url, "x=1") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_NONCOOKIEABLE_SCHEME})); + {CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME})); EXPECT_TRUE(SetCanonicalCookieReturnStatus( cm.get(), CanonicalCookie::Create(foo_url, "y=1", now, server_time), foo_url, false /*modify_httponly*/) .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_NONCOOKIEABLE_SCHEME})); + {CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME})); EXPECT_TRUE( CreateAndSetCookieReturnStatus(cm_foo.get(), foo_url, "x=1").IsInclude()); @@ -1466,15 +1513,13 @@ TEST_F(CookieMonsterTest, SetCookieableSchemes) { EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm_foo.get(), http_url, "x=1") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_NONCOOKIEABLE_SCHEME})); + {CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME})); EXPECT_TRUE(SetCanonicalCookieReturnStatus( cm_foo.get(), CanonicalCookie::Create(http_url, "y=1", now, server_time), http_url, false /*modify_httponly*/) .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_NONCOOKIEABLE_SCHEME})); + {CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME})); } TEST_F(CookieMonsterTest, GetAllCookiesForURL) { @@ -1573,7 +1618,7 @@ TEST_F(CookieMonsterTest, GetExcludedCookiesForURL) { CookieOptions do_not_return_excluded; do_not_return_excluded.unset_return_excluded_cookies(); - CookieStatusList excluded_cookies = GetExcludedCookiesForURLWithOptions( + CookieAccessResultList excluded_cookies = GetExcludedCookiesForURLWithOptions( cm.get(), http_www_foo_.url(), do_not_return_excluded); auto iter = excluded_cookies.begin(); @@ -1587,8 +1632,8 @@ TEST_F(CookieMonsterTest, GetExcludedCookiesForURL) { ASSERT_TRUE(iter != excluded_cookies.end()); EXPECT_EQ(http_www_foo_.Format(".%D"), iter->cookie.Domain()); EXPECT_EQ("E", iter->cookie.Name()); - EXPECT_TRUE(iter->status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY})); + EXPECT_TRUE(iter->access_result.status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_SECURE_ONLY})); ASSERT_TRUE(++iter == excluded_cookies.end()); @@ -1607,14 +1652,14 @@ TEST_F(CookieMonsterTest, GetExcludedCookiesForURL) { ASSERT_TRUE(iter != excluded_cookies.end()); EXPECT_EQ(http_www_foo_.host(), iter->cookie.Domain()); EXPECT_EQ("A", iter->cookie.Name()); - EXPECT_TRUE(iter->status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY})); + EXPECT_TRUE(iter->access_result.status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_HTTP_ONLY})); ASSERT_TRUE(++iter != excluded_cookies.end()); EXPECT_EQ(http_www_foo_.Format(".%D"), iter->cookie.Domain()); EXPECT_EQ("E", iter->cookie.Name()); - EXPECT_TRUE(iter->status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY})); + EXPECT_TRUE(iter->access_result.status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_SECURE_ONLY})); ASSERT_TRUE(++iter == excluded_cookies.end()); @@ -1674,15 +1719,15 @@ TEST_F(CookieMonsterTest, GetExcludedCookiesForURLPathMatching) { EXPECT_TRUE( CreateAndSetCookie(cm.get(), http_www_foo_.url(), "E=F;", options)); - CookieStatusList excluded_cookies = + CookieAccessResultList excluded_cookies = GetExcludedCookiesForURL(cm.get(), www_foo_foo_.url()); auto it = excluded_cookies.begin(); ASSERT_TRUE(it != excluded_cookies.end()); EXPECT_EQ("C", it->cookie.Name()); EXPECT_EQ("/bar", it->cookie.Path()); - EXPECT_TRUE(it->status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_NOT_ON_PATH})); + EXPECT_TRUE(it->access_result.status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_NOT_ON_PATH})); ASSERT_TRUE(++it == excluded_cookies.end()); @@ -1692,8 +1737,8 @@ TEST_F(CookieMonsterTest, GetExcludedCookiesForURLPathMatching) { ASSERT_TRUE(it != excluded_cookies.end()); EXPECT_EQ("A", it->cookie.Name()); EXPECT_EQ("/foo", it->cookie.Path()); - EXPECT_TRUE(it->status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_NOT_ON_PATH})); + EXPECT_TRUE(it->access_result.status.HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_NOT_ON_PATH})); ASSERT_TRUE(++it == excluded_cookies.end()); } @@ -2189,8 +2234,7 @@ TEST_F(CookieMonsterTest, WhileLoadingLoadCompletesBeforeKeyLoadCompletes) { auto cookie = CanonicalCookie::Create(kUrl, "a=b", base::Time::Now(), base::nullopt /* server_time */); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> - set_cookie_callback; + ResultSavingCookieCallback<CookieInclusionStatus> set_cookie_callback; cm->SetCanonicalCookieAsync(std::move(cookie), kUrl, CookieOptions::MakeAllInclusive(), set_cookie_callback.MakeCallback()); @@ -2278,8 +2322,7 @@ TEST_F(CookieMonsterTest, WhileLoadingGetAllSetGetAll) { auto cookie = CanonicalCookie::Create(kUrl, "a=b", base::Time::Now(), base::nullopt /* server_time */); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> - set_cookie_callback; + ResultSavingCookieCallback<CookieInclusionStatus> set_cookie_callback; cm->SetCanonicalCookieAsync(std::move(cookie), kUrl, CookieOptions::MakeAllInclusive(), set_cookie_callback.MakeCallback()); @@ -2326,8 +2369,7 @@ TEST_F(CookieMonsterTest, CheckOrderOfCookieTaskQueueWhenLoadingCompletes) { // Get all cookies task that queues a task to set a cookie when executed. auto cookie = CanonicalCookie::Create(kUrl, "a=b", base::Time::Now(), base::nullopt /* server_time */); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> - set_cookie_callback; + ResultSavingCookieCallback<CookieInclusionStatus> set_cookie_callback; cm->GetAllCookiesAsync(base::BindOnce( &RunClosureOnAllCookiesReceived, base::BindOnce(&CookieStore::SetCanonicalCookieAsync, @@ -2720,6 +2762,95 @@ TEST_F(CookieMonsterTest, CookieSourceHistogram) { CookieMonster::COOKIE_SOURCE_NONSECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME, 1); } +// Test that inserting the first cookie for a key and deleting the last cookie +// for a key correctly reflected in the Cookie.NumKeys histogram. +TEST_F(CookieMonsterTest, NumKeysHistogram) { + const char kHistogramName[] = "Cookie.NumKeys"; + + // Test loading cookies from store. + scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore); + std::vector<std::unique_ptr<CanonicalCookie>> initial_cookies; + initial_cookies.push_back(CanonicalCookie::Create( + GURL("http://domain1.test"), "A=1", base::Time::Now(), base::nullopt)); + initial_cookies.push_back(CanonicalCookie::Create( + GURL("http://domain2.test"), "A=1", base::Time::Now(), base::nullopt)); + initial_cookies.push_back( + CanonicalCookie::Create(GURL("http://sub.domain2.test"), "A=1", + base::Time::Now(), base::nullopt)); + initial_cookies.push_back(CanonicalCookie::Create( + GURL("http://domain3.test"), "A=1", base::Time::Now(), base::nullopt)); + initial_cookies.push_back(CanonicalCookie::Create( + GURL("http://domain3.test"), "B=1", base::Time::Now(), base::nullopt)); + store->SetLoadExpectation(true /* return_value */, + std::move(initial_cookies)); + auto cm = std::make_unique<CookieMonster>(store.get(), &net_log_); + { + base::HistogramTester histogram_tester; + // Access the cookies to trigger loading from the persistent store. + EXPECT_EQ(5u, this->GetAllCookies(cm.get()).size()); + EXPECT_TRUE(cm->DoRecordPeriodicStatsForTesting()); + // There should be 3 keys: "domain1.test", "domain2.test", and + // "domain3.test". + histogram_tester.ExpectUniqueSample(kHistogramName, 3 /* sample */, + 1 /* count */); + } + + // Test adding cookies for already existing key. + { + base::HistogramTester histogram_tester; + EXPECT_TRUE(CreateAndSetCookie(cm.get(), GURL("https://domain1.test"), + "B=1", CookieOptions::MakeAllInclusive())); + EXPECT_TRUE(CreateAndSetCookie(cm.get(), GURL("http://sub.domain1.test"), + "B=1", CookieOptions::MakeAllInclusive())); + EXPECT_TRUE(cm->DoRecordPeriodicStatsForTesting()); + histogram_tester.ExpectUniqueSample(kHistogramName, 3 /* sample */, + 1 /* count */); + } + + // Test adding a cookie for a new key. + { + base::HistogramTester histogram_tester; + EXPECT_TRUE(CreateAndSetCookie(cm.get(), GURL("https://domain4.test"), + "A=1", CookieOptions::MakeAllInclusive())); + EXPECT_TRUE(cm->DoRecordPeriodicStatsForTesting()); + histogram_tester.ExpectUniqueSample(kHistogramName, 4 /* sample */, + 1 /* count */); + } + + // Test overwriting the only cookie for a key. (Deletes and inserts, so the + // total doesn't change.) + { + base::HistogramTester histogram_tester; + EXPECT_TRUE(CreateAndSetCookie(cm.get(), GURL("https://domain4.test"), + "A=2", CookieOptions::MakeAllInclusive())); + EXPECT_TRUE(cm->DoRecordPeriodicStatsForTesting()); + histogram_tester.ExpectUniqueSample(kHistogramName, 4 /* sample */, + 1 /* count */); + } + + // Test deleting cookie for a key with more than one cookie. + { + base::HistogramTester histogram_tester; + EXPECT_TRUE(CreateAndSetCookie(cm.get(), GURL("https://domain2.test"), + "A=1; Max-Age=0", + CookieOptions::MakeAllInclusive())); + EXPECT_TRUE(cm->DoRecordPeriodicStatsForTesting()); + histogram_tester.ExpectUniqueSample(kHistogramName, 4 /* sample */, + 1 /* count */); + } + + // Test deleting cookie for a key with only one cookie. + { + base::HistogramTester histogram_tester; + EXPECT_TRUE(CreateAndSetCookie(cm.get(), GURL("https://domain4.test"), + "A=1; Max-Age=0", + CookieOptions::MakeAllInclusive())); + EXPECT_TRUE(cm->DoRecordPeriodicStatsForTesting()); + histogram_tester.ExpectUniqueSample(kHistogramName, 3 /* sample */, + 1 /* count */); + } +} + TEST_F(CookieMonsterTest, MaybeDeleteEquivalentCookieAndUpdateStatus) { scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore); std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), &net_log_)); @@ -2728,10 +2859,9 @@ TEST_F(CookieMonsterTest, MaybeDeleteEquivalentCookieAndUpdateStatus) { auto preexisting_cookie = CanonicalCookie::Create( https_www_foo_.url(), "A=B;Secure;HttpOnly", base::Time::Now(), base::nullopt /* server_time */); - CanonicalCookie::CookieInclusionStatus status = - SetCanonicalCookieReturnStatus(cm.get(), std::move(preexisting_cookie), - https_www_foo_.url(), - true /* can_modify_httponly */); + CookieInclusionStatus status = SetCanonicalCookieReturnStatus( + cm.get(), std::move(preexisting_cookie), https_www_foo_.url(), + true /* can_modify_httponly */); ASSERT_TRUE(status.IsInclude()); // Set a new cookie with a different name. Should work because cookies with @@ -2753,7 +2883,7 @@ TEST_F(CookieMonsterTest, MaybeDeleteEquivalentCookieAndUpdateStatus) { http_www_foo_.url(), true /* can_modify_httponly */); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); // The preexisting cookie should still be there. EXPECT_THAT(GetCookiesWithOptions(cm.get(), https_www_foo_.url(), CookieOptions::MakeAllInclusive()), @@ -2784,7 +2914,7 @@ TEST_F(CookieMonsterTest, MaybeDeleteEquivalentCookieAndUpdateStatus) { http_www_foo_.url(), true /* can_modify_httponly */); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); // The preexisting cookie should still be there. EXPECT_THAT(GetCookiesWithOptions(cm.get(), https_www_foo_.url(), CookieOptions::MakeAllInclusive()), @@ -2812,7 +2942,7 @@ TEST_F(CookieMonsterTest, MaybeDeleteEquivalentCookieAndUpdateStatus) { https_www_foo_.url(), false /* can_modify_httponly */); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY})); entries = net_log_.GetEntries(); ExpectLogContainsSomewhere( @@ -2832,10 +2962,9 @@ TEST_F(CookieMonsterTest, SkipDontOverwriteForMultipleReasons) { auto preexisting_cookie = CanonicalCookie::Create( https_www_foo_.url(), "A=B;Secure;HttpOnly", base::Time::Now(), base::nullopt /* server_time */); - CanonicalCookie::CookieInclusionStatus status = - SetCanonicalCookieReturnStatus(cm.get(), std::move(preexisting_cookie), - https_www_foo_.url(), - true /* can_modify_httponly */); + CookieInclusionStatus status = SetCanonicalCookieReturnStatus( + cm.get(), std::move(preexisting_cookie), https_www_foo_.url(), + true /* can_modify_httponly */); ASSERT_TRUE(status.IsInclude()); // Attempt to set a new cookie with the same name that is not Secure or @@ -2847,8 +2976,8 @@ TEST_F(CookieMonsterTest, SkipDontOverwriteForMultipleReasons) { http_www_foo_.url(), false /* can_modify_httponly */); EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE, - CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE, + CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY})); auto entries = net_log_.GetEntries(); ExpectLogContainsSomewhere( @@ -2868,21 +2997,19 @@ TEST_F(CookieMonsterTest, DontDeleteEquivalentCookieIfSetIsRejected) { auto preexisting_cookie = CanonicalCookie::Create( http_www_foo_.url(), "cookie=foo", base::Time::Now(), base::nullopt /* server_time */); - CanonicalCookie::CookieInclusionStatus status = - SetCanonicalCookieReturnStatus(cm.get(), std::move(preexisting_cookie), - http_www_foo_.url(), - false /* can_modify_httponly */); + CookieInclusionStatus status = SetCanonicalCookieReturnStatus( + cm.get(), std::move(preexisting_cookie), http_www_foo_.url(), + false /* can_modify_httponly */); ASSERT_TRUE(status.IsInclude()); auto bad_cookie = CanonicalCookie::Create( http_www_foo_.url(), "cookie=bar;secure", base::Time::Now(), base::nullopt /* server_time */); - CanonicalCookie::CookieInclusionStatus status2 = - SetCanonicalCookieReturnStatus(cm.get(), std::move(bad_cookie), - http_www_foo_.url(), - false /* can_modify_httponly */); + CookieInclusionStatus status2 = SetCanonicalCookieReturnStatus( + cm.get(), std::move(bad_cookie), http_www_foo_.url(), + false /* can_modify_httponly */); EXPECT_TRUE(status2.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY})); + {CookieInclusionStatus::EXCLUDE_SECURE_ONLY})); // Check that the original cookie is still there. EXPECT_EQ("cookie=foo", GetCookies(cm.get(), https_www_foo_.url())); @@ -2904,10 +3031,9 @@ TEST_F(CookieMonsterTest, SetSecureCookies) { CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=B;").IsInclude()); // A secure cookie cannot be set from a URL with an insecure scheme. - EXPECT_TRUE( - CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=B; Secure") - .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY})); + EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=B; Secure") + .HasExactlyExclusionReasonsForTesting( + {CookieInclusionStatus::EXCLUDE_SECURE_ONLY})); // A secure cookie can be set from a URL with a secure scheme. EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=B; Secure") @@ -2919,8 +3045,7 @@ TEST_F(CookieMonsterTest, SetSecureCookies) { .IsInclude()); EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=C;") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); // If a non-secure cookie is created from a URL with an secure scheme, and a // secure cookie with the same name already exists, update the cookie. @@ -2939,13 +3064,11 @@ TEST_F(CookieMonsterTest, SetSecureCookies) { .IsInclude()); EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=C; path=/") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); EXPECT_TRUE( CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=C; path=/my/path") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); // But if the existing cookie has a path somewhere under the root, cookies // with the same name may be set for paths which don't overlap the existing @@ -2963,13 +3086,11 @@ TEST_F(CookieMonsterTest, SetSecureCookies) { EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "WITH_PATH=C; path=/my/path") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "WITH_PATH=C; path=/my/path/sub") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); DeleteAll(cm.get()); @@ -2994,12 +3115,10 @@ TEST_F(CookieMonsterTest, SetSecureCookies) { EXPECT_TRUE( CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=D; path=/foo") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=D; path=/") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); EXPECT_THAT(GetCookies(cm.get(), https_foo_url), testing::HasSubstr("A=C")); // ...but the original insecure cookie is still retained. @@ -3022,13 +3141,11 @@ TEST_F(CookieMonsterTest, SetSecureCookies) { EXPECT_TRUE( CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=C; domain=foo.com") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=C; domain=www.foo.com") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); // Since A=B was set above with no domain string, set a different cookie here // so the insecure examples aren't trying to overwrite the one above. @@ -3038,17 +3155,14 @@ TEST_F(CookieMonsterTest, SetSecureCookies) { EXPECT_TRUE( CreateAndSetCookieReturnStatus(cm.get(), http_url, "B=D; domain=foo.com") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "B=D") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); EXPECT_TRUE( CreateAndSetCookieReturnStatus(cm.get(), http_superdomain_url, "B=D") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})); // Verify that if an httponly version of the cookie exists, adding a Secure // version of the cookie still does not overwrite it. @@ -3059,8 +3173,7 @@ TEST_F(CookieMonsterTest, SetSecureCookies) { // which in this case includes "exclude_httponly = true". EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), https_url, "C=E; Secure") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_HTTP_ONLY})); + {CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY})); auto entries = net_log_.GetEntries(); ExpectLogContainsSomewhere( @@ -3109,8 +3222,7 @@ TEST_F(CookieMonsterTest, LeaveSecureCookiesAlone_DomainMatch) { // cookie exists. EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=1") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})) + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})) << "Insecure host cookie from " << http_url << " should not be set if equivalent secure host cookie from " << preexisting_cookie_url << " exists."; @@ -3118,15 +3230,13 @@ TEST_F(CookieMonsterTest, LeaveSecureCookiesAlone_DomainMatch) { cm.get(), http_url, base::StrCat({"A=2; Domain=", new_cookie_host})) .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})) + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})) << "Insecure domain cookie from " << http_url << " should not be set if equivalent secure host cookie from " << preexisting_cookie_url << " exists."; EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "B=1") .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})) + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})) << "Insecure host cookie from " << http_url << " should not be set if equivalent secure domain cookie from " << preexisting_cookie_url << " exists."; @@ -3134,8 +3244,7 @@ TEST_F(CookieMonsterTest, LeaveSecureCookiesAlone_DomainMatch) { cm.get(), http_url, base::StrCat({"B=2; Domain=", new_cookie_host})) .HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE})) + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE})) << "Insecure domain cookie from " << http_url << " should not be set if equivalent secure domain cookie from " << preexisting_cookie_url << " exists."; @@ -3282,14 +3391,11 @@ TEST_F(CookieMonsterTest, LeaveSecureCookiesAlone_PathMatch) { // Don't set insecure cookie from an insecure URL if equivalent secure // cookie exists. - CanonicalCookie::CookieInclusionStatus set = - CreateAndSetCookieReturnStatus( - cm.get(), http_url, - base::StrCat({"A=1; Path=", new_cookie_path})); + CookieInclusionStatus set = CreateAndSetCookieReturnStatus( + cm.get(), http_url, base::StrCat({"A=1; Path=", new_cookie_path})); EXPECT_TRUE(should_path_match ? set.HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_OVERWRITE_SECURE}) + {CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE}) : set.IsInclude()) << "Insecure cookie from " << http_url << " should " << (should_path_match ? "not " : "") @@ -3507,8 +3613,7 @@ TEST_F(CookieMonsterTest, SetCanonicalCookieDoesNotBlockForLoadAll) { CookieMonster cm(persistent_store.get(), nullptr); // Start of a canonical cookie set. - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> - callback_set; + ResultSavingCookieCallback<CookieInclusionStatus> callback_set; GURL cookie_url("http://a.com/"); cm.SetCanonicalCookieAsync( CanonicalCookie::Create(cookie_url, "A=B", base::Time::Now(), @@ -3594,16 +3699,14 @@ TEST_F(CookieMonsterTest, DeleteCookieWithInheritedTimestamps) { // Write a cookie created at |t1|. auto cookie = CanonicalCookie::Create(url, cookie_line, t1, server_time); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> - set_callback_1; + ResultSavingCookieCallback<CookieInclusionStatus> set_callback_1; cm.SetCanonicalCookieAsync(std::move(cookie), url, options, set_callback_1.MakeCallback()); set_callback_1.WaitUntilDone(); // Overwrite the cookie at |t2|. cookie = CanonicalCookie::Create(url, cookie_line, t2, server_time); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> - set_callback_2; + ResultSavingCookieCallback<CookieInclusionStatus> set_callback_2; cm.SetCanonicalCookieAsync(std::move(cookie), url, options, set_callback_2.MakeCallback()); set_callback_2.WaitUntilDone(); @@ -3627,7 +3730,7 @@ TEST_F(CookieMonsterTest, RejectCreatedSameSiteCookieOnSet) { CookieOptions::SameSiteCookieContext( CookieOptions::SameSiteCookieContext::ContextType::CROSS_SITE)); - CanonicalCookie::CookieInclusionStatus status; + CookieInclusionStatus status; // Cookie can be created successfully; SameSite is not checked on Creation. auto cookie = CanonicalCookie::Create(url, cookie_line, base::Time::Now(), @@ -3636,12 +3739,12 @@ TEST_F(CookieMonsterTest, RejectCreatedSameSiteCookieOnSet) { ASSERT_TRUE(status.IsInclude()); // ... but the environment is checked on set, so this may be rejected then. - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieInclusionStatus> callback; cm.SetCanonicalCookieAsync(std::move(cookie), url, env_cross_site, callback.MakeCallback()); callback.WaitUntilDone(); EXPECT_TRUE(callback.result().HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX})); + {CookieInclusionStatus::EXCLUDE_SAMESITE_LAX})); } TEST_F(CookieMonsterTest, RejectCreatedSecureCookieOnSet) { @@ -3649,7 +3752,7 @@ TEST_F(CookieMonsterTest, RejectCreatedSecureCookieOnSet) { std::string cookie_line = "foo=bar; Secure"; CookieMonster cm(nullptr, nullptr); - CanonicalCookie::CookieInclusionStatus status; + CookieInclusionStatus status; // Cookie can be created successfully from an any url. Secure is not checked // on Create. auto cookie = @@ -3660,13 +3763,13 @@ TEST_F(CookieMonsterTest, RejectCreatedSecureCookieOnSet) { ASSERT_TRUE(status.IsInclude()); // Cookie is rejected when attempting to set from a non-secure scheme. - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieInclusionStatus> callback; cm.SetCanonicalCookieAsync(std::move(cookie), http_url, CookieOptions::MakeAllInclusive(), callback.MakeCallback()); callback.WaitUntilDone(); EXPECT_TRUE(callback.result().HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY})); + {CookieInclusionStatus::EXCLUDE_SECURE_ONLY})); } TEST_F(CookieMonsterTest, RejectCreatedHttpOnlyCookieOnSet) { @@ -3674,7 +3777,7 @@ TEST_F(CookieMonsterTest, RejectCreatedHttpOnlyCookieOnSet) { std::string cookie_line = "foo=bar; HttpOnly"; CookieMonster cm(nullptr, nullptr); - CanonicalCookie::CookieInclusionStatus status; + CookieInclusionStatus status; // Cookie can be created successfully; HttpOnly is not checked on Create. auto cookie = CanonicalCookie::Create(url, cookie_line, base::Time::Now(), @@ -3690,12 +3793,12 @@ TEST_F(CookieMonsterTest, RejectCreatedHttpOnlyCookieOnSet) { CookieOptions::SameSiteCookieContext( CookieOptions::SameSiteCookieContext::ContextType::SAME_SITE_STRICT)); options_no_httponly.set_exclude_httponly(); // Default, but make it explicit. - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieInclusionStatus> callback; cm.SetCanonicalCookieAsync(std::move(cookie), url, options_no_httponly, callback.MakeCallback()); callback.WaitUntilDone(); EXPECT_TRUE(callback.result().HasExactlyExclusionReasonsForTesting( - {CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY})); + {CookieInclusionStatus::EXCLUDE_HTTP_ONLY})); } // Test the CookiesWithoutSameSiteMustBeSecure experimental option (in @@ -3708,7 +3811,7 @@ TEST_F(CookieMonsterTest, CookiesWithoutSameSiteMustBeSecure) { bool is_cookies_without_samesite_must_be_secure_enabled; bool is_url_secure; std::string cookie_line; - CanonicalCookie::CookieInclusionStatus expected_set_cookie_result; + CookieInclusionStatus expected_set_cookie_result; // Only makes sense to check if result is INCLUDE: CookieEffectiveSameSite expected_effective_samesite = CookieEffectiveSameSite::NO_RESTRICTION; @@ -3716,80 +3819,67 @@ TEST_F(CookieMonsterTest, CookiesWithoutSameSiteMustBeSecure) { } test_cases[] = { // Feature enabled: // Cookie set from a secure URL with SameSite enabled is not rejected. - {true, true, "A=B; SameSite=Lax", - CanonicalCookie::CookieInclusionStatus(), + {true, true, "A=B; SameSite=Lax", CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE}, // Cookie set from a secure URL which is defaulted into Lax is not // rejected. {true, true, "A=B", // recently-set session cookie. - CanonicalCookie::CookieInclusionStatus(), - CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, kShortAge}, + CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, + kShortAge}, {true, true, "A=B", // not-recently-set session cookie. - CanonicalCookie::CookieInclusionStatus(), - CookieEffectiveSameSite::LAX_MODE, kLongAge}, + CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE, kLongAge}, // Cookie set from a secure URL with SameSite=None and Secure is set. - {true, true, "A=B; SameSite=None; Secure", - CanonicalCookie::CookieInclusionStatus(), + {true, true, "A=B; SameSite=None; Secure", CookieInclusionStatus(), CookieEffectiveSameSite::NO_RESTRICTION}, // Cookie set from a secure URL with SameSite=None but not specifying // Secure is rejected. {true, true, "A=B; SameSite=None", - CanonicalCookie::CookieInclusionStatus( - CanonicalCookie::CookieInclusionStatus:: - EXCLUDE_SAMESITE_NONE_INSECURE, - CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_NONE_INSECURE)}, + CookieInclusionStatus( + CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE, + CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE)}, // Cookie set from an insecure URL which defaults into LAX_MODE is not // rejected. {true, false, "A=B", // recently-set session cookie. - CanonicalCookie::CookieInclusionStatus(), - CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, kShortAge}, + CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, + kShortAge}, {true, false, "A=B", // not-recently-set session cookie. - CanonicalCookie::CookieInclusionStatus(), - CookieEffectiveSameSite::LAX_MODE, kLongAge}, + CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE, kLongAge}, {true, false, "A=B; Max-Age=1000000", // recently-set persistent cookie. - CanonicalCookie::CookieInclusionStatus(), - CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, kShortAge}, + CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, + kShortAge}, {true, false, "A=B; Max-Age=1000000", // not-recently-set persistent cookie. - CanonicalCookie::CookieInclusionStatus(), - CookieEffectiveSameSite::LAX_MODE, kLongAge}, + CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE, kLongAge}, // Feature not enabled (but SameSiteByDefaultCookies is still enabled): // Cookie set from a secure URL with SameSite enabled is not rejected. - {false, true, "A=B; SameSite=Lax", - CanonicalCookie::CookieInclusionStatus(), + {false, true, "A=B; SameSite=Lax", CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE}, // Cookie set from a secure URL which is defaulted into Lax is not // rejected. {false, true, "A=B", // recently-set session cookie. - CanonicalCookie::CookieInclusionStatus(), - CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, kShortAge}, + CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, + kShortAge}, {false, true, "A=B", // not-recently-set session cookie. - CanonicalCookie::CookieInclusionStatus(), - CookieEffectiveSameSite::LAX_MODE, kLongAge}, + CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE, kLongAge}, // Cookie set from a secure URL with SameSite=None and Secure is set. - {false, true, "A=B; SameSite=None; Secure", - CanonicalCookie::CookieInclusionStatus(), + {false, true, "A=B; SameSite=None; Secure", CookieInclusionStatus(), CookieEffectiveSameSite::NO_RESTRICTION}, // Cookie set from an insecure URL with SameSite=None (which can't ever be // secure because it's an insecure URL) is NOT rejected, because // CookiesWithoutSameSiteMustBeSecure is not enabled. {false, false, "A=B; SameSite=None", - CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting( - std::vector< - CanonicalCookie::CookieInclusionStatus::ExclusionReason>(), - {CanonicalCookie::CookieInclusionStatus:: - WARN_SAMESITE_NONE_INSECURE}), + CookieInclusionStatus::MakeFromReasonsForTesting( + std::vector<CookieInclusionStatus::ExclusionReason>(), + {CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE}), CookieEffectiveSameSite::NO_RESTRICTION}, // Cookie set from an insecure URL which is defaulted into Lax is not // rejected. {false, false, "A=B", // recently-set session cookie. - CanonicalCookie::CookieInclusionStatus(), - CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, kShortAge}, + CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE_ALLOW_UNSAFE, + kShortAge}, {false, false, "A=B", // not-recently-set session cookie. - CanonicalCookie::CookieInclusionStatus(), - CookieEffectiveSameSite::LAX_MODE, kLongAge}, + CookieInclusionStatus(), CookieEffectiveSameSite::LAX_MODE, kLongAge}, }; auto cm = std::make_unique<CookieMonster>(nullptr, nullptr); @@ -3820,10 +3910,9 @@ TEST_F(CookieMonsterTest, CookiesWithoutSameSiteMustBeSecure) { base::nullopt /* server_time */); // Make a copy so we can delete it after the test. CanonicalCookie cookie_copy = *cookie; - CanonicalCookie::CookieInclusionStatus result = - SetCanonicalCookieReturnStatus( - cm.get(), std::move(cookie), url, - true /* can_modify_httponly (irrelevant) */); + CookieInclusionStatus result = SetCanonicalCookieReturnStatus( + cm.get(), std::move(cookie), url, + true /* can_modify_httponly (irrelevant) */); EXPECT_EQ(test.expected_set_cookie_result, result) << "Test case " << i << " failed."; if (result.IsInclude()) { diff --git a/chromium/net/cookies/cookie_store.h b/chromium/net/cookies/cookie_store.h index 4157f0ce83a..47f2942cd32 100644 --- a/chromium/net/cookies/cookie_store.h +++ b/chromium/net/cookies/cookie_store.h @@ -20,6 +20,7 @@ #include "net/cookies/canonical_cookie.h" #include "net/cookies/cookie_access_delegate.h" #include "net/cookies/cookie_deletion_info.h" +#include "net/cookies/cookie_inclusion_status.h" #include "net/cookies/cookie_options.h" class GURL; @@ -45,8 +46,8 @@ class NET_EXPORT CookieStore { public: // Callback definitions. using GetCookieListCallback = - base::OnceCallback<void(const CookieStatusList& included_cookies, - const CookieStatusList& excluded_list)>; + base::OnceCallback<void(const CookieAccessResultList& included_cookies, + const CookieAccessResultList& excluded_list)>; using GetAllCookiesCallback = base::OnceCallback<void(const CookieList& cookies)>; // |access_semantics_list| is guaranteed to the same length as |cookies|. @@ -54,7 +55,7 @@ class NET_EXPORT CookieStore { const CookieList& cookies, const std::vector<CookieAccessSemantics>& access_semantics_list)>; using SetCookiesCallback = - base::OnceCallback<void(CanonicalCookie::CookieInclusionStatus status)>; + base::OnceCallback<void(CookieInclusionStatus status)>; using DeleteCallback = base::OnceCallback<void(uint32_t num_deleted)>; using SetCookieableSchemesCallback = base::OnceCallback<void(bool success)>; diff --git a/chromium/net/cookies/cookie_store_test_callbacks.cc b/chromium/net/cookies/cookie_store_test_callbacks.cc index a582a6eb8d2..67461b50bf0 100644 --- a/chromium/net/cookies/cookie_store_test_callbacks.cc +++ b/chromium/net/cookies/cookie_store_test_callbacks.cc @@ -60,10 +60,11 @@ GetCookieListCallback::GetCookieListCallback(base::Thread* run_in_thread) GetCookieListCallback::~GetCookieListCallback() = default; -void GetCookieListCallback::Run(const CookieStatusList& cookies, - const CookieStatusList& excluded_cookies) { - cookies_with_statuses_ = cookies; - cookies_ = cookie_util::StripStatuses(cookies); +void GetCookieListCallback::Run( + const CookieAccessResultList& cookies, + const CookieAccessResultList& excluded_cookies) { + cookies_with_access_results_ = cookies; + cookies_ = cookie_util::StripAccessResults(cookies); excluded_cookies_ = excluded_cookies; CallbackEpilogue(); } diff --git a/chromium/net/cookies/cookie_store_test_callbacks.h b/chromium/net/cookies/cookie_store_test_callbacks.h index 54b00b565d7..b3195c20aca 100644 --- a/chromium/net/cookies/cookie_store_test_callbacks.h +++ b/chromium/net/cookies/cookie_store_test_callbacks.h @@ -109,26 +109,27 @@ class GetCookieListCallback : public CookieCallback { ~GetCookieListCallback(); - void Run(const CookieStatusList& cookies, - const CookieStatusList& excluded_cookies); + void Run(const CookieAccessResultList& cookies, + const CookieAccessResultList& excluded_cookies); // Makes a callback that will invoke Run. Assumes that |this| will be kept // alive till the time the callback is used. - base::OnceCallback<void(const CookieStatusList&, const CookieStatusList&)> + base::OnceCallback<void(const CookieAccessResultList&, + const CookieAccessResultList&)> MakeCallback() { return base::BindOnce(&GetCookieListCallback::Run, base::Unretained(this)); } const CookieList& cookies() { return cookies_; } - const CookieStatusList& cookies_with_statuses() { - return cookies_with_statuses_; + const CookieAccessResultList& cookies_with_access_results() { + return cookies_with_access_results_; } - const CookieStatusList& excluded_cookies() { return excluded_cookies_; } + const CookieAccessResultList& excluded_cookies() { return excluded_cookies_; } private: CookieList cookies_; - CookieStatusList cookies_with_statuses_; - CookieStatusList excluded_cookies_; + CookieAccessResultList cookies_with_access_results_; + CookieAccessResultList excluded_cookies_; }; class GetAllCookiesCallback : public CookieCallback { diff --git a/chromium/net/cookies/cookie_store_test_helpers.cc b/chromium/net/cookies/cookie_store_test_helpers.cc index a709c84f134..aae0c873540 100644 --- a/chromium/net/cookies/cookie_store_test_helpers.cc +++ b/chromium/net/cookies/cookie_store_test_helpers.cc @@ -65,25 +65,24 @@ DelayedCookieMonsterChangeDispatcher::AddCallbackForAllChanges( } DelayedCookieMonster::DelayedCookieMonster() - : cookie_monster_(new CookieMonster(nullptr /* store */, - nullptr /* netlog */)), + : cookie_monster_( + new CookieMonster(nullptr /* store */, nullptr /* netlog */)), did_run_(false), - result_( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE) {} + result_(CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE) {} DelayedCookieMonster::~DelayedCookieMonster() = default; void DelayedCookieMonster::SetCookiesInternalCallback( - CanonicalCookie::CookieInclusionStatus result) { + CookieInclusionStatus result) { result_ = result; did_run_ = true; } void DelayedCookieMonster::GetCookieListWithOptionsInternalCallback( - const CookieStatusList& cookie_list, - const CookieStatusList& excluded_cookies) { - cookie_status_list_ = cookie_list; - cookie_list_ = cookie_util::StripStatuses(cookie_status_list_); + const CookieAccessResultList& cookie_list, + const CookieAccessResultList& excluded_cookies) { + cookie_access_result_list_ = cookie_list; + cookie_list_ = cookie_util::StripAccessResults(cookie_access_result_list_); did_run_ = true; } @@ -136,7 +135,8 @@ void DelayedCookieMonster::InvokeSetCookiesCallback( void DelayedCookieMonster::InvokeGetCookieListCallback( CookieMonster::GetCookieListCallback callback) { if (!callback.is_null()) - std::move(callback).Run(cookie_status_list_, CookieStatusList()); + std::move(callback).Run(cookie_access_result_list_, + CookieAccessResultList()); } void DelayedCookieMonster::DeleteCanonicalCookieAsync( diff --git a/chromium/net/cookies/cookie_store_test_helpers.h b/chromium/net/cookies/cookie_store_test_helpers.h index ae6a152b7f2..5f9f03d15d4 100644 --- a/chromium/net/cookies/cookie_store_test_helpers.h +++ b/chromium/net/cookies/cookie_store_test_helpers.h @@ -86,13 +86,12 @@ class DelayedCookieMonster : public CookieStore { private: // Be called immediately from CookieMonster. - void SetCookiesInternalCallback( - CanonicalCookie::CookieInclusionStatus result); + void SetCookiesInternalCallback(CookieInclusionStatus result); void GetCookiesWithOptionsInternalCallback(const std::string& cookie); void GetCookieListWithOptionsInternalCallback( - const CookieStatusList& cookie, - const CookieStatusList& excluded_cookies); + const CookieAccessResultList& cookie, + const CookieAccessResultList& excluded_cookies); // Invoke the original callbacks. @@ -107,10 +106,10 @@ class DelayedCookieMonster : public CookieStore { DelayedCookieMonsterChangeDispatcher change_dispatcher_; bool did_run_; - CanonicalCookie::CookieInclusionStatus result_; + CookieInclusionStatus result_; std::string cookie_; std::string cookie_line_; - CookieStatusList cookie_status_list_; + CookieAccessResultList cookie_access_result_list_; CookieList cookie_list_; DISALLOW_COPY_AND_ASSIGN(DelayedCookieMonster); diff --git a/chromium/net/cookies/cookie_store_unittest.h b/chromium/net/cookies/cookie_store_unittest.h index ee8e46f9b1d..026ed96ba11 100644 --- a/chromium/net/cookies/cookie_store_unittest.h +++ b/chromium/net/cookies/cookie_store_unittest.h @@ -171,7 +171,8 @@ class CookieStoreTest : public testing::Test { } // This does not update the access time on the cookies. - CookieStatusList GetExcludedCookiesForURL(CookieStore* cs, const GURL& url) { + CookieAccessResultList GetExcludedCookiesForURL(CookieStore* cs, + const GURL& url) { DCHECK(cs); GetCookieListCallback callback; CookieOptions options = CookieOptions::MakeAllInclusive(); @@ -200,7 +201,7 @@ class CookieStoreTest : public testing::Test { if (!cookie) return false; DCHECK(cs); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieInclusionStatus> callback; cs->SetCanonicalCookieAsync(std::move(cookie), url, options, callback.MakeCallback()); callback.WaitUntilDone(); @@ -212,7 +213,7 @@ class CookieStoreTest : public testing::Test { const GURL& source_url, bool can_modify_httponly) { DCHECK(cs); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieInclusionStatus> callback; CookieOptions options; if (can_modify_httponly) options.set_include_httponly(); @@ -248,11 +249,11 @@ class CookieStoreTest : public testing::Test { return CreateAndSetCookie(cs, url, cookie_line, options); } - CanonicalCookie::CookieInclusionStatus CreateAndSetCookieReturnStatus( + CookieInclusionStatus CreateAndSetCookieReturnStatus( CookieStore* cs, const GURL& url, const std::string& cookie_line) { - CanonicalCookie::CookieInclusionStatus create_status; + CookieInclusionStatus create_status; auto cookie = CanonicalCookie::Create(url, cookie_line, base::Time::Now(), base::nullopt /* server_time */, &create_status); @@ -267,20 +268,20 @@ class CookieStoreTest : public testing::Test { net::CookieOptions::SameSiteCookieContext::MakeInclusive()); DCHECK(cs); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieInclusionStatus> callback; cs->SetCanonicalCookieAsync(std::move(cookie), url, options, callback.MakeCallback()); callback.WaitUntilDone(); return callback.result(); } - CanonicalCookie::CookieInclusionStatus SetCanonicalCookieReturnStatus( + CookieInclusionStatus SetCanonicalCookieReturnStatus( CookieStore* cs, std::unique_ptr<CanonicalCookie> cookie, const GURL& source_url, bool can_modify_httponly) { DCHECK(cs); - ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> callback; + ResultSavingCookieCallback<CookieInclusionStatus> callback; CookieOptions options; if (can_modify_httponly) options.set_include_httponly(); @@ -568,12 +569,11 @@ TYPED_TEST_P(CookieStoreTest, SetCanonicalCookieTest) { base::Time(), true, false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT), this->http_www_foo_.url(), true) - .HasExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY)); + .HasExclusionReason(CookieInclusionStatus::EXCLUDE_SECURE_ONLY)); // A Secure cookie can be created from an insecure URL, but is rejected upon // setting. - CanonicalCookie::CookieInclusionStatus status; + CookieInclusionStatus status; auto cookie = CanonicalCookie::Create( this->http_www_foo_.url(), "foo=1; Secure", base::Time::Now(), base::nullopt /* server_time */, &status); @@ -582,8 +582,7 @@ TYPED_TEST_P(CookieStoreTest, SetCanonicalCookieTest) { EXPECT_TRUE( this->SetCanonicalCookieReturnStatus(cs, std::move(cookie), this->http_www_foo_.url(), true) - .HasExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY)); + .HasExclusionReason(CookieInclusionStatus::EXCLUDE_SECURE_ONLY)); // A secure source is also required for overwriting secure cookies. Writing // a secure cookie then overwriting it from a non-secure source should fail. @@ -603,8 +602,7 @@ TYPED_TEST_P(CookieStoreTest, SetCanonicalCookieTest) { base::Time(), true /* secure */, false /* httponly */, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT), this->http_www_foo_.url(), true /* modify_http_only */) - .HasExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY)); + .HasExclusionReason(CookieInclusionStatus::EXCLUDE_SECURE_ONLY)); if (TypeParam::supports_http_only) { // Permission to modify http only cookies is required to set an @@ -618,12 +616,11 @@ TYPED_TEST_P(CookieStoreTest, SetCanonicalCookieTest) { true /* httponly */, CookieSameSite::LAX_MODE, COOKIE_PRIORITY_DEFAULT), this->http_www_foo_.url(), false /* modify_http_only */) - .HasExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY)); + .HasExclusionReason(CookieInclusionStatus::EXCLUDE_HTTP_ONLY)); // A HttpOnly cookie can be created, but is rejected // upon setting if the options do not specify include_httponly. - CanonicalCookie::CookieInclusionStatus create_status; + CookieInclusionStatus create_status; auto c = CanonicalCookie::Create( this->http_www_foo_.url(), "bar=1; HttpOnly", base::Time::Now(), base::nullopt /* server_time */, &create_status); @@ -633,8 +630,7 @@ TYPED_TEST_P(CookieStoreTest, SetCanonicalCookieTest) { this->SetCanonicalCookieReturnStatus(cs, std::move(c), this->http_www_foo_.url(), false /* can_modify_httponly */) - .HasExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY)); + .HasExclusionReason(CookieInclusionStatus::EXCLUDE_HTTP_ONLY)); // Permission to modify httponly cookies is also required to overwrite // an httponly cookie. @@ -655,8 +651,7 @@ TYPED_TEST_P(CookieStoreTest, SetCanonicalCookieTest) { true /* httponly */, CookieSameSite::LAX_MODE, COOKIE_PRIORITY_DEFAULT), this->http_www_foo_.url(), false /* modify_http_only */) - .HasExclusionReason( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY)); + .HasExclusionReason(CookieInclusionStatus::EXCLUDE_HTTP_ONLY)); } else { // Leave store in same state as if the above tests had been run. EXPECT_TRUE(this->SetCanonicalCookie( diff --git a/chromium/net/cookies/cookie_util.cc b/chromium/net/cookies/cookie_util.cc index 7f3afe4e178..99859d89606 100644 --- a/chromium/net/cookies/cookie_util.cc +++ b/chromium/net/cookies/cookie_util.cc @@ -11,6 +11,7 @@ #include "base/callback.h" #include "base/check.h" #include "base/feature_list.h" +#include "base/metrics/histogram_macros.h" #include "base/notreached.h" #include "base/stl_util.h" #include "base/strings/string_piece.h" @@ -121,6 +122,10 @@ CookieOptions::SameSiteCookieContext ComputeSameSiteContextForSet( } // namespace +void FireStorageAccessHistogram(StorageAccessResult result) { + UMA_HISTOGRAM_ENUMERATION("API.StorageAccess.AllowedRequests", result); +} + bool DomainIsHostOnly(const std::string& domain_string) { return (domain_string.empty() || domain_string[0] != '.'); } @@ -551,6 +556,48 @@ CookieOptions::SameSiteCookieContext ComputeSameSiteContextForSubresource( return CookieOptions::SameSiteCookieContext::MakeInclusive(); } +bool IsSameSiteCompatPair(const CanonicalCookie& c1, + const CanonicalCookie& c2, + const CookieOptions& options) { + if (options.exclude_httponly() && (c1.IsHttpOnly() || c2.IsHttpOnly())) + return false; + + if (c1.IsEquivalent(c2)) + return false; + + // One of them is SameSite=None and Secure; the other one has unspecified + // SameSite. + bool same_site_attributes_ok = + c1.SameSite() == CookieSameSite::NO_RESTRICTION && c1.IsSecure() && + c2.SameSite() == CookieSameSite::UNSPECIFIED; + same_site_attributes_ok = + same_site_attributes_ok || + (c2.SameSite() == CookieSameSite::NO_RESTRICTION && c2.IsSecure() && + c1.SameSite() == CookieSameSite::UNSPECIFIED); + if (!same_site_attributes_ok) + return false; + + if (c1.Domain() != c2.Domain() || c1.Path() != c2.Path() || + c1.Value() != c2.Value()) { + return false; + } + + DCHECK(c1.Name() != c2.Name()); + std::string shorter, longer; + std::tie(shorter, longer) = (c1.Name().length() < c2.Name().length()) + ? std::tie(c1.Name(), c2.Name()) + : std::tie(c2.Name(), c1.Name()); + // One of them has a name that is a prefix or suffix of the other and has + // length at least 3 characters. + if (shorter.length() < kMinCompatPairNameLength) + return false; + if (base::StartsWith(longer, shorter, base::CompareCase::SENSITIVE) || + base::EndsWith(longer, shorter, base::CompareCase::SENSITIVE)) { + return true; + } + return false; +} + bool IsSameSiteByDefaultCookiesEnabled() { return base::FeatureList::IsEnabled(features::kSameSiteByDefaultCookies); } @@ -610,21 +657,23 @@ bool DoesCreationTimeGrantLegacySemantics(base::Time creation_date) { return (base::Time::Now() - creation_date) < recency_threshold; } -base::OnceCallback<void(net::CanonicalCookie::CookieInclusionStatus)> +base::OnceCallback<void(CookieInclusionStatus)> AdaptCookieInclusionStatusToBool(base::OnceCallback<void(bool)> callback) { return base::BindOnce( [](base::OnceCallback<void(bool)> inner_callback, - const net::CanonicalCookie::CookieInclusionStatus status) { + const CookieInclusionStatus status) { bool success = status.IsInclude(); std::move(inner_callback).Run(success); }, std::move(callback)); } -CookieList StripStatuses(const CookieStatusList& cookie_status_list) { +CookieList StripAccessResults( + const CookieAccessResultList& cookie_access_results_list) { CookieList cookies; - for (const CookieWithStatus& cookie_with_status : cookie_status_list) { - cookies.push_back(cookie_with_status.cookie); + for (const CookieWithAccessResult& cookie_with_access_result : + cookie_access_results_list) { + cookies.push_back(cookie_with_access_result.cookie); } return cookies; } diff --git a/chromium/net/cookies/cookie_util.h b/chromium/net/cookies/cookie_util.h index 3634058c1b0..be3cd3f458d 100644 --- a/chromium/net/cookies/cookie_util.h +++ b/chromium/net/cookies/cookie_util.h @@ -13,6 +13,7 @@ #include "base/time/time.h" #include "net/base/net_export.h" #include "net/cookies/canonical_cookie.h" +#include "net/cookies/cookie_inclusion_status.h" #include "net/cookies/cookie_options.h" #include "net/cookies/site_for_cookies.h" #include "url/origin.h" @@ -27,6 +28,23 @@ const int kVlogPerCookieMonster = 1; const int kVlogSetCookies = 7; const int kVlogGarbageCollection = 5; +// Minimum name length for SameSite compatibility pair heuristic (see +// IsSameSiteCompatPair() below.) +const int kMinCompatPairNameLength = 3; + +// This enum must match the numbering for StorageAccessResult in +// histograms/enums.xml. Do not reorder or remove items, only add new items +// at the end. +enum class StorageAccessResult { + ACCESS_BLOCKED = 0, + ACCESS_ALLOWED = 1, + ACCESS_ALLOWED_STORAGE_ACCESS_GRANT = 2, + kMaxValue = ACCESS_ALLOWED_STORAGE_ACCESS_GRANT, +}; +// Helper to fire telemetry indicating if a given request for storage was +// allowed or not by the provided |result|. +NET_EXPORT void FireStorageAccessHistogram(StorageAccessResult result); + // Returns the effective TLD+1 for a given host. This only makes sense for http // and https schemes. For other schemes, the host will be returned unchanged // (minus any leading period). @@ -172,6 +190,26 @@ ComputeSameSiteContextForSubresource(const GURL& url, const SiteForCookies& site_for_cookies, bool force_ignore_site_for_cookies); +// Evaluates a heuristic to determine whether |c1| and |c2| are likely to be a +// "double cookie" pair used for SameSite=None compatibility reasons. +// +// This returns true if all of the following are true: +// 1. The cookies are not equivalent (i.e. same name, domain, and path). +// 2. One of them is SameSite=None and Secure; the other one has unspecified +// SameSite. +// 3. Their domains are equal. +// 4. Their paths are equal. +// 5. Their values are equal. +// 6. One of them has a name that is a prefix or suffix of the other and has +// length at least 3 characters. +// +// |options| is the CookieOptions object used to access (get/set) the cookies. +// If the CookieOptions indicate that HttpOnly cookies are not allowed, this +// will return false if either of |c1| or |c2| is HttpOnly. +NET_EXPORT bool IsSameSiteCompatPair(const CanonicalCookie& c1, + const CanonicalCookie& c2, + const CookieOptions& options); + // Returns whether the respective SameSite feature is enabled. NET_EXPORT bool IsSameSiteByDefaultCookiesEnabled(); NET_EXPORT bool IsCookiesWithoutSameSiteMustBeSecureEnabled(); @@ -198,12 +236,13 @@ bool DoesCreationTimeGrantLegacySemantics(base::Time creation_date); // // Can be used with SetCanonicalCookie when you don't need to know why a cookie // was blocked, only whether it was blocked. -NET_EXPORT base::OnceCallback<void(CanonicalCookie::CookieInclusionStatus)> +NET_EXPORT base::OnceCallback<void(CookieInclusionStatus)> AdaptCookieInclusionStatusToBool(base::OnceCallback<void(bool)> callback); -// Turn a CookieStatusList into a CookieList by stripping out the statuses -// (for callers who don't care about the statuses). -NET_EXPORT CookieList StripStatuses(const CookieStatusList& cookie_status_list); +// Turn a CookieAccessResultList into a CookieList by stripping out access +// results (for callers who only care about cookies). +NET_EXPORT CookieList +StripAccessResults(const CookieAccessResultList& cookie_access_result_list); } // namespace cookie_util } // namespace net diff --git a/chromium/net/cookies/cookie_util_unittest.cc b/chromium/net/cookies/cookie_util_unittest.cc index b95e1d6da26..14f8edf50f7 100644 --- a/chromium/net/cookies/cookie_util_unittest.cc +++ b/chromium/net/cookies/cookie_util_unittest.cc @@ -1216,13 +1216,11 @@ TEST(CookieUtilTest, AdaptCookieInclusionStatusToBool) { base::OnceCallback<void(bool)> callback = base::BindLambdaForTesting( [&result_out](bool result) { result_out = result; }); - base::OnceCallback<void(CanonicalCookie::CookieInclusionStatus)> - adapted_callback = - cookie_util::AdaptCookieInclusionStatusToBool(std::move(callback)); + base::OnceCallback<void(CookieInclusionStatus)> adapted_callback = + cookie_util::AdaptCookieInclusionStatusToBool(std::move(callback)); std::move(adapted_callback) - .Run(CanonicalCookie::CookieInclusionStatus( - CanonicalCookie::CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR)); + .Run(CookieInclusionStatus(CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR)); EXPECT_FALSE(result_out); @@ -1233,11 +1231,144 @@ TEST(CookieUtilTest, AdaptCookieInclusionStatusToBool) { adapted_callback = cookie_util::AdaptCookieInclusionStatusToBool(std::move(callback)); - std::move(adapted_callback).Run(CanonicalCookie::CookieInclusionStatus()); + std::move(adapted_callback).Run(CookieInclusionStatus()); EXPECT_TRUE(result_out); } +TEST(CookieUtilTest, IsSameSiteCompatPair) { + ASSERT_EQ(3, cookie_util::kMinCompatPairNameLength) + << "This test assumes that SameSite compatibility pairs have cookie name " + "length at least 3."; + GURL url("https://www.site.example/path"); + + struct { + const char* cookie_line_1; + const char* cookie_line_2; + bool expected_is_same_site_compat_pair; + } kTestCases[] = { + // Matching cases + {"name=value; SameSite=None; Secure", "name_legacy=value", true}, + {"uid=value; SameSite=None; Secure", "uid_old=value", true}, + {"name=value; SameSite=None; Secure", "name2=value; Secure", true}, + {"name_samesite=value; SameSite=None; Secure", "name=value", true}, + {"__Secure-name=value; SameSite=None; Secure", "name=value", true}, + {"__Secure-3Pname=value; SameSite=None; Secure", "name=value", true}, + {"name=value; SameSite=None; Secure; HttpOnly", "name_legacy=value", + true}, + {"name=value; SameSite=None; Secure; Domain=site.example", + "name_legacy=value; Secure; Domain=site.example", true}, + // Fails because cookies are equivalent + {"name=value; SameSite=None; Secure", "name=value", false}, + // Fails SameSite criterion + {"name=value", "name_legacy=value", false}, + {"name=value; SameSite=None", "name_legacy=value", false}, + {"name=value; SameSite=None; Secure", "name_legacy=value; SameSite=None", + false}, + {"name=value; SameSite=None; Secure", + "name_legacy=value; SameSite=None; Secure", false}, + // Fails Domain criterion + {"name=value; SameSite=None; Secure; Domain=site.example", + "name_legacy=value", false}, + {"name=value; SameSite=None; Secure; Domain=www.site.example", + "name_legacy=value", false}, + {"name=value; SameSite=None; Secure", + "name_legacy=value; Domain=site.example", false}, + {"name=value; SameSite=None; Secure", + "name_legacy=value; Domain=www.site.example", false}, + // Fails Path criterion + {"name=value; SameSite=None; Secure; Path=/path", "name_legacy=value", + false}, + {"name=value; SameSite=None; Secure; Path=/path", + "name_legacy=value; Path=/", false}, + {"name=value; SameSite=None; Secure; Path=/", + "name_legacy=value; Path=/path", false}, + {"name=value; SameSite=None; Secure", "name_legacy=value; Path=/path", + false}, + // Fails value criterion + {"name=value; SameSite=None; Secure", "name_legacy=foobar", false}, + {"name=value; SameSite=None; Secure", "name_legacy=value2", false}, + // Fails name length criterion + {"id=value; SameSite=None; Secure", "id_legacy=value", false}, + {"id_samesite=value; SameSite=None; Secure", "id=value", false}, + {"value; SameSite=None; Secure", "legacy=value", false}, + // Fails suffix/prefix criterion + {"name_samesite=value; SameSite=None; Secure", "name_legacy=value", + false}, + {"name1=value; SameSite=None; Secure", "name2=value", false}, + }; + + for (const auto& test_case : kTestCases) { + auto cookie1 = CanonicalCookie::Create(url, test_case.cookie_line_1, + base::Time::Now(), base::nullopt); + auto cookie2 = CanonicalCookie::Create(url, test_case.cookie_line_2, + base::Time::Now(), base::nullopt); + + ASSERT_TRUE(cookie1); + ASSERT_TRUE(cookie2); + EXPECT_EQ(test_case.expected_is_same_site_compat_pair, + cookie_util::IsSameSiteCompatPair( + *cookie1, *cookie2, CookieOptions::MakeAllInclusive())); + EXPECT_EQ(test_case.expected_is_same_site_compat_pair, + cookie_util::IsSameSiteCompatPair( + *cookie2, *cookie1, CookieOptions::MakeAllInclusive())); + } +} + +TEST(CookieUtilTest, IsSameSiteCompatPair_HttpOnly) { + GURL url("https://www.site.example/path"); + auto new_cookie = + CanonicalCookie::Create(url, "name=value; SameSite=None; Secure", + base::Time::Now(), base::nullopt); + auto legacy_cookie = CanonicalCookie::Create( + url, "name_legacy=value", base::Time::Now(), base::nullopt); + auto http_only_new_cookie = CanonicalCookie::Create( + url, "name=value; SameSite=None; Secure; HttpOnly", base::Time::Now(), + base::nullopt); + auto http_only_legacy_cookie = CanonicalCookie::Create( + url, "name_legacy=value; HttpOnly", base::Time::Now(), base::nullopt); + ASSERT_TRUE(new_cookie); + ASSERT_TRUE(legacy_cookie); + ASSERT_TRUE(http_only_new_cookie); + ASSERT_TRUE(http_only_legacy_cookie); + + // Allows HttpOnly access. + CookieOptions inclusive_options = CookieOptions::MakeAllInclusive(); + // Disallows HttpOnly access. + CookieOptions restrictive_options; + // Allows SameSite but not HttpOnly access. (SameSite shouldn't matter.) + CookieOptions same_site_options; + same_site_options.set_same_site_cookie_context( + CookieOptions::SameSiteCookieContext::MakeInclusive()); + + EXPECT_TRUE(cookie_util::IsSameSiteCompatPair(*new_cookie, *legacy_cookie, + inclusive_options)); + EXPECT_TRUE(cookie_util::IsSameSiteCompatPair( + *http_only_new_cookie, *legacy_cookie, inclusive_options)); + EXPECT_TRUE(cookie_util::IsSameSiteCompatPair( + *new_cookie, *http_only_legacy_cookie, inclusive_options)); + EXPECT_TRUE(cookie_util::IsSameSiteCompatPair( + *http_only_new_cookie, *http_only_legacy_cookie, inclusive_options)); + + EXPECT_TRUE(cookie_util::IsSameSiteCompatPair(*new_cookie, *legacy_cookie, + restrictive_options)); + EXPECT_FALSE(cookie_util::IsSameSiteCompatPair( + *http_only_new_cookie, *legacy_cookie, restrictive_options)); + EXPECT_FALSE(cookie_util::IsSameSiteCompatPair( + *new_cookie, *http_only_legacy_cookie, restrictive_options)); + EXPECT_FALSE(cookie_util::IsSameSiteCompatPair( + *http_only_new_cookie, *http_only_legacy_cookie, restrictive_options)); + + EXPECT_TRUE(cookie_util::IsSameSiteCompatPair(*new_cookie, *legacy_cookie, + same_site_options)); + EXPECT_FALSE(cookie_util::IsSameSiteCompatPair( + *http_only_new_cookie, *legacy_cookie, same_site_options)); + EXPECT_FALSE(cookie_util::IsSameSiteCompatPair( + *new_cookie, *http_only_legacy_cookie, same_site_options)); + EXPECT_FALSE(cookie_util::IsSameSiteCompatPair( + *http_only_new_cookie, *http_only_legacy_cookie, same_site_options)); +} + } // namespace } // namespace net |