Update CookieAccessResult to include WARN status

When a cookie is created and it includes a WARN_*
CookieInclusionStatus, the status is not passed along when setting
the cookie. This impacts what messages show up in devtools issues.

These changes make it possible to show a message in devtools issues
for a cookie that has a WARN_* status.

Bug: 1254192
Change-Id: Iaf7432335264a9a4bc47e85acaa373fa92a326b9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3423085
Reviewed-by: Gauthier Ambard <[email protected]>
Reviewed-by: Steven Bingler <[email protected]>
Reviewed-by: Matt Menke <[email protected]>
Reviewed-by: Elly Fong-Jones <[email protected]>
Commit-Queue: Juba Borgohain <[email protected]>
Cr-Commit-Position: refs/heads/main@{#967347}
diff --git a/net/cookies/canonical_cookie.cc b/net/cookies/canonical_cookie.cc
index 76c08c5..5cec04a 100644
--- a/net/cookies/canonical_cookie.cc
+++ b/net/cookies/canonical_cookie.cc
@@ -1100,8 +1100,13 @@
     const GURL& source_url,
     const CookieOptions& options,
     const CookieAccessParams& params,
-    const std::vector<std::string>& cookieable_schemes) const {
+    const std::vector<std::string>& cookieable_schemes,
+    const CookieAccessResult* cookie_access_result) const {
   CookieAccessResult access_result;
+  if (cookie_access_result) {
+    access_result = *cookie_access_result;
+  }
+
   if (!base::Contains(cookieable_schemes, source_url.scheme())) {
     access_result.status.AddExclusionReason(
         CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME);
diff --git a/net/cookies/canonical_cookie.h b/net/cookies/canonical_cookie.h
index c406b47..984ade12 100644
--- a/net/cookies/canonical_cookie.h
+++ b/net/cookies/canonical_cookie.h
@@ -339,11 +339,16 @@
 
   // Returns if the cookie with given attributes can be set in context described
   // by |options| and |params|, and if no, describes why.
+  //
+  // |cookie_access_result| is an optional input status, to allow for status
+  // chaining from callers. It helps callers provide the status of a
+  // canonical cookie that may have warnings associated with it.
   CookieAccessResult IsSetPermittedInContext(
       const GURL& source_url,
       const CookieOptions& options,
       const CookieAccessParams& params,
-      const std::vector<std::string>& cookieable_schemes) const;
+      const std::vector<std::string>& cookieable_schemes,
+      const CookieAccessResult* cookie_access_result = nullptr) const;
 
   std::string DebugString() const;
 
diff --git a/net/cookies/canonical_cookie_unittest.cc b/net/cookies/canonical_cookie_unittest.cc
index 633a324..b25d6e2c 100644
--- a/net/cookies/canonical_cookie_unittest.cc
+++ b/net/cookies/canonical_cookie_unittest.cc
@@ -4337,6 +4337,29 @@
                              CookieSamePartyStatus::kNoSamePartyEnforcement),
           kCookieableSchemes),
       MatchesCookieAccessResult(IsInclude(), _, _, true));
+
+  // Test IsSetPermittedInContext successfully chains warnings by passing
+  // in a CookieAccessResult and expecting the result to have a
+  // WARN_ATTRIBUTE_VALUE_EXCEEDS_MAX_SIZE
+  CookieInclusionStatus status;
+  std::string long_path(ParsedCookie::kMaxCookieAttributeValueSize, 'a');
+
+  std::unique_ptr<CanonicalCookie> cookie_with_long_path =
+      CanonicalCookie::Create(url, "A=B; Path=/" + long_path, current_time,
+                              absl::nullopt, absl::nullopt, &status);
+  CookieAccessResult cookie_access_result(status);
+  CookieOptions cookie_with_long_path_options;
+  EXPECT_THAT(
+      cookie_with_long_path->IsSetPermittedInContext(
+          url, cookie_with_long_path_options,
+          CookieAccessParams(CookieAccessSemantics::UNKNOWN,
+                             false /* delegate_treats_url_as_trustworthy */,
+                             CookieSamePartyStatus::kNoSamePartyEnforcement),
+          kCookieableSchemes, &cookie_access_result),
+      MatchesCookieAccessResult(
+          HasWarningReason(
+              CookieInclusionStatus::WARN_ATTRIBUTE_VALUE_EXCEEDS_MAX_SIZE),
+          _, _, _));
 }
 
 TEST(CanonicalCookieTest, IsSetPermittedEffectiveSameSite) {
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
index 0aaef609..29341f25 100644
--- a/net/cookies/cookie_monster.cc
+++ b/net/cookies/cookie_monster.cc
@@ -419,7 +419,8 @@
     std::unique_ptr<CanonicalCookie> cookie,
     const GURL& source_url,
     const CookieOptions& options,
-    SetCookiesCallback callback) {
+    SetCookiesCallback callback,
+    const CookieAccessResult* cookie_access_result) {
   DCHECK(cookie->IsCanonical());
 
   std::string domain = cookie->Domain();
@@ -429,7 +430,8 @@
           // the callback on |*this|, so the callback will not outlive
           // the object.
           &CookieMonster::SetCanonicalCookie, base::Unretained(this),
-          std::move(cookie), source_url, options, std::move(callback)),
+          std::move(cookie), source_url, options, std::move(callback),
+          cookie_access_result),
       domain);
 }
 
