blob: 4d3d3ade00c7b6283f1ca83e83ea1138242787a9 [file] [log] [blame]
// Copyright 2018 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.
#include <memory>
#include "base/bind.h"
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "content/browser/cookie_store/cookie_store_context.h"
#include "content/browser/cookie_store/cookie_store_manager.h"
#include "content/browser/service_worker/embedded_worker_test_helper.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/storage_partition_impl.h"
#include "content/common/service_worker/service_worker_event_dispatcher.mojom.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace content {
namespace {
// Synchronous proxies to a wrapped CookieStore service's methods.
class CookieStoreSync {
public:
using Subscriptions = std::vector<blink::mojom::CookieChangeSubscriptionPtr>;
// The caller must ensure that the CookieStore service outlives this.
explicit CookieStoreSync(blink::mojom::CookieStore* cookie_store_service)
: cookie_store_service_(cookie_store_service) {}
~CookieStoreSync() = default;
bool AppendSubscriptions(int64_t service_worker_registration_id,
Subscriptions subscriptions) {
bool success;
base::RunLoop run_loop;
cookie_store_service_->AppendSubscriptions(
service_worker_registration_id, std::move(subscriptions),
base::BindOnce(
[](base::RunLoop* run_loop, bool* success, bool service_success) {
*success = service_success;
run_loop->Quit();
},
&run_loop, &success));
run_loop.Run();
return success;
}
base::Optional<Subscriptions> GetSubscriptions(
int64_t service_worker_registration_id) {
base::Optional<Subscriptions> result;
base::RunLoop run_loop;
cookie_store_service_->GetSubscriptions(
service_worker_registration_id,
base::BindOnce(
[](base::RunLoop* run_loop, base::Optional<Subscriptions>* result,
Subscriptions service_result, bool service_success) {
if (service_success)
*result = std::move(service_result);
run_loop->Quit();
},
&run_loop, &result));
run_loop.Run();
return result;
}
private:
blink::mojom::CookieStore* cookie_store_service_;
DISALLOW_COPY_AND_ASSIGN(CookieStoreSync);
};
const char kExampleScope[] = "https://example.com/a";
const char kExampleWorkerScript[] = "https://example.com/a/script.js";
const char kGoogleScope[] = "https://google.com/a";
const char kGoogleWorkerScript[] = "https://google.com/a/script.js";
// Mocks a service worker that uses the cookieStore API.
class CookieStoreWorkerTestHelper : public EmbeddedWorkerTestHelper {
public:
using EmbeddedWorkerTestHelper::EmbeddedWorkerTestHelper;
// Sets the cookie change subscriptions requested in the next install event.
void SetOnInstallSubscriptions(
std::vector<CookieStoreSync::Subscriptions> subscription_batches,
blink::mojom::CookieStore* cookie_store_service) {
install_subscription_batches_ = std::move(subscription_batches);
cookie_store_service_ = cookie_store_service;
}
// Spins inside a run loop until a service worker activate event is received.
void WaitForActivateEvent() {
base::RunLoop run_loop;
quit_on_activate_ = &run_loop;
run_loop.Run();
}
// The data in the CookieChangeEvents received by the worker.
std::vector<
std::pair<net::CanonicalCookie, ::network::mojom::CookieChangeCause>>&
changes() {
return changes_;
}
protected:
// Collects the worker's registration ID for OnInstallEvent().
void OnStartWorker(
int embedded_worker_id,
int64_t service_worker_version_id,
const GURL& scope,
const GURL& script_url,
bool pause_after_download,
mojom::ServiceWorkerEventDispatcherRequest dispatcher_request,
mojom::ControllerServiceWorkerRequest controller_request,
mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host,
mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info,
blink::mojom::ServiceWorkerInstalledScriptsInfoPtr installed_scripts_info)
override {
ServiceWorkerVersion* service_worker_version =
context()->GetLiveVersion(service_worker_version_id);
DCHECK(service_worker_version);
service_worker_registration_id_ = service_worker_version->registration_id();
EmbeddedWorkerTestHelper::OnStartWorker(
embedded_worker_id, service_worker_version_id, scope, script_url,
pause_after_download, std::move(dispatcher_request),
std::move(controller_request), std::move(instance_host),
std::move(provider_info), std::move(installed_scripts_info));
}
// Cookie change subscriptions can only be created in this event handler.
void OnInstallEvent(
mojom::ServiceWorkerEventDispatcher::DispatchInstallEventCallback
callback) override {
for (auto& subscriptions : install_subscription_batches_) {
cookie_store_service_->AppendSubscriptions(
service_worker_registration_id_, std::move(subscriptions),
base::BindOnce([](bool success) {
CHECK(success) << "AppendSubscriptions failed";
}));
}
install_subscription_batches_.clear();
EmbeddedWorkerTestHelper::OnInstallEvent(std::move(callback));
}
// Used to implement WaitForActivateEvent().
void OnActivateEvent(
mojom::ServiceWorkerEventDispatcher::DispatchActivateEventCallback
callback) override {
if (quit_on_activate_) {
quit_on_activate_->Quit();
quit_on_activate_ = nullptr;
}
EmbeddedWorkerTestHelper::OnActivateEvent(std::move(callback));
}
void OnCookieChangeEvent(
const net::CanonicalCookie& cookie,
::network::mojom::CookieChangeCause cause,
mojom::ServiceWorkerEventDispatcher::DispatchCookieChangeEventCallback
callback) override {
changes_.emplace_back(cookie, cause);
std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
base::Time::Now());
}
private:
// Used to add cookie change subscriptions during OnInstallEvent().
blink::mojom::CookieStore* cookie_store_service_ = nullptr;
std::vector<CookieStoreSync::Subscriptions> install_subscription_batches_;
int64_t service_worker_registration_id_;
// Set by WaitForActivateEvent(), used in OnActivateEvent().
base::RunLoop* quit_on_activate_ = nullptr;
// Collects the changes reported to OnCookieChangeEvent().
std::vector<
std::pair<net::CanonicalCookie, ::network::mojom::CookieChangeCause>>
changes_;
};
} // namespace
// This class cannot be in an anonymous namespace because it needs to be a
// friend of StoragePartitionImpl, to access its constructor.
class CookieStoreManagerTest
: public testing::Test,
public testing::WithParamInterface<bool /* reset_context */> {
public:
CookieStoreManagerTest()
: thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {}
void SetUp() override {
// Use an on-disk service worker storage to test saving and loading.
ASSERT_TRUE(user_data_directory_.CreateUniqueTempDir());
ResetServiceWorkerContext();
}
void TearDown() override {
thread_bundle_.RunUntilIdle();
// Smart pointers are reset manually in destruction order because this is
// called by ResetServiceWorkerContext().
example_service_.reset();
google_service_.reset();
example_service_ptr_.reset();
google_service_ptr_.reset();
cookie_manager_.reset();
cookie_store_context_ = nullptr;
storage_partition_impl_.reset();
worker_test_helper_.reset();
}
void ResetServiceWorkerContext() {
if (cookie_store_context_)
TearDown();
worker_test_helper_ = std::make_unique<CookieStoreWorkerTestHelper>(
user_data_directory_.GetPath());
cookie_store_context_ = base::MakeRefCounted<CookieStoreContext>();
cookie_store_context_->Initialize(worker_test_helper_->context_wrapper(),
base::BindOnce([](bool success) {
CHECK(success) << "Initialize failed";
}));
storage_partition_impl_ = base::WrapUnique(
new StoragePartitionImpl(worker_test_helper_->browser_context(),
user_data_directory_.GetPath(), nullptr));
storage_partition_impl_->SetURLRequestContext(
worker_test_helper_->browser_context()
->CreateRequestContextForStoragePartition(
user_data_directory_.GetPath(), false, nullptr,
URLRequestInterceptorScopedVector()));
::network::mojom::NetworkContext* network_context =
storage_partition_impl_->GetNetworkContext();
cookie_store_context_->ListenToCookieChanges(
network_context, base::BindOnce([](bool success) {
CHECK(success) << "ListenToCookieChanges failed";
}));
network_context->GetCookieManager(mojo::MakeRequest(&cookie_manager_));
cookie_store_context_->CreateService(
mojo::MakeRequest(&example_service_ptr_),
url::Origin::Create(GURL(kExampleScope)));
example_service_ =
std::make_unique<CookieStoreSync>(example_service_ptr_.get());
cookie_store_context_->CreateService(
mojo::MakeRequest(&google_service_ptr_),
url::Origin::Create(GURL(kGoogleScope)));
google_service_ =
std::make_unique<CookieStoreSync>(google_service_ptr_.get());
}
int64_t RegisterServiceWorker(const char* scope, const char* script_url) {
bool success = false;
int64_t registration_id;
blink::mojom::ServiceWorkerRegistrationOptions options;
options.scope = GURL(scope);
base::RunLoop run_loop;
worker_test_helper_->context()->RegisterServiceWorker(
GURL(script_url), options,
base::BindOnce(
[](base::RunLoop* run_loop, bool* success, int64_t* registration_id,
blink::ServiceWorkerStatusCode status,
const std::string& status_message,
int64_t service_worker_registration_id) {
*success = (status == blink::SERVICE_WORKER_OK);
*registration_id = service_worker_registration_id;
EXPECT_EQ(blink::SERVICE_WORKER_OK, status)
<< ServiceWorkerStatusToString(status);
run_loop->Quit();
},
&run_loop, &success, &registration_id));
run_loop.Run();
if (!success)
return kInvalidRegistrationId;
worker_test_helper_->WaitForActivateEvent();
return registration_id;
}
// Synchronous helper for CookieManager::SetCanonicalCookie.
bool SetCanonicalCookie(const net::CanonicalCookie& cookie) {
base::RunLoop run_loop;
bool success = false;
cookie_manager_->SetCanonicalCookie(
cookie, /* secure_source = */ true, /* can_modify_httponly = */ true,
base::BindOnce(
[](base::RunLoop* run_loop, bool* success, bool service_success) {
*success = success;
run_loop->Quit();
},
&run_loop, &success));
run_loop.Run();
return success;
}
// Simplified helper for SetCanonicalCookie.
//
// Creates a CanonicalCookie that is not secure, not http-only,
// and not restricted to first parties. Returns false if creation fails.
bool SetSessionCookie(const char* name,
const char* value,
const char* domain,
const char* path) {
return SetCanonicalCookie(net::CanonicalCookie(
name, value, domain, path, base::Time(), base::Time(), base::Time(),
/* secure = */ false,
/* httponly = */ false, net::CookieSameSite::NO_RESTRICTION,
net::COOKIE_PRIORITY_DEFAULT));
}
bool reset_context_during_test() const { return GetParam(); }
static constexpr const int64_t kInvalidRegistrationId = -1;
protected:
TestBrowserThreadBundle thread_bundle_;
base::ScopedTempDir user_data_directory_;
std::unique_ptr<CookieStoreWorkerTestHelper> worker_test_helper_;
std::unique_ptr<StoragePartitionImpl> storage_partition_impl_;
scoped_refptr<CookieStoreContext> cookie_store_context_;
::network::mojom::CookieManagerPtr cookie_manager_;
blink::mojom::CookieStorePtr example_service_ptr_, google_service_ptr_;
std::unique_ptr<CookieStoreSync> example_service_, google_service_;
};
const int64_t CookieStoreManagerTest::kInvalidRegistrationId;
namespace {
// Useful for sorting a vector of cookie change subscriptions.
bool CookieChangeSubscriptionLessThan(
const blink::mojom::CookieChangeSubscriptionPtr& lhs,
const blink::mojom::CookieChangeSubscriptionPtr& rhs) {
return std::tie(lhs->name, lhs->match_type, lhs->url) <
std::tie(rhs->name, rhs->match_type, rhs->url);
}
TEST_P(CookieStoreManagerTest, NoSubscriptions) {
worker_test_helper_->SetOnInstallSubscriptions(
std::vector<CookieStoreSync::Subscriptions>(),
example_service_ptr_.get());
int64_t registration_id =
RegisterServiceWorker(kExampleScope, kExampleWorkerScript);
ASSERT_NE(registration_id, kInvalidRegistrationId);
if (reset_context_during_test())
ResetServiceWorkerContext();
base::Optional<CookieStoreSync::Subscriptions> all_subscriptions_opt =
example_service_->GetSubscriptions(registration_id);
ASSERT_TRUE(all_subscriptions_opt.has_value());
EXPECT_EQ(0u, all_subscriptions_opt.value().size());
}
TEST_P(CookieStoreManagerTest, EmptySubscriptions) {
std::vector<CookieStoreSync::Subscriptions> batches;
batches.emplace_back();
worker_test_helper_->SetOnInstallSubscriptions(std::move(batches),
example_service_ptr_.get());
int64_t registration_id =
RegisterServiceWorker(kExampleScope, kExampleWorkerScript);
ASSERT_NE(registration_id, kInvalidRegistrationId);
if (reset_context_during_test())
ResetServiceWorkerContext();
base::Optional<CookieStoreSync::Subscriptions> all_subscriptions_opt =
example_service_->GetSubscriptions(registration_id);
ASSERT_TRUE(all_subscriptions_opt.has_value());
EXPECT_EQ(0u, all_subscriptions_opt.value().size());
}
TEST_P(CookieStoreManagerTest, OneSubscription) {
std::vector<CookieStoreSync::Subscriptions> batches;
batches.emplace_back();
CookieStoreSync::Subscriptions& subscriptions = batches.back();
subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New());
subscriptions.back()->name = "cookie_name_prefix";
subscriptions.back()->match_type =
::network::mojom::CookieMatchType::STARTS_WITH;
subscriptions.back()->url = GURL(kExampleScope);
worker_test_helper_->SetOnInstallSubscriptions(std::move(batches),
example_service_ptr_.get());
int64_t registration_id =
RegisterServiceWorker(kExampleScope, kExampleWorkerScript);
ASSERT_NE(registration_id, kInvalidRegistrationId);
if (reset_context_during_test())
ResetServiceWorkerContext();
base::Optional<CookieStoreSync::Subscriptions> all_subscriptions_opt =
example_service_->GetSubscriptions(registration_id);
ASSERT_TRUE(all_subscriptions_opt.has_value());
CookieStoreSync::Subscriptions all_subscriptions =
std::move(all_subscriptions_opt).value();
EXPECT_EQ(1u, all_subscriptions.size());
EXPECT_EQ("cookie_name_prefix", all_subscriptions[0]->name);
EXPECT_EQ(::network::mojom::CookieMatchType::STARTS_WITH,
all_subscriptions[0]->match_type);
EXPECT_EQ(GURL(kExampleScope), all_subscriptions[0]->url);
}
TEST_P(CookieStoreManagerTest, AppendSubscriptionsAfterEmptyInstall) {
worker_test_helper_->SetOnInstallSubscriptions(
std::vector<CookieStoreSync::Subscriptions>(),
example_service_ptr_.get());
int64_t registration_id =
RegisterServiceWorker(kExampleScope, kExampleWorkerScript);
ASSERT_NE(registration_id, kInvalidRegistrationId);
CookieStoreSync::Subscriptions subscriptions;
subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New());
subscriptions.back()->name = "cookie_name_prefix";
subscriptions.back()->match_type =
::network::mojom::CookieMatchType::STARTS_WITH;
subscriptions.back()->url = GURL(kExampleScope);
EXPECT_FALSE(example_service_->AppendSubscriptions(registration_id,
std::move(subscriptions)));
if (reset_context_during_test())
ResetServiceWorkerContext();
base::Optional<CookieStoreSync::Subscriptions> all_subscriptions_opt =
example_service_->GetSubscriptions(registration_id);
ASSERT_TRUE(all_subscriptions_opt.has_value());
EXPECT_EQ(0u, all_subscriptions_opt.value().size());
}
TEST_P(CookieStoreManagerTest, AppendSubscriptionsAfterInstall) {
{
std::vector<CookieStoreSync::Subscriptions> batches;
batches.emplace_back();
CookieStoreSync::Subscriptions& subscriptions = batches.back();
subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New());
subscriptions.back()->name = "cookie_name_prefix";
subscriptions.back()->match_type =
::network::mojom::CookieMatchType::STARTS_WITH;
subscriptions.back()->url = GURL(kExampleScope);
worker_test_helper_->SetOnInstallSubscriptions(std::move(batches),
example_service_ptr_.get());
}
int64_t registration_id =
RegisterServiceWorker(kExampleScope, kExampleWorkerScript);
ASSERT_NE(registration_id, kInvalidRegistrationId);
{
CookieStoreSync::Subscriptions subscriptions;
subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New());
subscriptions.back()->name = "cookie_name";
subscriptions.back()->match_type =
::network::mojom::CookieMatchType::EQUALS;
subscriptions.back()->url = GURL(kExampleScope);
EXPECT_FALSE(example_service_->AppendSubscriptions(
registration_id, std::move(subscriptions)));
}
if (reset_context_during_test())
ResetServiceWorkerContext();
base::Optional<CookieStoreSync::Subscriptions> all_subscriptions_opt =
example_service_->GetSubscriptions(registration_id);
ASSERT_TRUE(all_subscriptions_opt.has_value());
CookieStoreSync::Subscriptions all_subscriptions =
std::move(all_subscriptions_opt).value();
EXPECT_EQ(1u, all_subscriptions.size());
EXPECT_EQ("cookie_name_prefix", all_subscriptions[0]->name);
EXPECT_EQ(::network::mojom::CookieMatchType::STARTS_WITH,
all_subscriptions[0]->match_type);
EXPECT_EQ(GURL(kExampleScope), all_subscriptions[0]->url);
}
TEST_P(CookieStoreManagerTest, AppendSubscriptionsFromWrongOrigin) {
worker_test_helper_->SetOnInstallSubscriptions(
std::vector<CookieStoreSync::Subscriptions>(),
example_service_ptr_.get());
int64_t example_registration_id =
RegisterServiceWorker(kExampleScope, kExampleWorkerScript);
ASSERT_NE(example_registration_id, kInvalidRegistrationId);
CookieStoreSync::Subscriptions subscriptions;
subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New());
subscriptions.back()->name = "cookie_name_prefix";
subscriptions.back()->match_type =
::network::mojom::CookieMatchType::STARTS_WITH;
subscriptions.back()->url = GURL(kExampleScope);
if (reset_context_during_test())
ResetServiceWorkerContext();
EXPECT_FALSE(google_service_->AppendSubscriptions(example_registration_id,
std::move(subscriptions)));
base::Optional<CookieStoreSync::Subscriptions> all_subscriptions_opt =
example_service_->GetSubscriptions(example_registration_id);
ASSERT_TRUE(all_subscriptions_opt.has_value());
EXPECT_EQ(0u, all_subscriptions_opt.value().size());
}
TEST_P(CookieStoreManagerTest, AppendSubscriptionsInvalidRegistrationId) {
worker_test_helper_->SetOnInstallSubscriptions(
std::vector<CookieStoreSync::Subscriptions>(),
example_service_ptr_.get());
int64_t registration_id =
RegisterServiceWorker(kExampleScope, kExampleWorkerScript);
ASSERT_NE(registration_id, kInvalidRegistrationId);
if (reset_context_during_test())
ResetServiceWorkerContext();
CookieStoreSync::Subscriptions subscriptions;
subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New());
subscriptions.back()->name = "cookie_name_prefix";
subscriptions.back()->match_type =
::network::mojom::CookieMatchType::STARTS_WITH;
subscriptions.back()->url = GURL(kExampleScope);
EXPECT_FALSE(example_service_->AppendSubscriptions(registration_id + 100,
std::move(subscriptions)));
base::Optional<CookieStoreSync::Subscriptions> all_subscriptions_opt =
example_service_->GetSubscriptions(registration_id);
ASSERT_TRUE(all_subscriptions_opt.has_value());
EXPECT_EQ(0u, all_subscriptions_opt.value().size());
}
TEST_P(CookieStoreManagerTest, MultiWorkerSubscriptions) {
{
std::vector<CookieStoreSync::Subscriptions> batches;
batches.emplace_back();
CookieStoreSync::Subscriptions& subscriptions = batches.back();
subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New());
subscriptions.back()->name = "cookie_name_prefix";
subscriptions.back()->match_type =
::network::mojom::CookieMatchType::STARTS_WITH;
subscriptions.back()->url = GURL(kExampleScope);
worker_test_helper_->SetOnInstallSubscriptions(std::move(batches),
example_service_ptr_.get());
}
int64_t example_registration_id =
RegisterServiceWorker(kExampleScope, kExampleWorkerScript);
ASSERT_NE(example_registration_id, kInvalidRegistrationId);
{
std::vector<CookieStoreSync::Subscriptions> batches;
batches.emplace_back();
CookieStoreSync::Subscriptions& subscriptions = batches.back();
subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New());
subscriptions.back()->name = "cookie_name";
subscriptions.back()->match_type =
::network::mojom::CookieMatchType::EQUALS;
subscriptions.back()->url = GURL(kGoogleScope);
worker_test_helper_->SetOnInstallSubscriptions(std::move(batches),
google_service_ptr_.get());
}
int64_t google_registration_id =
RegisterServiceWorker(kGoogleScope, kGoogleWorkerScript);
ASSERT_NE(google_registration_id, kInvalidRegistrationId);
EXPECT_NE(example_registration_id, google_registration_id);
if (reset_context_during_test())
ResetServiceWorkerContext();
base::Optional<CookieStoreSync::Subscriptions> example_subscriptions_opt =
example_service_->GetSubscriptions(example_registration_id);
ASSERT_TRUE(example_subscriptions_opt.has_value());
CookieStoreSync::Subscriptions example_subscriptions =
std::move(example_subscriptions_opt).value();
EXPECT_EQ(1u, example_subscriptions.size());
EXPECT_EQ("cookie_name_prefix", example_subscriptions[0]->name);
EXPECT_EQ(::network::mojom::CookieMatchType::STARTS_WITH,
example_subscriptions[0]->match_type);
EXPECT_EQ(GURL(kExampleScope), example_subscriptions[0]->url);
base::Optional<CookieStoreSync::Subscriptions> google_subscriptions_opt =
google_service_->GetSubscriptions(google_registration_id);
ASSERT_TRUE(google_subscriptions_opt.has_value());
CookieStoreSync::Subscriptions google_subscriptions =
std::move(google_subscriptions_opt).value();
EXPECT_EQ(1u, google_subscriptions.size());
EXPECT_EQ("cookie_name", google_subscriptions[0]->name);
EXPECT_EQ(::network::mojom::CookieMatchType::EQUALS,
google_subscriptions[0]->match_type);
EXPECT_EQ(GURL(kGoogleScope), google_subscriptions[0]->url);
}
TEST_P(CookieStoreManagerTest, MultipleSubscriptions) {
std::vector<CookieStoreSync::Subscriptions> batches;
{
batches.emplace_back();
CookieStoreSync::Subscriptions& subscriptions = batches.back();
subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New());
subscriptions.back()->name = "name1";
subscriptions.back()->match_type =
::network::mojom::CookieMatchType::STARTS_WITH;
subscriptions.back()->url = GURL("https://example.com/a/1");
subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New());
subscriptions.back()->name = "name2";
subscriptions.back()->match_type =
::network::mojom::CookieMatchType::EQUALS;
subscriptions.back()->url = GURL("https://example.com/a/2");
}
batches.emplace_back();
{
batches.emplace_back();
CookieStoreSync::Subscriptions& subscriptions = batches.back();
subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New());
subscriptions.back()->name = "name3";
subscriptions.back()->match_type =
::network::mojom::CookieMatchType::STARTS_WITH;
subscriptions.back()->url = GURL("https://example.com/a/3");
}
worker_test_helper_->SetOnInstallSubscriptions(std::move(batches),
example_service_ptr_.get());
int64_t registration_id =
RegisterServiceWorker(kExampleScope, kExampleWorkerScript);
ASSERT_NE(registration_id, kInvalidRegistrationId);
if (reset_context_during_test())
ResetServiceWorkerContext();
base::Optional<CookieStoreSync::Subscriptions> all_subscriptions_opt =
example_service_->GetSubscriptions(registration_id);
ASSERT_TRUE(all_subscriptions_opt.has_value());
CookieStoreSync::Subscriptions all_subscriptions =
std::move(all_subscriptions_opt).value();
std::sort(all_subscriptions.begin(), all_subscriptions.end(),
CookieChangeSubscriptionLessThan);
EXPECT_EQ(3u, all_subscriptions.size());
EXPECT_EQ("name1", all_subscriptions[0]->name);
EXPECT_EQ(::network::mojom::CookieMatchType::STARTS_WITH,
all_subscriptions[0]->match_type);
EXPECT_EQ(GURL("https://example.com/a/1"), all_subscriptions[0]->url);
EXPECT_EQ("name2", all_subscriptions[1]->name);
EXPECT_EQ(::network::mojom::CookieMatchType::EQUALS,
all_subscriptions[1]->match_type);
EXPECT_EQ(GURL("https://example.com/a/2"), all_subscriptions[1]->url);
EXPECT_EQ("name3", all_subscriptions[2]->name);
EXPECT_EQ(::network::mojom::CookieMatchType::STARTS_WITH,
all_subscriptions[2]->match_type);
EXPECT_EQ(GURL("https://example.com/a/3"), all_subscriptions[2]->url);
}
TEST_P(CookieStoreManagerTest, OneCookieChange) {
std::vector<CookieStoreSync::Subscriptions> batches;
batches.emplace_back();
CookieStoreSync::Subscriptions& subscriptions = batches.back();
subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New());
subscriptions.back()->name = "";
subscriptions.back()->match_type =
::network::mojom::CookieMatchType::STARTS_WITH;
subscriptions.back()->url = GURL(kExampleScope);
worker_test_helper_->SetOnInstallSubscriptions(std::move(batches),
example_service_ptr_.get());
int64_t registration_id =
RegisterServiceWorker(kExampleScope, kExampleWorkerScript);
ASSERT_NE(registration_id, kInvalidRegistrationId);
base::Optional<CookieStoreSync::Subscriptions> all_subscriptions_opt =
example_service_->GetSubscriptions(registration_id);
ASSERT_TRUE(all_subscriptions_opt.has_value());
ASSERT_EQ(1u, all_subscriptions_opt.value().size());
if (reset_context_during_test())
ResetServiceWorkerContext();
ASSERT_TRUE(
SetSessionCookie("cookie-name", "cookie-value", "example.com", "/"));
thread_bundle_.RunUntilIdle();
ASSERT_EQ(1u, worker_test_helper_->changes().size());
EXPECT_EQ("cookie-name", worker_test_helper_->changes()[0].first.Name());
EXPECT_EQ("cookie-value", worker_test_helper_->changes()[0].first.Value());
EXPECT_EQ("example.com", worker_test_helper_->changes()[0].first.Domain());
EXPECT_EQ("/", worker_test_helper_->changes()[0].first.Path());
EXPECT_EQ(::network::mojom::CookieChangeCause::INSERTED,
worker_test_helper_->changes()[0].second);
}
TEST_P(CookieStoreManagerTest, CookieChangeNameStartsWith) {
std::vector<CookieStoreSync::Subscriptions> batches;
batches.emplace_back();
CookieStoreSync::Subscriptions& subscriptions = batches.back();
subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New());
subscriptions.back()->name = "cookie-name-2";
subscriptions.back()->match_type =
::network::mojom::CookieMatchType::STARTS_WITH;
subscriptions.back()->url = GURL(kExampleScope);
worker_test_helper_->SetOnInstallSubscriptions(std::move(batches),
example_service_ptr_.get());
int64_t registration_id =
RegisterServiceWorker(kExampleScope, kExampleWorkerScript);
ASSERT_NE(registration_id, kInvalidRegistrationId);
base::Optional<CookieStoreSync::Subscriptions> all_subscriptions_opt =
example_service_->GetSubscriptions(registration_id);
ASSERT_TRUE(all_subscriptions_opt.has_value());
ASSERT_EQ(1u, all_subscriptions_opt.value().size());
if (reset_context_during_test())
ResetServiceWorkerContext();
ASSERT_TRUE(
SetSessionCookie("cookie-name-1", "cookie-value-1", "example.com", "/"));
thread_bundle_.RunUntilIdle();
EXPECT_EQ(0u, worker_test_helper_->changes().size());
worker_test_helper_->changes().clear();
ASSERT_TRUE(
SetSessionCookie("cookie-name-2", "cookie-value-2", "example.com", "/"));
thread_bundle_.RunUntilIdle();
ASSERT_EQ(1u, worker_test_helper_->changes().size());
EXPECT_EQ("cookie-name-2", worker_test_helper_->changes()[0].first.Name());
EXPECT_EQ("cookie-value-2", worker_test_helper_->changes()[0].first.Value());
EXPECT_EQ("example.com", worker_test_helper_->changes()[0].first.Domain());
EXPECT_EQ("/", worker_test_helper_->changes()[0].first.Path());
EXPECT_EQ(::network::mojom::CookieChangeCause::INSERTED,
worker_test_helper_->changes()[0].second);
worker_test_helper_->changes().clear();
ASSERT_TRUE(SetSessionCookie("cookie-name-22", "cookie-value-22",
"example.com", "/"));
thread_bundle_.RunUntilIdle();
ASSERT_EQ(1u, worker_test_helper_->changes().size());
EXPECT_EQ("cookie-name-22", worker_test_helper_->changes()[0].first.Name());
EXPECT_EQ("cookie-value-22", worker_test_helper_->changes()[0].first.Value());
EXPECT_EQ("example.com", worker_test_helper_->changes()[0].first.Domain());
EXPECT_EQ("/", worker_test_helper_->changes()[0].first.Path());
EXPECT_EQ(::network::mojom::CookieChangeCause::INSERTED,
worker_test_helper_->changes()[0].second);
}
TEST_P(CookieStoreManagerTest, CookieChangeUrl) {
std::vector<CookieStoreSync::Subscriptions> batches;
batches.emplace_back();
CookieStoreSync::Subscriptions& subscriptions = batches.back();
subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New());
subscriptions.back()->name = "";
subscriptions.back()->match_type =
::network::mojom::CookieMatchType::STARTS_WITH;
subscriptions.back()->url = GURL(kExampleScope);
worker_test_helper_->SetOnInstallSubscriptions(std::move(batches),
example_service_ptr_.get());
int64_t registration_id =
RegisterServiceWorker(kExampleScope, kExampleWorkerScript);
ASSERT_NE(registration_id, kInvalidRegistrationId);
base::Optional<CookieStoreSync::Subscriptions> all_subscriptions_opt =
example_service_->GetSubscriptions(registration_id);
ASSERT_TRUE(all_subscriptions_opt.has_value());
ASSERT_EQ(1u, all_subscriptions_opt.value().size());
if (reset_context_during_test())
ResetServiceWorkerContext();
ASSERT_TRUE(
SetSessionCookie("cookie-name-1", "cookie-value-1", "google.com", "/"));
thread_bundle_.RunUntilIdle();
ASSERT_EQ(0u, worker_test_helper_->changes().size());
worker_test_helper_->changes().clear();
ASSERT_TRUE(SetSessionCookie("cookie-name-2", "cookie-value-2", "example.com",
"/a/subpath"));
thread_bundle_.RunUntilIdle();
EXPECT_EQ(0u, worker_test_helper_->changes().size());
worker_test_helper_->changes().clear();
ASSERT_TRUE(
SetSessionCookie("cookie-name-3", "cookie-value-3", "example.com", "/"));
thread_bundle_.RunUntilIdle();
ASSERT_EQ(1u, worker_test_helper_->changes().size());
EXPECT_EQ("cookie-name-3", worker_test_helper_->changes()[0].first.Name());
EXPECT_EQ("cookie-value-3", worker_test_helper_->changes()[0].first.Value());
EXPECT_EQ("example.com", worker_test_helper_->changes()[0].first.Domain());
EXPECT_EQ("/", worker_test_helper_->changes()[0].first.Path());
EXPECT_EQ(::network::mojom::CookieChangeCause::INSERTED,
worker_test_helper_->changes()[0].second);
worker_test_helper_->changes().clear();
ASSERT_TRUE(
SetSessionCookie("cookie-name-4", "cookie-value-4", "example.com", "/a"));
thread_bundle_.RunUntilIdle();
ASSERT_EQ(1u, worker_test_helper_->changes().size());
EXPECT_EQ("cookie-name-4", worker_test_helper_->changes()[0].first.Name());
EXPECT_EQ("cookie-value-4", worker_test_helper_->changes()[0].first.Value());
EXPECT_EQ("example.com", worker_test_helper_->changes()[0].first.Domain());
EXPECT_EQ("/a", worker_test_helper_->changes()[0].first.Path());
EXPECT_EQ(::network::mojom::CookieChangeCause::INSERTED,
worker_test_helper_->changes()[0].second);
}
TEST_P(CookieStoreManagerTest, HttpOnlyCookieChange) {
std::vector<CookieStoreSync::Subscriptions> batches;
batches.emplace_back();
CookieStoreSync::Subscriptions& subscriptions = batches.back();
subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New());
subscriptions.back()->name = "";
subscriptions.back()->match_type =
::network::mojom::CookieMatchType::STARTS_WITH;
subscriptions.back()->url = GURL(kExampleScope);
worker_test_helper_->SetOnInstallSubscriptions(std::move(batches),
example_service_ptr_.get());
int64_t registration_id =
RegisterServiceWorker(kExampleScope, kExampleWorkerScript);
ASSERT_NE(registration_id, kInvalidRegistrationId);
base::Optional<CookieStoreSync::Subscriptions> all_subscriptions_opt =
example_service_->GetSubscriptions(registration_id);
ASSERT_TRUE(all_subscriptions_opt.has_value());
ASSERT_EQ(1u, all_subscriptions_opt.value().size());
if (reset_context_during_test())
ResetServiceWorkerContext();
ASSERT_TRUE(SetCanonicalCookie(net::CanonicalCookie(
"cookie-name-1", "cookie-value-1", "example.com", "/", base::Time(),
base::Time(), base::Time(),
/* secure = */ false,
/* httponly = */ true, net::CookieSameSite::NO_RESTRICTION,
net::COOKIE_PRIORITY_DEFAULT)));
thread_bundle_.RunUntilIdle();
EXPECT_EQ(0u, worker_test_helper_->changes().size());
worker_test_helper_->changes().clear();
ASSERT_TRUE(SetCanonicalCookie(net::CanonicalCookie(
"cookie-name-2", "cookie-value-2", "example.com", "/", base::Time(),
base::Time(), base::Time(),
/* secure = */ false,
/* httponly = */ false, net::CookieSameSite::NO_RESTRICTION,
net::COOKIE_PRIORITY_DEFAULT)));
thread_bundle_.RunUntilIdle();
ASSERT_EQ(1u, worker_test_helper_->changes().size());
EXPECT_EQ("cookie-name-2", worker_test_helper_->changes()[0].first.Name());
EXPECT_EQ("cookie-value-2", worker_test_helper_->changes()[0].first.Value());
EXPECT_EQ("example.com", worker_test_helper_->changes()[0].first.Domain());
EXPECT_EQ("/", worker_test_helper_->changes()[0].first.Path());
EXPECT_EQ(::network::mojom::CookieChangeCause::INSERTED,
worker_test_helper_->changes()[0].second);
}
TEST_P(CookieStoreManagerTest, GetSubscriptionsFromWrongOrigin) {
std::vector<CookieStoreSync::Subscriptions> batches;
batches.emplace_back();
CookieStoreSync::Subscriptions& subscriptions = batches.back();
subscriptions.emplace_back(blink::mojom::CookieChangeSubscription::New());
subscriptions.back()->name = "cookie_name_prefix";
subscriptions.back()->match_type =
::network::mojom::CookieMatchType::STARTS_WITH;
subscriptions.back()->url = GURL(kExampleScope);
worker_test_helper_->SetOnInstallSubscriptions(std::move(batches),
example_service_ptr_.get());
int64_t example_registration_id =
RegisterServiceWorker(kExampleScope, kExampleWorkerScript);
ASSERT_NE(example_registration_id, kInvalidRegistrationId);
if (reset_context_during_test())
ResetServiceWorkerContext();
base::Optional<CookieStoreSync::Subscriptions> all_subscriptions_opt =
example_service_->GetSubscriptions(example_registration_id);
ASSERT_TRUE(all_subscriptions_opt.has_value());
EXPECT_EQ(1u, all_subscriptions_opt.value().size());
base::Optional<CookieStoreSync::Subscriptions> wrong_subscriptions_opt =
google_service_->GetSubscriptions(example_registration_id);
EXPECT_FALSE(wrong_subscriptions_opt.has_value());
}
INSTANTIATE_TEST_CASE_P(CookieStoreManagerTest,
CookieStoreManagerTest,
testing::Bool() /* reset_storage_during_test */);
} // namespace
} // namespace content