Unnest CanonicalCookie::CookieInclusionStatus

The nesting of CookieInclusionStatus inside CanonicalCookie is a
holdover from when it was just an enum.
There's really no great reason to keep it that way,
so we should unnest it and move it to its own file.

[email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected]

TBRing reviewers:
boliu: Please review changes to android_webview/
avi: Please review changes to chrome/
droger: Please review changes to component/signin/
alexmos: Please review changes to content/
ajgo: Please review changes to fuchsia/
mrefaat: Please review changes to ios/
agl: Please review changes to net/
blundell: Please review changes to services/

Bug: 1080767
Change-Id: Ieb9570ceeecd9ae3c2025ad46387aaef820995e2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2203171
Reviewed-by: David Roger <[email protected]>
Reviewed-by: Bo <[email protected]>
Reviewed-by: Avi Drissman <[email protected]>
Reviewed-by: Alex Gough <[email protected]>
Reviewed-by: Lily Chen <[email protected]>
Commit-Queue: Lily Chen <[email protected]>
Cr-Commit-Position: refs/heads/master@{#770652}
diff --git a/net/cookies/cookie_inclusion_status.h b/net/cookies/cookie_inclusion_status.h
new file mode 100644
index 0000000..8f958a4
--- /dev/null
+++ b/net/cookies/cookie_inclusion_status.h
@@ -0,0 +1,256 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_COOKIES_COOKIE_INCLUSION_STATUS_H_
+#define NET_COOKIES_COOKIE_INCLUSION_STATUS_H_
+
+#include <string>
+#include <vector>
+
+#include "net/base/net_export.h"
+
+class GURL;
+
+namespace net {
+
+// This class represents if a cookie was included or excluded in a cookie get or
+// set operation, and if excluded why. It holds a vector of reasons for
+// exclusion, where cookie inclusion is represented by the absence of any
+// exclusion reasons. Also marks whether a cookie should be warned about, e.g.
+// for deprecation or intervention reasons.
+class NET_EXPORT CookieInclusionStatus {
+ public:
+  // Types of reasons why a cookie might be excluded.
+  // If adding a ExclusionReason, please also update the GetDebugString()
+  // method.
+  enum ExclusionReason {
+    EXCLUDE_UNKNOWN_ERROR = 0,
+
+    EXCLUDE_HTTP_ONLY = 1,
+    EXCLUDE_SECURE_ONLY = 2,
+    EXCLUDE_DOMAIN_MISMATCH = 3,
+    EXCLUDE_NOT_ON_PATH = 4,
+    EXCLUDE_SAMESITE_STRICT = 5,
+    EXCLUDE_SAMESITE_LAX = 6,
+
+    // The following two are used for the SameSiteByDefaultCookies experiment,
+    // where if the SameSite attribute is not specified, it will be treated as
+    // SameSite=Lax by default.
+    EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX = 7,
+    // This is used if SameSite=None is specified, but the cookie is not
+    // Secure.
+    EXCLUDE_SAMESITE_NONE_INSECURE = 8,
+    EXCLUDE_USER_PREFERENCES = 9,
+
+    // Statuses specific to setting cookies
+    EXCLUDE_FAILURE_TO_STORE = 10,
+    EXCLUDE_NONCOOKIEABLE_SCHEME = 11,
+    EXCLUDE_OVERWRITE_SECURE = 12,
+    EXCLUDE_OVERWRITE_HTTP_ONLY = 13,
+    EXCLUDE_INVALID_DOMAIN = 14,
+    EXCLUDE_INVALID_PREFIX = 15,
+
+    // This should be kept last.
+    NUM_EXCLUSION_REASONS
+  };
+
+  // Reason to warn about a cookie. If you add one, please update
+  // GetDebugString().
+  enum WarningReason {
+    // Of the following 3 SameSite warnings, there will be, at most, a single
+    // active one.
+
+    // Warn if a cookie with unspecified SameSite attribute is used in a
+    // cross-site context.
+    WARN_SAMESITE_UNSPECIFIED_CROSS_SITE_CONTEXT = 0,
+    // Warn if a cookie with SameSite=None is not Secure.
+    WARN_SAMESITE_NONE_INSECURE = 1,
+    // Warn if a cookie with unspecified SameSite attribute is defaulted into
+    // Lax and is sent on a request with unsafe method, only because it is new
+    // enough to activate the Lax-allow-unsafe intervention.
+    WARN_SAMESITE_UNSPECIFIED_LAX_ALLOW_UNSAFE = 2,
+
+    // The following warnings indicate that an included cookie with an effective
+    // SameSite is experiencing a SameSiteCookieContext::|context| ->
+    // SameSiteCookieContext::|schemeful_context| downgrade that will prevent
+    // its access schemefully.
+    // This situation means that a cookie is accessible when the
+    // SchemefulSameSite feature is disabled but not when it's enabled,
+    // indicating changed behavior and potential breakage.
+    //
+    // For example, a Strict to Lax downgrade for an effective SameSite=Strict
+    // cookie:
+    // This cookie would be accessible in the Strict context as its SameSite
+    // value is Strict. However its context for schemeful same-site becomes Lax.
+    // A strict cookie cannot be accessed in a Lax context and therefore the
+    // behavior has changed.
+    // As a counterexample, a Strict to Lax downgrade for an effective
+    // SameSite=Lax cookie: A Lax cookie can be accessed in both Strict and Lax
+    // contexts so there is no behavior change (and we don't warn about it).
+    //
+    // The warnings are in the following format:
+    // WARN_{context}_{schemeful_context}_DOWNGRADE_{samesite_value}_SAMESITE
+    //
+    // Of the following 5 SameSite warnings, there will be, at most, a single
+    // active one.
+
+    // Strict to Lax downgrade for an effective SameSite=Strict cookie.
+    // This warning is only applicable for cookies being sent because a Strict
+    // cookie will be set in both Strict and Lax Contexts so the downgrade will
+    // not affect it.
+    WARN_STRICT_LAX_DOWNGRADE_STRICT_SAMESITE = 3,
+    // Strict to Cross-site downgrade for an effective SameSite=Strict cookie.
+    // This also applies to Strict to Lax Unsafe downgrades due to Lax Unsafe
+    // behaving like Cross-site.
+    WARN_STRICT_CROSS_DOWNGRADE_STRICT_SAMESITE = 4,
+    // Strict to Cross-site downgrade for an effective SameSite=Lax cookie.
+    // This also applies to Strict to Lax Unsafe downgrades due to Lax Unsafe
+    // behaving like Cross-site.
+    WARN_STRICT_CROSS_DOWNGRADE_LAX_SAMESITE = 5,
+    // Lax to Cross-site downgrade for an effective SameSite=Strict cookie.
+    // This warning is only applicable for cookies being set because a Strict
+    // cookie will not be sent in a Lax context so the downgrade would not
+    // affect it.
+    WARN_LAX_CROSS_DOWNGRADE_STRICT_SAMESITE = 6,
+    // Lax to Cross-site downgrade for an effective SameSite=Lax cookie.
+    WARN_LAX_CROSS_DOWNGRADE_LAX_SAMESITE = 7,
+
+    // This should be kept last.
+    NUM_WARNING_REASONS
+  };
+
+  // These enums encode the context downgrade warnings + the secureness of the
+  // url sending/setting the cookie. They're used for metrics only. The format
+  // is {context}_{schemeful_context}_{samesite_value}_{securness}.
+  // NO_DOWNGRADE_{securness} indicates that a cookie didn't have a breaking
+  // context downgrade and was A) included B) excluded only due to insufficient
+  // same-site context. I.e. the cookie wasn't excluded due to other reasons
+  // such as third-party cookie blocking. Keep this in line with
+  // SameSiteCookieContextBreakingDowngradeWithSecureness in enums.xml.
+  enum ContextDowngradeMetricValues {
+    NO_DOWNGRADE_INSECURE = 0,
+    NO_DOWNGRADE_SECURE = 1,
+
+    STRICT_LAX_STRICT_INSECURE = 2,
+    STRICT_CROSS_STRICT_INSECURE = 3,
+    STRICT_CROSS_LAX_INSECURE = 4,
+    LAX_CROSS_STRICT_INSECURE = 5,
+    LAX_CROSS_LAX_INSECURE = 6,
+
+    STRICT_LAX_STRICT_SECURE = 7,
+    STRICT_CROSS_STRICT_SECURE = 8,
+    STRICT_CROSS_LAX_SECURE = 9,
+    LAX_CROSS_STRICT_SECURE = 10,
+    LAX_CROSS_LAX_SECURE = 11,
+
+    // Keep last.
+    kMaxValue = LAX_CROSS_LAX_SECURE
+  };
+  // Makes a status that says include and should not warn.
+  CookieInclusionStatus();
+
+  // Make a status that contains the given exclusion reason.
+  explicit CookieInclusionStatus(ExclusionReason reason);
+  // Makes a status that contains the given exclusion reason and warning.
+  CookieInclusionStatus(ExclusionReason reason, WarningReason warning);
+
+  bool operator==(const CookieInclusionStatus& other) const;
+  bool operator!=(const CookieInclusionStatus& other) const;
+
+  // Whether the status is to include the cookie, and has no other reasons for
+  // exclusion.
+  bool IsInclude() const;
+
+  // Whether the given reason for exclusion is present.
+  bool HasExclusionReason(ExclusionReason status_type) const;
+
+  // Add an exclusion reason.
+  void AddExclusionReason(ExclusionReason status_type);
+
+  // Remove an exclusion reason.
+  void RemoveExclusionReason(ExclusionReason reason);
+
+  // If the cookie would have been excluded for reasons other than
+  // SAMESITE_UNSPECIFIED_TREATED_AS_LAX or SAMESITE_NONE_INSECURE, don't bother
+  // warning about it (clear the warning).
+  void MaybeClearSameSiteWarning();
+
+  // Whether to record the breaking downgrade metrics if the cookie is included
+  // or if it's only excluded because of insufficient same-site context.
+  bool ShouldRecordDowngradeMetrics() const;
+
+  // Whether the cookie should be warned about.
+  bool ShouldWarn() const;
+
+  // Whether the given reason for warning is present.
+  bool HasWarningReason(WarningReason reason) const;
+
+  // Whether a schemeful downgrade warning is present.
+  // A schemeful downgrade means that an included cookie with an effective
+  // SameSite is experiencing a SameSiteCookieContext::|context| ->
+  // SameSiteCookieContext::|schemeful_context| downgrade that will prevent its
+  // access schemefully. If the function returns true and |reason| is valid then
+  // |reason| will contain which warning was found.
+  bool HasDowngradeWarning(
+      CookieInclusionStatus::WarningReason* reason = nullptr) const;
+
+  // Add an warning reason.
+  void AddWarningReason(WarningReason reason);
+
+  // Remove an warning reason.
+  void RemoveWarningReason(WarningReason reason);
+
+  // Used for serialization/deserialization.
+  uint32_t exclusion_reasons() const { return exclusion_reasons_; }
+  void set_exclusion_reasons(uint32_t exclusion_reasons) {
+    exclusion_reasons_ = exclusion_reasons;
+  }
+
+  uint32_t warning_reasons() const { return warning_reasons_; }
+  void set_warning_reasons(uint32_t warning_reasons) {
+    warning_reasons_ = warning_reasons;
+  }
+
+  ContextDowngradeMetricValues GetBreakingDowngradeMetricsEnumValue(
+      const GURL& url) const;
+
+  // Get exclusion reason(s) and warning in string format.
+  std::string GetDebugString() const;
+
+  // Checks that the underlying bit vector representation doesn't contain any
+  // extraneous bits that are not mapped to any enum values. Does not check
+  // for reasons which semantically cannot coexist.
+  bool IsValid() const;
+
+  // Checks whether the exclusion reasons are exactly the set of exclusion
+  // reasons in the vector. (Ignores warnings.)
+  bool HasExactlyExclusionReasonsForTesting(
+      std::vector<ExclusionReason> reasons) const;
+
+  // Checks whether the warning reasons are exactly the set of warning
+  // reasons in the vector. (Ignores exclusions.)
+  bool HasExactlyWarningReasonsForTesting(
+      std::vector<WarningReason> reasons) const;
+
+  // Makes a status that contains the given exclusion reasons and warning.
+  static CookieInclusionStatus MakeFromReasonsForTesting(
+      std::vector<ExclusionReason> reasons,
+      std::vector<WarningReason> warnings = std::vector<WarningReason>());
+
+ private:
+  // A bit vector of the applicable exclusion reasons.
+  uint32_t exclusion_reasons_ = 0u;
+
+  // A bit vector of the applicable warning reasons.
+  uint32_t warning_reasons_ = 0u;
+};
+
+NET_EXPORT inline std::ostream& operator<<(std::ostream& os,
+                                           const CookieInclusionStatus status) {
+  return os << status.GetDebugString();
+}
+
+}  // namespace net
+
+#endif  // NET_COOKIES_COOKIE_INCLUSION_STATUS_H_