blob: 4ee375f3c26058d18749c5a8a29b6ac165ae5648 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/browsing_data/content/browsing_data_model.h"
#include <array>
#include <memory>
#include <string>
#include <string_view>
#include "base/check.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/bind.h"
#include "base/test/gmock_expected_support.h"
#include "base/test/run_until.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_future.h"
#include "base/test/test_timeouts.h"
#include "base/threading/platform_thread.h"
#include "chrome/browser/browsing_data/chrome_browsing_data_model_delegate.h"
#include "chrome/browser/media/clear_key_cdm_test_helper.h"
#include "chrome/browser/privacy_sandbox/privacy_sandbox_attestations/privacy_sandbox_attestations_mixin.h"
#include "chrome/browser/privacy_sandbox/privacy_sandbox_settings_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/web_applications/test/isolated_web_app_test_utils.h"
#include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h"
#include "chrome/browser/web_applications/isolated_web_apps/test/isolated_web_app_builder.h"
#include "chrome/browser/web_applications/os_integration/os_integration_manager.h"
#include "chrome/common/chrome_features.h"
#include "chrome/test/base/chrome_test_utils.h"
#include "chrome/test/base/mixin_based_in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/browsing_data/content/browsing_data_model_test_util.h"
#include "components/browsing_data/content/browsing_data_test_util.h"
#include "components/browsing_data/content/shared_worker_info.h"
#include "components/content_settings/browser/page_specific_content_settings.h"
#include "components/content_settings/core/browser/cookie_settings.h"
#include "components/network_session_configurator/common/network_switches.h"
#include "components/performance_manager/public/features.h"
#include "components/privacy_sandbox/privacy_sandbox_attestations/privacy_sandbox_attestations.h"
#include "components/privacy_sandbox/privacy_sandbox_settings.h"
#include "components/services/storage/public/mojom/local_storage_control.mojom.h"
#include "components/services/storage/public/mojom/storage_usage_info.mojom.h"
#include "components/services/storage/shared_storage/shared_storage_manager.h"
#include "components/unexportable_keys/features.h"
#include "content/public/browser/attribution_data_model.h"
#include "content/public/browser/dom_storage_context.h"
#include "content/public/browser/network_service_instance.h"
#include "content/public/browser/private_aggregation_data_model.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/storage_usage_info.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test_content_browser_client.h"
#include "media/base/media_switches.h"
#include "net/base/features.h"
#include "net/base/schemeful_site.h"
#include "net/device_bound_sessions/test_support.h"
#include "net/dns/mock_host_resolver.h"
#include "net/shared_dictionary/shared_dictionary_isolation_key.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/request_handler_util.h"
#include "services/network/public/cpp/cors/cors.h"
#include "services/network/public/cpp/features.h"
#include "services/network/public/mojom/network_service.mojom.h"
#include "services/network/test/trust_token_request_handler.h"
#include "services/network/test/trust_token_test_server_handler_registration.h"
#include "services/network/test/trust_token_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/features.h"
#include "url/gurl.h"
#include "url/origin.h"
using base::test::FeatureRef;
using base::test::FeatureRefAndParams;
using net::test_server::BasicHttpResponse;
using net::test_server::HttpMethod;
using net::test_server::HttpRequest;
using net::test_server::HttpResponse;
namespace {
constexpr char kTestHost[] = "a.test";
constexpr char kTestHost2[] = "b.test";
constexpr char kTestHost3[] = "c.test";
// FedCM constants
constexpr char kAccountId[] = "carl21334213";
constexpr char kIdpOrigin[] = "https://127.0.0.1";
constexpr char kExpectedConfigPath[] = "/fedcm.json";
constexpr char kExpectedWellKnownPath[] = "/.well-known/web-identity";
constexpr char kTestContentType[] = "application/json";
constexpr char kIdpForbiddenHeader[] = "Sec-FedCM-CSRF";
static constexpr char kSetLoginHeader[] = "Set-Login";
static constexpr char kLoggedInHeaderValue[] = "logged-in";
static constexpr char kLoggedOutHeaderValue[] = "logged-out";
constexpr char kToken[] = "[not a real token]";
class TestDeviceBoundSessionAccessObserver
: public content::WebContentsObserver {
public:
TestDeviceBoundSessionAccessObserver(content::WebContents* web_contents,
base::OnceClosure on_access_closure)
: WebContentsObserver(web_contents),
on_access_closure_(std::move(on_access_closure)) {}
// WebContentsObserver
void OnDeviceBoundSessionAccessed(
content::RenderFrameHost* render_frame_host,
const net::device_bound_sessions::SessionAccess& access) override {
if (on_access_closure_) {
std::move(on_access_closure_).Run();
}
}
void OnDeviceBoundSessionAccessed(
content::NavigationHandle* navigation_handle,
const net::device_bound_sessions::SessionAccess& access) override {
if (on_access_closure_) {
std::move(on_access_closure_).Run();
}
}
private:
base::OnceClosure on_access_closure_;
};
void ProvideRequestHandlerKeyCommitmentsToNetworkService(
std::string_view host,
net::EmbeddedTestServer* https_server,
const network::test::TrustTokenRequestHandler& request_handler) {
base::flat_map<url::Origin, std::string_view> origins_and_commitments;
std::string key_commitments = request_handler.GetKeyCommitmentRecord();
GURL::Replacements replacements;
replacements.SetHostStr(host);
origins_and_commitments.insert_or_assign(
url::Origin::Create(
https_server->base_url().ReplaceComponents(replacements)),
key_commitments);
base::RunLoop run_loop;
content::GetNetworkService()->SetTrustTokenKeyCommitments(
network::WrapKeyCommitmentsForIssuers(std::move(origins_and_commitments)),
run_loop.QuitClosure());
run_loop.Run();
}
void JoinInterestGroup(const content::ToRenderFrameHost& adapter,
net::EmbeddedTestServer* https_server,
const std::string& owner_host) {
// join interest group
auto command = content::JsReplace(
R"(
(async () => {
try {
navigator.joinAdInterestGroup(
{
name: 'cars',
owner: $1,
biddingLogicURL: $2,
trustedBiddingSignalsURL: $3,
trustedBiddingSignalsKeys: ['key1'],
userBiddingSignals: {some: 'json', data: {here: [1, 2, 3]}},
ads: [{
renderURL: $4,
metadata: {ad: 'metadata', here: [1, 2, 3]},
}],
},
/*joinDurationSec=*/ 1000);
} catch (e) {
return e.toString();
}
return "Success";
})())",
https_server->GetURL(owner_host, "/"),
https_server->GetURL(owner_host, "/interest_group/bidding_logic.js"),
https_server->GetURL(owner_host,
"/interest_group/trusted_bidding_signals.json"),
GURL("https://example.com/render"));
EXPECT_EQ("Success", EvalJs(adapter, command));
}
void RunAdAuction(const content::ToRenderFrameHost& adapter,
net::EmbeddedTestServer* https_server,
const std::string& seller_host,
const std::string& buyer_host) {
std::string command = content::JsReplace(
R"(
(async function() {
try {
await navigator.runAdAuction({
seller: $1,
decisionLogicURL: $2,
interestGroupBuyers: [$3],
});
} catch (e) {
return e.toString();
}
return "Success";
})())",
https_server->GetURL(seller_host, "/"),
https_server->GetURL(seller_host, "/interest_group/decision_logic.js"),
https_server->GetURL(buyer_host, "/"));
EXPECT_EQ("Success", EvalJs(adapter, command));
}
void ExecuteScriptInSharedStorageWorklet(
const content::ToRenderFrameHost& execution_target,
const std::string& script,
GURL* out_module_script_url,
net::EmbeddedTestServer* https_server) {
CHECK(out_module_script_url);
base::StringPairs run_function_body_replacement;
run_function_body_replacement.emplace_back("{{RUN_FUNCTION_BODY}}", script);
std::string host =
execution_target.render_frame_host()->GetLastCommittedOrigin().host();
*out_module_script_url =
https_server->GetURL(host, net::test_server::GetFilePathWithReplacements(
"/shared_storage/customizable_module.js",
run_function_body_replacement));
EXPECT_TRUE(ExecJs(execution_target,
content::JsReplace("sharedStorage.worklet.addModule($1)",
*out_module_script_url)));
testing::AssertionResult result =
ExecJs(execution_target,
"sharedStorage.run('test-operation', {keepAlive: true});");
}
void AccessTopics(const content::ToRenderFrameHost& adapter) {
std::string command =
R"(
(async () => {
try {
document.browsingTopics();
} catch (e) {
return e.toString();
}
return "Success";
})())";
EXPECT_EQ("Success", EvalJs(adapter, command));
}
class IdpTestServer {
public:
struct ConfigDetails {
net::HttpStatusCode status_code;
std::string content_type;
std::string accounts_endpoint_url;
std::string client_metadata_endpoint_url;
std::string id_assertion_endpoint_url;
std::string login_url;
std::map<std::string,
base::RepeatingCallback<std::unique_ptr<HttpResponse>(
const HttpRequest&)>>
servlets;
};
IdpTestServer() = default;
~IdpTestServer() = default;
IdpTestServer(const IdpTestServer&) = delete;
IdpTestServer& operator=(const IdpTestServer&) = delete;
std::unique_ptr<HttpResponse> HandleRequest(const HttpRequest& request) {
// RP files are fetched from the /test base directory. Assume anything
// to other paths is directed to the IdP.
if (request.relative_url.rfind("/test", 0) == 0) {
return nullptr;
}
if (request.relative_url.rfind("/header/", 0) == 0) {
return BuildIdpHeaderResponse(request);
}
if (request.all_headers.find(kIdpForbiddenHeader) != std::string::npos) {
EXPECT_EQ(request.headers.at(kIdpForbiddenHeader), "?1");
}
auto response = std::make_unique<BasicHttpResponse>();
if (IsGetRequestWithPath(request, kExpectedConfigPath)) {
BuildConfigResponseFromDetails(*response.get(), config_details_);
return response;
}
if (IsGetRequestWithPath(request, kExpectedWellKnownPath)) {
BuildWellKnownResponse(*response.get());
return response;
}
if (config_details_.servlets[request.relative_url]) {
return config_details_.servlets[request.relative_url].Run(request);
}
return nullptr;
}
std::unique_ptr<HttpResponse> BuildIdpHeaderResponse(
const HttpRequest& request) {
auto response = std::make_unique<BasicHttpResponse>();
if (request.relative_url.find("/header/signin") != std::string::npos) {
response->AddCustomHeader(kSetLoginHeader, kLoggedInHeaderValue);
} else if (request.relative_url.find("/header/signout") !=
std::string::npos) {
response->AddCustomHeader(kSetLoginHeader, kLoggedOutHeaderValue);
} else {
return nullptr;
}
response->set_code(net::HTTP_OK);
response->set_content_type("text/plain");
response->set_content("Header sent.");
return response;
}
void SetConfigResponseDetails(ConfigDetails details) {
config_details_ = details;
}
private:
void BuildConfigResponseFromDetails(BasicHttpResponse& response,
const ConfigDetails& details) {
std::string content = ConvertToJsonDictionary(
{{"accounts_endpoint", details.accounts_endpoint_url},
{"client_metadata_endpoint", details.client_metadata_endpoint_url},
{"id_assertion_endpoint", details.id_assertion_endpoint_url},
{"login_url", details.login_url}});
response.set_code(details.status_code);
response.set_content(content);
response.set_content_type(details.content_type);
}
void BuildWellKnownResponse(BasicHttpResponse& response) {
std::string content = base::StringPrintf("{\"provider_urls\": [\"%s\"]}",
kExpectedConfigPath);
response.set_code(net::HTTP_OK);
response.set_content(content);
response.set_content_type("application/json");
}
std::string ConvertToJsonDictionary(
const std::map<std::string, std::string>& data) {
std::string out = "{";
for (auto it : data) {
out += "\"" + it.first + "\":\"" + it.second + "\",";
}
if (!out.empty()) {
out[out.length() - 1] = '}';
}
return out;
}
bool IsGetRequestWithPath(const HttpRequest& request,
const std::string& expected_path) {
return request.method == net::test_server::HttpMethod::METHOD_GET &&
request.relative_url == expected_path;
}
ConfigDetails config_details_;
};
std::string GetIdpConfigUrl(net::EmbeddedTestServer* https_server) {
return std::string(kIdpOrigin) + ":" +
base::NumberToString(https_server->port()) + "/fedcm.json";
}
IdpTestServer::ConfigDetails BuildValidConfigDetails() {
std::string accounts_endpoint_url = "/fedcm/accounts_endpoint.json";
std::string client_metadata_endpoint_url =
"/fedcm/client_metadata_endpoint.json";
std::string id_assertion_endpoint_url = "/fedcm/id_assertion_endpoint.json";
std::string login_url = "/fedcm/login.html";
std::map<std::string, base::RepeatingCallback<std::unique_ptr<HttpResponse>(
const HttpRequest&)>>
servlets;
servlets[id_assertion_endpoint_url] = base::BindRepeating(
[](const HttpRequest& request) -> std::unique_ptr<HttpResponse> {
EXPECT_EQ(request.method, HttpMethod::METHOD_POST);
EXPECT_EQ(request.has_content, true);
auto response = std::make_unique<BasicHttpResponse>();
response->set_code(net::HTTP_OK);
response->set_content_type("text/json");
DCHECK(request.headers.contains("Origin"));
response->AddCustomHeader(
network::cors::header_names::kAccessControlAllowOrigin,
request.headers.at("Origin"));
response->AddCustomHeader(
network::cors::header_names::kAccessControlAllowCredentials,
"true");
// Standard scopes were used, so no extra permission needed.
// Return a token immediately.
response->set_content(R"({"token": ")" + std::string(kToken) + R"("})");
return response;
});
return {net::HTTP_OK,
kTestContentType,
accounts_endpoint_url,
client_metadata_endpoint_url,
id_assertion_endpoint_url,
login_url,
servlets};
}
void RunFedCm(const content::ToRenderFrameHost& adapter,
net::EmbeddedTestServer* https_server) {
std::string command = content::JsReplace(
R"(
(async () => {
try {
let cred = await navigator.credentials.get({
identity: {
providers: [{
configURL: $1,
clientId: '123',
nonce: '2',
}]
},
mediation: 'required'
});
return cred.token;
} catch (e) {
return e.toString();
}
})())",
GetIdpConfigUrl(https_server));
EXPECT_EQ(kToken, EvalJs(adapter, command));
}
void AddLocalStorageUsage(content::RenderFrameHost* render_frame_host,
int size) {
auto command =
content::JsReplace("localStorage.setItem('key', '!'.repeat($1))", size);
EXPECT_TRUE(ExecJs(render_frame_host, command));
}
void WaitForModelUpdate(BrowsingDataModel* model, size_t expected_size) {
ASSERT_TRUE(
base::test::RunUntil([&]() { return model->size() == expected_size; }));
}
void RemoveBrowsingDataForDataOwner(BrowsingDataModel* model,
BrowsingDataModel::DataOwner data_owner) {
base::RunLoop run_loop;
model->RemoveBrowsingData(data_owner, run_loop.QuitClosure());
run_loop.Run();
}
// Calls the accessStorage javascript function and awaits its completion for
// each frame in the active web contents for |browser|.
void EnsurePageAccessedStorage(content::WebContents* web_contents) {
web_contents->GetPrimaryMainFrame()->ForEachRenderFrameHost(
[](content::RenderFrameHost* frame) {
EXPECT_TRUE(
content::EvalJs(frame,
"(async () => { return await accessStorage();})()")
.ExtractBool());
});
}
} // namespace
using browsing_data_model_test_util::ValidateBrowsingDataEntries;
using browsing_data_model_test_util::ValidateBrowsingDataEntriesNonZeroUsage;
using OperationResult = storage::SharedStorageDatabase::OperationResult;
using browsing_data_test_util::HasDataForType;
using browsing_data_test_util::SetDataForType;
class BrowsingDataModelBrowserTest
: public MixinBasedInProcessBrowserTest,
public ::testing::WithParamInterface<bool> {
public:
BrowsingDataModelBrowserTest() {
std::vector<FeatureRefAndParams> enabled_features = {
{features::kPrivacySandboxAdsAPIsOverride, {}},
{features::kIsolatedWebApps, {}},
{features::kIsolatedWebAppDevMode, {}},
{network::features::kSharedStorageAPI, {}},
{network::features::kInterestGroupStorage, {}},
{blink::features::kPrivateAggregationApi, {}},
{blink::features::kAdInterestGroupAPI, {}},
{blink::features::kFledge, {}},
{blink::features::kFencedFrames, {}},
{network::features::kBrowsingTopics, {}},
{net::features::kThirdPartyStoragePartitioning, {}},
{network::features::kCompressionDictionaryTransport, {}},
};
std::vector<FeatureRef> disabled_features = {
// Need to disable kCompressionDictionaryTransportRequireKnownRootCert
// because EmbeddedTestServer's certificate is not rooted at a standard
// CA root.
net::features::kCompressionDictionaryTransportRequireKnownRootCert,
// Model update success is sensitive to how quickly some best effort
// tasks are run so the test is not compatible with delaying
// them through EnableBestEffortTaskInhibitingPolicy.
performance_manager::features::kEnableBestEffortTaskInhibitingPolicy};
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
enabled_features.push_back({media::kExternalClearKeyForTesting, {}});
#endif
#if BUILDFLAG(ENABLE_DEVICE_BOUND_SESSIONS)
enabled_features.push_back({net::features::kDeviceBoundSessions,
{{"RequireOriginTrialTokens", "false"}}});
enabled_features.push_back(
{unexportable_keys::
kEnableBoundSessionCredentialsSoftwareKeysForManualTesting,
{}});
#endif
feature_list_.InitWithFeaturesAndParameters(enabled_features,
disabled_features);
}
~BrowsingDataModelBrowserTest() override = default;
void SetUpOnMainThread() override {
PrivacySandboxSettingsFactory::GetForProfile(browser()->profile())
->SetAllPrivacySandboxAllowedForTesting();
// Mark all Privacy Sandbox APIs as attested since the test cases are
// testing behaviors not related to attestations.
privacy_sandbox::PrivacySandboxAttestations::GetInstance()
->SetAllPrivacySandboxAttestedForTesting(true);
host_resolver()->AddRule("*", "127.0.0.1");
https_server_ = std::make_unique<net::EmbeddedTestServer>(
net::test_server::EmbeddedTestServer::TYPE_HTTPS);
https_server_->SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
https_server_->AddDefaultHandlers(
base::FilePath(FILE_PATH_LITERAL("content/test/data")));
network::test::RegisterTrustTokenTestHandlers(https_test_server(),
&request_handler_);
idp_server_ = std::make_unique<IdpTestServer>();
https_server_->RegisterRequestHandler(base::BindRepeating(
&IdpTestServer::HandleRequest, base::Unretained(idp_server_.get())));
ASSERT_TRUE(https_server_->InitializeAndListen());
// Must come after `InitializeAndListen` so we know the `base_url()`.
// We are testing DBSC against kTestHost, so register a handler for it.
https_server_->RegisterRequestHandler(
net::device_bound_sessions::GetTestRequestHandler(
https_server_->GetURL(kTestHost, "/")));
https_server_->StartAcceptingConnections();
}
void SetUpCommandLine(base::CommandLine* command_line) override {
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
// Testing MediaLicenses requires additional command line parameters as
// it uses the External Clear Key CDM.
RegisterClearKeyCdm(command_line);
#endif
// These switches are needed to run FedCM and auto-select the first account.
command_line->AppendSwitch(switches::kIgnoreCertificateErrors);
command_line->AppendSwitchASCII(switches::kUseFakeUIForFedCM, kAccountId);
}
protected:
std::unique_ptr<BrowsingDataModel> BuildBrowsingDataModel() {
base::test::TestFuture<std::unique_ptr<BrowsingDataModel>>
browsing_data_model;
BrowsingDataModel::BuildFromDisk(
browser()->profile(),
ChromeBrowsingDataModelDelegate::CreateForProfile(browser()->profile()),
browsing_data_model.GetCallback());
return browsing_data_model.Take();
}
content::StoragePartition* default_storage_partition() {
return browser()->profile()->GetDefaultStoragePartition();
}
content::WebContents* web_contents() {
return browser()->tab_strip_model()->GetActiveWebContents();
}
net::EmbeddedTestServer* https_test_server() { return https_server_.get(); }
GURL test_url() { return https_server_->GetURL(kTestHost, "/echo"); }
void AccessStorage() {
ASSERT_TRUE(content::NavigateToURL(
chrome_test_utils::GetActiveWebContents(this), storage_accessor_url()));
base::RunLoop().RunUntilIdle();
EnsurePageAccessedStorage(chrome_test_utils::GetActiveWebContents(this));
}
GURL storage_accessor_url() {
auto host_port_pair =
net::HostPortPair::FromURL(https_test_server()->GetURL(kTestHost, "/"));
base::StringPairs replacement_text = {
{"REPLACE_WITH_HOST_AND_PORT", host_port_pair.ToString()}};
auto replaced_path = net::test_server::GetFilePathWithReplacements(
"/browsing_data/storage_accessor.html", replacement_text);
return https_test_server()->GetURL(kTestHost, replaced_path);
}
IdpTestServer* idp_server() { return idp_server_.get(); }
network::test::TrustTokenRequestHandler request_handler_;
private:
std::unique_ptr<net::EmbeddedTestServer> https_server_;
privacy_sandbox::PrivacySandboxAttestationsMixin
privacy_sandbox_attestations_mixin_{&mixin_host_};
web_app::OsIntegrationTestOverrideBlockingRegistration faked_os_integration_;
base::test::ScopedFeatureList feature_list_;
std::unique_ptr<IdpTestServer> idp_server_;
};
IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest,
SharedStorageHandledCorrectly) {
// Add origin shared storage.
auto* shared_storage_manager =
default_storage_partition()->GetSharedStorageManager();
ASSERT_NE(nullptr, shared_storage_manager);
base::test::TestFuture<OperationResult> future;
url::Origin testOrigin = url::Origin::Create(GURL("https://a.test"));
shared_storage_manager->Set(
testOrigin, u"key", u"value", future.GetCallback(),
storage::SharedStorageDatabase::SetBehavior::kDefault);
EXPECT_EQ(OperationResult::kSet, future.Get());
std::unique_ptr<BrowsingDataModel> browsing_data_model =
BuildBrowsingDataModel();
// Validate shared storage entry saved correctly.
base::test::TestFuture<uint64_t> test_entry_storage_size;
shared_storage_manager->FetchOrigins(base::BindLambdaForTesting(
[&](std::vector<::storage::mojom::StorageUsageInfoPtr>
storage_usage_info) {
ASSERT_EQ(1U, storage_usage_info.size());
test_entry_storage_size.SetValue(
storage_usage_info[0]->total_size_bytes);
}));
ValidateBrowsingDataEntries(
browsing_data_model.get(),
{{kTestHost,
blink::StorageKey::CreateFirstParty(testOrigin),
{{BrowsingDataModel::StorageType::kSharedStorage},
test_entry_storage_size.Get(),
/*cookie_count=*/0}}});
// Remove origin.
RemoveBrowsingDataForDataOwner(browsing_data_model.get(), kTestHost);
// Rebuild Browsing Data Model and verify entries are empty.
browsing_data_model = BuildBrowsingDataModel();
ValidateBrowsingDataEntries(browsing_data_model.get(), {});
}
IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest,
SharedStorageAccessReportedCorrectly) {
// Navigate to test page.
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), test_url()));
auto* content_settings =
content_settings::PageSpecificContentSettings::GetForFrame(
web_contents()->GetPrimaryMainFrame());
// Validate that the allowed browsing data model is empty.
ValidateBrowsingDataEntries(content_settings->allowed_browsing_data_model(),
{});
// Create a SharedStorage entry.
std::string command = R"(
(async () => {
try {
await window.sharedStorage.set('age-group', 1);
return true;
} catch {
return false;
}
})();)";
EXPECT_EQ(true, EvalJs(web_contents(), command));
// Validate that the allowed browsing data model is populated with
// SharedStorage entry for `kTestHost`.
url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost);
ValidateBrowsingDataEntries(
content_settings->allowed_browsing_data_model(),
{{kTestHost,
blink::StorageKey::CreateFirstParty(testOrigin),
{{BrowsingDataModel::StorageType::kSharedStorage},
/*storage_size=*/0,
/*cookie_count=*/0}}});
}
IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest, TrustTokenIssuance) {
// Setup the test server to be able to issue trust tokens, and have it issue
// some to the profile.
ProvideRequestHandlerKeyCommitmentsToNetworkService(
kTestHost, https_test_server(), request_handler_);
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), https_test_server()->GetURL(kTestHost, "/title1.html")));
std::string issuance_origin =
url::Origin::Create(https_test_server()->GetURL(kTestHost, "/"))
.Serialize();
std::string command = content::JsReplace(R"(
(async () => {
try {
await fetch("/issue", {privateToken: {version: 1,
operation: 'token-request'}});
return await document.hasPrivateToken($1);
} catch {
return false;
}
})();)",
issuance_origin);
EXPECT_EQ(true, EvalJs(web_contents(), command));
browser()
->profile()
->GetDefaultStoragePartition()
->FlushNetworkInterfaceForTesting();
// Confirm that a BrowsingDataModel built from disk contains the issued token
// information.
std::unique_ptr<BrowsingDataModel> browsing_data_model =
BuildBrowsingDataModel();
ValidateBrowsingDataEntries(
browsing_data_model.get(),
{{kTestHost,
https_test_server()->GetOrigin(kTestHost),
{{BrowsingDataModel::StorageType::kTrustTokens}, 100, 0}}});
// Remove data for the host, and confirm the model updates appropriately.
RemoveBrowsingDataForDataOwner(browsing_data_model.get(), kTestHost);
ValidateBrowsingDataEntries(browsing_data_model.get(), {});
// Build another model from disk, ensuring the data is no longer present.
browsing_data_model = BuildBrowsingDataModel();
ValidateBrowsingDataEntries(browsing_data_model.get(), {});
}
IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest,
InterestGroupsHandledCorrectly) {
// Check that no interest groups are joined at the beginning of the test.
std::unique_ptr<BrowsingDataModel> browsing_data_model =
BuildBrowsingDataModel();
ValidateBrowsingDataEntries(browsing_data_model.get(), {});
ASSERT_EQ(browsing_data_model->size(), 0u);
// Join an interest group.
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), test_url()));
JoinInterestGroup(web_contents(), https_test_server(), kTestHost);
// Waiting for the browsing data model to be populated, otherwise the test is
// flaky.
do {
browsing_data_model = BuildBrowsingDataModel();
base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
} while (browsing_data_model->size() != 1);
// Validate that an interest group is added.
url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost);
content::InterestGroupManager::InterestGroupDataKey data_key{testOrigin,
testOrigin};
ValidateBrowsingDataEntries(
browsing_data_model.get(),
{{kTestHost,
data_key,
{{BrowsingDataModel::StorageType::kInterestGroup},
/*storage_size=*/1024,
/*cookie_count=*/0}}});
// Remove Interest Group.
RemoveBrowsingDataForDataOwner(browsing_data_model.get(), kTestHost);
// Rebuild Browsing Data Model and verify entries are empty.
browsing_data_model = BuildBrowsingDataModel();
ValidateBrowsingDataEntries(browsing_data_model.get(), {});
}
IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest,
InterestGroupsAccessReportedCorrectly) {
// Navigate to test page.
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), test_url()));
auto* content_settings =
content_settings::PageSpecificContentSettings::GetForFrame(
web_contents()->GetPrimaryMainFrame());
// Validate that the allowed browsing data model is empty.
auto* allowed_browsing_data_model =
content_settings->allowed_browsing_data_model();
ValidateBrowsingDataEntries(allowed_browsing_data_model, {});
ASSERT_EQ(allowed_browsing_data_model->size(), 0u);
// Join an interest group.
JoinInterestGroup(web_contents(), https_test_server(), kTestHost);
WaitForModelUpdate(allowed_browsing_data_model, 1);
// Validate that an interest group is reported to the browsing data model.
url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost);
content::InterestGroupManager::InterestGroupDataKey data_key{testOrigin,
testOrigin};
ValidateBrowsingDataEntries(
allowed_browsing_data_model,
{{kTestHost,
data_key,
{{BrowsingDataModel::StorageType::kInterestGroup},
/*storage_size=*/0,
/*cookie_count=*/0}}});
}
IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest,
AuctionWinReportedCorrectly) {
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), test_url()));
JoinInterestGroup(web_contents(), https_test_server(), kTestHost);
// Run an auction on `kTestHost2`. A different host is used to ensure the
// correct host (`kTestHost`) is reported as having accessed storage.
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), https_test_server()->GetURL(kTestHost2, "/echo")));
auto* content_settings =
content_settings::PageSpecificContentSettings::GetForFrame(
web_contents()->GetPrimaryMainFrame());
// Validate that the allowed browsing data model is empty.
auto* allowed_browsing_data_model =
content_settings->allowed_browsing_data_model();
ValidateBrowsingDataEntries(allowed_browsing_data_model, {});
ASSERT_EQ(allowed_browsing_data_model->size(), 0u);
RunAdAuction(web_contents(), https_test_server(), /*seller_host=*/kTestHost2,
/*buyer_host=*/kTestHost);
WaitForModelUpdate(allowed_browsing_data_model, 1);
url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost);
content::InterestGroupManager::InterestGroupDataKey data_key{testOrigin,
testOrigin};
ValidateBrowsingDataEntries(
allowed_browsing_data_model,
{{kTestHost,
data_key,
{{BrowsingDataModel::StorageType::kInterestGroup},
/*storage_size=*/0,
/*cookie_count=*/0}}});
}
IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest,
AttributionReportingAccessReportedCorrectly) {
const GURL kTestCases[] = {
https_test_server()->GetURL(
"a.test", "/attribution_reporting/register_source_headers.html"),
https_test_server()->GetURL(
"a.test", "/attribution_reporting/register_trigger_headers.html")};
for (const auto& register_url : kTestCases) {
// Navigate to test page.
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), test_url()));
auto* content_settings =
content_settings::PageSpecificContentSettings::GetForFrame(
web_contents()->GetPrimaryMainFrame());
// Validate that the allowed browsing data model is empty.
auto* allowed_browsing_data_model =
content_settings->allowed_browsing_data_model();
ValidateBrowsingDataEntries(allowed_browsing_data_model, {});
ASSERT_EQ(allowed_browsing_data_model->size(), 0u);
// Register a source.
ASSERT_TRUE(ExecJs(web_contents(), content::JsReplace(R"(
const img = document.createElement('img');
img.attributionSrc = $1;)",
register_url)));
WaitForModelUpdate(allowed_browsing_data_model, 1);
// Validate that an attribution reporting datakey is reported to the
// browsing data model.
url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost);
content::AttributionDataModel::DataKey data_key{testOrigin};
ValidateBrowsingDataEntries(
allowed_browsing_data_model,
{{kTestHost,
data_key,
{{BrowsingDataModel::StorageType::kAttributionReporting},
/*storage_size=*/0,
/*cookie_count=*/0}}});
}
}
IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest,
PrivateAggregationHandledCorrectly) {
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), test_url()));
// Validate that there are no entries in the browsing data model.
std::unique_ptr<BrowsingDataModel> browsing_data_model =
BuildBrowsingDataModel();
ValidateBrowsingDataEntries(browsing_data_model.get(), {});
GURL out_script_url;
ExecuteScriptInSharedStorageWorklet(web_contents(), R"(
privateAggregation.contributeToHistogram({bucket: 1n, value: 2});
)",
&out_script_url, https_test_server());
do {
browsing_data_model = BuildBrowsingDataModel();
base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
} while (browsing_data_model->size() < 1);
// Validate that a private aggregation data key is added.
url::Origin test_origin = https_test_server()->GetOrigin(kTestHost);
content::PrivateAggregationDataModel::DataKey data_key{test_origin};
ValidateBrowsingDataEntries(
browsing_data_model.get(),
{{kTestHost,
data_key,
{{BrowsingDataModel::StorageType::kPrivateAggregation},
/*storage_size=*/100,
/*cookie_count=*/0}}});
// Remove datakey from aggregation service and private budgeter.
RemoveBrowsingDataForDataOwner(browsing_data_model.get(), kTestHost);
// Rebuild Browsing Data Model and verify entries are empty.
browsing_data_model = BuildBrowsingDataModel();
ValidateBrowsingDataEntries(browsing_data_model.get(), {});
}
IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest,
TopicsAccessReportedCorrectly) {
// Navigate to test page.
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), test_url()));
auto* content_settings =
content_settings::PageSpecificContentSettings::GetForFrame(
web_contents()->GetPrimaryMainFrame());
// Validate that the allowed browsing data model is empty.
auto* allowed_browsing_data_model =
content_settings->allowed_browsing_data_model();
ValidateBrowsingDataEntries(allowed_browsing_data_model, {});
ASSERT_EQ(allowed_browsing_data_model->size(), 0u);
// Get Topics
AccessTopics(web_contents());
WaitForModelUpdate(allowed_browsing_data_model, 1);
// Validate Topics are reported correctly
url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost);
ValidateBrowsingDataEntries(
allowed_browsing_data_model,
{{kTestHost,
testOrigin,
{{static_cast<BrowsingDataModel::StorageType>(
ChromeBrowsingDataModelDelegate::StorageType::kTopics)},
/*storage_size=*/0,
/*cookie_count=*/0}}});
ASSERT_EQ(allowed_browsing_data_model->size(), 1u);
// Clear Topic via BDM
RemoveBrowsingDataForDataOwner(allowed_browsing_data_model, kTestHost);
// Validate that the allowed browsing data model is cleared.
ValidateBrowsingDataEntries(allowed_browsing_data_model, {});
ASSERT_EQ(allowed_browsing_data_model->size(), 0u);
}
IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest,
IsolatedWebAppUsageInDefaultStoragePartitionModel) {
// Check that no IWAs are installed at the beginning of the test.
std::unique_ptr<BrowsingDataModel> browsing_data_model =
BuildBrowsingDataModel();
ValidateBrowsingDataEntries(browsing_data_model.get(), {});
ASSERT_EQ(browsing_data_model->size(), 0u);
Profile* profile = browser()->profile();
std::unique_ptr<web_app::ScopedBundledIsolatedWebApp> app1 =
web_app::IsolatedWebAppBuilder(web_app::ManifestBuilder()).BuildBundle();
ASSERT_OK_AND_ASSIGN(web_app::IsolatedWebAppUrlInfo iwa_url_info1,
app1->Install(profile));
auto* iwa_frame1 =
web_app::OpenIsolatedWebApp(profile, iwa_url_info1.app_id());
AddLocalStorageUsage(iwa_frame1, 100);
std::unique_ptr<web_app::ScopedBundledIsolatedWebApp> app2 =
web_app::IsolatedWebAppBuilder(web_app::ManifestBuilder()).BuildBundle();
ASSERT_OK_AND_ASSIGN(web_app::IsolatedWebAppUrlInfo iwa_url_info2,
app2->Install(profile));
auto* iwa_frame2 =
web_app::OpenIsolatedWebApp(profile, iwa_url_info2.app_id());
AddLocalStorageUsage(iwa_frame2, 500);
browsing_data_model = BuildBrowsingDataModel();
ValidateBrowsingDataEntries(
browsing_data_model.get(),
{{iwa_url_info1.origin(),
iwa_url_info1.origin(),
{{static_cast<BrowsingDataModel::StorageType>(
ChromeBrowsingDataModelDelegate::StorageType::kIsolatedWebApp)},
/*storage_size=*/105,
/*cookie_count=*/0}},
{iwa_url_info2.origin(),
iwa_url_info2.origin(),
{{static_cast<BrowsingDataModel::StorageType>(
ChromeBrowsingDataModelDelegate::StorageType::kIsolatedWebApp)},
/*storage_size=*/505,
/*cookie_count=*/0}}});
}
IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest,
QuotaStorageHandledCorrectly) {
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(),
https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html")));
// Ensure that there isn't any data fetched.
std::unique_ptr<BrowsingDataModel> browsing_data_model =
BuildBrowsingDataModel();
ValidateBrowsingDataEntries(browsing_data_model.get(), {});
ASSERT_EQ(browsing_data_model->size(), 0u);
std::vector<std::string> quota_storage_data_types = {
"ServiceWorker", "IndexedDb", "FileSystem"};
for (auto data_type : quota_storage_data_types) {
SetDataForType(data_type, web_contents());
ASSERT_TRUE(HasDataForType(data_type, web_contents()));
// Ensure that quota data is fetched
browsing_data_model = BuildBrowsingDataModel();
// Validate that quota data is fetched to browsing data model.
url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost);
auto data_key = blink::StorageKey::CreateFirstParty(testOrigin);
ValidateBrowsingDataEntriesNonZeroUsage(
browsing_data_model.get(),
{{kTestHost,
data_key,
{{BrowsingDataModel::StorageType::kQuotaStorage},
/*storage_size=*/0,
/*cookie_count=*/0}}});
ASSERT_EQ(browsing_data_model->size(), 1u);
// Remove quota entry.
RemoveBrowsingDataForDataOwner(browsing_data_model.get(), kTestHost);
// Rebuild Browsing Data Model and verify entries are empty.
browsing_data_model = BuildBrowsingDataModel();
ValidateBrowsingDataEntries(browsing_data_model.get(), {});
ASSERT_EQ(browsing_data_model->size(), 0u);
}
}
IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest,
LocalStorageHandledCorrectly) {
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(),
https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html")));
// Ensure that there isn't any data fetched.
std::unique_ptr<BrowsingDataModel> browsing_data_model =
BuildBrowsingDataModel();
ValidateBrowsingDataEntries(browsing_data_model.get(), {});
ASSERT_EQ(browsing_data_model->size(), 0u);
SetDataForType("LocalStorage", web_contents());
// Flush storage size to disk.
auto* storage_partition = browser()->profile()->GetDefaultStoragePartition();
storage_partition->Flush();
// To ensure that flushing is completed.
base::RunLoop().RunUntilIdle();
auto* dom_storage_context = storage_partition->GetDOMStorageContext();
// Fetch local storage size from backend.
base::test::TestFuture<uint64_t> test_entry_storage_size;
dom_storage_context->GetLocalStorageUsage(base::BindLambdaForTesting(
[&](const std::vector<content::StorageUsageInfo>& storage_usage_info) {
ASSERT_EQ(1U, storage_usage_info.size());
test_entry_storage_size.SetValue(
storage_usage_info[0].total_size_bytes);
}));
// Ensure that local storage is fetched
browsing_data_model = BuildBrowsingDataModel();
// Validate that local storage is fetched to browsing data model.
url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost);
auto data_key = blink::StorageKey::CreateFirstParty(testOrigin);
ValidateBrowsingDataEntries(
browsing_data_model.get(),
{{kTestHost,
data_key,
{{BrowsingDataModel::StorageType::kLocalStorage},
test_entry_storage_size.Get(),
/*cookie_count=*/0}}});
ASSERT_EQ(browsing_data_model->size(), 1u);
// Remove local storage entry.
RemoveBrowsingDataForDataOwner(browsing_data_model.get(), kTestHost);
// Rebuild Browsing Data Model and verify entries are empty.
browsing_data_model = BuildBrowsingDataModel();
ValidateBrowsingDataEntries(browsing_data_model.get(), {});
ASSERT_EQ(browsing_data_model->size(), 0u);
}
IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest,
LocalStorageAccessReportedCorrectly) {
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(),
https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html")));
auto* content_settings =
content_settings::PageSpecificContentSettings::GetForFrame(
web_contents()->GetPrimaryMainFrame());
// Validate that the allowed browsing data model is empty.
auto* allowed_browsing_data_model =
content_settings->allowed_browsing_data_model();
ValidateBrowsingDataEntries(allowed_browsing_data_model, {});
ASSERT_EQ(allowed_browsing_data_model->size(), 0u);
SetDataForType("LocalStorage", web_contents());
WaitForModelUpdate(allowed_browsing_data_model, /*expected_size=*/1);
// Validate Local Storage is reported.
url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost);
auto data_key = blink::StorageKey::CreateFirstParty(testOrigin);
ValidateBrowsingDataEntries(
allowed_browsing_data_model,
{{kTestHost,
data_key,
{{BrowsingDataModel::StorageType::kLocalStorage},
/*storage_size=*/0,
/*cookie_count=*/0}}});
ASSERT_EQ(allowed_browsing_data_model->size(), 1u);
// Delete Local Storage
RemoveBrowsingDataForDataOwner(allowed_browsing_data_model, kTestHost);
// Validate that the allowed browsing data model is empty.
ValidateBrowsingDataEntries(allowed_browsing_data_model, {});
ASSERT_EQ(allowed_browsing_data_model->size(), 0u);
}
IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest,
SessionStorageAccessReportedCorrectly) {
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(),
https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html")));
auto* content_settings =
content_settings::PageSpecificContentSettings::GetForFrame(
web_contents()->GetPrimaryMainFrame());
// Validate that the allowed browsing data model is empty.
auto* allowed_browsing_data_model =
content_settings->allowed_browsing_data_model();
ValidateBrowsingDataEntries(allowed_browsing_data_model, {});
ASSERT_EQ(allowed_browsing_data_model->size(), 0u);
SetDataForType("SessionStorage", web_contents());
WaitForModelUpdate(allowed_browsing_data_model, /*expected_size=*/1);
// Validate Session Storage is reported.
url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost);
auto storage_key = blink::StorageKey::CreateFirstParty(testOrigin);
// Obtaining Session Storage namespace_id from the navigation controller.
const auto& session_storage_namespace_map =
web_contents()->GetController().GetSessionStorageNamespaceMap();
const auto& storage_partition_config =
content::StoragePartitionConfig::CreateDefault(
web_contents()->GetBrowserContext());
const auto& namespace_id =
session_storage_namespace_map.at(storage_partition_config);
content::SessionStorageUsageInfo data_key{storage_key, namespace_id->id()};
ValidateBrowsingDataEntries(
allowed_browsing_data_model,
{{kTestHost,
data_key,
{{BrowsingDataModel::StorageType::kSessionStorage},
/*storage_size=*/0,
/*cookie_count=*/0}}});
ASSERT_EQ(allowed_browsing_data_model->size(), 1u);
// Delete Session Storage
RemoveBrowsingDataForDataOwner(allowed_browsing_data_model, kTestHost);
// Validate that the allowed browsing data model is empty.
ValidateBrowsingDataEntries(allowed_browsing_data_model, {});
ASSERT_EQ(allowed_browsing_data_model->size(), 0u);
// Reloading the page to ensure the renderer reflects deletion before checking
// if the storage type still exists on disk.
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(),
https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html")));
ASSERT_FALSE(HasDataForType("SessionStorage", web_contents()));
}
IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest,
QuotaStorageAccessReportedCorrectly) {
// Keeping the `ServiceWorker` type last as checking it after deletion counts
// as a new access report and repopulates the model, this way we keep it from
// affecting other quota storage types test.
std::vector<std::string> quota_storage_data_types = {
"IndexedDb", "FileSystem", "ServiceWorker"};
for (auto data_type : quota_storage_data_types) {
// Re-Navigate to the page for every data type, to prevent any cached data
// access results from impacting whether access is reported or not.
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), https_test_server()->GetURL(
kTestHost, "/browsing_data/site_data.html")));
auto* content_settings =
content_settings::PageSpecificContentSettings::GetForFrame(
web_contents()->GetPrimaryMainFrame());
// Validate that the allowed browsing data model is empty.
auto* allowed_browsing_data_model =
content_settings->allowed_browsing_data_model();
ValidateBrowsingDataEntries(allowed_browsing_data_model, {});
ASSERT_EQ(allowed_browsing_data_model->size(), 0u);
SetDataForType(data_type, web_contents());
WaitForModelUpdate(allowed_browsing_data_model, /*expected_size=*/1);
// Validate quota storage is reported.
url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost);
auto data_key = blink::StorageKey::CreateFirstParty(testOrigin);
ValidateBrowsingDataEntries(
allowed_browsing_data_model,
{{kTestHost,
data_key,
{{BrowsingDataModel::StorageType::kQuotaStorage},
/*storage_size=*/0,
/*cookie_count=*/0}}});
ASSERT_EQ(allowed_browsing_data_model->size(), 1u);
// Delete quota storage
RemoveBrowsingDataForDataOwner(allowed_browsing_data_model, kTestHost);
// Validate that the allowed browsing data model is empty.
ValidateBrowsingDataEntries(allowed_browsing_data_model, {});
ASSERT_EQ(allowed_browsing_data_model->size(), 0u);
ASSERT_FALSE(HasDataForType(data_type, web_contents()));
}
}
IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest,
SharedWorkerAccessReportedCorrectly) {
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(),
https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html")));
auto* content_settings =
content_settings::PageSpecificContentSettings::GetForFrame(
web_contents()->GetPrimaryMainFrame());
// Validate that the allowed browsing data model is empty.
auto* allowed_browsing_data_model =
content_settings->allowed_browsing_data_model();
ValidateBrowsingDataEntries(allowed_browsing_data_model, {});
ASSERT_EQ(allowed_browsing_data_model->size(), 0u);
SetDataForType("SharedWorker", web_contents());
WaitForModelUpdate(allowed_browsing_data_model, /*expected_size=*/1);
// Validate Shared Worker is reported.
url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost);
GURL::Replacements replacements;
replacements.SetPathStr("browsing_data/shared_worker.js");
GURL worker = testOrigin.GetURL().ReplaceComponents(replacements);
browsing_data::SharedWorkerInfo data_key(
worker, /*name=*/"", blink::StorageKey::CreateFirstParty(testOrigin),
blink::mojom::SharedWorkerSameSiteCookies::kAll);
ValidateBrowsingDataEntries(
allowed_browsing_data_model,
{{kTestHost,
data_key,
{{BrowsingDataModel::StorageType::kSharedWorker},
/*storage_size=*/0,
/*cookie_count=*/0}}});
ASSERT_EQ(allowed_browsing_data_model->size(), 1u);
// Delete Shared Worker
RemoveBrowsingDataForDataOwner(allowed_browsing_data_model, kTestHost);
// Validate that the allowed browsing data model is empty.
ValidateBrowsingDataEntries(allowed_browsing_data_model, {});
ASSERT_EQ(allowed_browsing_data_model->size(), 0u);
}
IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest,
LocalStorageRemovedBasedOnPartition) {
// Build BDM from disk.
std::unique_ptr<BrowsingDataModel> browsing_data_model =
BuildBrowsingDataModel();
ValidateBrowsingDataEntries(browsing_data_model.get(), {});
// Navigate to a.test.
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), https_test_server()->GetURL(
kTestHost, "/browsing_data/embedded_site_data.html")));
// Set local storage (a on a).
SetDataForType("LocalStorage", content::ChildFrameAt(web_contents(), 0));
// Navigate to b.test.
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), https_test_server()->GetURL(
kTestHost2, "/browsing_data/embedded_site_data.html")));
// Set local storage (a on b).
SetDataForType("LocalStorage", content::ChildFrameAt(web_contents(), 0));
// Navigate to c.test.
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), https_test_server()->GetURL(
kTestHost3, "/browsing_data/embedded_site_data.html")));
// Set local storage (a on c).
SetDataForType("LocalStorage", content::ChildFrameAt(web_contents(), 0));
// Flush storage size to disk.
auto* storage_partition = browser()->profile()->GetDefaultStoragePartition();
storage_partition->Flush();
// To ensure that flushing is completed.
base::RunLoop().RunUntilIdle();
auto* dom_storage_context = storage_partition->GetDOMStorageContext();
// Fetch local storage size from backend.
std::array<base::test::TestFuture<uint64_t>, 3> test_entry_storage_size;
dom_storage_context->GetLocalStorageUsage(base::BindLambdaForTesting(
[&](const std::vector<content::StorageUsageInfo>& storage_usage_info) {
ASSERT_EQ(3U, storage_usage_info.size());
test_entry_storage_size[0].SetValue(
storage_usage_info[0].total_size_bytes);
test_entry_storage_size[1].SetValue(
storage_usage_info[1].total_size_bytes);
test_entry_storage_size[2].SetValue(
storage_usage_info[2].total_size_bytes);
}));
// Rebuild from disk.
browsing_data_model = BuildBrowsingDataModel();
auto testHostOrigin = https_test_server()->GetOrigin(kTestHost);
auto top_level_site_a = net::SchemefulSite(GURL("https://a.test"));
auto storage_key_a =
blink::StorageKey::Create(testHostOrigin, top_level_site_a,
blink::mojom::AncestorChainBit::kSameSite);
auto top_level_site_b = net::SchemefulSite(GURL("https://b.test"));
auto storage_key_b =
blink::StorageKey::Create(testHostOrigin, top_level_site_b,
blink::mojom::AncestorChainBit::kCrossSite);
auto top_level_site_c = net::SchemefulSite(GURL("https://c.test"));
auto storage_key_c =
blink::StorageKey::Create(testHostOrigin, top_level_site_c,
blink::mojom::AncestorChainBit::kCrossSite);
// Validate entries {{a on a}, {a on b}, {a on c}}.
ValidateBrowsingDataEntries(
browsing_data_model.get(),
{{kTestHost,
storage_key_a,
{{BrowsingDataModel::StorageType::kLocalStorage},
test_entry_storage_size[0].Get(),
/*cookie_count=*/0}},
{kTestHost,
storage_key_b,
{{BrowsingDataModel::StorageType::kLocalStorage},
test_entry_storage_size[1].Get(),
/*cookie_count=*/0}},
{kTestHost,
storage_key_c,
{{BrowsingDataModel::StorageType::kLocalStorage},
test_entry_storage_size[2].Get(),
/*cookie_count=*/0}}});
// Remove {a on b}.
{
base::RunLoop run_loop;
browsing_data_model->RemovePartitionedBrowsingData(
kTestHost, top_level_site_b, run_loop.QuitClosure());
run_loop.Run();
}
// Rebuild from disk.
browsing_data_model = BuildBrowsingDataModel();
// Validate entries {{a on a}, {a on c}}.
ValidateBrowsingDataEntries(
browsing_data_model.get(),
{{kTestHost,
storage_key_a,
{{BrowsingDataModel::StorageType::kLocalStorage},
test_entry_storage_size[0].Get(),
/*cookie_count=*/0}},
{kTestHost,
storage_key_c,
{{BrowsingDataModel::StorageType::kLocalStorage},
test_entry_storage_size[2].Get(),
/*cookie_count=*/0}}});
// Remove {a on a}
{
base::RunLoop run_loop;
browsing_data_model->RemoveUnpartitionedBrowsingData(
kTestHost, run_loop.QuitClosure());
run_loop.Run();
}
// Rebuild from disk.
browsing_data_model = BuildBrowsingDataModel();
// Validate entries {{a on c}}.
ValidateBrowsingDataEntries(
browsing_data_model.get(),
{{kTestHost,
storage_key_c,
{{BrowsingDataModel::StorageType::kLocalStorage},
test_entry_storage_size[2].Get(),
/*cookie_count=*/0}}});
}
IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest,
SharedDictionaryHandledCorrectly) {
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(),
https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html")));
// Ensure that there isn't any data fetched.
std::unique_ptr<BrowsingDataModel> browsing_data_model =
BuildBrowsingDataModel();
ValidateBrowsingDataEntries(browsing_data_model.get(), {});
ASSERT_EQ(browsing_data_model->size(), 0u);
SetDataForType("SharedDictionary", web_contents());
// Ensure that shared dictionary is fetched
browsing_data_model = BuildBrowsingDataModel();
// Validate that shared dictionary is fetched to browsing data model.
url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost);
auto isolation_key = net::SharedDictionaryIsolationKey(
testOrigin, net::SchemefulSite(testOrigin));
ValidateBrowsingDataEntriesNonZeroUsage(
browsing_data_model.get(),
{{kTestHost,
isolation_key,
{{BrowsingDataModel::StorageType::kSharedDictionary},
/*storage_size=*/0,
/*cookie_count=*/0}}});
ASSERT_EQ(browsing_data_model->size(), 1u);
// Remove shared dictionary entry.
RemoveBrowsingDataForDataOwner(browsing_data_model.get(), kTestHost);
// Shared dictionary must have been removed.
EXPECT_FALSE(HasDataForType("SharedDictionary", web_contents()));
// Rebuild Browsing Data Model and verify entries are empty.
browsing_data_model = BuildBrowsingDataModel();
ValidateBrowsingDataEntries(browsing_data_model.get(), {});
ASSERT_EQ(browsing_data_model->size(), 0u);
}
IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest,
SharedDictionaryAccessReportedCorrectly) {
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(),
https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html")));
auto* content_settings =
content_settings::PageSpecificContentSettings::GetForFrame(
web_contents()->GetPrimaryMainFrame());
// Validate that the allowed browsing data model is empty.
ValidateBrowsingDataEntries(content_settings->allowed_browsing_data_model(),
{});
SetDataForType("SharedDictionary", web_contents());
// Calling SetDataForType("SharedDictionary") registers a shared dictionary.
// This must be reported to the data model.
WaitForModelUpdate(content_settings->allowed_browsing_data_model(), 1);
// Validate that the allowed browsing data model is populated with
// SharedDictionary entry for `kTestHost`.
url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost);
auto isolation_key = net::SharedDictionaryIsolationKey(
testOrigin, net::SchemefulSite(testOrigin));
ValidateBrowsingDataEntries(
content_settings->allowed_browsing_data_model(),
{{kTestHost,
isolation_key,
{{BrowsingDataModel::StorageType::kSharedDictionary},
/*storage_size=*/0,
/*cookie_count=*/0}}});
// Navigate to about:blank to clear the browsing data model state.
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL("about:blank")));
// Validate that the allowed browsing data model is empty.
ValidateBrowsingDataEntries(
content_settings::PageSpecificContentSettings::GetForFrame(
web_contents()->GetPrimaryMainFrame())
->allowed_browsing_data_model(),
{});
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(),
https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html")));
// Validate that the allowed browsing data model is empty.
ValidateBrowsingDataEntries(
content_settings::PageSpecificContentSettings::GetForFrame(
web_contents()->GetPrimaryMainFrame())
->allowed_browsing_data_model(),
{});
// Need this polling because the shared dictionary is used only if the
// metadata database has been read when sending the HTTP request.
while (!HasDataForType("SharedDictionary", web_contents())) {
base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
}
// Checking HasDataForType("SharedDictionary") accesses the registered
// shared dictionary. This must be reported to the data model.
content_settings = content_settings::PageSpecificContentSettings::GetForFrame(
web_contents()->GetPrimaryMainFrame());
WaitForModelUpdate(content_settings->allowed_browsing_data_model(), 1);
// Validate that the allowed browsing data model is populated with
// SharedDictionary entry for `kTestHost`.
ValidateBrowsingDataEntries(
content_settings->allowed_browsing_data_model(),
{{kTestHost,
isolation_key,
{{BrowsingDataModel::StorageType::kSharedDictionary},
/*storage_size=*/0,
/*cookie_count=*/0}}});
}
IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest,
SharedDictionaryAccessForNavigationReportedCorrectly) {
// Registers a shared dictionary.
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(),
https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html")));
SetDataForType("SharedDictionary", web_contents());
// Navigate to about:blank to clear the browsing data model state.
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL("about:blank")));
// Validate that the allowed browsing data model is empty.
ValidateBrowsingDataEntries(
content_settings::PageSpecificContentSettings::GetForFrame(
web_contents()->GetPrimaryMainFrame())
->allowed_browsing_data_model(),
{});
// Need this polling because the shared dictionary is used only if the
// metadata database has been read when sending the HTTP request.
int retry = 0;
while (true) {
const std::string kExpectedResult =
"This is compressed test data using a test dictionary";
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(),
https_test_server()->GetURL(
kTestHost,
base::StringPrintf(
"/shared_dictionary/path/compressed.data?retry=%d", ++retry))));
const std::string innerText =
EvalJs(web_contents()->GetPrimaryMainFrame(), "document.body.innerText")
.ExtractString();
if (innerText == kExpectedResult) {
break;
}
}
auto* content_settings =
content_settings::PageSpecificContentSettings::GetForFrame(
web_contents()->GetPrimaryMainFrame());
WaitForModelUpdate(content_settings->allowed_browsing_data_model(), 1);
// Validate that the allowed browsing data model is populated with
// SharedDictionary entry for `kTestHost`.
url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost);
auto isolation_key = net::SharedDictionaryIsolationKey(
testOrigin, net::SchemefulSite(testOrigin));
ValidateBrowsingDataEntries(
content_settings->allowed_browsing_data_model(),
{{kTestHost,
isolation_key,
{{BrowsingDataModel::StorageType::kSharedDictionary},
/*storage_size=*/0,
/*cookie_count=*/0}}});
}
IN_PROC_BROWSER_TEST_F(
BrowsingDataModelBrowserTest,
SharedDictionaryAccessForIframeNavigationReportedCorrectly) {
// Registers a shared dictionary.
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(),
https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html")));
SetDataForType("SharedDictionary", web_contents());
// Navigate to about:blank to clear the browsing data model state.
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL("about:blank")));
// Validate that the allowed browsing data model is empty.
ValidateBrowsingDataEntries(
content_settings::PageSpecificContentSettings::GetForFrame(
web_contents()->GetPrimaryMainFrame())
->allowed_browsing_data_model(),
{});
// Return to the test page.
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(),
https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html")));
// Validate that the allowed browsing data model is empty.
ValidateBrowsingDataEntries(
content_settings::PageSpecificContentSettings::GetForFrame(
web_contents()->GetPrimaryMainFrame())
->allowed_browsing_data_model(),
{});
// Need this polling because the shared dictionary is used only if the
// metadata database has been read when sending the HTTP request.
while (true) {
const std::string kExpectedResult =
"This is compressed test data using a test dictionary";
const std::string iframeInnerText =
EvalJs(web_contents()->GetPrimaryMainFrame(), R"(
(async () => {
const iframe = document.createElement('iframe');
iframe.src = '/shared_dictionary/path/compressed.data';
const promise =
new Promise(resolve => { iframe.addEventListener('load', resolve); });
document.body.appendChild(iframe);
await promise;
return iframe.contentDocument.body.innerText;
})())")
.ExtractString();
if (iframeInnerText == kExpectedResult) {
break;
}
}
auto* content_settings =
content_settings::PageSpecificContentSettings::GetForFrame(
web_contents()->GetPrimaryMainFrame());
WaitForModelUpdate(content_settings->allowed_browsing_data_model(), 1);
// Validate that the allowed browsing data model is populated with
// SharedDictionary entry for `kTestHost`.
url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost);
auto isolation_key = net::SharedDictionaryIsolationKey(
testOrigin, net::SchemefulSite(testOrigin));
ValidateBrowsingDataEntries(
content_settings->allowed_browsing_data_model(),
{{kTestHost,
isolation_key,
{{BrowsingDataModel::StorageType::kSharedDictionary},
/*storage_size=*/0,
/*cookie_count=*/0}}});
}
IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest, CookiesHandledCorrectly) {
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(),
https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html")));
// Ensure that there isn't any data fetched.
std::unique_ptr<BrowsingDataModel> browsing_data_model =
BuildBrowsingDataModel();
ValidateBrowsingDataEntries(browsing_data_model.get(), {});
ASSERT_EQ(browsing_data_model->size(), 0u);
SetDataForType("Cookie", web_contents());
// Ensure that cookie is fetched.
browsing_data_model = BuildBrowsingDataModel();
// Validate that cookie is fetched to browsing data model.
url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost);
std::unique_ptr<net::CanonicalCookie> data_key =
net::CanonicalCookie::CreateForTesting(testOrigin.GetURL(),
"foo=bar; Path=/browsing_data",
base::Time::Now());
ValidateBrowsingDataEntries(browsing_data_model.get(),
{{kTestHost,
*(data_key.get()),
{{BrowsingDataModel::StorageType::kCookie},
/*storage_size=*/0,
/*cookie_count=*/1}}});
ASSERT_EQ(browsing_data_model->size(), 1u);
// Remove cookie entry.
RemoveBrowsingDataForDataOwner(browsing_data_model.get(), kTestHost);
// Rebuild Browsing Data Model and verify entries are empty.
browsing_data_model = BuildBrowsingDataModel();
ValidateBrowsingDataEntries(browsing_data_model.get(), {});
ASSERT_EQ(browsing_data_model->size(), 0u);
ASSERT_FALSE(HasDataForType("Cookie", web_contents()));
}
IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest,
CookiesAccessReportedCorrectly) {
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(),
https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html")));
auto* content_settings =
content_settings::PageSpecificContentSettings::GetForFrame(
web_contents()->GetPrimaryMainFrame());
// Validate that the allowed browsing data model is empty.
auto* allowed_browsing_data_model =
content_settings->allowed_browsing_data_model();
ValidateBrowsingDataEntries(allowed_browsing_data_model, {});
ASSERT_EQ(allowed_browsing_data_model->size(), 0u);
SetDataForType("Cookie", web_contents());
WaitForModelUpdate(allowed_browsing_data_model, /*expected_size=*/1);
// Validate that cookie is fetched to browsing data model.
url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost);
std::unique_ptr<net::CanonicalCookie> data_key =
net::CanonicalCookie::CreateForTesting(testOrigin.GetURL(),
"foo=bar; Path=/browsing_data",
base::Time::Now());
ValidateBrowsingDataEntries(allowed_browsing_data_model,
{{kTestHost,
*(data_key.get()),
{{BrowsingDataModel::StorageType::kCookie},
/*storage_size=*/0,
/*cookie_count=*/1}}});
ASSERT_EQ(allowed_browsing_data_model->size(), 1u);
// Remove cookie entry.
RemoveBrowsingDataForDataOwner(allowed_browsing_data_model, kTestHost);
// Validate that the allowed browsing data model is empty.
ValidateBrowsingDataEntries(allowed_browsing_data_model, {});
ASSERT_EQ(allowed_browsing_data_model->size(), 0u);
ASSERT_FALSE(HasDataForType("Cookie", web_contents()));
}
IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest,
FederatedIdentityHandledCorrectly) {
// Setup identity provider (IDP).
idp_server()->SetConfigResponseDetails(BuildValidConfigDetails());
// Navigate to test page.
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), https_test_server()->GetURL(kTestHost, "/title1.html")));
// Validate that the browsing data model built from disk is empty.
std::unique_ptr<BrowsingDataModel> browsing_data_model =
BuildBrowsingDataModel();
ValidateBrowsingDataEntries(browsing_data_model.get(), {});
ASSERT_EQ(browsing_data_model->size(), 0u);
// Run FedCM and grant sharing permission by selecting an account.
RunFedCm(web_contents(), https_test_server());
// Waiting for the browsing data model to be populated, otherwise the test is
// flaky.
do {
browsing_data_model = BuildBrowsingDataModel();
base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
} while (browsing_data_model->size() != 1);
// Validate that an entry for FederatedIdentity is added to the browsing data
// model.
url::Origin testRpOrigin = https_test_server()->GetOrigin(kTestHost);
url::Origin testIdpOrigin =
url::Origin::Create(GURL(GetIdpConfigUrl(https_test_server())));
webid::FederatedIdentityDataModel::DataKey data_key{
testRpOrigin, testRpOrigin, testIdpOrigin, kAccountId};
ValidateBrowsingDataEntries(
browsing_data_model.get(),
{{kTestHost,
data_key,
{{static_cast<BrowsingDataModel::StorageType>(
ChromeBrowsingDataModelDelegate::StorageType::kFederatedIdentity)},
/*storage_size=*/100,
/*cookie_count=*/0}}});
// Clear FederatedIdentity in browsing data model using relying party embedder
// (data owner).
RemoveBrowsingDataForDataOwner(browsing_data_model.get(), kTestHost);
// Rebuild browsing data model and verify entries are empty.
browsing_data_model = BuildBrowsingDataModel();
ValidateBrowsingDataEntries(browsing_data_model.get(), {});
}
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest,
CdmStorageHandledCorrectly) {
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(),
https_test_server()->GetURL(kTestHost, "/browsing_data/site_data.html")));
// Ensure that there isn't any data fetched.
std::unique_ptr<BrowsingDataModel> browsing_data_model =
BuildBrowsingDataModel();
ValidateBrowsingDataEntries(browsing_data_model.get(), {});
ASSERT_EQ(browsing_data_model->size(), 0u);
SetDataForType("MediaLicense", web_contents());
browsing_data_model = BuildBrowsingDataModel();
url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost);
auto storage_key = blink::StorageKey::CreateFirstParty(testOrigin);
ValidateBrowsingDataEntries(browsing_data_model.get(),
{{kTestHost,
storage_key,
{{BrowsingDataModel::StorageType::kCdmStorage},
/*storage_size=*/112,
/*cookie_count=*/0}}});
RemoveBrowsingDataForDataOwner(browsing_data_model.get(), kTestHost);
// Rebuild browsing data model and verify entries are empty.
browsing_data_model = BuildBrowsingDataModel();
ValidateBrowsingDataEntries(browsing_data_model.get(), {});
}
#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS)
#if BUILDFLAG(ENABLE_DEVICE_BOUND_SESSIONS)
IN_PROC_BROWSER_TEST_F(BrowsingDataModelBrowserTest,
DeviceBoundSessionsStoredCorrectly) {
// Check that no device bound sessions exist at the beginning of the test.
std::unique_ptr<BrowsingDataModel> browsing_data_model =
BuildBrowsingDataModel();
ValidateBrowsingDataEntries(browsing_data_model.get(), {});
ASSERT_EQ(browsing_data_model->size(), 0u);
// Register a session
base::RunLoop run_loop;
TestDeviceBoundSessionAccessObserver observer(web_contents(),
run_loop.QuitClosure());
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), https_test_server()->GetURL(kTestHost, "/dbsc_required")));
run_loop.Run();
// Validate the device bound session and the cookie it protects are added
url::Origin testOrigin = https_test_server()->GetOrigin(kTestHost);
std::unique_ptr<net::CanonicalCookie> cookie_data_key =
net::CanonicalCookie::CreateForTesting(testOrigin.GetURL(),
"auth_cookie=abcdef0123; Path=/",
base::Time::Now());
net::device_bound_sessions::SessionKey session_data_key(
net::SchemefulSite(https_test_server()->GetURL(kTestHost, "/")),
net::device_bound_sessions::SessionKey::Id("session_id"));
browsing_data_model = BuildBrowsingDataModel();
ValidateBrowsingDataEntries(
browsing_data_model.get(),
{{kTestHost,
session_data_key,
{{BrowsingDataModel::StorageType::kDeviceBoundSession},
/*storage_size=*/100,
/*cookie_count=*/0}},
{kTestHost,
*(cookie_data_key.get()),
{{BrowsingDataModel::StorageType::kCookie},
/*storage_size=*/0,
/*cookie_count=*/1}}});
// Remove device bound session
RemoveBrowsingDataForDataOwner(browsing_data_model.get(), kTestHost);
// Rebuild Browsing Data Model and verify entries are empty.
browsing_data_model = BuildBrowsingDataModel();
ValidateBrowsingDataEntries(browsing_data_model.get(), {});
}
#endif // BUILDFLAG(ENABLE_DEVICE_BOUND_SESSIONS)