@@ -1471,10 +1473,12 @@
   return std::make_pair(partition_it, cookie_it);
 }
 
-void CookieMonster::SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cc,
-                                       const GURL& source_url,
-                                       const CookieOptions& options,
-                                       SetCookiesCallback callback) {
+void CookieMonster::SetCanonicalCookie(
+    std::unique_ptr<CanonicalCookie> cc,
+    const GURL& source_url,
+    const CookieOptions& options,
+    SetCookiesCallback callback,
+    const CookieAccessResult* cookie_access_result) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   bool delegate_treats_url_as_trustworthy =
@@ -1487,7 +1491,7 @@
                          delegate_treats_url_as_trustworthy,
                          cookie_util::GetSamePartyStatus(
                              *cc, options, first_party_sets_enabled_)),
-      cookieable_schemes_);
+      cookieable_schemes_, cookie_access_result);
 
   const std::string key(GetKey(cc->Domain()));
 
diff --git a/net/cookies/cookie_monster.h b/net/cookies/cookie_monster.h
index 1ed421b..5ba0bca 100644
--- a/net/cookies/cookie_monster.h
+++ b/net/cookies/cookie_monster.h
@@ -179,10 +179,12 @@
   void SetAllCookiesAsync(const CookieList& list, SetCookiesCallback callback);
 
   // CookieStore implementation.
-  void SetCanonicalCookieAsync(std::unique_ptr<CanonicalCookie> cookie,
-                               const GURL& source_url,
-                               const CookieOptions& options,
-                               SetCookiesCallback callback) override;
+  void SetCanonicalCookieAsync(
+      std::unique_ptr<CanonicalCookie> cookie,
+      const GURL& source_url,
+      const CookieOptions& options,
+      SetCookiesCallback callback,
+      const CookieAccessResult* cookie_access_result = nullptr) override;
   void GetCookieListWithOptionsAsync(const GURL& url,
                                      const CookieOptions& options,
                                      const CookiePartitionKeyCollection& s,
@@ -370,10 +372,16 @@
   //
   // |options| indicates if this setting operation is allowed
   // to affect http_only or same-site cookies.
-  void SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cookie,
-                          const GURL& source_url,
-                          const CookieOptions& options,
-                          SetCookiesCallback callback);
+  //
+  // |cookie_access_result| is an optional input status, to allow for status
+  // chaining from callers. It helps callers provide the status of a
+  // canonical cookie that may have warnings associated with it.
+  void SetCanonicalCookie(
+      std::unique_ptr<CanonicalCookie> cookie,
+      const GURL& source_url,
+      const CookieOptions& options,
+      SetCookiesCallback callback,
+      const CookieAccessResult* cookie_access_result = nullptr);
 
   void GetAllCookies(GetAllCookiesCallback callback);
 
