Add a SetCanonicalCookie method for CookieMonster.
This includes some refactoring of creation time defaulting, as well
as a histogram revision bump because the information about whether a
cookie is being set based on a null URL is no longer available at
the point of histogram creation.
BUG=721395, 723734
[email protected]
Review-Url: https://codereview.chromium.org/2882063002
Cr-Commit-Position: refs/heads/master@{#481227}
diff --git a/android_webview/browser/net/aw_cookie_store_wrapper.cc b/android_webview/browser/net/aw_cookie_store_wrapper.cc
index 70f7b4c..17423fd 100644
--- a/android_webview/browser/net/aw_cookie_store_wrapper.cc
+++ b/android_webview/browser/net/aw_cookie_store_wrapper.cc
@@ -16,8 +16,8 @@
namespace {
// Posts |task| to the thread that the global CookieStore lives on.
-void PostTaskToCookieStoreTaskRunner(const base::Closure& task) {
- GetCookieStoreTaskRunner()->PostTask(FROM_HERE, task);
+void PostTaskToCookieStoreTaskRunner(base::OnceClosure task) {
+ GetCookieStoreTaskRunner()->PostTask(FROM_HERE, std::move(task));
}
// Wraps a subscription to cookie change notifications for the global
@@ -128,6 +128,15 @@
last_access_time, secure, http_only, same_site, priority, callback);
}
+void SetCanonicalCookieAsyncOnCookieThread(
+ std::unique_ptr<net::CanonicalCookie> cookie,
+ bool secure_source,
+ bool modify_http_only,
+ const net::CookieStore::SetCookiesCallback& callback) {
+ GetCookieStore()->SetCanonicalCookieAsync(std::move(cookie), secure_source,
+ modify_http_only, callback);
+}
+
void GetCookiesWithOptionsAsyncOnCookieThread(
const GURL& url,
const net::CookieOptions& options,
@@ -230,6 +239,17 @@
CreateWrappedCallback<bool>(callback)));
}
+void AwCookieStoreWrapper::SetCanonicalCookieAsync(
+ std::unique_ptr<net::CanonicalCookie> cookie,
+ bool secure_source,
+ bool modify_http_only,
+ const SetCookiesCallback& callback) {
+ DCHECK(client_task_runner_->RunsTasksOnCurrentThread());
+ PostTaskToCookieStoreTaskRunner(base::BindOnce(
+ &SetCanonicalCookieAsyncOnCookieThread, std::move(cookie), secure_source,
+ modify_http_only, CreateWrappedCallback<bool>(callback)));
+}
+
void AwCookieStoreWrapper::GetCookiesWithOptionsAsync(
const GURL& url,
const net::CookieOptions& options,
diff --git a/android_webview/browser/net/aw_cookie_store_wrapper.h b/android_webview/browser/net/aw_cookie_store_wrapper.h
index cf8bfbd..860f81a4a 100644
--- a/android_webview/browser/net/aw_cookie_store_wrapper.h
+++ b/android_webview/browser/net/aw_cookie_store_wrapper.h
@@ -58,6 +58,10 @@
net::CookieSameSite same_site,
net::CookiePriority priority,
const SetCookiesCallback& callback) override;
+ void SetCanonicalCookieAsync(std::unique_ptr<net::CanonicalCookie> cookie,
+ bool secure_source,
+ bool modify_http_only,
+ const SetCookiesCallback& callback) override;
void GetCookiesWithOptionsAsync(const GURL& url,
const net::CookieOptions& options,
const GetCookiesCallback& callback) override;
diff --git a/chrome/browser/extensions/api/cookies/cookies_unittest.cc b/chrome/browser/extensions/api/cookies/cookies_unittest.cc
index a236be2..6aeccbf 100644
--- a/chrome/browser/extensions/api/cookies/cookies_unittest.cc
+++ b/chrome/browser/extensions/api/cookies/cookies_unittest.cc
@@ -188,7 +188,7 @@
std::unique_ptr<net::CanonicalCookie> canonical_cookie(
net::CanonicalCookie::Create(GURL("http://test.com"),
"=011Q255bNX_1!yd\203e+;path=/path\203",
- base::Time(), net::CookieOptions()));
+ base::Time::Now(), net::CookieOptions()));
ASSERT_NE(nullptr, canonical_cookie.get());
Cookie cookie =
cookies_helpers::CreateCookie(*canonical_cookie, "some cookie store");
diff --git a/headless/public/util/testing/generic_url_request_mocks.cc b/headless/public/util/testing/generic_url_request_mocks.cc
index 54f1ed9..a4053dc 100644
--- a/headless/public/util/testing/generic_url_request_mocks.cc
+++ b/headless/public/util/testing/generic_url_request_mocks.cc
@@ -84,6 +84,14 @@
CHECK(false);
}
+void MockCookieStore::SetCanonicalCookieAsync(
+ std::unique_ptr<net::CanonicalCookie> cookie,
+ bool secure_source,
+ bool can_modify_httponly,
+ const SetCookiesCallback& callback) {
+ CHECK(false);
+}
+
void MockCookieStore::GetCookiesWithOptionsAsync(
const GURL& url,
const net::CookieOptions& options,
diff --git a/headless/public/util/testing/generic_url_request_mocks.h b/headless/public/util/testing/generic_url_request_mocks.h
index 94e0e5c0..98f5e9d 100644
--- a/headless/public/util/testing/generic_url_request_mocks.h
+++ b/headless/public/util/testing/generic_url_request_mocks.h
@@ -74,6 +74,11 @@
net::CookiePriority priority,
const SetCookiesCallback& callback) override;
+ void SetCanonicalCookieAsync(std::unique_ptr<net::CanonicalCookie> cookie,
+ bool secure_source,
+ bool modify_http_only,
+ const SetCookiesCallback& callback) override;
+
void GetCookiesWithOptionsAsync(const GURL& url,
const net::CookieOptions& options,
const GetCookiesCallback& callback) override;
diff --git a/ios/net/cookies/cookie_store_ios.h b/ios/net/cookies/cookie_store_ios.h
index 85671c9..68ac20f 100644
--- a/ios/net/cookies/cookie_store_ios.h
+++ b/ios/net/cookies/cookie_store_ios.h
@@ -89,6 +89,10 @@
CookieSameSite same_site,
CookiePriority priority,
const SetCookiesCallback& callback) override;
+ void SetCanonicalCookieAsync(std::unique_ptr<CanonicalCookie> cookie,
+ bool secure_source,
+ bool modify_http_only,
+ const SetCookiesCallback& callback) override;
void GetCookiesWithOptionsAsync(const GURL& url,
const net::CookieOptions& options,
const GetCookiesCallback& callback) override;
diff --git a/ios/net/cookies/cookie_store_ios.mm b/ios/net/cookies/cookie_store_ios.mm
index 2ea0715..f24def3 100644
--- a/ios/net/cookies/cookie_store_ios.mm
+++ b/ios/net/cookies/cookie_store_ios.mm
@@ -25,6 +25,7 @@
#include "base/task_runner_util.h"
#include "base/threading/thread_restrictions.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
#include "ios/net/cookies/cookie_creation_time_manager.h"
#include "ios/net/cookies/cookie_store_ios_client.h"
#include "ios/net/cookies/system_cookie_util.h"
@@ -404,8 +405,6 @@
cookie_path = std::string(canon_path.data() + canon_path_component.begin,
canon_path_component.len);
- // First create a CanonicalCookie, to normalize the arguments,
- // particularly domain and path, and perform validation.
std::unique_ptr<net::CanonicalCookie> canonical_cookie =
base::MakeUnique<net::CanonicalCookie>(
name, value, cookie_domain, cookie_path, creation_time,
@@ -428,6 +427,40 @@
callback.Run(success);
}
+void CookieStoreIOS::SetCanonicalCookieAsync(
+ std::unique_ptr<net::CanonicalCookie> cookie,
+ bool secure_source,
+ bool modify_http_only,
+ const SetCookiesCallback& callback) {
+ DCHECK(cookie->IsCanonical());
+ // The exclude_httponly() option would only be used by a javascript
+ // engine.
+ DCHECK(modify_http_only);
+
+ if (cookie->IsSecure() && !secure_source) {
+ if (!callback.is_null())
+ callback.Run(false);
+ return;
+ }
+
+ NSHTTPCookie* ns_cookie = SystemCookieFromCanonicalCookie(*cookie.get());
+
+ if (ns_cookie != nil) {
+ [system_store_ setCookie:ns_cookie];
+ creation_time_manager_->SetCreationTime(
+ ns_cookie,
+ creation_time_manager_->MakeUniqueCreationTime(
+ cookie->CreationDate().is_null() ? base::Time::Now()
+ : cookie->CreationDate()));
+ if (!callback.is_null())
+ callback.Run(true);
+ return;
+ }
+
+ if (!callback.is_null())
+ callback.Run(false);
+}
+
void CookieStoreIOS::GetCookiesWithOptionsAsync(
const GURL& url,
const net::CookieOptions& options,
diff --git a/ios/net/cookies/cookie_store_ios_persistent.h b/ios/net/cookies/cookie_store_ios_persistent.h
index ce3bd470..18dba8f 100644
--- a/ios/net/cookies/cookie_store_ios_persistent.h
+++ b/ios/net/cookies/cookie_store_ios_persistent.h
@@ -53,6 +53,10 @@
CookieSameSite same_site,
CookiePriority priority,
const SetCookiesCallback& callback) override;
+ void SetCanonicalCookieAsync(std::unique_ptr<CanonicalCookie> cookie,
+ bool secure_source,
+ bool modify_http_only,
+ const SetCookiesCallback& callback) override;
void GetCookiesWithOptionsAsync(const GURL& url,
const net::CookieOptions& options,
const GetCookiesCallback& callback) override;
diff --git a/ios/net/cookies/cookie_store_ios_persistent.mm b/ios/net/cookies/cookie_store_ios_persistent.mm
index a0ed1ada..9a8527c 100644
--- a/ios/net/cookies/cookie_store_ios_persistent.mm
+++ b/ios/net/cookies/cookie_store_ios_persistent.mm
@@ -57,6 +57,18 @@
WrapSetCallback(callback));
}
+void CookieStoreIOSPersistent::SetCanonicalCookieAsync(
+ std::unique_ptr<CanonicalCookie> cookie,
+ bool secure_source,
+ bool modify_http_only,
+ const SetCookiesCallback& callback) {
+ DCHECK(thread_checker().CalledOnValidThread());
+
+ cookie_monster()->SetCanonicalCookieAsync(std::move(cookie), secure_source,
+ modify_http_only,
+ WrapSetCallback(callback));
+}
+
void CookieStoreIOSPersistent::GetCookiesWithOptionsAsync(
const GURL& url,
const net::CookieOptions& options,
diff --git a/net/cookies/canonical_cookie.cc b/net/cookies/canonical_cookie.cc
index 8e3158a..4372bde3 100644
--- a/net/cookies/canonical_cookie.cc
+++ b/net/cookies/canonical_cookie.cc
@@ -226,6 +226,7 @@
if (options.has_server_time())
server_time = options.server_time();
+ DCHECK(!creation_time.is_null());
Time cookie_expires = CanonicalCookie::CanonExpiration(parsed_cookie,
creation_time,
server_time);
@@ -447,6 +448,11 @@
return true;
}
+void CanonicalCookie::SetCreationDate(base::Time new_creation_date) {
+ DCHECK(CreationDate().is_null());
+ creation_date_ = new_creation_date;
+}
+
// static
CanonicalCookie::CookiePrefix CanonicalCookie::GetCookiePrefix(
const std::string& name) {
diff --git a/net/cookies/canonical_cookie.h b/net/cookies/canonical_cookie.h
index 1d3b3ed5..78870ec 100644
--- a/net/cookies/canonical_cookie.h
+++ b/net/cookies/canonical_cookie.h
@@ -47,8 +47,8 @@
// Supports the default copy constructor.
// Creates a new |CanonicalCookie| from the |cookie_line| and the
- // |creation_time|. Canonicalizes and validates inputs. May return NULL if
- // an attribute value is invalid.
+ // |creation_time|. Canonicalizes and validates inputs. May return NULL if
+ // an attribute value is invalid. |creation_time| may not be null.
static std::unique_ptr<CanonicalCookie> Create(
const GURL& url,
const std::string& cookie_line,
@@ -159,6 +159,11 @@
// greater than the last access time.
bool IsCanonical() const;
+ // Sets the creation date of the cookie to the specified value. It
+ // is only valid to call this method if the existing creation date
+ // is null.
+ void SetCreationDate(base::Time new_creation_date);
+
private:
FRIEND_TEST_ALL_PREFIXES(CanonicalCookieTest, TestPrefixHistograms);
diff --git a/net/cookies/canonical_cookie_unittest.cc b/net/cookies/canonical_cookie_unittest.cc
index aaa9c69d..a2f3cf7 100644
--- a/net/cookies/canonical_cookie_unittest.cc
+++ b/net/cookies/canonical_cookie_unittest.cc
@@ -864,6 +864,17 @@
.IsCanonical());
}
+TEST(CanonicalCookieTest, TestSetCreationDate) {
+ CanonicalCookie cookie("A", "B", "x.y", "/path", base::Time(), base::Time(),
+ base::Time(), false, false,
+ CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_LOW);
+ EXPECT_TRUE(cookie.CreationDate().is_null());
+
+ base::Time now(base::Time::Now());
+ cookie.SetCreationDate(now);
+ EXPECT_EQ(now, cookie.CreationDate());
+}
+
TEST(CanonicalCookieTest, TestPrefixHistograms) {
base::HistogramTester histograms;
const char kCookiePrefixHistogram[] = "Cookie.CookiePrefix";
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
index 7ccf452..60eccfe 100644
--- a/net/cookies/cookie_monster.cc
+++ b/net/cookies/cookie_monster.cc
@@ -694,6 +694,42 @@
return this->cookie_monster()->DeleteCanonicalCookie(cookie_);
}
+// Task class for SetCanonicalCookie call.
+class CookieMonster::SetCanonicalCookieTask : public CookieMonsterTask {
+ public:
+ SetCanonicalCookieTask(CookieMonster* cookie_monster,
+ std::unique_ptr<CanonicalCookie> cookie,
+ bool secure_source,
+ bool modify_http_only,
+ const SetCookiesCallback& callback)
+ : CookieMonsterTask(cookie_monster),
+ cookie_(std::move(cookie)),
+ secure_source_(secure_source),
+ modify_http_only_(modify_http_only),
+ callback_(callback) {}
+
+ // CookieMonsterTask:
+ void Run() override;
+
+ protected:
+ ~SetCanonicalCookieTask() override {}
+
+ private:
+ std::unique_ptr<CanonicalCookie> cookie_;
+ bool secure_source_;
+ bool modify_http_only_;
+ SetCookiesCallback callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(SetCanonicalCookieTask);
+};
+
+void CookieMonster::SetCanonicalCookieTask::Run() {
+ bool result = this->cookie_monster()->SetCanonicalCookie(
+ std::move(cookie_), secure_source_, modify_http_only_);
+ if (!callback_.is_null())
+ callback_.Run(result);
+}
+
// Task class for SetCookieWithOptions call.
class CookieMonster::SetCookieWithOptionsTask : public CookieMonsterTask {
public:
@@ -902,6 +938,22 @@
DoCookieTask(task);
}
+void CookieMonster::SetCanonicalCookieAsync(
+ std::unique_ptr<CanonicalCookie> cookie,
+ bool secure_source,
+ bool modify_http_only,
+ const SetCookiesCallback& callback) {
+ DCHECK(cookie->IsCanonical());
+ scoped_refptr<SetCanonicalCookieTask> task = new SetCanonicalCookieTask(
+ this, std::move(cookie), secure_source, modify_http_only, callback);
+
+ // TODO(rdsmith): Switch to DoCookieTaskForURL (or the equivalent).
+ // This is tricky because we don't have the scheme in this routine
+ // and DoCookieTaskForURL uses cookie_util::GetEffectiveDomain(scheme, host)
+ // to generate the database key to block behind.
+ DoCookieTask(task);
+}
+
void CookieMonster::SetCookieWithOptionsAsync(
const GURL& url,
const std::string& cookie_line,
@@ -1067,16 +1119,6 @@
if (!HasCookieableScheme(url))
return false;
- // TODO(mmenke): This class assumes each cookie to have a unique creation
- // time. Allowing the caller to set the creation time violates that
- // assumption. Worth fixing? Worth noting that time changes between browser
- // restarts can cause the same issue.
- base::Time actual_creation_time = creation_time;
- if (creation_time.is_null()) {
- actual_creation_time = CurrentTime();
- last_time_seen_ = actual_creation_time;
- }
-
// Validate consistency of passed arguments.
if (ParsedCookie::ParseTokenString(name) != name ||
ParsedCookie::ParseValueString(value) != value ||
@@ -1103,9 +1145,8 @@
canon_path_component.len);
std::unique_ptr<CanonicalCookie> cc(base::MakeUnique<CanonicalCookie>(
- name, value, cookie_domain, cookie_path, actual_creation_time,
- expiration_time, last_access_time, secure, http_only, same_site,
- priority));
+ name, value, cookie_domain, cookie_path, creation_time, expiration_time,
+ last_access_time, secure, http_only, same_site, priority));
return SetCanonicalCookie(std::move(cc), url.SchemeIsCryptographic(), true);
}
@@ -1765,9 +1806,19 @@
if (cc->IsSecure() && !secure_source)
return false;
- Time creation_time = cc->CreationDate();
const std::string key(GetKey(cc->Domain()));
- bool already_expired = cc->IsExpired(creation_time);
+
+ // TODO(mmenke): This class assumes each cookie to have a unique creation
+ // time. Allowing the caller to set the creation time violates that
+ // assumption. Worth fixing? Worth noting that time changes between browser
+ // restarts can cause the same issue.
+ base::Time creation_date = cc->CreationDate();
+ if (creation_date.is_null()) {
+ creation_date = CurrentTime();
+ cc->SetCreationDate(creation_date);
+ last_time_seen_ = creation_date;
+ }
+ bool already_expired = cc->IsExpired(creation_date);
if (DeleteAnyEquivalentCookie(key, *cc, secure_source, !modify_http_only,
already_expired)) {
@@ -1789,7 +1840,7 @@
// See InitializeHistograms() for details.
if (cc->IsPersistent()) {
histogram_expiration_duration_minutes_->Add(
- (cc->ExpiryDate() - creation_time).InMinutes());
+ (cc->ExpiryDate() - creation_date).InMinutes());
}
// Histogram the type of scheme used on URLs that set cookies. This
@@ -1817,7 +1868,7 @@
// 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_time, key);
+ GarbageCollect(creation_date, key);
return true;
}
diff --git a/net/cookies/cookie_monster.h b/net/cookies/cookie_monster.h
index 42afd9a..9382e935 100644
--- a/net/cookies/cookie_monster.h
+++ b/net/cookies/cookie_monster.h
@@ -176,6 +176,10 @@
CookieSameSite same_site,
CookiePriority priority,
const SetCookiesCallback& callback) override;
+ void SetCanonicalCookieAsync(std::unique_ptr<CanonicalCookie> cookie,
+ bool secure_source,
+ bool modify_http_only,
+ const SetCookiesCallback& callback) override;
void GetCookiesWithOptionsAsync(const GURL& url,
const CookieOptions& options,
const GetCookiesCallback& callback) override;
@@ -247,6 +251,7 @@
class SetAllCookiesTask;
class SetCookieWithDetailsTask;
class SetCookieWithOptionsTask;
+ class SetCanonicalCookieTask;
class DeleteSessionCookiesTask;
// Testing support.
@@ -427,6 +432,15 @@
CookieSameSite same_site,
CookiePriority priority);
+ // Sets a canonical cookie, deletes equivalents and performs garbage
+ // collection. |source_secure| indicates if the cookie is being set
+ // from a secure source (e.g. a cryptographic scheme).
+ // |modify_http_only| indicates if this setting operation is allowed
+ // to affect http_only cookies.
+ bool SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cookie,
+ bool secure_source,
+ bool can_modify_httponly);
+
CookieList GetAllCookies();
CookieList GetCookieListWithOptions(const GURL& url,
@@ -545,15 +559,6 @@
const base::Time& creation_time,
const CookieOptions& options);
- // Sets a canonical cookie, deletes equivalents and performs garbage
- // collection. |source_secure| indicates if the cookie is being set
- // from a secure source (e.g. a cryptographic scheme).
- // |modify_http_only| indicates if this setting operation is allowed
- // to affect http_only cookies.
- bool SetCanonicalCookie(std::unique_ptr<CanonicalCookie> cookie,
- bool secure_source,
- bool can_modify_httponly);
-
// Sets all cookies from |list| after deleting any equivalent cookie.
// For data gathering purposes, this routine is treated as if it is
// restoring saved cookies; some statistics are not gathered in this case.
diff --git a/net/cookies/cookie_monster_unittest.cc b/net/cookies/cookie_monster_unittest.cc
index 0b60812a..6878898 100644
--- a/net/cookies/cookie_monster_unittest.cc
+++ b/net/cookies/cookie_monster_unittest.cc
@@ -148,6 +148,20 @@
return callback.result();
}
+ bool SetCanonicalCookie(std::unique_ptr<CookieMonster> cm,
+ std::unique_ptr<CanonicalCookie> cookie,
+ bool secure_source,
+ bool modify_http_only) {
+ DCHECK(cm);
+ ResultSavingCookieCallback<bool> callback;
+ cm->SetCanonicalCookieAsync(
+ std::move(cookie), secure_source, modify_http_only,
+ base::Bind(&ResultSavingCookieCallback<bool>::Run,
+ base::Unretained(&callback)));
+ callback.WaitUntilDone();
+ return callback.result();
+ }
+
int DeleteAllCreatedBetween(CookieMonster* cm,
const base::Time& delete_begin,
const base::Time& delete_end) {
@@ -2303,7 +2317,7 @@
// When passed to the CookieMonster, it takes ownership of the pointed to
// cookies.
cookies.push_back(
- CanonicalCookie::Create(kUrl, "a=b", base::Time(), CookieOptions()));
+ CanonicalCookie::Create(kUrl, "a=b", base::Time::Now(), CookieOptions()));
ASSERT_TRUE(cookies[0]);
store->commands()[0].loaded_callback.Run(std::move(cookies));
diff --git a/net/cookies/cookie_store.h b/net/cookies/cookie_store.h
index a2be255..931b2ea1 100644
--- a/net/cookies/cookie_store.h
+++ b/net/cookies/cookie_store.h
@@ -127,6 +127,18 @@
CookiePriority priority,
const SetCookiesCallback& callback) = 0;
+ // TODO(rdsmith): Remove SetCookieWithDetailsAsync in favor of this.
+ // Set the cookie on the cookie store. |cookie.IsCanonical()| must
+ // be true. |secure_source| indicates if the source of the setting
+ // may be considered secure (if from a URL, the scheme is
+ // cryptographic), and |modify_http_only| indicates if the source of
+ // the setting may modify http_only cookies. The current time will
+ // be used in place of a null creation time.
+ virtual void SetCanonicalCookieAsync(std::unique_ptr<CanonicalCookie> cookie,
+ bool secure_source,
+ bool modify_http_only,
+ const SetCookiesCallback& callback) = 0;
+
// TODO(???): what if the total size of all the cookies >4k, can we have a
// header that big or do we need multiple Cookie: headers?
// Note: Some sites, such as Facebook, occasionally use Cookie headers >4k.
diff --git a/net/cookies/cookie_store_test_helpers.cc b/net/cookies/cookie_store_test_helpers.cc
index bed506f1..d1c1ed5 100644
--- a/net/cookies/cookie_store_test_helpers.cc
+++ b/net/cookies/cookie_store_test_helpers.cc
@@ -92,6 +92,14 @@
NOTREACHED();
}
+void DelayedCookieMonster::SetCanonicalCookieAsync(
+ std::unique_ptr<CanonicalCookie> cookie,
+ bool secure_source,
+ bool modify_http_only,
+ const SetCookiesCallback& callback) {
+ NOTREACHED();
+}
+
void DelayedCookieMonster::GetCookiesWithOptionsAsync(
const GURL& url,
const CookieOptions& options,
diff --git a/net/cookies/cookie_store_test_helpers.h b/net/cookies/cookie_store_test_helpers.h
index bb6d656b..7a9c34c 100644
--- a/net/cookies/cookie_store_test_helpers.h
+++ b/net/cookies/cookie_store_test_helpers.h
@@ -45,6 +45,11 @@
CookiePriority priority,
const SetCookiesCallback& callback) override;
+ void SetCanonicalCookieAsync(std::unique_ptr<CanonicalCookie> cookie,
+ bool secure_source,
+ bool modify_http_only,
+ const SetCookiesCallback& callback) override;
+
void GetCookiesWithOptionsAsync(
const GURL& url,
const CookieOptions& options,
diff --git a/net/cookies/cookie_store_unittest.h b/net/cookies/cookie_store_unittest.h
index 14aa3e9..4aa2a3c 100644
--- a/net/cookies/cookie_store_unittest.h
+++ b/net/cookies/cookie_store_unittest.h
@@ -181,6 +181,20 @@
return callback.result();
}
+ bool SetCanonicalCookie(CookieStore* cs,
+ std::unique_ptr<CanonicalCookie> cookie,
+ bool secure_source,
+ bool can_modify_httponly) {
+ DCHECK(cs);
+ ResultSavingCookieCallback<bool> callback;
+ cs->SetCanonicalCookieAsync(
+ std::move(cookie), secure_source, can_modify_httponly,
+ base::Bind(&ResultSavingCookieCallback<bool>::Run,
+ base::Unretained(&callback)));
+ callback.WaitUntilDone();
+ return callback.result();
+ }
+
bool SetCookieWithServerTime(CookieStore* cs,
const GURL& url,
const std::string& cookie_line,
@@ -465,6 +479,131 @@
EXPECT_TRUE(++it == cookies.end());
}
+TYPED_TEST_P(CookieStoreTest, SetCanonicalCookieTest) {
+ CookieStore* cs = this->GetCookieStore();
+
+ base::Time two_hours_ago = base::Time::Now() - base::TimeDelta::FromHours(2);
+ base::Time one_hour_ago = base::Time::Now() - base::TimeDelta::FromHours(1);
+ base::Time one_hour_from_now =
+ base::Time::Now() + base::TimeDelta::FromHours(1);
+
+ std::string foo_foo_host(this->www_foo_foo_.url().host());
+ std::string foo_bar_domain(this->www_foo_bar_.domain());
+ std::string http_foo_host(this->http_www_foo_.url().host());
+ std::string https_foo_host(this->https_www_foo_.url().host());
+
+ EXPECT_TRUE(this->SetCanonicalCookie(
+ cs,
+ base::MakeUnique<CanonicalCookie>(
+ "A", "B", foo_foo_host, "/foo", one_hour_ago, one_hour_from_now,
+ base::Time(), false, false, CookieSameSite::DEFAULT_MODE,
+ COOKIE_PRIORITY_DEFAULT),
+ false, true));
+ // Note that for the creation time to be set exactly, without modification,
+ // it must be different from the one set by the line above.
+ EXPECT_TRUE(this->SetCanonicalCookie(
+ cs,
+ base::MakeUnique<CanonicalCookie>(
+ "C", "D", "." + foo_bar_domain, "/bar", two_hours_ago, base::Time(),
+ one_hour_ago, false, true, CookieSameSite::DEFAULT_MODE,
+ COOKIE_PRIORITY_DEFAULT),
+ false, true));
+
+ // A secure source is required for creating secure cookies.
+ EXPECT_FALSE(this->SetCanonicalCookie(
+ cs,
+ base::MakeUnique<CanonicalCookie>(
+ "E", "F", http_foo_host, "/", base::Time(), base::Time(),
+ base::Time(), true, false, CookieSameSite::DEFAULT_MODE,
+ COOKIE_PRIORITY_DEFAULT),
+ false, true));
+
+ // A secure source is also required for overwriting secure cookies. Writing
+ // a secure cookie then overwriting it from a non-secure source should fail.
+ EXPECT_TRUE(this->SetCanonicalCookie(
+ cs,
+ base::MakeUnique<CanonicalCookie>(
+ "E", "F", http_foo_host, "/", base::Time(), base::Time(),
+ base::Time(), true, false, CookieSameSite::DEFAULT_MODE,
+ COOKIE_PRIORITY_DEFAULT),
+ true, true));
+
+ EXPECT_FALSE(this->SetCanonicalCookie(
+ cs,
+ base::MakeUnique<CanonicalCookie>(
+ "E", "F", http_foo_host, "/", base::Time(), base::Time(),
+ base::Time(), true, false, CookieSameSite::DEFAULT_MODE,
+ COOKIE_PRIORITY_DEFAULT),
+ false, true));
+
+ // Get all the cookies for a given URL, regardless of properties. This 'get()'
+ // operation shouldn't update the access time, as the test checks that the
+ // access time is set properly upon creation. Updating the access time would
+ // make that difficult.
+ CookieOptions options;
+ options.set_include_httponly();
+ options.set_same_site_cookie_mode(
+ CookieOptions::SameSiteCookieMode::INCLUDE_STRICT_AND_LAX);
+ options.set_do_not_update_access_time();
+
+ CookieList cookies =
+ this->GetCookieListWithOptions(cs, this->www_foo_foo_.url(), options);
+ CookieList::iterator it = cookies.begin();
+
+ ASSERT_EQ(1u, cookies.size());
+ EXPECT_EQ("A", it->Name());
+ EXPECT_EQ("B", it->Value());
+ EXPECT_EQ(this->www_foo_foo_.host(), it->Domain());
+ EXPECT_EQ("/foo", it->Path());
+ EXPECT_EQ(one_hour_ago, it->CreationDate());
+ EXPECT_TRUE(it->IsPersistent());
+ // Expect expiration date is in the right range. Some cookie implementations
+ // may not record it with millisecond accuracy.
+ EXPECT_LE((one_hour_from_now - it->ExpiryDate()).magnitude().InSeconds(), 5);
+ // Some CookieStores don't store last access date.
+ if (!it->LastAccessDate().is_null())
+ EXPECT_EQ(one_hour_ago, it->LastAccessDate());
+ EXPECT_FALSE(it->IsSecure());
+ EXPECT_FALSE(it->IsHttpOnly());
+
+ // Get the cookie using the wide open |options|:
+ cookies =
+ this->GetCookieListWithOptions(cs, this->www_foo_bar_.url(), options);
+ ASSERT_EQ(1u, cookies.size());
+ it = cookies.begin();
+
+ EXPECT_EQ("C", it->Name());
+ EXPECT_EQ("D", it->Value());
+ EXPECT_EQ(this->www_foo_bar_.Format(".%D"), it->Domain());
+ EXPECT_EQ("/bar", it->Path());
+ EXPECT_EQ(two_hours_ago, it->CreationDate());
+ EXPECT_FALSE(it->IsPersistent());
+ // Some CookieStores don't store last access date.
+ if (!it->LastAccessDate().is_null())
+ EXPECT_EQ(one_hour_ago, it->LastAccessDate());
+ EXPECT_FALSE(it->IsSecure());
+ EXPECT_TRUE(it->IsHttpOnly());
+
+ cookies =
+ this->GetCookieListWithOptions(cs, this->https_www_foo_.url(), options);
+ ASSERT_EQ(1u, cookies.size());
+ it = cookies.begin();
+
+ EXPECT_EQ("E", it->Name());
+ EXPECT_EQ("F", it->Value());
+ EXPECT_EQ("/", it->Path());
+ EXPECT_EQ(this->https_www_foo_.host(), it->Domain());
+ // Cookie should have its creation time set, and be in a reasonable range.
+ EXPECT_LE((base::Time::Now() - it->CreationDate()).magnitude().InMinutes(),
+ 2);
+ EXPECT_FALSE(it->IsPersistent());
+ // Some CookieStores don't store last access date.
+ if (!it->LastAccessDate().is_null())
+ EXPECT_EQ(it->CreationDate(), it->LastAccessDate());
+ EXPECT_TRUE(it->IsSecure());
+ EXPECT_FALSE(it->IsHttpOnly());
+}
+
// Test enforcement around setting secure cookies.
TYPED_TEST_P(CookieStoreTest, SetCookieWithDetailsSecureEnforcement) {
CookieStore* cs = this->GetCookieStore();
@@ -1476,6 +1615,7 @@
REGISTER_TYPED_TEST_CASE_P(CookieStoreTest,
SetCookieWithDetailsAsync,
+ SetCanonicalCookieTest,
SetCookieWithDetailsSecureEnforcement,
EmptyKeyTest,
DomainTest,