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);
 }