CookieInclusionStatus: Support warnings and multiple exclusion reasons
Previously CookieInclusionStatus was just an enum with one value for
inclusion and a number of other values for exclusion due to different
reasons.
This changes CookieInclusionStatus to hold multiple exclusion reasons,
with inclusion represented as a lack of any exclusion reasons. This is
implemented as a bit vector with each exclusion reason represented as
a single bit.
This also adds warnings to CookieInclusionStatus, which indicate when
warnings should be emitted about a cookie (regardless of inclusion or
exclusion). This removes the need for the previous hack which indicated
warnings by making a duplicate of the cookie with a different
CookieInclusionStatus.
Bug: 993843
Change-Id: I8f4f76ea5c7225cd01342786b20f9e0b05f582c3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1756157
Commit-Queue: Lily Chen <[email protected]>
Reviewed-by: Sylvain Defresne <[email protected]>
Reviewed-by: Victor Costan <[email protected]>
Reviewed-by: Boris Sazonov <[email protected]>
Reviewed-by: Toni Baržić <[email protected]>
Reviewed-by: Christian Dullweber <[email protected]>
Reviewed-by: Kyle Horimoto <[email protected]>
Reviewed-by: Wez <[email protected]>
Reviewed-by: Maks Orlovich <[email protected]>
Reviewed-by: Karan Bhatia <[email protected]>
Reviewed-by: Balazs Engedy <[email protected]>
Reviewed-by: Daniel Cheng <[email protected]>
Reviewed-by: John Abd-El-Malek <[email protected]>
Reviewed-by: Andrey Kosyakov <[email protected]>
Cr-Commit-Position: refs/heads/master@{#691902}
diff --git a/net/cookies/canonical_cookie.cc b/net/cookies/canonical_cookie.cc
index 1b5b386..584caa6 100644
--- a/net/cookies/canonical_cookie.cc
+++ b/net/cookies/canonical_cookie.cc
@@ -44,11 +44,13 @@
#include "net/cookies/canonical_cookie.h"
+#include <sstream>
#include <utility>
#include "base/format_macros.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
+#include "base/strings/strcat.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "net/base/url_util.h"
@@ -101,6 +103,36 @@
*cookie_line += cookie.Value();
}
+uint32_t GetBitmask(
+ CanonicalCookie::CookieInclusionStatus::ExclusionReason reason) {
+ return 1u << static_cast<uint32_t>(reason);
+}
+
+void ApplySameSiteCookieWarningToStatus(
+ CookieSameSite samesite,
+ CookieSameSite effective_samesite,
+ bool is_secure,
+ CookieOptions::SameSiteCookieContext context,
+ CanonicalCookie::CookieInclusionStatus* status) {
+ if (samesite == CookieSameSite::UNSPECIFIED &&
+ context < CookieOptions::SameSiteCookieContext::SAME_SITE_LAX) {
+ status->set_warning(CanonicalCookie::CookieInclusionStatus::
+ WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT);
+ }
+ // This will overwrite the previous warning but it is more specific so that
+ // is ok.
+ if (effective_samesite == CookieSameSite::LAX_MODE_ALLOW_UNSAFE &&
+ context ==
+ CookieOptions::SameSiteCookieContext::SAME_SITE_LAX_METHOD_UNSAFE) {
+ status->set_warning(CanonicalCookie::CookieInclusionStatus::
+ WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE);
+ }
+ if (samesite == CookieSameSite::NO_RESTRICTION && !is_secure) {
+ status->set_warning(
+ CanonicalCookie::CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE);
+ }
+}
+
} // namespace
// Keep defaults here in sync with content/public/common/cookie_manager.mojom.
@@ -211,23 +243,25 @@
if (status == nullptr) {
status = &blank_status;
}
- *status = CookieInclusionStatus::INCLUDE;
+ *status = CookieInclusionStatus();
ParsedCookie parsed_cookie(cookie_line);
if (!parsed_cookie.IsValid()) {
DVLOG(net::cookie_util::kVlogSetCookies)
<< "WARNING: Couldn't parse cookie";
- *status = CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE;
+ status->AddExclusionReason(CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE);
+ // Don't continue, because an invalid ParsedCookie doesn't have any
+ // attributes.
+ // TODO(chlily): Log metrics.
return nullptr;
}
std::string cookie_domain;
if (!GetCookieDomain(url, parsed_cookie, &cookie_domain)) {
DVLOG(net::cookie_util::kVlogSetCookies)
- << "Create() failed to get a cookie domain";
- *status = CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN;
- return nullptr;
+ << "Create() failed to get a valid cookie domain";
+ status->AddExclusionReason(CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN);
}
std::string cookie_path = CanonPathWithString(
@@ -242,15 +276,18 @@
parsed_cookie, creation_time, cookie_server_time);
CookiePrefix prefix = GetCookiePrefix(parsed_cookie.Name());
- bool is_cookie_valid = IsCookiePrefixValid(prefix, url, parsed_cookie);
- RecordCookiePrefixMetrics(prefix, is_cookie_valid);
- if (!is_cookie_valid) {
+ bool is_cookie_prefix_valid = IsCookiePrefixValid(prefix, url, parsed_cookie);
+ RecordCookiePrefixMetrics(prefix, is_cookie_prefix_valid);
+ if (!is_cookie_prefix_valid) {
DVLOG(net::cookie_util::kVlogSetCookies)
<< "Create() failed because the cookie violated prefix rules.";
- *status = CookieInclusionStatus::EXCLUDE_INVALID_PREFIX;
- return nullptr;
+ status->AddExclusionReason(CookieInclusionStatus::EXCLUDE_INVALID_PREFIX);
}
+ // TODO(chlily): Log metrics.
+ if (!status->IsInclude())
+ return nullptr;
+
std::unique_ptr<CanonicalCookie> cc(std::make_unique<CanonicalCookie>(
parsed_cookie.Name(), parsed_cookie.Value(), cookie_domain, cookie_path,
creation_time, cookie_expires, creation_time, parsed_cookie.IsSecure(),
@@ -258,7 +295,8 @@
parsed_cookie.Priority()));
DCHECK(cc->IsCanonical());
- DCHECK(*status == CookieInclusionStatus::INCLUDE);
+
+ // TODO(chlily): Log metrics.
return cc;
}
@@ -376,26 +414,29 @@
const GURL& url,
const CookieOptions& options) const {
base::TimeDelta cookie_age = base::Time::Now() - CreationDate();
+ CookieInclusionStatus status;
// Filter out HttpOnly cookies, per options.
if (options.exclude_httponly() && IsHttpOnly())
- return CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY;
+ status.AddExclusionReason(CookieInclusionStatus::EXCLUDE_HTTP_ONLY);
// Secure cookies should not be included in requests for URLs with an
// insecure scheme.
if (IsSecure() && !url.SchemeIsCryptographic())
- return CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY;
+ status.AddExclusionReason(CookieInclusionStatus::EXCLUDE_SECURE_ONLY);
// Don't include cookies for requests that don't apply to the cookie domain.
if (!IsDomainMatch(url.host()))
- return CanonicalCookie::CookieInclusionStatus::EXCLUDE_DOMAIN_MISMATCH;
+ status.AddExclusionReason(CookieInclusionStatus::EXCLUDE_DOMAIN_MISMATCH);
// Don't include cookies for requests with a url path that does not path
// match the cookie-path.
if (!IsOnPath(url.path()))
- return CanonicalCookie::CookieInclusionStatus::EXCLUDE_NOT_ON_PATH;
+ status.AddExclusionReason(CookieInclusionStatus::EXCLUDE_NOT_ON_PATH);
// Don't include same-site cookies for cross-site requests.
- switch (GetEffectiveSameSite()) {
+ CookieSameSite effective_same_site = GetEffectiveSameSite();
+ switch (effective_same_site) {
case CookieSameSite::STRICT_MODE:
if (options.same_site_cookie_context() <
CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT) {
- return CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT;
+ status.AddExclusionReason(
+ CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT);
}
break;
case CookieSameSite::LAX_MODE:
@@ -412,11 +453,11 @@
base::TimeDelta::FromMinutes(1), base::TimeDelta::FromDays(5),
100);
}
- return (SameSite() == CookieSameSite::UNSPECIFIED)
- ? CanonicalCookie::CookieInclusionStatus::
- EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX
- : CanonicalCookie::CookieInclusionStatus::
- EXCLUDE_SAMESITE_LAX;
+ status.AddExclusionReason(
+ (SameSite() == CookieSameSite::UNSPECIFIED)
+ ? CookieInclusionStatus::
+ EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX
+ : CookieInclusionStatus::EXCLUDE_SAMESITE_LAX);
}
break;
// TODO(crbug.com/990439): Add a browsertest for this behavior.
@@ -425,8 +466,8 @@
if (options.same_site_cookie_context() <
CookieOptions::SameSiteCookieContext::SAME_SITE_LAX_METHOD_UNSAFE) {
// TODO(chlily): Do we need a separate CookieInclusionStatus for this?
- return CanonicalCookie::CookieInclusionStatus::
- EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX;
+ status.AddExclusionReason(
+ CookieInclusionStatus::EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX);
} else if (options.same_site_cookie_context() ==
CookieOptions::SameSiteCookieContext::
SAME_SITE_LAX_METHOD_UNSAFE) {
@@ -448,22 +489,29 @@
// be set while the options are on).
if (cookie_util::IsCookiesWithoutSameSiteMustBeSecureEnabled() &&
IsEffectivelySameSiteNone() && !IsSecure()) {
- return CanonicalCookie::CookieInclusionStatus::
- EXCLUDE_SAMESITE_NONE_INSECURE;
+ status.AddExclusionReason(
+ CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE);
}
- return CanonicalCookie::CookieInclusionStatus::INCLUDE;
+ ApplySameSiteCookieWarningToStatus(
+ SameSite(), effective_same_site, IsSecure(),
+ options.same_site_cookie_context(), &status);
+
+ // TODO(chlily): Log metrics.
+ return status;
}
CanonicalCookie::CookieInclusionStatus CanonicalCookie::IsSetPermittedInContext(
const CookieOptions& options) const {
+ CookieInclusionStatus status;
if (options.exclude_httponly() && IsHttpOnly()) {
DVLOG(net::cookie_util::kVlogSetCookies)
<< "HttpOnly cookie not permitted in script context.";
- return CookieInclusionStatus::EXCLUDE_HTTP_ONLY;
+ status.AddExclusionReason(CookieInclusionStatus::EXCLUDE_HTTP_ONLY);
}
- switch (GetEffectiveSameSite()) {
+ CookieSameSite effective_same_site = GetEffectiveSameSite();
+ switch (effective_same_site) {
case CookieSameSite::STRICT_MODE:
// This intentionally checks for `< SAME_SITE_LAX`, as we allow
// `SameSite=Strict` cookies to be set for top-level navigations that
@@ -473,7 +521,8 @@
DVLOG(net::cookie_util::kVlogSetCookies)
<< "Trying to set a `SameSite=Strict` cookie from a "
"cross-site URL.";
- return CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT;
+ status.AddExclusionReason(
+ CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT);
}
break;
case CookieSameSite::LAX_MODE:
@@ -484,12 +533,14 @@
DVLOG(net::cookie_util::kVlogSetCookies)
<< "Cookies with no known SameSite attribute being treated as "
"lax; attempt to set from a cross-site URL denied.";
- return CanonicalCookie::CookieInclusionStatus::
- EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX;
+ status.AddExclusionReason(
+ CookieInclusionStatus::
+ EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX);
} else {
DVLOG(net::cookie_util::kVlogSetCookies)
<< "Trying to set a `SameSite=Lax` cookie from a cross-site URL.";
- return CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX;
+ status.AddExclusionReason(
+ CookieInclusionStatus::EXCLUDE_SAMESITE_LAX);
}
}
break;
@@ -497,7 +548,12 @@
break;
}
- return CookieInclusionStatus::INCLUDE;
+ ApplySameSiteCookieWarningToStatus(
+ SameSite(), effective_same_site, IsSecure(),
+ options.same_site_cookie_context(), &status);
+
+ // TODO(chlily): Log metrics.
+ return status;
}
std::string CanonicalCookie::DebugString() const {
@@ -672,6 +728,142 @@
return domain_.substr(1);
}
+CanonicalCookie::CookieInclusionStatus::CookieInclusionStatus()
+ : exclusion_reasons_(0u), warning_(DO_NOT_WARN) {}
+
+CanonicalCookie::CookieInclusionStatus::CookieInclusionStatus(
+ ExclusionReason reason,
+ WarningReason warning)
+ : exclusion_reasons_(GetBitmask(reason)), warning_(warning) {}
+
+bool CanonicalCookie::CookieInclusionStatus::operator==(
+ const CookieInclusionStatus& other) const {
+ return exclusion_reasons_ == other.exclusion_reasons_ &&
+ warning_ == other.warning_;
+}
+
+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_ & GetBitmask(reason);
+}
+
+void CanonicalCookie::CookieInclusionStatus::AddExclusionReason(
+ ExclusionReason reason) {
+ exclusion_reasons_ |= GetBitmask(reason);
+}
+
+void CanonicalCookie::CookieInclusionStatus::AddExclusionReasonsAndWarningIfAny(
+ const CookieInclusionStatus& other) {
+ exclusion_reasons_ |= other.exclusion_reasons_;
+ if (other.warning_ != DO_NOT_WARN)
+ warning_ = other.warning_;
+}
+
+void CanonicalCookie::CookieInclusionStatus::RemoveExclusionReason(
+ ExclusionReason reason) {
+ exclusion_reasons_ &= ~(GetBitmask(reason));
+}
+
+bool CanonicalCookie::CookieInclusionStatus::ShouldWarn() const {
+ return warning_ != DO_NOT_WARN;
+}
+
+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_EXTENDED))
+ base::StrAppend(&out, {"EXCLUDE_SAMESITE_EXTENDED, "});
+ 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
+ switch (warning_) {
+ case DO_NOT_WARN:
+ base::StrAppend(&out, {"DO_NOT_WARN"});
+ break;
+ case WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT:
+ base::StrAppend(&out, {"WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT"});
+ break;
+ case WARN_SAMESITE_NONE_INSECURE:
+ base::StrAppend(&out, {"WARN_SAMESITE_NONE_INSECURE"});
+ break;
+ case WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE:
+ base::StrAppend(&out, {"WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE"});
+ break;
+ }
+
+ return out;
+}
+
+bool CanonicalCookie::CookieInclusionStatus::IsValid() const {
+ // Bit positions where there should not be any true bits.
+ uint32_t mask = ~0u << static_cast<int>(NUM_EXCLUSION_REASONS);
+ return (mask & exclusion_reasons_) == 0u;
+}
+
+bool CanonicalCookie::CookieInclusionStatus::
+ HasExactlyExclusionReasonsForTesting(
+ std::vector<CanonicalCookie::CookieInclusionStatus::ExclusionReason>
+ reasons) const {
+ CookieInclusionStatus expected = MakeFromReasonsForTesting(reasons);
+ return expected.exclusion_reasons_ == exclusion_reasons_;
+}
+
+// static
+CanonicalCookie::CookieInclusionStatus
+CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting(
+ std::vector<ExclusionReason> reasons,
+ WarningReason warning) {
+ CookieInclusionStatus status;
+ for (ExclusionReason reason : reasons) {
+ status.AddExclusionReason(reason);
+ }
+ status.set_warning(warning);
+ return status;
+}
+
CookieAndLineWithStatus::CookieAndLineWithStatus() = default;
CookieAndLineWithStatus::CookieAndLineWithStatus(
diff --git a/net/cookies/canonical_cookie.h b/net/cookies/canonical_cookie.h
index 061d6b7..e91331d 100644
--- a/net/cookies/canonical_cookie.h
+++ b/net/cookies/canonical_cookie.h
@@ -33,6 +33,8 @@
class NET_EXPORT CanonicalCookie {
public:
+ class CookieInclusionStatus;
+
CanonicalCookie();
CanonicalCookie(const CanonicalCookie& other);
@@ -58,39 +60,6 @@
// Supports the default copy constructor.
- // This enum represents if a cookie was included or excluded, and if excluded
- // why.
- enum class CookieInclusionStatus {
- INCLUDE = 0,
- EXCLUDE_HTTP_ONLY,
- EXCLUDE_SECURE_ONLY,
- EXCLUDE_DOMAIN_MISMATCH,
- EXCLUDE_NOT_ON_PATH,
- EXCLUDE_SAMESITE_STRICT,
- EXCLUDE_SAMESITE_LAX,
- // TODO(crbug.com/989171): Replace this with FirstPartyLax and
- // FirstPartyStrict.
- EXCLUDE_SAMESITE_EXTENDED,
- // 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,
- // This is used if SameSite=None is specified, but the cookie is not Secure.
- EXCLUDE_SAMESITE_NONE_INSECURE,
- EXCLUDE_USER_PREFERENCES,
-
- // Statuses specific to setting cookies
- EXCLUDE_FAILURE_TO_STORE,
- EXCLUDE_NONCOOKIEABLE_SCHEME,
- EXCLUDE_OVERWRITE_SECURE,
- EXCLUDE_OVERWRITE_HTTP_ONLY,
- EXCLUDE_INVALID_DOMAIN,
- EXCLUDE_INVALID_PREFIX,
-
- // Please keep last
- EXCLUDE_UNKNOWN_ERROR
- };
-
// Creates a new |CanonicalCookie| from the |cookie_line| and the
// |creation_time|. Canonicalizes inputs. May return nullptr if
// an attribute value is invalid. |url| must be valid. |creation_time| may
@@ -321,6 +290,138 @@
CookiePriority priority_;
};
+// 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,
+ // TODO(crbug.com/989171): Replace this with FirstPartyLax and
+ // FirstPartyStrict.
+ EXCLUDE_SAMESITE_EXTENDED = 7,
+ // 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 = 8,
+ // This is used if SameSite=None is specified, but the cookie is not
+ // Secure.
+ EXCLUDE_SAMESITE_NONE_INSECURE = 9,
+ EXCLUDE_USER_PREFERENCES = 10,
+
+ // Statuses specific to setting cookies
+ EXCLUDE_FAILURE_TO_STORE = 11,
+ EXCLUDE_NONCOOKIEABLE_SCHEME = 12,
+ EXCLUDE_OVERWRITE_SECURE = 13,
+ EXCLUDE_OVERWRITE_HTTP_ONLY = 14,
+ EXCLUDE_INVALID_DOMAIN = 15,
+ EXCLUDE_INVALID_PREFIX = 16,
+
+ // This should be kept last.
+ NUM_EXCLUSION_REASONS
+ };
+
+ // Reason to warn about a cookie. If you add one, please update
+ // GetDebugString().
+ // TODO(chlily): Do we need to support multiple warning statuses?
+ enum WarningReason {
+ DO_NOT_WARN = 0,
+ // Warn if a cookie with unspecified SameSite attribute is used in a
+ // cross-site context.
+ WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT,
+ // Warn if a cookie with SameSite=None is not Secure.
+ WARN_SAMESITE_NONE_INSECURE,
+ // 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,
+ };
+
+ // Makes a status that says include.
+ CookieInclusionStatus();
+
+ // Makes a status that contains the given exclusion reason and warning.
+ explicit CookieInclusionStatus(ExclusionReason reason,
+ WarningReason warning = DO_NOT_WARN);
+
+ 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);
+
+ // Add all the exclusion reasons given in |other|. If there is a warning in
+ // |other| (other than DO_NOT_WARN), also apply that. This could overwrite the
+ // existing warning, so set the most important warnings last.
+ void AddExclusionReasonsAndWarningIfAny(const CookieInclusionStatus& other);
+
+ // Remove an exclusion reason.
+ void RemoveExclusionReason(ExclusionReason reason);
+
+ // Whether the cookie should be warned about.
+ bool ShouldWarn() const;
+
+ WarningReason warning() const { return warning_; }
+ void set_warning(WarningReason warning) { warning_ = warning; }
+
+ // Used for serialization/deserialization.
+ uint32_t exclusion_reasons() const { return exclusion_reasons_; }
+ void set_exclusion_reasons(uint32_t exclusion_reasons) {
+ exclusion_reasons_ = exclusion_reasons;
+ }
+
+ // 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;
+
+ // Makes a status that contains the given exclusion reasons and warning.
+ static CookieInclusionStatus MakeFromReasonsForTesting(
+ std::vector<ExclusionReason> reasons,
+ WarningReason warning = DO_NOT_WARN);
+
+ private:
+ // A bit vector of the applicable exclusion reasons.
+ uint32_t exclusion_reasons_ = 0u;
+
+ // Applicable warning reason.
+ WarningReason warning_ = DO_NOT_WARN;
+};
+
+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 {
diff --git a/net/cookies/canonical_cookie_unittest.cc b/net/cookies/canonical_cookie_unittest.cc
index 2d2018e0..04afd97 100644
--- a/net/cookies/canonical_cookie_unittest.cc
+++ b/net/cookies/canonical_cookie_unittest.cc
@@ -201,7 +201,7 @@
std::unique_ptr<CanonicalCookie> cookie =
CanonicalCookie::Create(url, "A=2; HttpOnly", now, server_time, &status);
EXPECT_TRUE(cookie->IsHttpOnly());
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE, status);
+ EXPECT_TRUE(status.IsInclude());
}
TEST(CanonicalCookieTest, CreateWithInvalidDomain) {
@@ -213,8 +213,8 @@
std::unique_ptr<CanonicalCookie> cookie = CanonicalCookie::Create(
url, "A=2; Domain=wrongdomain.com", now, server_time, &status);
EXPECT_EQ(nullptr, cookie.get());
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN,
- status);
+ EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN}));
}
TEST(CanonicalCookieTest, EmptyExpiry) {
@@ -630,40 +630,50 @@
std::unique_ptr<CanonicalCookie> cookie(
CanonicalCookie::Create(url, "A=2", creation_time, server_time));
- EXPECT_EQ(cookie->IncludeForRequestURL(url, options),
- CanonicalCookie::CookieInclusionStatus::INCLUDE);
- EXPECT_EQ(cookie->IncludeForRequestURL(GURL("http://www.example.com/foo/bar"),
- options),
- CanonicalCookie::CookieInclusionStatus::INCLUDE);
- EXPECT_EQ(cookie->IncludeForRequestURL(
- GURL("https://www.example.com/foo/bar"), options),
- CanonicalCookie::CookieInclusionStatus::INCLUDE);
- EXPECT_EQ(
- cookie->IncludeForRequestURL(GURL("https://sub.example.com"), options),
- CanonicalCookie::CookieInclusionStatus::EXCLUDE_DOMAIN_MISMATCH);
- EXPECT_EQ(cookie->IncludeForRequestURL(GURL("https://sub.www.example.com"),
- options),
- CanonicalCookie::CookieInclusionStatus::EXCLUDE_DOMAIN_MISMATCH);
+ EXPECT_TRUE(cookie->IncludeForRequestURL(url, options).IsInclude());
+ EXPECT_TRUE(cookie
+ ->IncludeForRequestURL(GURL("http://www.example.com/foo/bar"),
+ options)
+ .IsInclude());
+ EXPECT_TRUE(cookie
+ ->IncludeForRequestURL(
+ GURL("https://www.example.com/foo/bar"), options)
+ .IsInclude());
+ EXPECT_TRUE(
+ cookie->IncludeForRequestURL(GURL("https://sub.example.com"), options)
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::
+ EXCLUDE_DOMAIN_MISMATCH}));
+ EXPECT_TRUE(
+ cookie->IncludeForRequestURL(GURL("https://sub.www.example.com"), options)
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::
+ EXCLUDE_DOMAIN_MISMATCH}));
// Test that cookie with a cookie path that does not match the url path are
// not included.
cookie = CanonicalCookie::Create(url, "A=2; Path=/foo/bar", creation_time,
server_time);
- EXPECT_EQ(cookie->IncludeForRequestURL(url, options),
- CanonicalCookie::CookieInclusionStatus::EXCLUDE_NOT_ON_PATH);
- EXPECT_EQ(cookie->IncludeForRequestURL(
- GURL("http://www.example.com/foo/bar/index.html"), options),
- CanonicalCookie::CookieInclusionStatus::INCLUDE);
+ EXPECT_TRUE(
+ cookie->IncludeForRequestURL(url, options)
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_NOT_ON_PATH}));
+ EXPECT_TRUE(
+ cookie
+ ->IncludeForRequestURL(
+ GURL("http://www.example.com/foo/bar/index.html"), options)
+ .IsInclude());
// Test that a secure cookie is not included for a non secure URL.
GURL secure_url("https://www.example.com");
cookie = CanonicalCookie::Create(secure_url, "A=2; Secure", creation_time,
server_time);
EXPECT_TRUE(cookie->IsSecure());
- EXPECT_EQ(cookie->IncludeForRequestURL(secure_url, options),
- CanonicalCookie::CookieInclusionStatus::INCLUDE);
- EXPECT_EQ(cookie->IncludeForRequestURL(url, options),
- CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY);
+ EXPECT_TRUE(cookie->IncludeForRequestURL(secure_url, options).IsInclude());
+ EXPECT_TRUE(
+ cookie->IncludeForRequestURL(url, options)
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY}));
// Test that http only cookies are only included if the include httponly flag
// is set on the cookie options.
@@ -671,11 +681,12 @@
cookie =
CanonicalCookie::Create(url, "A=2; HttpOnly", creation_time, server_time);
EXPECT_TRUE(cookie->IsHttpOnly());
- EXPECT_EQ(cookie->IncludeForRequestURL(url, options),
- CanonicalCookie::CookieInclusionStatus::INCLUDE);
+ EXPECT_TRUE(cookie->IncludeForRequestURL(url, options).IsInclude());
options.set_exclude_httponly();
- EXPECT_EQ(cookie->IncludeForRequestURL(url, options),
- CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY);
+ EXPECT_TRUE(
+ cookie->IncludeForRequestURL(url, options)
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY}));
}
TEST(CanonicalCookieTest, IncludeForRequestURLSameSite) {
@@ -696,167 +707,191 @@
{"A=2; SameSite=Strict", false, CookieSameSite::STRICT_MODE,
CookieSameSite::STRICT_MODE,
CookieOptions::SameSiteCookieContext::CROSS_SITE,
- CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT},
+ CanonicalCookie::CookieInclusionStatus(
+ CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT)},
{"A=2; SameSite=Strict", false, CookieSameSite::STRICT_MODE,
CookieSameSite::STRICT_MODE,
CookieOptions::SameSiteCookieContext::SAME_SITE_LAX_METHOD_UNSAFE,
- CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT},
+ CanonicalCookie::CookieInclusionStatus(
+ CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT)},
{"A=2; SameSite=Strict", false, CookieSameSite::STRICT_MODE,
CookieSameSite::STRICT_MODE,
CookieOptions::SameSiteCookieContext::SAME_SITE_LAX,
- CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT},
+ CanonicalCookie::CookieInclusionStatus(
+ CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT)},
{"A=2; SameSite=Strict", false, CookieSameSite::STRICT_MODE,
CookieSameSite::STRICT_MODE,
CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT,
- CanonicalCookie::CookieInclusionStatus::INCLUDE},
+ CanonicalCookie::CookieInclusionStatus()},
// Lax cookies:
{"A=2; SameSite=Lax", false, CookieSameSite::LAX_MODE,
CookieSameSite::LAX_MODE,
CookieOptions::SameSiteCookieContext::CROSS_SITE,
- CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX},
+ CanonicalCookie::CookieInclusionStatus(
+ CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX)},
{"A=2; SameSite=Lax", false, CookieSameSite::LAX_MODE,
CookieSameSite::LAX_MODE,
CookieOptions::SameSiteCookieContext::SAME_SITE_LAX_METHOD_UNSAFE,
- CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX},
+ CanonicalCookie::CookieInclusionStatus(
+ CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX)},
{"A=2; SameSite=Lax", false, CookieSameSite::LAX_MODE,
CookieSameSite::LAX_MODE,
CookieOptions::SameSiteCookieContext::SAME_SITE_LAX,
- CanonicalCookie::CookieInclusionStatus::INCLUDE},
+ CanonicalCookie::CookieInclusionStatus()},
{"A=2; SameSite=Lax", false, CookieSameSite::LAX_MODE,
CookieSameSite::LAX_MODE,
CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT,
- CanonicalCookie::CookieInclusionStatus::INCLUDE},
+ CanonicalCookie::CookieInclusionStatus()},
// None cookies:
{"A=2; SameSite=None; Secure", false, CookieSameSite::NO_RESTRICTION,
CookieSameSite::NO_RESTRICTION,
CookieOptions::SameSiteCookieContext::CROSS_SITE,
- CanonicalCookie::CookieInclusionStatus::INCLUDE},
- {"A=2; SameSite=None; Secure", false, CookieSameSite::NO_RESTRICTION,
- CookieSameSite::NO_RESTRICTION,
- CookieOptions::SameSiteCookieContext::CROSS_SITE,
- CanonicalCookie::CookieInclusionStatus::INCLUDE},
+ CanonicalCookie::CookieInclusionStatus()},
{"A=2; SameSite=None; Secure", false, CookieSameSite::NO_RESTRICTION,
CookieSameSite::NO_RESTRICTION,
CookieOptions::SameSiteCookieContext::SAME_SITE_LAX_METHOD_UNSAFE,
- CanonicalCookie::CookieInclusionStatus::INCLUDE},
+ CanonicalCookie::CookieInclusionStatus()},
{"A=2; SameSite=None; Secure", false, CookieSameSite::NO_RESTRICTION,
CookieSameSite::NO_RESTRICTION,
CookieOptions::SameSiteCookieContext::SAME_SITE_LAX,
- CanonicalCookie::CookieInclusionStatus::INCLUDE},
+ CanonicalCookie::CookieInclusionStatus()},
{"A=2; SameSite=None; Secure", false, CookieSameSite::NO_RESTRICTION,
CookieSameSite::NO_RESTRICTION,
CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT,
- CanonicalCookie::CookieInclusionStatus::INCLUDE},
+ CanonicalCookie::CookieInclusionStatus()},
// Unspecified cookies (without SameSite-by-default):
{"A=2", false, CookieSameSite::UNSPECIFIED,
CookieSameSite::NO_RESTRICTION,
CookieOptions::SameSiteCookieContext::CROSS_SITE,
- CanonicalCookie::CookieInclusionStatus::INCLUDE},
- {"A=2", false, CookieSameSite::UNSPECIFIED,
- CookieSameSite::NO_RESTRICTION,
- CookieOptions::SameSiteCookieContext::CROSS_SITE,
- CanonicalCookie::CookieInclusionStatus::INCLUDE},
+ CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting(
+ std::vector<
+ CanonicalCookie::CookieInclusionStatus::ExclusionReason>(),
+ CanonicalCookie::CookieInclusionStatus::
+ WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT)},
{"A=2", false, CookieSameSite::UNSPECIFIED,
CookieSameSite::NO_RESTRICTION,
CookieOptions::SameSiteCookieContext::SAME_SITE_LAX_METHOD_UNSAFE,
- CanonicalCookie::CookieInclusionStatus::INCLUDE},
+ CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting(
+ std::vector<
+ CanonicalCookie::CookieInclusionStatus::ExclusionReason>(),
+ CanonicalCookie::CookieInclusionStatus::
+ WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT)},
{"A=2", false, CookieSameSite::UNSPECIFIED,
CookieSameSite::NO_RESTRICTION,
CookieOptions::SameSiteCookieContext::SAME_SITE_LAX,
- CanonicalCookie::CookieInclusionStatus::INCLUDE},
+ CanonicalCookie::CookieInclusionStatus()},
{"A=2", false, CookieSameSite::UNSPECIFIED,
CookieSameSite::NO_RESTRICTION,
CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT,
- CanonicalCookie::CookieInclusionStatus::INCLUDE},
+ CanonicalCookie::CookieInclusionStatus()},
// SameSite-by-default is enabled:
// Strict cookies:
{"A=2; SameSite=Strict", true, CookieSameSite::STRICT_MODE,
CookieSameSite::STRICT_MODE,
CookieOptions::SameSiteCookieContext::CROSS_SITE,
- CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT},
+ CanonicalCookie::CookieInclusionStatus(
+ CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT)},
{"A=2; SameSite=Strict", true, CookieSameSite::STRICT_MODE,
CookieSameSite::STRICT_MODE,
CookieOptions::SameSiteCookieContext::SAME_SITE_LAX_METHOD_UNSAFE,
- CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT},
+ CanonicalCookie::CookieInclusionStatus(
+ CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT)},
{"A=2; SameSite=Strict", true, CookieSameSite::STRICT_MODE,
CookieSameSite::STRICT_MODE,
CookieOptions::SameSiteCookieContext::SAME_SITE_LAX,
- CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT},
+ CanonicalCookie::CookieInclusionStatus(
+ CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT)},
{"A=2; SameSite=Strict", true, CookieSameSite::STRICT_MODE,
CookieSameSite::STRICT_MODE,
CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT,
- CanonicalCookie::CookieInclusionStatus::INCLUDE},
+ CanonicalCookie::CookieInclusionStatus()},
// Lax cookies:
{"A=2; SameSite=Lax", true, CookieSameSite::LAX_MODE,
CookieSameSite::LAX_MODE,
CookieOptions::SameSiteCookieContext::CROSS_SITE,
- CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX},
+ CanonicalCookie::CookieInclusionStatus(
+ CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX)},
{"A=2; SameSite=Lax", true, CookieSameSite::LAX_MODE,
CookieSameSite::LAX_MODE,
CookieOptions::SameSiteCookieContext::SAME_SITE_LAX_METHOD_UNSAFE,
- CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX},
+ CanonicalCookie::CookieInclusionStatus(
+ CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX)},
{"A=2; SameSite=Lax", true, CookieSameSite::LAX_MODE,
CookieSameSite::LAX_MODE,
CookieOptions::SameSiteCookieContext::SAME_SITE_LAX,
- CanonicalCookie::CookieInclusionStatus::INCLUDE},
+ CanonicalCookie::CookieInclusionStatus()},
{"A=2; SameSite=Lax", true, CookieSameSite::LAX_MODE,
CookieSameSite::LAX_MODE,
CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT,
- CanonicalCookie::CookieInclusionStatus::INCLUDE},
+ CanonicalCookie::CookieInclusionStatus()},
// None cookies:
{"A=2; SameSite=None; Secure", true, CookieSameSite::NO_RESTRICTION,
CookieSameSite::NO_RESTRICTION,
CookieOptions::SameSiteCookieContext::CROSS_SITE,
- CanonicalCookie::CookieInclusionStatus::INCLUDE},
+ CanonicalCookie::CookieInclusionStatus()},
{"A=2; SameSite=None; Secure", true, CookieSameSite::NO_RESTRICTION,
CookieSameSite::NO_RESTRICTION,
CookieOptions::SameSiteCookieContext::SAME_SITE_LAX_METHOD_UNSAFE,
- CanonicalCookie::CookieInclusionStatus::INCLUDE},
+ CanonicalCookie::CookieInclusionStatus()},
{"A=2; SameSite=None; Secure", true, CookieSameSite::NO_RESTRICTION,
CookieSameSite::NO_RESTRICTION,
CookieOptions::SameSiteCookieContext::SAME_SITE_LAX,
- CanonicalCookie::CookieInclusionStatus::INCLUDE},
+ CanonicalCookie::CookieInclusionStatus()},
{"A=2; SameSite=None; Secure", true, CookieSameSite::NO_RESTRICTION,
CookieSameSite::NO_RESTRICTION,
CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT,
- CanonicalCookie::CookieInclusionStatus::INCLUDE},
+ CanonicalCookie::CookieInclusionStatus()},
// Unspecified recently-created cookies (with SameSite-by-default):
{"A=2", true, CookieSameSite::UNSPECIFIED,
CookieSameSite::LAX_MODE_ALLOW_UNSAFE,
CookieOptions::SameSiteCookieContext::CROSS_SITE,
- CanonicalCookie::CookieInclusionStatus::
- EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
+ CanonicalCookie::CookieInclusionStatus(
+ CanonicalCookie::CookieInclusionStatus::
+ EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
+ CanonicalCookie::CookieInclusionStatus::
+ WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT),
kShortAge},
{"A=2", true, CookieSameSite::UNSPECIFIED,
CookieSameSite::LAX_MODE_ALLOW_UNSAFE,
CookieOptions::SameSiteCookieContext::SAME_SITE_LAX_METHOD_UNSAFE,
- CanonicalCookie::CookieInclusionStatus::INCLUDE, kShortAge},
+ CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting(
+ std::vector<
+ CanonicalCookie::CookieInclusionStatus::ExclusionReason>(),
+ CanonicalCookie::CookieInclusionStatus::
+ WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE),
+ kShortAge},
{"A=2", true, CookieSameSite::UNSPECIFIED,
CookieSameSite::LAX_MODE_ALLOW_UNSAFE,
CookieOptions::SameSiteCookieContext::SAME_SITE_LAX,
- CanonicalCookie::CookieInclusionStatus::INCLUDE, kShortAge},
+ CanonicalCookie::CookieInclusionStatus(), kShortAge},
{"A=2", true, CookieSameSite::UNSPECIFIED,
CookieSameSite::LAX_MODE_ALLOW_UNSAFE,
CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT,
- CanonicalCookie::CookieInclusionStatus::INCLUDE, kShortAge},
+ CanonicalCookie::CookieInclusionStatus(), kShortAge},
// Unspecified not-recently-created cookies (with SameSite-by-default):
{"A=2", true, CookieSameSite::UNSPECIFIED, CookieSameSite::LAX_MODE,
CookieOptions::SameSiteCookieContext::CROSS_SITE,
- CanonicalCookie::CookieInclusionStatus::
- EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
+ CanonicalCookie::CookieInclusionStatus(
+ CanonicalCookie::CookieInclusionStatus::
+ EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
+ CanonicalCookie::CookieInclusionStatus::
+ WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT),
kLongAge},
{"A=2", true, CookieSameSite::UNSPECIFIED, CookieSameSite::LAX_MODE,
CookieOptions::SameSiteCookieContext::SAME_SITE_LAX_METHOD_UNSAFE,
- CanonicalCookie::CookieInclusionStatus::
- EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
+ CanonicalCookie::CookieInclusionStatus(
+ CanonicalCookie::CookieInclusionStatus::
+ EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
+ CanonicalCookie::CookieInclusionStatus::
+ WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT),
kLongAge},
{"A=2", true, CookieSameSite::UNSPECIFIED, CookieSameSite::LAX_MODE,
CookieOptions::SameSiteCookieContext::SAME_SITE_LAX,
- CanonicalCookie::CookieInclusionStatus::INCLUDE, kLongAge},
+ CanonicalCookie::CookieInclusionStatus(), kLongAge},
{"A=2", true, CookieSameSite::UNSPECIFIED, CookieSameSite::LAX_MODE,
CookieOptions::SameSiteCookieContext::SAME_SITE_STRICT,
- CanonicalCookie::CookieInclusionStatus::INCLUDE, kLongAge},
+ CanonicalCookie::CookieInclusionStatus(), kLongAge},
};
GURL url("https://example.test");
@@ -914,12 +949,60 @@
features::kCookiesWithoutSameSiteMustBeSecure} /* enabled_features */,
{} /* disabled_features */);
- EXPECT_EQ(
- CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE,
- cookie->IncludeForRequestURL(url, options));
+ EXPECT_TRUE(cookie->IncludeForRequestURL(url, options)
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::
+ EXCLUDE_SAMESITE_NONE_INSECURE}));
}
}
+TEST(CanonicalCookieTest, MultipleExclusionReasons) {
+ GURL url("http://www.not-secure.com/foo");
+ base::Time creation_time = base::Time::Now();
+ base::Optional<base::Time> server_time = base::nullopt;
+ CookieOptions options;
+ options.set_exclude_httponly();
+ options.set_same_site_cookie_context(
+ CookieOptions::SameSiteCookieContext::CROSS_SITE);
+
+ // Test IncludeForRequestURL()
+ // Note: This is a cookie that should never exist normally, because Create()
+ // would weed it out.
+ CanonicalCookie cookie1 = CanonicalCookie(
+ "name", "value", "other-domain.com", "/bar", creation_time, base::Time(),
+ base::Time(), true /* secure */, true /* httponly */,
+ CookieSameSite::STRICT_MODE, COOKIE_PRIORITY_DEFAULT);
+ EXPECT_TRUE(
+ cookie1.IncludeForRequestURL(url, options)
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY,
+ CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY,
+ CanonicalCookie::CookieInclusionStatus::EXCLUDE_DOMAIN_MISMATCH,
+ CanonicalCookie::CookieInclusionStatus::EXCLUDE_NOT_ON_PATH,
+ CanonicalCookie::CookieInclusionStatus::
+ EXCLUDE_SAMESITE_STRICT}));
+
+ // Test Create()
+ CanonicalCookie::CookieInclusionStatus create_status;
+ auto cookie2 = CanonicalCookie::Create(
+ url, "__Secure-notactuallysecure=value;Domain=some-other-domain.com",
+ creation_time, server_time, &create_status);
+ ASSERT_FALSE(cookie2);
+ EXPECT_TRUE(create_status.HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX,
+ CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN}));
+
+ // Test IsSetPermittedInContext()
+ auto cookie3 = CanonicalCookie::Create(
+ url, "name=value;HttpOnly;SameSite=Lax", creation_time, server_time);
+ ASSERT_TRUE(cookie3);
+ EXPECT_TRUE(
+ cookie3->IsSetPermittedInContext(options)
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY,
+ CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX}));
+}
+
TEST(CanonicalCookieTest, PartialCompare) {
GURL url("http://www.example.com");
base::Time creation_time = base::Time::Now();
@@ -958,13 +1041,13 @@
// A __Secure- cookie must be Secure.
EXPECT_FALSE(CanonicalCookie::Create(https_url, "__Secure-A=B", creation_time,
server_time, &status));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX,
- status);
+ EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX}));
EXPECT_FALSE(CanonicalCookie::Create(https_url, "__Secure-A=B; httponly",
creation_time, server_time, &status));
// (EXCLUDE_HTTP_ONLY would be fine, too)
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX,
- status);
+ EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX}));
// A typoed prefix does not have to be Secure.
EXPECT_TRUE(CanonicalCookie::Create(https_url, "__secure-A=B; Secure",
@@ -979,8 +1062,8 @@
// A __Secure- cookie can't be set on a non-secure origin.
EXPECT_FALSE(CanonicalCookie::Create(http_url, "__Secure-A=B; Secure",
creation_time, server_time, &status));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX,
- status);
+ EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX}));
}
TEST(CanonicalCookieTest, HostCookiePrefix) {
@@ -994,13 +1077,13 @@
// A __Host- cookie must be Secure.
EXPECT_FALSE(CanonicalCookie::Create(https_url, "__Host-A=B;", creation_time,
server_time, &status));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX,
- status);
+ EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX}));
EXPECT_FALSE(CanonicalCookie::Create(
https_url, "__Host-A=B; Domain=" + domain + "; Path=/;", creation_time,
server_time, &status));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX,
- status);
+ EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX}));
EXPECT_TRUE(CanonicalCookie::Create(https_url, "__Host-A=B; Path=/; Secure;",
creation_time, server_time));
@@ -1008,8 +1091,8 @@
EXPECT_FALSE(CanonicalCookie::Create(
http_url, "__Host-A=B; Domain=" + domain + "; Path=/; Secure;",
creation_time, server_time, &status));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX,
- status);
+ EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX}));
EXPECT_TRUE(CanonicalCookie::Create(https_url, "__Host-A=B; Path=/; Secure;",
creation_time, server_time));
@@ -1017,13 +1100,13 @@
EXPECT_FALSE(CanonicalCookie::Create(
https_url, "__Host-A=B; Domain=" + domain + "; Path=/; Secure;",
creation_time, server_time, &status));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX,
- status);
+ EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX}));
EXPECT_FALSE(CanonicalCookie::Create(
https_url, "__Host-A=B; Domain=" + domain + "; Secure;", creation_time,
server_time, &status));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX,
- status);
+ EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX}));
// A __Host- cookie may have a domain if it's an IP address that matches the
// URL.
@@ -1041,12 +1124,12 @@
EXPECT_FALSE(CanonicalCookie::Create(https_url,
"__Host-A=B; Path=/foo; Secure;",
creation_time, server_time, &status));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX,
- status);
+ EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX}));
EXPECT_FALSE(CanonicalCookie::Create(https_url, "__Host-A=B; Secure;",
creation_time, server_time, &status));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX,
- status);
+ EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX}));
EXPECT_TRUE(CanonicalCookie::Create(https_url, "__Host-A=B; Secure; Path=/;",
creation_time, server_time));
@@ -1806,15 +1889,17 @@
CookieOptions context_network;
context_network.set_include_httponly();
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- cookie_scriptable.IsSetPermittedInContext(context_network));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- cookie_scriptable.IsSetPermittedInContext(context_script));
+ EXPECT_TRUE(
+ cookie_scriptable.IsSetPermittedInContext(context_network).IsInclude());
+ EXPECT_TRUE(
+ cookie_scriptable.IsSetPermittedInContext(context_script).IsInclude());
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- cookie_httponly.IsSetPermittedInContext(context_network));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY,
- cookie_httponly.IsSetPermittedInContext(context_script));
+ EXPECT_TRUE(
+ cookie_httponly.IsSetPermittedInContext(context_network).IsInclude());
+ EXPECT_TRUE(
+ cookie_httponly.IsSetPermittedInContext(context_script)
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY}));
CookieOptions context_cross_site;
CookieOptions context_same_site_lax;
@@ -1830,15 +1915,15 @@
base::Time(), true /*secure*/, false /*httponly*/,
CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT);
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- cookie_same_site_unrestricted.IsSetPermittedInContext(
- context_cross_site));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- cookie_same_site_unrestricted.IsSetPermittedInContext(
- context_same_site_lax));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- cookie_same_site_unrestricted.IsSetPermittedInContext(
- context_same_site_strict));
+ EXPECT_TRUE(cookie_same_site_unrestricted
+ .IsSetPermittedInContext(context_cross_site)
+ .IsInclude());
+ EXPECT_TRUE(cookie_same_site_unrestricted
+ .IsSetPermittedInContext(context_same_site_lax)
+ .IsInclude());
+ EXPECT_TRUE(cookie_same_site_unrestricted
+ .IsSetPermittedInContext(context_same_site_strict)
+ .IsInclude());
}
{
@@ -1847,14 +1932,16 @@
base::Time(), true /*secure*/, false /*httponly*/,
CookieSameSite::LAX_MODE, COOKIE_PRIORITY_DEFAULT);
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX,
- cookie_same_site_lax.IsSetPermittedInContext(context_cross_site));
- EXPECT_EQ(
- CanonicalCookie::CookieInclusionStatus::INCLUDE,
- cookie_same_site_lax.IsSetPermittedInContext(context_same_site_lax));
- EXPECT_EQ(
- CanonicalCookie::CookieInclusionStatus::INCLUDE,
- cookie_same_site_lax.IsSetPermittedInContext(context_same_site_strict));
+ EXPECT_TRUE(cookie_same_site_lax.IsSetPermittedInContext(context_cross_site)
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::
+ EXCLUDE_SAMESITE_LAX}));
+ EXPECT_TRUE(
+ cookie_same_site_lax.IsSetPermittedInContext(context_same_site_lax)
+ .IsInclude());
+ EXPECT_TRUE(
+ cookie_same_site_lax.IsSetPermittedInContext(context_same_site_strict)
+ .IsInclude());
}
{
@@ -1865,15 +1952,17 @@
// TODO(morlovich): Do compatibility testing on whether set of strict in lax
// context really should be accepted.
- EXPECT_EQ(
- CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT,
- cookie_same_site_strict.IsSetPermittedInContext(context_cross_site));
- EXPECT_EQ(
- CanonicalCookie::CookieInclusionStatus::INCLUDE,
- cookie_same_site_strict.IsSetPermittedInContext(context_same_site_lax));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- cookie_same_site_strict.IsSetPermittedInContext(
- context_same_site_strict));
+ EXPECT_TRUE(
+ cookie_same_site_strict.IsSetPermittedInContext(context_cross_site)
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::
+ EXCLUDE_SAMESITE_STRICT}));
+ EXPECT_TRUE(
+ cookie_same_site_strict.IsSetPermittedInContext(context_same_site_lax)
+ .IsInclude());
+ EXPECT_TRUE(cookie_same_site_strict
+ .IsSetPermittedInContext(context_same_site_strict)
+ .IsInclude());
}
// Behavior of UNSPECIFIED depends on an experiment.
@@ -1886,32 +1975,130 @@
base::test::ScopedFeatureList feature_list;
feature_list.InitAndDisableFeature(features::kSameSiteByDefaultCookies);
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- cookie_same_site_unspecified.IsSetPermittedInContext(
- context_cross_site));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- cookie_same_site_unspecified.IsSetPermittedInContext(
- context_same_site_lax));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- cookie_same_site_unspecified.IsSetPermittedInContext(
- context_same_site_strict));
+ EXPECT_TRUE(
+ cookie_same_site_unspecified.IsSetPermittedInContext(context_cross_site)
+ .IsInclude());
+ EXPECT_TRUE(cookie_same_site_unspecified
+ .IsSetPermittedInContext(context_same_site_lax)
+ .IsInclude());
+ EXPECT_TRUE(cookie_same_site_unspecified
+ .IsSetPermittedInContext(context_same_site_strict)
+ .IsInclude());
}
{
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(features::kSameSiteByDefaultCookies);
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::
- EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
- cookie_same_site_unspecified.IsSetPermittedInContext(
- context_cross_site));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- cookie_same_site_unspecified.IsSetPermittedInContext(
- context_same_site_lax));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- cookie_same_site_unspecified.IsSetPermittedInContext(
- context_same_site_strict));
+ EXPECT_TRUE(
+ cookie_same_site_unspecified.IsSetPermittedInContext(context_cross_site)
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::
+ EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX}));
+ EXPECT_TRUE(cookie_same_site_unspecified
+ .IsSetPermittedInContext(context_same_site_lax)
+ .IsInclude());
+ EXPECT_TRUE(cookie_same_site_unspecified
+ .IsSetPermittedInContext(context_same_site_strict)
+ .IsInclude());
}
}
+TEST(CookieInclusionStatusTest, IncludeStatus) {
+ int num_exclusion_reasons = static_cast<int>(
+ CanonicalCookie::CookieInclusionStatus::NUM_EXCLUSION_REASONS);
+ // Zero-argument constructor
+ CanonicalCookie::CookieInclusionStatus status;
+ EXPECT_TRUE(status.IsValid());
+ EXPECT_TRUE(status.IsInclude());
+ for (int i = 0; i < num_exclusion_reasons; ++i) {
+ EXPECT_FALSE(status.HasExclusionReason(
+ static_cast<CanonicalCookie::CookieInclusionStatus::ExclusionReason>(
+ 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);
+ status.set_exclusion_reasons(1 << num_exclusion_reasons);
+ EXPECT_FALSE(status.IsInclude());
+ EXPECT_FALSE(status.IsValid());
+
+ status.set_exclusion_reasons(~0u);
+ EXPECT_FALSE(status.IsInclude());
+ EXPECT_FALSE(status.IsValid());
+}
+
+TEST(CookieInclusionStatusTest, AddExclusionReason) {
+ CanonicalCookie::CookieInclusionStatus status;
+ status.AddExclusionReason(
+ CanonicalCookie::CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR);
+ EXPECT_TRUE(status.IsValid());
+ EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR}));
+}
+
+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, AddExclusionReasonsAndWarningIfAny) {
+ CanonicalCookie::CookieInclusionStatus status1;
+ CanonicalCookie::CookieInclusionStatus status2;
+
+ status1.set_exclusion_reasons(0b00011111u);
+ status2.set_exclusion_reasons(0b11111000u);
+ status2.set_warning(
+ CanonicalCookie::CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE);
+
+ status1.AddExclusionReasonsAndWarningIfAny(status2);
+
+ EXPECT_EQ(0b11111111u, status1.exclusion_reasons());
+ EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE,
+ status1.warning());
+}
+
} // namespace net
diff --git a/net/cookies/cookie_deletion_info.cc b/net/cookies/cookie_deletion_info.cc
index 3dd42902..c791ba5c 100644
--- a/net/cookies/cookie_deletion_info.cc
+++ b/net/cookies/cookie_deletion_info.cc
@@ -121,8 +121,7 @@
}
if (url.has_value() &&
- cookie.IncludeForRequestURL(url.value(), cookie_options) !=
- CanonicalCookie::CookieInclusionStatus::INCLUDE) {
+ !cookie.IncludeForRequestURL(url.value(), cookie_options).IsInclude()) {
return false;
}
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
index c742cfc..d522c4d 100644
--- a/net/cookies/cookie_monster.cc
+++ b/net/cookies/cookie_monster.cc
@@ -975,7 +975,7 @@
CanonicalCookie::CookieInclusionStatus status =
(*it)->IncludeForRequestURL(url, options);
- if (status != CanonicalCookie::CookieInclusionStatus::INCLUDE) {
+ if (!status.IsInclude()) {
if (options.return_excluded_cookies())
excluded_cookies->push_back({**it, status});
continue;
@@ -988,13 +988,14 @@
}
}
-CanonicalCookie::CookieInclusionStatus CookieMonster::DeleteAnyEquivalentCookie(
+void CookieMonster::MaybeDeleteEquivalentCookieAndUpdateStatus(
const std::string& key,
const CanonicalCookie& ecc,
bool source_secure,
bool skip_httponly,
bool already_expired,
- base::Time* creation_date_to_inherit) {
+ base::Time* creation_date_to_inherit,
+ CanonicalCookie::CookieInclusionStatus* status) {
DCHECK(thread_checker_.CalledOnValidThread());
bool found_equivalent_cookie = false;
@@ -1037,6 +1038,9 @@
if (!skip_httponly || !cc->IsHttpOnly()) {
histogram_cookie_delete_equivalent_->Add(
COOKIE_DELETE_EQUIVALENT_WOULD_HAVE_DELETED);
+ } else {
+ // Would also have skipped for being httponly, so make a note of that.
+ skipped_httponly = true;
}
}
} else if (ecc.IsEquivalent(*cc)) {
@@ -1065,10 +1069,11 @@
if (cookie_it_to_possibly_delete != cookies_.end()) {
CanonicalCookie* cc_to_possibly_delete =
cookie_it_to_possibly_delete->second.get();
- // If a secure cookie was encountered (and left alone), don't actually
+ // 1) If a secure cookie was encountered (and left alone), don't actually
// modify any of the pre-existing cookies. Only delete if no secure cookies
- // were skipped.
- if (!skipped_secure_cookie) {
+ // were skipped. 2) Only delete if the status of the current cookie-addition
+ // is "include", so that we don't throw out a valid cookie for a bad cookie.
+ if (!skipped_secure_cookie && status->IsInclude()) {
histogram_cookie_delete_equivalent_->Add(COOKIE_DELETE_EQUIVALENT_FOUND);
if (cc_to_possibly_delete->Value() == ecc.Value()) {
*creation_date_to_inherit = cc_to_possibly_delete->CreationDate();
@@ -1078,7 +1083,7 @@
InternalDeleteCookie(cookie_it_to_possibly_delete, true,
already_expired ? DELETE_COOKIE_EXPIRED_OVERWRITE
: DELETE_COOKIE_OVERWRITE);
- } else {
+ } else if (skipped_secure_cookie) {
// If any secure cookie was skipped, preserve the pre-existing cookie.
DCHECK(cc_skipped_secure);
net_log_.AddEvent(
@@ -1090,13 +1095,15 @@
}
}
- if (skipped_httponly)
- return CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY;
+ if (skipped_httponly) {
+ status->AddExclusionReason(
+ CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY);
+ }
- if (skipped_secure_cookie)
- return CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE;
-
- return CanonicalCookie::CookieInclusionStatus::INCLUDE;
+ if (skipped_secure_cookie) {
+ status->AddExclusionReason(
+ CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE);
+ }
}
CookieMonster::CookieMap::iterator CookieMonster::InternalInsertCookie(
@@ -1135,42 +1142,33 @@
SetCookiesCallback callback) {
DCHECK(thread_checker_.CalledOnValidThread());
+ CanonicalCookie::CookieInclusionStatus status;
+
std::string scheme_lower = base::ToLowerASCII(source_scheme);
bool secure_source = GURL::SchemeIsCryptographic(scheme_lower);
if ((cc->IsSecure() && !secure_source)) {
- MaybeRunCookieCallback(
- std::move(callback),
+ status.AddExclusionReason(
CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY);
- return;
}
- CanonicalCookie::CookieInclusionStatus status =
- cc->IsSetPermittedInContext(options);
- if (status != CanonicalCookie::CookieInclusionStatus::INCLUDE) {
- // IsSetPermittedInContext already logs if it rejects a cookie, so
- // CookieMonster doesn't need to.
- MaybeRunCookieCallback(std::move(callback), status);
- return;
- }
+ status.AddExclusionReasonsAndWarningIfAny(
+ cc->IsSetPermittedInContext(options));
if (!IsCookieableScheme(scheme_lower)) {
- MaybeRunCookieCallback(
- std::move(callback),
+ status.AddExclusionReason(
CanonicalCookie::CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME);
- return;
}
// If both SameSiteByDefaultCookies and CookiesWithoutSameSiteMustBeSecure
// are enabled, non-SameSite cookies without the Secure attribute will be
- // rejected.
+ // rejected. A warning for this would have been added by
+ // IsSetPermittedInContext().
if (cookie_util::IsCookiesWithoutSameSiteMustBeSecureEnabled() &&
cc->IsEffectivelySameSiteNone() && !cc->IsSecure()) {
DVLOG(net::cookie_util::kVlogSetCookies)
<< "SetCookie() rejecting insecure cookie with SameSite=None.";
- status =
- CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE;
- MaybeRunCookieCallback(std::move(callback), status);
- return;
+ status.AddExclusionReason(
+ CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE);
}
const std::string key(GetKey(cc->Domain()));
@@ -1184,67 +1182,67 @@
base::Time creation_date_to_inherit;
- status = DeleteAnyEquivalentCookie(
+ MaybeDeleteEquivalentCookieAndUpdateStatus(
key, *cc, secure_source, options.exclude_httponly(), already_expired,
- &creation_date_to_inherit);
+ &creation_date_to_inherit, &status);
- if (status != CanonicalCookie::CookieInclusionStatus::INCLUDE) {
- std::string error;
- error =
- "SetCookie() not clobbering httponly cookie or secure cookie for "
- "insecure scheme";
-
- DVLOG(net::cookie_util::kVlogSetCookies) << error;
- MaybeRunCookieCallback(std::move(callback), status);
- return;
- }
-
- DVLOG(net::cookie_util::kVlogSetCookies)
- << "SetCookie() key: " << key << " cc: " << cc->DebugString();
-
- // Realize that we might be setting an expired cookie, and the only point
- // was to delete the cookie which we've already done.
- if (!already_expired) {
- // See InitializeHistograms() for details.
- if (cc->IsPersistent()) {
- histogram_expiration_duration_minutes_->Add(
- (cc->ExpiryDate() - creation_date).InMinutes());
- }
-
- // Histogram the type of scheme used on URLs that set cookies. This
- // intentionally includes cookies that are set or overwritten by
- // http:// URLs, but not cookies that are cleared by http:// URLs, to
- // understand if the former behavior can be deprecated for Secure
- // cookies.
- CookieSource cookie_source_sample =
- (secure_source
- ? (cc->IsSecure()
- ? COOKIE_SOURCE_SECURE_COOKIE_CRYPTOGRAPHIC_SCHEME
- : COOKIE_SOURCE_NONSECURE_COOKIE_CRYPTOGRAPHIC_SCHEME)
- : (cc->IsSecure()
- ? COOKIE_SOURCE_SECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME
- : COOKIE_SOURCE_NONSECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME));
- histogram_cookie_source_scheme_->Add(cookie_source_sample);
-
- if (!creation_date_to_inherit.is_null()) {
- cc->SetCreationDate(creation_date_to_inherit);
- }
-
- InternalInsertCookie(key, std::move(cc), true);
- } else {
+ if (status.HasExclusionReason(
+ CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE) ||
+ status.HasExclusionReason(CanonicalCookie::CookieInclusionStatus::
+ EXCLUDE_OVERWRITE_HTTP_ONLY)) {
DVLOG(net::cookie_util::kVlogSetCookies)
- << "SetCookie() not storing already expired cookie.";
+ << "SetCookie() not clobbering httponly cookie or secure cookie for "
+ "insecure scheme";
}
- // We assume that hopefully setting a cookie will be less common than
- // querying a cookie. Since setting a cookie can put us over our limits,
- // make sure that we garbage collect... We can also make the assumption that
- // if a cookie was set, in the common case it will be used soon after,
- // and we will purge the expired cookies in GetCookies().
- GarbageCollect(creation_date, key);
+ if (status.IsInclude()) {
+ DVLOG(net::cookie_util::kVlogSetCookies)
+ << "SetCookie() key: " << key << " cc: " << cc->DebugString();
- MaybeRunCookieCallback(std::move(callback),
- CanonicalCookie::CookieInclusionStatus::INCLUDE);
+ // Realize that we might be setting an expired cookie, and the only point
+ // was to delete the cookie which we've already done.
+ if (!already_expired) {
+ // See InitializeHistograms() for details.
+ if (cc->IsPersistent()) {
+ histogram_expiration_duration_minutes_->Add(
+ (cc->ExpiryDate() - creation_date).InMinutes());
+ }
+
+ // Histogram the type of scheme used on URLs that set cookies. This
+ // intentionally includes cookies that are set or overwritten by
+ // http:// URLs, but not cookies that are cleared by http:// URLs, to
+ // understand if the former behavior can be deprecated for Secure
+ // cookies.
+ CookieSource cookie_source_sample =
+ (secure_source
+ ? (cc->IsSecure()
+ ? COOKIE_SOURCE_SECURE_COOKIE_CRYPTOGRAPHIC_SCHEME
+ : COOKIE_SOURCE_NONSECURE_COOKIE_CRYPTOGRAPHIC_SCHEME)
+ : (cc->IsSecure()
+ ? COOKIE_SOURCE_SECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME
+ : COOKIE_SOURCE_NONSECURE_COOKIE_NONCRYPTOGRAPHIC_SCHEME));
+ histogram_cookie_source_scheme_->Add(cookie_source_sample);
+
+ if (!creation_date_to_inherit.is_null()) {
+ cc->SetCreationDate(creation_date_to_inherit);
+ }
+
+ InternalInsertCookie(key, std::move(cc), true);
+ } else {
+ DVLOG(net::cookie_util::kVlogSetCookies)
+ << "SetCookie() not storing already expired cookie.";
+ }
+
+ // We assume that hopefully setting a cookie will be less common than
+ // querying a cookie. Since setting a cookie can put us over our limits,
+ // make sure that we garbage collect... We can also make the assumption
+ // that if a cookie was set, in the common case it will be used soon after,
+ // and we will purge the expired cookies in GetCookies().
+ GarbageCollect(creation_date, key);
+ }
+
+ // TODO(chlily): Log metrics.
+ MaybeRunCookieCallback(std::move(callback), status);
}
void CookieMonster::SetAllCookies(CookieList list,
@@ -1278,7 +1276,7 @@
// https://codereview.chromium.org/2882063002/#msg64), which would
// solve the return value problem.
MaybeRunCookieCallback(std::move(callback),
- CanonicalCookie::CookieInclusionStatus::INCLUDE);
+ CanonicalCookie::CookieInclusionStatus());
}
void CookieMonster::InternalUpdateCookieAccessTime(CanonicalCookie* cc,
diff --git a/net/cookies/cookie_monster.h b/net/cookies/cookie_monster.h
index 24fdb41..a0bd017 100644
--- a/net/cookies/cookie_monster.h
+++ b/net/cookies/cookie_monster.h
@@ -440,14 +440,19 @@
// If a cookie is deleted, and its value matches |ecc|'s value, then
// |creation_date_to_inherit| will be set to that cookie's creation date.
//
+ // The cookie will not be deleted if |*status| is not "include" when calling
+ // the function. The function will update |*status| with exclusion reasons if
+ // a secure cookie was skipped or an httponly cookie was skipped.
+ //
// NOTE: There should never be more than a single matching equivalent cookie.
- CanonicalCookie::CookieInclusionStatus DeleteAnyEquivalentCookie(
+ void MaybeDeleteEquivalentCookieAndUpdateStatus(
const std::string& key,
const CanonicalCookie& ecc,
bool source_secure,
bool skip_httponly,
bool already_expired,
- base::Time* creation_date_to_inherit);
+ base::Time* creation_date_to_inherit,
+ CanonicalCookie::CookieInclusionStatus* status);
// Inserts |cc| into cookies_. Returns an iterator that points to the inserted
// cookie in cookies_. Guarantee: all iterators to cookies_ remain valid.
diff --git a/net/cookies/cookie_monster_change_dispatcher.cc b/net/cookies/cookie_monster_change_dispatcher.cc
index 7d09ea4..36f432f 100644
--- a/net/cookies/cookie_monster_change_dispatcher.cc
+++ b/net/cookies/cookie_monster_change_dispatcher.cc
@@ -60,9 +60,10 @@
net::CookieChangeCause change_cause) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- if (!url_.is_empty() && cookie.IncludeForRequestURL(url_, options_) !=
- CanonicalCookie::CookieInclusionStatus::INCLUDE)
+ if (!url_.is_empty() &&
+ !cookie.IncludeForRequestURL(url_, options_).IsInclude()) {
return;
+ }
// TODO(mmenke, pwnall): Run callbacks synchronously?
task_runner_->PostTask(
diff --git a/net/cookies/cookie_monster_perftest.cc b/net/cookies/cookie_monster_perftest.cc
index 463b9ccd..2829477 100644
--- a/net/cookies/cookie_monster_perftest.cc
+++ b/net/cookies/cookie_monster_perftest.cc
@@ -74,7 +74,7 @@
private:
void Run(CanonicalCookie::CookieInclusionStatus status) {
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE, status);
+ EXPECT_TRUE(status.IsInclude());
CookieTestCallback::Run();
}
CookieOptions options_;
diff --git a/net/cookies/cookie_monster_unittest.cc b/net/cookies/cookie_monster_unittest.cc
index 3a101a1..c3fe16e 100644
--- a/net/cookies/cookie_monster_unittest.cc
+++ b/net/cookies/cookie_monster_unittest.cc
@@ -141,7 +141,7 @@
ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> callback;
cm->SetAllCookiesAsync(list, callback.MakeCallback());
callback.WaitUntilDone();
- return callback.result() == CanonicalCookie::CookieInclusionStatus::INCLUDE;
+ return callback.result().IsInclude();
}
bool SetCookieWithCreationTime(CookieMonster* cm,
@@ -156,7 +156,7 @@
base::nullopt /* server_time */),
url.scheme(), CookieOptions(), callback.MakeCallback());
callback.WaitUntilDone();
- return callback.result() == CanonicalCookie::CookieInclusionStatus::INCLUDE;
+ return callback.result().IsInclude();
}
uint32_t DeleteAllCreatedInTimeRange(CookieMonster* cm,
@@ -963,7 +963,7 @@
ExecuteLoads(CookieStoreCommand::LOAD_COOKIES_FOR_KEY);
call1.WaitUntilDone();
- EXPECT_EQ(call1.result(), CanonicalCookie::CookieInclusionStatus::INCLUDE);
+ EXPECT_TRUE(call1.result().IsInclude());
EXPECT_EQ("LOAD; LOAD_FOR_KEY:foo.com; ADD; ", TakeCommandSummary());
ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> call2;
@@ -972,7 +972,7 @@
base::nullopt /* server_time */),
http_www_foo_.url().scheme(), CookieOptions(), call2.MakeCallback());
ASSERT_TRUE(call2.was_run());
- EXPECT_EQ(call2.result(), CanonicalCookie::CookieInclusionStatus::INCLUDE);
+ EXPECT_TRUE(call2.result().IsInclude());
EXPECT_EQ("ADD; ", TakeCommandSummary());
}
@@ -997,14 +997,14 @@
ExecuteLoads(CookieStoreCommand::LOAD);
call1.WaitUntilDone();
- EXPECT_EQ(call1.result(), CanonicalCookie::CookieInclusionStatus::INCLUDE);
+ EXPECT_TRUE(call1.result().IsInclude());
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;
cookie_monster_->SetAllCookiesAsync(list, call2.MakeCallback());
ASSERT_TRUE(call2.was_run());
- EXPECT_EQ(call2.result(), CanonicalCookie::CookieInclusionStatus::INCLUDE);
+ EXPECT_TRUE(call2.result().IsInclude());
EXPECT_EQ("REMOVE; REMOVE; ADD; ADD; ", TakeCommandSummary());
}
@@ -1241,8 +1241,7 @@
EXPECT_EQ("LOAD; LOAD_FOR_KEY:foo.com; ADD; ", TakeCommandSummary());
EXPECT_TRUE(get_cookie_list_callback_was_run);
ASSERT_TRUE(set_cookies_callback.was_run());
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- set_cookies_callback.result());
+ EXPECT_TRUE(set_cookies_callback.result().IsInclude());
ASSERT_TRUE(get_cookie_list_callback_deferred.was_run());
EXPECT_THAT(get_cookie_list_callback_deferred.cookies(),
@@ -1455,40 +1454,45 @@
base::Time now = base::Time::Now();
base::Optional<base::Time> server_time = base::nullopt;
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- CreateAndSetCookieReturnStatus(cm.get(), http_url, "x=1"));
- EXPECT_EQ(
- CanonicalCookie::CookieInclusionStatus::INCLUDE,
- SetCanonicalCookieReturnStatus(
- cm.get(), CanonicalCookie::Create(http_url, "y=1", now, server_time),
- "http", false /*modify_httponly*/));
+ EXPECT_TRUE(
+ CreateAndSetCookieReturnStatus(cm.get(), http_url, "x=1").IsInclude());
+ EXPECT_TRUE(SetCanonicalCookieReturnStatus(
+ cm.get(),
+ CanonicalCookie::Create(http_url, "y=1", now, server_time),
+ "http", false /*modify_httponly*/)
+ .IsInclude());
- EXPECT_EQ(
- CanonicalCookie::CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME,
- CreateAndSetCookieReturnStatus(cm.get(), foo_url, "x=1"));
- EXPECT_EQ(
- CanonicalCookie::CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME,
- SetCanonicalCookieReturnStatus(
- cm.get(), CanonicalCookie::Create(foo_url, "y=1", now, server_time),
- "foo", false /*modify_httponly*/));
+ EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), foo_url, "x=1")
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::
+ EXCLUDE_NONCOOKIEABLE_SCHEME}));
+ EXPECT_TRUE(SetCanonicalCookieReturnStatus(
+ cm.get(),
+ CanonicalCookie::Create(foo_url, "y=1", now, server_time),
+ "foo", false /*modify_httponly*/)
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::
+ EXCLUDE_NONCOOKIEABLE_SCHEME}));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- CreateAndSetCookieReturnStatus(cm_foo.get(), foo_url, "x=1"));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- SetCanonicalCookieReturnStatus(
- cm_foo.get(),
- CanonicalCookie::Create(foo_url, "y=1", now, server_time),
- "foo", false /*modify_httponly*/));
+ EXPECT_TRUE(
+ CreateAndSetCookieReturnStatus(cm_foo.get(), foo_url, "x=1").IsInclude());
+ EXPECT_TRUE(SetCanonicalCookieReturnStatus(
+ cm_foo.get(),
+ CanonicalCookie::Create(foo_url, "y=1", now, server_time),
+ "foo", false /*modify_httponly*/)
+ .IsInclude());
- EXPECT_EQ(
- CanonicalCookie::CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME,
- CreateAndSetCookieReturnStatus(cm_foo.get(), http_url, "x=1"));
- EXPECT_EQ(
- CanonicalCookie::CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME,
- SetCanonicalCookieReturnStatus(
- cm_foo.get(),
- CanonicalCookie::Create(http_url, "y=1", now, server_time), "http",
- false /*modify_httponly*/));
+ EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm_foo.get(), http_url, "x=1")
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::
+ EXCLUDE_NONCOOKIEABLE_SCHEME}));
+ EXPECT_TRUE(SetCanonicalCookieReturnStatus(
+ cm_foo.get(),
+ CanonicalCookie::Create(http_url, "y=1", now, server_time),
+ "http", false /*modify_httponly*/)
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::
+ EXCLUDE_NONCOOKIEABLE_SCHEME}));
}
TEST_F(CookieMonsterTest, GetAllCookiesForURL) {
@@ -1600,8 +1604,8 @@
ASSERT_TRUE(iter != excluded_cookies.end());
EXPECT_EQ(http_www_foo_.Format(".%D"), iter->cookie.Domain());
EXPECT_EQ("E", iter->cookie.Name());
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY,
- iter->status);
+ EXPECT_TRUE(iter->status.HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY}));
ASSERT_TRUE(++iter == excluded_cookies.end());
@@ -1617,14 +1621,14 @@
ASSERT_TRUE(iter != excluded_cookies.end());
EXPECT_EQ(http_www_foo_.host(), iter->cookie.Domain());
EXPECT_EQ("A", iter->cookie.Name());
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY,
- iter->status);
+ EXPECT_TRUE(iter->status.HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::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_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY,
- iter->status);
+ EXPECT_TRUE(iter->status.HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY}));
ASSERT_TRUE(++iter == excluded_cookies.end());
@@ -1691,8 +1695,8 @@
ASSERT_TRUE(it != excluded_cookies.end());
EXPECT_EQ("C", it->cookie.Name());
EXPECT_EQ("/bar", it->cookie.Path());
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_NOT_ON_PATH,
- it->status);
+ EXPECT_TRUE(it->status.HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_NOT_ON_PATH}));
ASSERT_TRUE(++it == excluded_cookies.end());
@@ -1702,8 +1706,8 @@
ASSERT_TRUE(it != excluded_cookies.end());
EXPECT_EQ("A", it->cookie.Name());
EXPECT_EQ("/foo", it->cookie.Path());
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_NOT_ON_PATH,
- it->status);
+ EXPECT_TRUE(it->status.HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_NOT_ON_PATH}));
ASSERT_TRUE(++it == excluded_cookies.end());
}
@@ -2219,8 +2223,7 @@
// The tasks should run in order, and the get should see the cookies.
set_cookie_callback.WaitUntilDone();
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- set_cookie_callback.result());
+ EXPECT_TRUE(set_cookie_callback.result().IsInclude());
get_cookies_callback1.WaitUntilDone();
EXPECT_EQ(1u, get_cookies_callback1.cookies().size());
@@ -2307,8 +2310,7 @@
EXPECT_EQ(0u, get_cookies_callback1.cookies().size());
set_cookie_callback.WaitUntilDone();
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- set_cookie_callback.result());
+ EXPECT_TRUE(set_cookie_callback.result().IsInclude());
get_cookies_callback2.WaitUntilDone();
EXPECT_EQ(1u, get_cookies_callback2.cookies().size());
@@ -2362,8 +2364,7 @@
EXPECT_EQ(0u, get_cookies_callback1.cookies().size());
set_cookie_callback.WaitUntilDone();
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- set_cookie_callback.result());
+ EXPECT_TRUE(set_cookie_callback.result().IsInclude());
// A subsequent get cookies call should see the new cookie.
GetAllCookiesCallback get_cookies_callback2;
@@ -2834,6 +2835,60 @@
CookieMonster::COOKIE_DELETE_EQUIVALENT_FOUND_WITH_SAME_VALUE, 1);
}
+// Test skipping a cookie in DeleteAnyEquivalentCookie for multiple reasons
+// (Secure and HttpOnly).
+TEST_F(CookieMonsterTest, SkipDontOverwriteForMultipleReasons) {
+ scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore);
+ std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), &net_log_));
+
+ // Set a secure, httponly cookie from a secure origin
+ 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", true /* can_modify_httponly */);
+ ASSERT_TRUE(status.IsInclude());
+
+ // Attempt to set a new cookie with the same name that is not Secure or
+ // Httponly from an insecure scheme.
+ auto cookie =
+ CanonicalCookie::Create(http_www_foo_.url(), "A=B", base::Time::Now(),
+ base::nullopt /* server_time */);
+ status = SetCanonicalCookieReturnStatus(cm.get(), std::move(cookie), "http",
+ false /* can_modify_httponly */);
+ EXPECT_TRUE(status.HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE,
+ CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY}));
+}
+
+// Test that when we check for equivalent cookies, we don't remove any if the
+// cookie should not be set.
+TEST_F(CookieMonsterTest, DontDeleteEquivalentCookieIfSetIsRejected) {
+ scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore);
+ std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), &net_log_));
+
+ 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),
+ "https", 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",
+ false /* can_modify_httponly */);
+ EXPECT_TRUE(status2.HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY}));
+
+ // Check that the original cookie is still there.
+ EXPECT_EQ("cookie=foo", GetCookies(cm.get(), https_www_foo_.url()));
+}
+
TEST_F(CookieMonsterTest, SetSecureCookies) {
std::unique_ptr<CookieMonster> cm(new CookieMonster(nullptr, &net_log_));
GURL http_url("http://www.foo.com");
@@ -2844,32 +2899,36 @@
// A non-secure cookie can be created from either a URL with a secure or
// insecure scheme.
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=C;"));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=B;"));
+ EXPECT_TRUE(
+ CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=C;").IsInclude());
+ EXPECT_TRUE(
+ CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=B;").IsInclude());
// A secure cookie cannot be created from a URL with an insecure scheme.
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY,
- CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=B; Secure"));
+ EXPECT_TRUE(
+ CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=B; Secure")
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY}));
// A secure cookie can be created from a URL with a secure scheme.
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=B; Secure"));
+ EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=B; Secure")
+ .IsInclude());
// If a non-secure cookie is created from a URL with an insecure scheme, and a
// secure cookie with the same name already exists, do not update the cookie.
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=B; Secure"));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE,
- CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=C;"));
+ EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=B; Secure")
+ .IsInclude());
+ EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=C;")
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::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.
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=B; Secure"));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=C;"));
+ EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=B; Secure")
+ .IsInclude());
+ EXPECT_TRUE(
+ CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=C;").IsInclude());
// If a non-secure cookie is created from a URL with an insecure scheme, and
// a secure cookie with the same name already exists, do not update the cookie
@@ -2877,44 +2936,52 @@
//
// With an existing cookie whose path is '/', a cookie with the same name
// cannot be set on the same domain, regardless of path:
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=B; Secure"));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE,
- CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=C; path=/"));
- EXPECT_EQ(
- CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE,
- CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=C; path=/my/path"));
+ EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=B; Secure")
+ .IsInclude());
+ EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=C; path=/")
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::
+ EXCLUDE_OVERWRITE_SECURE}));
+ EXPECT_TRUE(
+ CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=C; path=/my/path")
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::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
// cookie.
EXPECT_TRUE(
SetCookie(cm.get(), https_url, "WITH_PATH=B; Secure; path=/my/path"));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- CreateAndSetCookieReturnStatus(cm.get(), http_url, "WITH_PATH=C"));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- CreateAndSetCookieReturnStatus(cm.get(), http_url,
- "WITH_PATH=C; path=/"));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- CreateAndSetCookieReturnStatus(cm.get(), http_url,
- "WITH_PATH=C; path=/your/path"));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE,
- CreateAndSetCookieReturnStatus(cm.get(), http_url,
- "WITH_PATH=C; path=/my/path"));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE,
- CreateAndSetCookieReturnStatus(cm.get(), http_url,
- "WITH_PATH=C; path=/my/path/sub"));
+ EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "WITH_PATH=C")
+ .IsInclude());
+ EXPECT_TRUE(
+ CreateAndSetCookieReturnStatus(cm.get(), http_url, "WITH_PATH=C; path=/")
+ .IsInclude());
+ EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url,
+ "WITH_PATH=C; path=/your/path")
+ .IsInclude());
+ EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url,
+ "WITH_PATH=C; path=/my/path")
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::
+ EXCLUDE_OVERWRITE_SECURE}));
+ EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url,
+ "WITH_PATH=C; path=/my/path/sub")
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::
+ EXCLUDE_OVERWRITE_SECURE}));
DeleteAll(cm.get());
// If a secure cookie is set on top of an existing insecure cookie but with a
// different path, both are retained.
- EXPECT_EQ(
- CanonicalCookie::CookieInclusionStatus::INCLUDE,
- CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=B; path=/foo"));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- CreateAndSetCookieReturnStatus(cm.get(), https_url,
- "A=C; Secure; path=/"));
+ EXPECT_TRUE(
+ CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=B; path=/foo")
+ .IsInclude());
+ EXPECT_TRUE(
+ CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=C; Secure; path=/")
+ .IsInclude());
// Querying from an insecure url gets only the insecure cookie, but querying
// from a secure url returns both.
@@ -2925,11 +2992,15 @@
// Attempting to set an insecure cookie (from an insecure scheme) that domain-
// matches and path-matches the secure cookie fails i.e. the secure cookie is
// left alone...
- EXPECT_EQ(
- CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE,
- CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=D; path=/foo"));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE,
- CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=D; path=/"));
+ EXPECT_TRUE(
+ CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=D; path=/foo")
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::
+ EXCLUDE_OVERWRITE_SECURE}));
+ EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=D; path=/")
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::
+ EXCLUDE_OVERWRITE_SECURE}));
EXPECT_THAT(GetCookies(cm.get(), https_foo_url), testing::HasSubstr("A=C"));
// ...but the original insecure cookie is still retained.
@@ -2938,37 +3009,47 @@
testing::Not(testing::HasSubstr("A=D")));
// Deleting the secure cookie leaves only the original insecure cookie.
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- CreateAndSetCookieReturnStatus(
- cm.get(), https_url,
- "A=C; path=/; Expires=Thu, 01-Jan-1970 00:00:01 GMT"));
+ EXPECT_TRUE(CreateAndSetCookieReturnStatus(
+ cm.get(), https_url,
+ "A=C; path=/; Expires=Thu, 01-Jan-1970 00:00:01 GMT")
+ .IsInclude());
EXPECT_EQ("A=B", GetCookies(cm.get(), https_foo_url));
// If a non-secure cookie is created from a URL with an insecure scheme, and
// a secure cookie with the same name already exists, if the domain strings
// domain-match, do not update the cookie.
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=B; Secure"));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE,
- CreateAndSetCookieReturnStatus(cm.get(), http_url,
- "A=C; domain=foo.com"));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE,
- CreateAndSetCookieReturnStatus(cm.get(), http_url,
- "A=C; domain=www.foo.com"));
+ EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=B; Secure")
+ .IsInclude());
+ EXPECT_TRUE(
+ CreateAndSetCookieReturnStatus(cm.get(), http_url, "A=C; domain=foo.com")
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::
+ EXCLUDE_OVERWRITE_SECURE}));
+ EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url,
+ "A=C; domain=www.foo.com")
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::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.
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- CreateAndSetCookieReturnStatus(cm.get(), https_url,
- "B=C; Secure; domain=foo.com"));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE,
- CreateAndSetCookieReturnStatus(cm.get(), http_url,
- "B=D; domain=foo.com"));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE,
- CreateAndSetCookieReturnStatus(cm.get(), http_url, "B=D"));
- EXPECT_EQ(
- CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE,
- CreateAndSetCookieReturnStatus(cm.get(), http_superdomain_url, "B=D"));
+ EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), https_url,
+ "B=C; Secure; domain=foo.com")
+ .IsInclude());
+ EXPECT_TRUE(
+ CreateAndSetCookieReturnStatus(cm.get(), http_url, "B=D; domain=foo.com")
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::
+ EXCLUDE_OVERWRITE_SECURE}));
+ EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), http_url, "B=D")
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::
+ EXCLUDE_OVERWRITE_SECURE}));
+ EXPECT_TRUE(
+ CreateAndSetCookieReturnStatus(cm.get(), http_superdomain_url, "B=D")
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::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.
@@ -2978,8 +3059,10 @@
include_httponly));
// Note that the lack of an explicit options object below uses the default,
// which in this case includes "exclude_httponly = true".
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY,
- CreateAndSetCookieReturnStatus(cm.get(), https_url, "C=E; Secure"));
+ EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), https_url, "C=E; Secure")
+ .HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::
+ EXCLUDE_OVERWRITE_HTTP_ONLY}));
auto entries = net_log_.GetEntries();
ExpectLogContainsSomewhere(
@@ -3119,20 +3202,20 @@
// Tests that non-equivalent cookies because of the path attribute can be set
// successfully.
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=B; Secure"));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- CreateAndSetCookieReturnStatus(cm.get(), https_url,
- "A=C; path=/some/other/path"));
+ EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=B; Secure")
+ .IsInclude());
+ EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), https_url,
+ "A=C; path=/some/other/path")
+ .IsInclude());
EXPECT_FALSE(SetCookie(cm.get(), http_url, "A=D; path=/some/other/path"));
// Tests that non-equivalent cookies because of the domain attribute can be
// set successfully.
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=B; Secure"));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE,
- CreateAndSetCookieReturnStatus(cm.get(), https_url,
- "A=C; domain=foo.com"));
+ EXPECT_TRUE(CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=B; Secure")
+ .IsInclude());
+ EXPECT_TRUE(
+ CreateAndSetCookieReturnStatus(cm.get(), https_url, "A=C; domain=foo.com")
+ .IsInclude());
EXPECT_FALSE(SetCookie(cm.get(), http_url, "A=D; domain=foo.com"));
}
@@ -3265,15 +3348,15 @@
CanonicalCookie::Create(url, cookie_line, base::Time::Now(),
base::nullopt /* server_time */, &status);
ASSERT_TRUE(cookie != nullptr);
- ASSERT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE, status);
+ ASSERT_TRUE(status.IsInclude());
// ... but the environment is checked on set, so this may be rejected then.
ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> callback;
cm.SetCanonicalCookieAsync(std::move(cookie), "http", env_cross_site,
callback.MakeCallback());
callback.WaitUntilDone();
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX,
- callback.result());
+ EXPECT_TRUE(callback.result().HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX}));
}
TEST_F(CookieMonsterTest, RejectCreatedSecureCookieOnSet) {
@@ -3289,15 +3372,15 @@
base::nullopt /* server_time */, &status);
ASSERT_TRUE(cookie != nullptr);
- ASSERT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE, status);
+ ASSERT_TRUE(status.IsInclude());
// Cookie is rejected when attempting to set from a non-secure scheme.
ResultSavingCookieCallback<CanonicalCookie::CookieInclusionStatus> callback;
cm.SetCanonicalCookieAsync(std::move(cookie), "http", CookieOptions(),
callback.MakeCallback());
callback.WaitUntilDone();
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY,
- callback.result());
+ EXPECT_TRUE(callback.result().HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY}));
}
TEST_F(CookieMonsterTest, RejectCreatedHttpOnlyCookieOnSet) {
@@ -3312,7 +3395,7 @@
base::nullopt /* server_time */, &status);
ASSERT_TRUE(cookie != nullptr);
- ASSERT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE, status);
+ ASSERT_TRUE(status.IsInclude());
// Cookie is rejected when attempting to set with a CookieOptions that does
// not allow httponly.
@@ -3322,8 +3405,8 @@
cm.SetCanonicalCookieAsync(std::move(cookie), "http", options_no_httponly,
callback.MakeCallback());
callback.WaitUntilDone();
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY,
- callback.result());
+ EXPECT_TRUE(callback.result().HasExactlyExclusionReasonsForTesting(
+ {CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY}));
}
// Test the CookiesWithoutSameSiteMustBeSecure experimental option (in
@@ -3344,71 +3427,76 @@
// Feature enabled:
// Cookie set from a secure URL with SameSite enabled is not rejected.
{true, true, "A=B; SameSite=Lax",
- CanonicalCookie::CookieInclusionStatus::INCLUDE,
- CookieSameSite::LAX_MODE},
+ CanonicalCookie::CookieInclusionStatus(), CookieSameSite::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::INCLUDE,
+ CanonicalCookie::CookieInclusionStatus(),
CookieSameSite::LAX_MODE_ALLOW_UNSAFE, kShortAge},
{true, true, "A=B", // not-recently-set session cookie.
- CanonicalCookie::CookieInclusionStatus::INCLUDE,
- CookieSameSite::LAX_MODE, kLongAge},
+ CanonicalCookie::CookieInclusionStatus(), CookieSameSite::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::INCLUDE,
+ CanonicalCookie::CookieInclusionStatus(),
CookieSameSite::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::EXCLUDE_SAMESITE_NONE_INSECURE},
+ CanonicalCookie::CookieInclusionStatus(
+ CanonicalCookie::CookieInclusionStatus::
+ EXCLUDE_SAMESITE_NONE_INSECURE,
+ CanonicalCookie::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::INCLUDE,
+ CanonicalCookie::CookieInclusionStatus(),
CookieSameSite::LAX_MODE_ALLOW_UNSAFE, kShortAge},
{true, false, "A=B", // not-recently-set session cookie.
- CanonicalCookie::CookieInclusionStatus::INCLUDE,
- CookieSameSite::LAX_MODE, kLongAge},
+ CanonicalCookie::CookieInclusionStatus(), CookieSameSite::LAX_MODE,
+ kLongAge},
{true, false, "A=B; Max-Age=1000000", // recently-set persistent cookie.
- CanonicalCookie::CookieInclusionStatus::INCLUDE,
+ CanonicalCookie::CookieInclusionStatus(),
CookieSameSite::LAX_MODE_ALLOW_UNSAFE, kShortAge},
{true, false,
"A=B; Max-Age=1000000", // not-recently-set persistent cookie.
- CanonicalCookie::CookieInclusionStatus::INCLUDE,
- CookieSameSite::LAX_MODE, kLongAge},
+ CanonicalCookie::CookieInclusionStatus(), CookieSameSite::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::INCLUDE,
- CookieSameSite::LAX_MODE},
+ CanonicalCookie::CookieInclusionStatus(), CookieSameSite::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::INCLUDE,
+ CanonicalCookie::CookieInclusionStatus(),
CookieSameSite::LAX_MODE_ALLOW_UNSAFE, kShortAge},
{false, true, "A=B", // not-recently-set session cookie.
- CanonicalCookie::CookieInclusionStatus::INCLUDE,
- CookieSameSite::LAX_MODE, kLongAge},
+ CanonicalCookie::CookieInclusionStatus(), CookieSameSite::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::INCLUDE,
+ CanonicalCookie::CookieInclusionStatus(),
CookieSameSite::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::INCLUDE,
+ CanonicalCookie::CookieInclusionStatus::MakeFromReasonsForTesting(
+ std::vector<
+ CanonicalCookie::CookieInclusionStatus::ExclusionReason>(),
+ CanonicalCookie::CookieInclusionStatus::WARN_SAMESITE_NONE_INSECURE),
CookieSameSite::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::INCLUDE,
+ CanonicalCookie::CookieInclusionStatus(),
CookieSameSite::LAX_MODE_ALLOW_UNSAFE, kShortAge},
{false, false, "A=B", // not-recently-set session cookie.
- CanonicalCookie::CookieInclusionStatus::INCLUDE,
- CookieSameSite::LAX_MODE, kLongAge},
+ CanonicalCookie::CookieInclusionStatus(), CookieSameSite::LAX_MODE,
+ kLongAge},
};
auto cm = std::make_unique<CookieMonster>(nullptr, nullptr);
@@ -3447,7 +3535,7 @@
true /* can_modify_httponly (irrelevant) */);
EXPECT_EQ(test.expected_set_cookie_result, result)
<< "Test case " << i << " failed.";
- if (result == CanonicalCookie::CookieInclusionStatus::INCLUDE) {
+ if (result.IsInclude()) {
auto cookies = GetAllCookiesForURL(cm.get(), url);
ASSERT_EQ(1u, cookies.size());
EXPECT_EQ(test.expected_effective_samesite,
diff --git a/net/cookies/cookie_store_unittest.h b/net/cookies/cookie_store_unittest.h
index 79f61fcf..8fe683929 100644
--- a/net/cookies/cookie_store_unittest.h
+++ b/net/cookies/cookie_store_unittest.h
@@ -193,7 +193,7 @@
cs->SetCanonicalCookieAsync(std::move(cookie), url.scheme(), options,
callback.MakeCallback());
callback.WaitUntilDone();
- return callback.result() == CanonicalCookie::CookieInclusionStatus::INCLUDE;
+ return callback.result().IsInclude();
}
bool SetCanonicalCookie(CookieStore* cs,
@@ -210,7 +210,7 @@
cs->SetCanonicalCookieAsync(std::move(cookie), std::move(source_scheme),
options, callback.MakeCallback());
callback.WaitUntilDone();
- return callback.result() == CanonicalCookie::CookieInclusionStatus::INCLUDE;
+ return callback.result().IsInclude();
}
bool SetCookieWithServerTime(CookieStore* cs,
@@ -544,14 +544,16 @@
"http", true));
// A secure source is required for setting secure cookies.
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY,
- this->SetCanonicalCookieReturnStatus(
- cs,
- std::make_unique<CanonicalCookie>(
- "E", "F", http_foo_host, "/", base::Time(), base::Time(),
- base::Time(), true, false, CookieSameSite::NO_RESTRICTION,
- COOKIE_PRIORITY_DEFAULT),
- "http", true));
+ EXPECT_TRUE(
+ this->SetCanonicalCookieReturnStatus(
+ cs,
+ std::make_unique<CanonicalCookie>(
+ "E", "F", http_foo_host, "/", base::Time(), base::Time(),
+ base::Time(), true, false, CookieSameSite::NO_RESTRICTION,
+ COOKIE_PRIORITY_DEFAULT),
+ "http", true)
+ .HasExclusionReason(
+ CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY));
// A Secure cookie can be created from an insecure URL, but is rejected upon
// setting.
@@ -560,10 +562,11 @@
this->http_www_foo_.url(), "foo=1; Secure", base::Time::Now(),
base::nullopt /* server_time */, &status);
EXPECT_TRUE(cookie->IsSecure());
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE, status);
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY,
- this->SetCanonicalCookieReturnStatus(cs, std::move(cookie), "http",
- true));
+ EXPECT_TRUE(status.IsInclude());
+ EXPECT_TRUE(
+ this->SetCanonicalCookieReturnStatus(cs, std::move(cookie), "http", true)
+ .HasExclusionReason(
+ CanonicalCookie::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.
@@ -575,27 +578,31 @@
CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT),
"https", true /* modify_http_only */));
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY,
- this->SetCanonicalCookieReturnStatus(
- cs,
- std::make_unique<CanonicalCookie>(
- "E", "F", http_foo_host, "/", base::Time(), base::Time(),
- base::Time(), true /* secure */, false /* httponly */,
- CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT),
- "http", true /* modify_http_only */));
+ EXPECT_TRUE(
+ this->SetCanonicalCookieReturnStatus(
+ cs,
+ std::make_unique<CanonicalCookie>(
+ "E", "F", http_foo_host, "/", base::Time(), base::Time(),
+ base::Time(), true /* secure */, false /* httponly */,
+ CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT),
+ "http", true /* modify_http_only */)
+ .HasExclusionReason(
+ CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY));
if (TypeParam::supports_http_only) {
// Permission to modify http only cookies is required to set an
// httponly cookie.
- EXPECT_EQ(
- CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY,
+ EXPECT_TRUE(
this->SetCanonicalCookieReturnStatus(
- cs,
- std::make_unique<CanonicalCookie>(
- "G", "H", http_foo_host, "/unique", base::Time(), base::Time(),
- base::Time(), false /* secure */, true /* httponly */,
- CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT),
- "http", false /* modify_http_only */));
+ cs,
+ std::make_unique<CanonicalCookie>(
+ "G", "H", http_foo_host, "/unique", base::Time(),
+ base::Time(), base::Time(), false /* secure */,
+ true /* httponly */, CookieSameSite::NO_RESTRICTION,
+ COOKIE_PRIORITY_DEFAULT),
+ "http", false /* modify_http_only */)
+ .HasExclusionReason(
+ CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY));
// A HttpOnly cookie can be created, but is rejected
// upon setting if the options do not specify include_httponly.
@@ -604,10 +611,12 @@
"bar=1; HttpOnly", base::Time::Now(),
base::nullopt /* server_time */, &status);
EXPECT_TRUE(c->IsHttpOnly());
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::INCLUDE, status);
- EXPECT_EQ(CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY,
- this->SetCanonicalCookieReturnStatus(
- cs, std::move(c), "http", false /* can_modify_httponly */));
+ EXPECT_TRUE(status.IsInclude());
+ EXPECT_TRUE(
+ this->SetCanonicalCookieReturnStatus(cs, std::move(c), "http",
+ false /* can_modify_httponly */)
+ .HasExclusionReason(
+ CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY));
// Permission to modify httponly cookies is also required to overwrite
// an httponly cookie.
@@ -619,15 +628,17 @@
CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT),
"http", true /* modify_http_only */));
- EXPECT_EQ(
- CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY,
+ EXPECT_TRUE(
this->SetCanonicalCookieReturnStatus(
- cs,
- std::make_unique<CanonicalCookie>(
- "G", "H", http_foo_host, "/unique", base::Time(), base::Time(),
- base::Time(), false /* secure */, true /* httponly */,
- CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT),
- "http", false /* modify_http_only */));
+ cs,
+ std::make_unique<CanonicalCookie>(
+ "G", "H", http_foo_host, "/unique", base::Time(),
+ base::Time(), base::Time(), false /* secure */,
+ true /* httponly */, CookieSameSite::NO_RESTRICTION,
+ COOKIE_PRIORITY_DEFAULT),
+ "http", false /* modify_http_only */)
+ .HasExclusionReason(
+ CanonicalCookie::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/net/cookies/cookie_util.cc b/net/cookies/cookie_util.cc
index d423de2..19dafb80 100644
--- a/net/cookies/cookie_util.cc
+++ b/net/cookies/cookie_util.cc
@@ -482,28 +482,6 @@
return CookieOptions::SameSiteCookieContext::CROSS_SITE;
}
-CanonicalCookie::CookieInclusionStatus CookieWouldBeExcludedDueToSameSite(
- const CanonicalCookie& cookie,
- const CookieOptions& options) {
- // Check if cookie would be excluded under SameSiteByDefaultCookies.
- bool cross_site_context = options.same_site_cookie_context() ==
- CookieOptions::SameSiteCookieContext::CROSS_SITE;
- if (cross_site_context && cookie.SameSite() == CookieSameSite::UNSPECIFIED) {
- DCHECK(cookie.IsEffectivelySameSiteNone());
- return CanonicalCookie::CookieInclusionStatus::
- EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX;
- }
-
- // Check if cookie would be excluded under CookiesWithoutSameSiteMustBeSecure.
- if (cookie.SameSite() == CookieSameSite::NO_RESTRICTION &&
- !cookie.IsSecure()) {
- return CanonicalCookie::CookieInclusionStatus::
- EXCLUDE_SAMESITE_NONE_INSECURE;
- }
-
- return CanonicalCookie::CookieInclusionStatus::INCLUDE;
-}
-
bool IsSameSiteByDefaultCookiesEnabled() {
return base::FeatureList::IsEnabled(features::kSameSiteByDefaultCookies);
}
@@ -519,8 +497,7 @@
return base::BindOnce(
[](base::OnceCallback<void(bool)> inner_callback,
const net::CanonicalCookie::CookieInclusionStatus status) {
- bool success =
- (status == net::CanonicalCookie::CookieInclusionStatus::INCLUDE);
+ bool success = status.IsInclude();
std::move(inner_callback).Run(success);
},
std::move(callback));
diff --git a/net/cookies/cookie_util.h b/net/cookies/cookie_util.h
index 0582da4..57cc28f 100644
--- a/net/cookies/cookie_util.h
+++ b/net/cookies/cookie_util.h
@@ -144,25 +144,13 @@
ComputeSameSiteContextForSubresource(const GURL& url,
const GURL& site_for_cookies);
-// Checks whether a cookie would be excluded due to SameSite restrictions,
-// assuming SameSiteByDefaultCookies and CookiesWithoutSameSiteMustBeSecure
-// were turned on. This should be called on a cookie that is in fact included,
-// (presumably because SameSiteByDefaultCookies and
-// CookiesWithoutSameSiteMustBeSecure are not actually enabled). If the
-// return value is not INCLUDE, the cookie should be added to the excluded
-// cookies list so that an appropriate warning message can be shown in the
-// console.
-NET_EXPORT CanonicalCookie::CookieInclusionStatus
-CookieWouldBeExcludedDueToSameSite(const CanonicalCookie& cookie,
- const CookieOptions& options);
-
// Returns whether the respective SameSite feature is enabled.
NET_EXPORT bool IsSameSiteByDefaultCookiesEnabled();
NET_EXPORT bool IsCookiesWithoutSameSiteMustBeSecureEnabled();
// Takes a callback accepting a CookieInclusionStatus and returns a callback
// that accepts a bool, setting the bool to true if the CookieInclusionStatus
-// was set to INCLUDE, else sending false.
+// was set to "include", else sending false.
//
// Can be used with SetCanonicalCookie when you don't need to know why a cookie
// was blocked, only whether it was blocked.
diff --git a/net/cookies/cookie_util_unittest.cc b/net/cookies/cookie_util_unittest.cc
index 5ac2aa3..10dd9c5 100644
--- a/net/cookies/cookie_util_unittest.cc
+++ b/net/cookies/cookie_util_unittest.cc
@@ -416,7 +416,8 @@
cookie_util::AdaptCookieInclusionStatusToBool(std::move(callback));
std::move(adapted_callback)
- .Run(CanonicalCookie::CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR);
+ .Run(CanonicalCookie::CookieInclusionStatus(
+ CanonicalCookie::CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR));
EXPECT_FALSE(result_out);
@@ -427,8 +428,7 @@
adapted_callback =
cookie_util::AdaptCookieInclusionStatusToBool(std::move(callback));
- std::move(adapted_callback)
- .Run(CanonicalCookie::CookieInclusionStatus::INCLUDE);
+ std::move(adapted_callback).Run(CanonicalCookie::CookieInclusionStatus());
EXPECT_TRUE(result_out);
}