diff --git a/net/cookies/cookie_monster_unittest.cc b/net/cookies/cookie_monster_unittest.cc
index 5ef9e35..40579c0 100644
--- a/net/cookies/cookie_monster_unittest.cc
+++ b/net/cookies/cookie_monster_unittest.cc
@@ -2904,7 +2904,7 @@
       base::BindOnce(&CookieStore::SetCanonicalCookieAsync,
                      base::Unretained(cm.get()), std::move(cookie), kUrl,
                      CookieOptions::MakeAllInclusive(),
-                     set_cookie_callback.MakeCallback())));
+                     set_cookie_callback.MakeCallback(), nullptr)));
 
   // Get cookie task. Queued before the delete task is executed, so should not
   // see the set cookie.
diff --git a/net/cookies/cookie_store.h b/net/cookies/cookie_store.h
index 8631b10..4dbe5fd 100644
--- a/net/cookies/cookie_store.h
+++ b/net/cookies/cookie_store.h
@@ -64,10 +64,16 @@
   // which cookies it can alter (e.g. http only, or same site).
   //
   // The current time will be used in place of a null creation time.
-  virtual void SetCanonicalCookieAsync(std::unique_ptr<CanonicalCookie> cookie,
-                                       const GURL& source_url,
-                                       const CookieOptions& options,
-                                       SetCookiesCallback callback) = 0;
+  //
+  // |cookie_access_result| is an optional input status, to allow for status
+  // chaining from callers. It helps callers provide the status of a
+  // canonical cookie that may have warnings associated with it.
+  virtual void SetCanonicalCookieAsync(
+      std::unique_ptr<CanonicalCookie> cookie,
+      const GURL& source_url,
+      const CookieOptions& options,
+      SetCookiesCallback callback,
+      const CookieAccessResult* cookie_access_result = nullptr) = 0;
 
   // Obtains a CookieList for the given |url| and |options|. The returned
   // cookies are passed into |callback|, ordered by longest path, then earliest
diff --git a/net/cookies/cookie_store_test_helpers.cc b/net/cookies/cookie_store_test_helpers.cc
index 6bd7395..501eaf58 100644
--- a/net/cookies/cookie_store_test_helpers.cc
+++ b/net/cookies/cookie_store_test_helpers.cc
@@ -96,12 +96,14 @@
     std::unique_ptr<CanonicalCookie> cookie,
     const GURL& source_url,
     const CookieOptions& options,
-    SetCookiesCallback callback) {
+    SetCookiesCallback callback,
+    const CookieAccessResult* cookie_access_result) {
   did_run_ = false;
   cookie_monster_->SetCanonicalCookieAsync(
       std::move(cookie), source_url, options,
       base::BindOnce(&DelayedCookieMonster::SetCookiesInternalCallback,
-                     base::Unretained(this)));
+                     base::Unretained(this)),
+      cookie_access_result);
   DCHECK_EQ(did_run_, true);
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
diff --git a/net/cookies/cookie_store_test_helpers.h b/net/cookies/cookie_store_test_helpers.h
index acbae8b..c75ec70 100644
--- a/net/cookies/cookie_store_test_helpers.h
+++ b/net/cookies/cookie_store_test_helpers.h
@@ -59,10 +59,12 @@
   // invoke the internal callback.
   // Post a delayed task to invoke the original callback with the results.
 
-  void SetCanonicalCookieAsync(std::unique_ptr<CanonicalCookie> cookie,
-                               const GURL& source_url,
-                               const CookieOptions& options,
-                               SetCookiesCallback callback) override;
+  void SetCanonicalCookieAsync(
+      std::unique_ptr<CanonicalCookie> cookie,
+      const GURL& source_url,
+      const CookieOptions& options,
+      SetCookiesCallback callback,
+      const CookieAccessResult* cookie_access_result = nullptr) override;
 
   void GetCookieListWithOptionsAsync(
       const GURL& url,
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index 8e20b8d..090668e9 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -915,12 +915,13 @@
                         CookieAccessResult(returned_status));
       continue;
     }
-
+    CookieAccessResult cookie_access_result(returned_status);
     cookie_store->SetCanonicalCookieAsync(
         std::move(cookie), request_->url(), options,
         base::BindOnce(&URLRequestHttpJob::OnSetCookieResult,
                        weak_factory_.GetWeakPtr(), options, cookie_to_return,
-                       cookie_string));
+                       cookie_string),
+        &cookie_access_result);
   }
   // Removing the 1 that |num_cookie_lines_left| started with, signifing that
   // loop has been exited.