blob: 63c7311c8b0069a1a96a0b1abc3040bcc9cc0963 [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/interest_group/interest_group_manager_impl.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/containers/flat_map.h"
#include "base/containers/span.h"
#include "base/files/file_path.h"
#include "base/functional/callback.h"
#include "base/json/values_util.h"
#include "base/memory/scoped_refptr.h"
#include "base/metrics/histogram_functions.h"
#include "base/observer_list.h"
#include "base/strings/strcat.h"
#include "base/strings/to_string.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "base/types/expected.h"
#include "base/unguessable_token.h"
#include "content/browser/devtools/devtools_instrumentation.h"
#include "content/browser/devtools/network_service_devtools_observer.h"
#include "content/browser/interest_group/interest_group_caching_storage.h"
#include "content/browser/interest_group/interest_group_storage.h"
#include "content/browser/interest_group/interest_group_update.h"
#include "content/browser/renderer_host/frame_tree_node.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/mojom/client_security_state.mojom.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/interest_group/interest_group.h"
#include "url/gurl.h"
namespace content {
namespace {
// The maximum number of active report requests at a time.
constexpr int kMaxActiveReportRequests = 5;
// The maximum number of report URLs that can be stored in `report_requests_`
// queue.
constexpr int kMaxReportQueueLength = 1000;
// The maximum amount of time allowed to fetch report requests in the queue.
constexpr base::TimeDelta kMaxReportingRoundDuration = base::Minutes(10);
// The time interval to wait before sending the next report after sending one.
constexpr base::TimeDelta kReportingInterval = base::Milliseconds(50);
constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
net::DefineNetworkTrafficAnnotation("auction_report_sender", R"(
semantics {
sender: "Interest group based Ad Auction report"
description:
"Facilitates reporting the result of an in-browser interest group "
"based ad auction to an auction participant. "
"See https://github.com/WICG/turtledove/blob/main/FLEDGE.md"
trigger:
"Requested after running a in-browser interest group based ad "
"auction to report the auction result back to auction participants."
data: "URL associated with an interest group or seller."
destination: WEBSITE
}
policy {
cookies_allowed: NO
setting:
"These requests are controlled by a feature flag that is off by "
"default now. When enabled, they can be disabled by the Privacy"
" Sandbox setting."
policy_exception_justification:
"These requests are triggered by a website."
})");
mojo::PendingRemote<network::mojom::DevToolsObserver> CreateDevtoolsObserver(
int frame_tree_node_id) {
if (frame_tree_node_id != FrameTreeNode::kFrameTreeNodeInvalidId) {
FrameTreeNode* initiator_frame_tree_node =
FrameTreeNode::GloballyFindByID(frame_tree_node_id);
if (initiator_frame_tree_node) {
return NetworkServiceDevToolsObserver::MakeSelfOwned(
initiator_frame_tree_node);
}
}
return mojo::PendingRemote<network::mojom::DevToolsObserver>();
}
// Creates an uncredentialed request to use for the SimpleURLLoader and
// reporting to devtools.
std::unique_ptr<network::ResourceRequest> BuildUncredentialedRequest(
GURL url,
const url::Origin& frame_origin,
int frame_tree_node_id,
const network::mojom::ClientSecurityState& client_security_state) {
auto resource_request = std::make_unique<network::ResourceRequest>();
resource_request->url = std::move(url);
resource_request->devtools_request_id =
base::UnguessableToken::Create().ToString();
resource_request->redirect_mode = network::mojom::RedirectMode::kError;
resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
resource_request->request_initiator = frame_origin;
resource_request->trusted_params = network::ResourceRequest::TrustedParams();
resource_request->trusted_params->isolation_info =
net::IsolationInfo::CreateTransient();
resource_request->trusted_params->client_security_state =
client_security_state.Clone();
bool network_instrumentation_enabled = false;
if (frame_tree_node_id != FrameTreeNode::kFrameTreeNodeInvalidId) {
FrameTreeNode* frame_tree_node =
FrameTreeNode::GloballyFindByID(frame_tree_node_id);
if (frame_tree_node != nullptr) {
devtools_instrumentation::ApplyAuctionNetworkRequestOverrides(
frame_tree_node, resource_request.get(),
&network_instrumentation_enabled);
}
}
if (network_instrumentation_enabled) {
resource_request->enable_load_timing = true;
resource_request->trusted_params->devtools_observer =
CreateDevtoolsObserver(frame_tree_node_id);
}
return resource_request;
}
// Makes a SimpleURLLoader for a given request. Returns the SimpleURLLoader
// which will be used to report the result of an in-browser interest group based
// ad auction to an auction participant.
std::unique_ptr<network::SimpleURLLoader> BuildSimpleUrlLoader(
std::unique_ptr<network::ResourceRequest> resource_request) {
auto simple_url_loader = network::SimpleURLLoader::Create(
std::move(resource_request), kTrafficAnnotation);
simple_url_loader->SetTimeoutDuration(base::Seconds(30));
simple_url_loader->SetAllowHttpErrorResults(true);
return simple_url_loader;
}
std::vector<InterestGroupManager::InterestGroupDataKey>
ConvertOwnerJoinerPairsToDataKeys(
std::vector<std::pair<url::Origin, url::Origin>> owner_joiner_pairs) {
std::vector<InterestGroupManager::InterestGroupDataKey> data_keys;
for (auto& key : owner_joiner_pairs) {
data_keys.emplace_back(
InterestGroupManager::InterestGroupDataKey{key.first, key.second});
}
return data_keys;
}
} // namespace
InterestGroupManagerImpl::ReportRequest::ReportRequest() = default;
InterestGroupManagerImpl::ReportRequest::~ReportRequest() = default;
InterestGroupManagerImpl::AdAuctionDataLoaderState::AdAuctionDataLoaderState() =
default;
InterestGroupManagerImpl::AdAuctionDataLoaderState::AdAuctionDataLoaderState(
AdAuctionDataLoaderState&& state) = default;
InterestGroupManagerImpl::AdAuctionDataLoaderState::
~AdAuctionDataLoaderState() = default;
InterestGroupManagerImpl::InterestGroupManagerImpl(
const base::FilePath& path,
bool in_memory,
ProcessMode process_mode,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
KAnonymityServiceDelegate* k_anonymity_service)
: caching_storage_(path, in_memory),
auction_process_manager_(
base::WrapUnique(process_mode == ProcessMode::kDedicated
? static_cast<AuctionProcessManager*>(
new DedicatedAuctionProcessManager())
: new InRendererAuctionProcessManager())),
update_manager_(this, std::move(url_loader_factory)),
k_anonymity_manager_(std::make_unique<InterestGroupKAnonymityManager>(
this,
k_anonymity_service)),
max_active_report_requests_(kMaxActiveReportRequests),
max_report_queue_length_(kMaxReportQueueLength),
reporting_interval_(kReportingInterval),
max_reporting_round_duration_(kMaxReportingRoundDuration) {}
InterestGroupManagerImpl::~InterestGroupManagerImpl() = default;
void InterestGroupManagerImpl::GetAllInterestGroupJoiningOrigins(
base::OnceCallback<void(std::vector<url::Origin>)> callback) {
caching_storage_.GetAllInterestGroupJoiningOrigins(std::move(callback));
}
void InterestGroupManagerImpl::GetAllInterestGroupDataKeys(
base::OnceCallback<void(std::vector<InterestGroupDataKey>)> callback) {
caching_storage_.GetAllInterestGroupOwnerJoinerPairs(
base::BindOnce(&ConvertOwnerJoinerPairsToDataKeys)
.Then(std::move(callback)));
}
void InterestGroupManagerImpl::RemoveInterestGroupsByDataKey(
InterestGroupDataKey data_key,
base::OnceClosure callback) {
caching_storage_.RemoveInterestGroupsMatchingOwnerAndJoiner(
data_key.owner, data_key.joining_origin, std::move(callback));
}
void InterestGroupManagerImpl::CheckPermissionsAndJoinInterestGroup(
blink::InterestGroup group,
const GURL& joining_url,
const url::Origin& frame_origin,
const net::NetworkIsolationKey& network_isolation_key,
bool report_result_only,
network::mojom::URLLoaderFactory& url_loader_factory,
AreReportingOriginsAttestedCallback attestation_callback,
blink::mojom::AdAuctionService::JoinInterestGroupCallback callback) {
url::Origin interest_group_owner = group.owner;
permissions_checker_.CheckPermissions(
InterestGroupPermissionsChecker::Operation::kJoin, frame_origin,
interest_group_owner, network_isolation_key, url_loader_factory,
base::BindOnce(
&InterestGroupManagerImpl::OnJoinInterestGroupPermissionsChecked,
base::Unretained(this), std::move(group), joining_url,
report_result_only, std::move(attestation_callback),
std::move(callback)));
}
void InterestGroupManagerImpl::CheckPermissionsAndLeaveInterestGroup(
const blink::InterestGroupKey& group_key,
const url::Origin& main_frame,
const url::Origin& frame_origin,
const net::NetworkIsolationKey& network_isolation_key,
bool report_result_only,
network::mojom::URLLoaderFactory& url_loader_factory,
blink::mojom::AdAuctionService::LeaveInterestGroupCallback callback) {
permissions_checker_.CheckPermissions(
InterestGroupPermissionsChecker::Operation::kLeave, frame_origin,
group_key.owner, network_isolation_key, url_loader_factory,
base::BindOnce(
&InterestGroupManagerImpl::OnLeaveInterestGroupPermissionsChecked,
base::Unretained(this), group_key, main_frame, report_result_only,
std::move(callback)));
}
void InterestGroupManagerImpl::
CheckPermissionsAndClearOriginJoinedInterestGroups(
const url::Origin& owner,
const std::vector<std::string>& interest_groups_to_keep,
const url::Origin& main_frame_origin,
const url::Origin& frame_origin,
const net::NetworkIsolationKey& network_isolation_key,
bool report_result_only,
network::mojom::URLLoaderFactory& url_loader_factory,
blink::mojom::AdAuctionService::LeaveInterestGroupCallback callback) {
permissions_checker_.CheckPermissions(
InterestGroupPermissionsChecker::Operation::kLeave, frame_origin, owner,
network_isolation_key, url_loader_factory,
base::BindOnce(&InterestGroupManagerImpl::
OnClearOriginJoinedInterestGroupsPermissionsChecked,
base::Unretained(this), owner,
std::set<std::string>(interest_groups_to_keep.begin(),
interest_groups_to_keep.end()),
main_frame_origin, report_result_only,
std::move(callback)));
}
void InterestGroupManagerImpl::JoinInterestGroup(blink::InterestGroup group,
const GURL& joining_url) {
// Create notify callback first.
base::OnceClosure notify_callback = CreateNotifyInterestGroupAccessedCallback(
InterestGroupObserver::kJoin, group.owner, group.name);
blink::InterestGroupKey group_key(group.owner, group.name);
caching_storage_.JoinInterestGroup(group, joining_url,
std::move(notify_callback));
// This needs to happen second so that the DB row is created.
QueueKAnonymityUpdateForInterestGroup(group_key);
}
void InterestGroupManagerImpl::LeaveInterestGroup(
const blink::InterestGroupKey& group_key,
const ::url::Origin& main_frame) {
caching_storage_.LeaveInterestGroup(
group_key, main_frame,
CreateNotifyInterestGroupAccessedCallback(
InterestGroupObserver::kLeave, group_key.owner, group_key.name));
}
void InterestGroupManagerImpl::ClearOriginJoinedInterestGroups(
const url::Origin& owner,
std::set<std::string> interest_groups_to_keep,
url::Origin main_frame_origin) {
caching_storage_.ClearOriginJoinedInterestGroups(
owner, interest_groups_to_keep, main_frame_origin,
base::BindOnce(
&InterestGroupManagerImpl::OnClearOriginJoinedInterestGroupsComplete,
weak_factory_.GetWeakPtr(), owner));
}
void InterestGroupManagerImpl::OnClearOriginJoinedInterestGroupsComplete(
const url::Origin& owner,
std::vector<std::string> left_interest_group_names) {
for (const auto& name : left_interest_group_names) {
NotifyInterestGroupAccessed(InterestGroupObserver::kClear, owner, name);
}
}
void InterestGroupManagerImpl::UpdateInterestGroupsOfOwner(
const url::Origin& owner,
network::mojom::ClientSecurityStatePtr client_security_state,
AreReportingOriginsAttestedCallback callback) {
update_manager_.UpdateInterestGroupsOfOwner(
owner, std::move(client_security_state), std::move(callback));
}
void InterestGroupManagerImpl::UpdateInterestGroupsOfOwners(
base::span<url::Origin> owners,
network::mojom::ClientSecurityStatePtr client_security_state,
AreReportingOriginsAttestedCallback callback) {
update_manager_.UpdateInterestGroupsOfOwners(
owners, std::move(client_security_state), std::move(callback));
}
void InterestGroupManagerImpl::RecordInterestGroupBids(
const blink::InterestGroupSet& group_keys) {
if (group_keys.empty()) {
return;
}
caching_storage_.RecordInterestGroupBids(group_keys);
}
void InterestGroupManagerImpl::RecordInterestGroupWin(
const blink::InterestGroupKey& group_key,
const std::string& ad_json) {
caching_storage_.RecordInterestGroupWin(group_key, ad_json);
}
void InterestGroupManagerImpl::RegisterAdKeysAsJoined(
base::flat_set<std::string> keys) {
k_anonymity_manager_->RegisterAdKeysAsJoined(std::move(keys));
}
void InterestGroupManagerImpl::GetInterestGroup(
const url::Origin& owner,
const std::string& name,
base::OnceCallback<void(absl::optional<StorageInterestGroup>)> callback) {
GetInterestGroup(blink::InterestGroupKey(owner, name), std::move(callback));
}
void InterestGroupManagerImpl::GetInterestGroup(
const blink::InterestGroupKey& group_key,
base::OnceCallback<void(absl::optional<StorageInterestGroup>)> callback) {
caching_storage_.GetInterestGroup(group_key, std::move(callback));
}
void InterestGroupManagerImpl::GetAllInterestGroupOwners(
base::OnceCallback<void(std::vector<url::Origin>)> callback) {
caching_storage_.GetAllInterestGroupOwners(std::move(callback));
}
void InterestGroupManagerImpl::GetInterestGroupsForOwner(
const url::Origin& owner,
base::OnceCallback<void(scoped_refptr<StorageInterestGroups>)> callback) {
caching_storage_.GetInterestGroupsForOwner(
owner,
base::BindOnce(&InterestGroupManagerImpl::OnGetInterestGroupsComplete,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
void InterestGroupManagerImpl::DeleteInterestGroupData(
StoragePartition::StorageKeyMatcherFunction storage_key_matcher,
base::OnceClosure completion_callback) {
caching_storage_.DeleteInterestGroupData(storage_key_matcher,
std::move(completion_callback));
}
void InterestGroupManagerImpl::DeleteAllInterestGroupData(
base::OnceClosure completion_callback) {
caching_storage_.DeleteAllInterestGroupData(std::move(completion_callback));
}
void InterestGroupManagerImpl::GetLastMaintenanceTimeForTesting(
base::RepeatingCallback<void(base::Time)> callback) const {
caching_storage_.GetLastMaintenanceTimeForTesting( // IN-TEST
std::move(callback));
}
void InterestGroupManagerImpl::EnqueueReports(
ReportType report_type,
std::vector<GURL> report_urls,
int frame_tree_node_id,
const url::Origin& frame_origin,
const network::mojom::ClientSecurityState& client_security_state,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
if (report_urls.empty()) {
return;
}
// For memory usage reasons, purge the queue if it has at least
// `max_report_queue_length_` entries at the time we're about to add new
// entries.
if (report_requests_.size() >=
static_cast<unsigned int>(max_report_queue_length_)) {
report_requests_.clear();
}
const char* report_type_name;
switch (report_type) {
case ReportType::kSendReportTo:
report_type_name = "SendReportToReport";
break;
case ReportType::kDebugWin:
report_type_name = "DebugWinReport";
break;
case ReportType::kDebugLoss:
report_type_name = "DebugLossReport";
break;
}
for (GURL& report_url : report_urls) {
auto report_request = std::make_unique<ReportRequest>();
report_request->request_url_size_bytes = report_url.spec().size();
report_request->report_url = std::move(report_url);
report_request->frame_origin = frame_origin;
report_request->client_security_state = client_security_state;
report_request->name = report_type_name;
report_request->url_loader_factory = url_loader_factory;
report_request->frame_tree_node_id = frame_tree_node_id;
report_requests_.emplace_back(std::move(report_request));
}
while (!report_requests_.empty() &&
num_active_ < max_active_report_requests_) {
++num_active_;
TrySendingOneReport();
}
}
void InterestGroupManagerImpl::SetInterestGroupPriority(
const blink::InterestGroupKey& group_key,
double priority) {
caching_storage_.SetInterestGroupPriority(group_key, priority);
}
void InterestGroupManagerImpl::UpdateInterestGroupPriorityOverrides(
const blink::InterestGroupKey& group_key,
base::flat_map<std::string,
auction_worklet::mojom::PrioritySignalsDoublePtr>
update_priority_signals_overrides) {
caching_storage_.UpdateInterestGroupPriorityOverrides(
group_key, std::move(update_priority_signals_overrides));
}
void InterestGroupManagerImpl::ClearPermissionsCache() {
permissions_checker_.ClearCache();
}
void InterestGroupManagerImpl::QueueKAnonymityUpdateForInterestGroup(
const blink::InterestGroupKey& group_key) {
k_anonymity_manager_->QueryKAnonymityForInterestGroup(group_key);
}
void InterestGroupManagerImpl::UpdateKAnonymity(
const StorageInterestGroup::KAnonymityData& data) {
caching_storage_.UpdateKAnonymity(data);
}
void InterestGroupManagerImpl::GetLastKAnonymityReported(
const std::string& key,
base::OnceCallback<void(absl::optional<base::Time>)> callback) {
caching_storage_.GetLastKAnonymityReported(key, std::move(callback));
}
void InterestGroupManagerImpl::UpdateLastKAnonymityReported(
const std::string& key) {
caching_storage_.UpdateLastKAnonymityReported(key);
}
void InterestGroupManagerImpl::GetInterestGroupAdAuctionData(
url::Origin top_level_origin,
base::Uuid generation_id,
base::OnceCallback<void(BiddingAndAuctionData)> callback) {
AdAuctionDataLoaderState state;
state.serializer.SetPublisher(top_level_origin.host());
state.serializer.SetGenerationId(std::move(generation_id));
state.callback = std::move(callback);
GetAllInterestGroupOwners(base::BindOnce(
&InterestGroupManagerImpl::LoadNextInterestGroupAdAuctionData,
weak_factory_.GetWeakPtr(), std::move(state)));
}
void InterestGroupManagerImpl::LoadNextInterestGroupAdAuctionData(
AdAuctionDataLoaderState state,
std::vector<url::Origin> owners) {
if (!owners.empty()) {
url::Origin next_owner = std::move(owners.back());
owners.pop_back();
GetInterestGroupsForOwner(
next_owner,
base::BindOnce(
&InterestGroupManagerImpl::OnLoadedNextInterestGroupAdAuctionData,
weak_factory_.GetWeakPtr(), std::move(state), std::move(owners),
next_owner));
return;
}
// Loading is finished.
OnAdAuctionDataLoadComplete(std::move(state));
}
void InterestGroupManagerImpl::OnLoadedNextInterestGroupAdAuctionData(
AdAuctionDataLoaderState state,
std::vector<url::Origin> owners,
url::Origin owner,
scoped_refptr<StorageInterestGroups> groups) {
state.serializer.AddGroups(std::move(owner), std::move(groups));
LoadNextInterestGroupAdAuctionData(std::move(state), std::move(owners));
}
void InterestGroupManagerImpl::OnAdAuctionDataLoadComplete(
AdAuctionDataLoaderState state) {
std::move(state.callback).Run(state.serializer.Build());
}
void InterestGroupManagerImpl::GetBiddingAndAuctionServerKey(
network::mojom::URLLoaderFactory* loader,
absl::optional<url::Origin> coordinator,
base::OnceCallback<void(
base::expected<BiddingAndAuctionServerKey, std::string>)> callback) {
ba_key_fetcher_.GetOrFetchKey(loader, std::move(coordinator),
std::move(callback));
}
void InterestGroupManagerImpl::OnJoinInterestGroupPermissionsChecked(
blink::InterestGroup group,
const GURL& joining_url,
bool report_result_only,
AreReportingOriginsAttestedCallback attestation_callback,
blink::mojom::AdAuctionService::JoinInterestGroupCallback callback,
bool can_join) {
// Invoke callback before calling JoinInterestGroup(), which posts a task to
// another thread. Any FLEDGE call made from the renderer will need to pass
// through the UI thread and then bounce over the database thread, so it will
// see the new InterestGroup, so it's not necessary to actually wait for the
// database to be updated before invoking the callback. Waiting before
// invoking the callback may potentially leak whether the user was previously
// in the InterestGroup through timing differences.
std::move(callback).Run(/*failed_well_known_check=*/!can_join);
if (!report_result_only && can_join) {
// All ads' allowed reporting origins must be attested. Otherwise don't
// join.
if (group.ads) {
for (auto& ad : *group.ads) {
if (ad.allowed_reporting_origins) {
// Sort and de-duplicate by passing it through a flat_set.
ad.allowed_reporting_origins =
base::flat_set<url::Origin>(
std::move(ad.allowed_reporting_origins.value()))
.extract();
if (!attestation_callback.Run(ad.allowed_reporting_origins.value())) {
return;
}
}
}
}
JoinInterestGroup(std::move(group), joining_url);
}
}
void InterestGroupManagerImpl::OnLeaveInterestGroupPermissionsChecked(
const blink::InterestGroupKey& group_key,
const url::Origin& main_frame,
bool report_result_only,
blink::mojom::AdAuctionService::LeaveInterestGroupCallback callback,
bool can_leave) {
// Invoke callback before calling LeaveInterestGroup(), which posts a task to
// another thread. Any FLEDGE call made from the renderer will need to pass
// through the UI thread and then bounce over the database thread, so it will
// see the new InterestGroup, so it's not necessary to actually wait for the
// database to be updated before invoking the callback. Waiting before
// invoking the callback may potentially leak whether the user was previously
// in the InterestGroup through timing differences.
std::move(callback).Run(/*failed_well_known_check=*/!can_leave);
if (!report_result_only && can_leave) {
LeaveInterestGroup(group_key, main_frame);
}
}
void InterestGroupManagerImpl::
OnClearOriginJoinedInterestGroupsPermissionsChecked(
url::Origin owner,
std::set<std::string> interest_groups_to_keep,
url::Origin main_frame_origin,
bool report_result_only,
blink::mojom::AdAuctionService::LeaveInterestGroupCallback callback,
bool can_leave) {
// Invoke callback before calling ClearOriginJoinedInterestGroups(), which
// posts a task to another thread. Any FLEDGE call made from the renderer will
// need to pass through the UI thread and then bounce over the database
// thread, so it will see the new InterestGroup, so it's not necessary to
// actually wait for the database to be updated before invoking the callback.
// Waiting before invoking the callback may potentially leak whether the user
// was previously in the InterestGroup through timing differences.
std::move(callback).Run(/*failed_well_known_check=*/!can_leave);
if (!report_result_only && can_leave) {
ClearOriginJoinedInterestGroups(std::move(owner),
std::move(interest_groups_to_keep),
std::move(main_frame_origin));
}
}
void InterestGroupManagerImpl::GetInterestGroupsForUpdate(
const url::Origin& owner,
int groups_limit,
base::OnceCallback<void(std::vector<InterestGroupUpdateParameter>)>
callback) {
caching_storage_.GetInterestGroupsForUpdate(owner, groups_limit,
std::move(callback));
}
void InterestGroupManagerImpl::GetKAnonymityDataForUpdate(
const blink::InterestGroupKey& group_key,
base::OnceCallback<void(
const std::vector<StorageInterestGroup::KAnonymityData>&)> callback) {
caching_storage_.GetKAnonymityDataForUpdate(group_key, std::move(callback));
}
void InterestGroupManagerImpl::UpdateInterestGroup(
const blink::InterestGroupKey& group_key,
InterestGroupUpdate update,
base::OnceCallback<void(bool)> callback) {
NotifyInterestGroupAccessed(InterestGroupObserver::kUpdate, group_key.owner,
group_key.name);
caching_storage_.UpdateInterestGroup(
group_key, std::move(update),
base::BindOnce(&InterestGroupManagerImpl::OnUpdateComplete,
weak_factory_.GetWeakPtr(), group_key.owner,
group_key.name, std::move(callback)));
}
void InterestGroupManagerImpl::OnUpdateComplete(
const url::Origin& owner_origin,
const std::string& name,
base::OnceCallback<void(bool)> callback,
bool success) {
NotifyInterestGroupAccessed(InterestGroupObserver::kUpdate, owner_origin,
name);
std::move(callback).Run(success);
}
void InterestGroupManagerImpl::ReportUpdateFailed(
const blink::InterestGroupKey& group_key,
bool parse_failure) {
caching_storage_.ReportUpdateFailed(group_key, parse_failure);
}
void InterestGroupManagerImpl::OnGetInterestGroupsComplete(
base::OnceCallback<void(scoped_refptr<StorageInterestGroups>)> callback,
scoped_refptr<StorageInterestGroups> groups) {
for (const SingleStorageInterestGroup& group : groups->GetInterestGroups()) {
NotifyInterestGroupAccessed(InterestGroupObserver::kLoaded,
group->interest_group.owner,
group->interest_group.name);
}
std::move(callback).Run(std::move(groups));
}
void InterestGroupManagerImpl::NotifyInterestGroupAccessed(
InterestGroupObserver::AccessType type,
const url::Origin& owner_origin,
const std::string& name) {
// Don't bother getting the time if there are no observers.
if (observers_.empty()) {
return;
}
base::Time now = base::Time::Now();
for (InterestGroupObserver& observer : observers_) {
observer.OnInterestGroupAccessed(now, type, owner_origin, name);
}
}
void InterestGroupManagerImpl::TrySendingOneReport() {
DCHECK_GT(num_active_, 0);
if (report_requests_.empty()) {
--num_active_;
if (num_active_ == 0) {
timeout_timer_.Stop();
}
return;
}
if (!timeout_timer_.IsRunning()) {
timeout_timer_.Start(
FROM_HERE, max_reporting_round_duration_,
base::BindOnce(&InterestGroupManagerImpl::TimeoutReports,
base::Unretained(this)));
}
std::unique_ptr<ReportRequest> report_request =
std::move(report_requests_.front());
report_requests_.pop_front();
int frame_tree_node_id = report_request->frame_tree_node_id;
base::UmaHistogramCounts100000(
base::StrCat(
{"Ads.InterestGroup.Net.RequestUrlSizeBytes.", report_request->name}),
report_request->request_url_size_bytes);
base::UmaHistogramCounts100(
base::StrCat(
{"Ads.InterestGroup.Net.ResponseSizeBytes.", report_request->name}),
0);
std::unique_ptr<network::ResourceRequest> resource_request =
BuildUncredentialedRequest(report_request->report_url,
report_request->frame_origin,
report_request->frame_tree_node_id,
report_request->client_security_state);
std::string devtools_request_id =
resource_request->devtools_request_id.value();
devtools_instrumentation::OnAuctionWorkletNetworkRequestWillBeSent(
report_request->frame_tree_node_id, *resource_request,
base::TimeTicks::Now());
std::unique_ptr<network::SimpleURLLoader> simple_url_loader =
BuildSimpleUrlLoader(std::move(resource_request));
// Pass simple_url_loader to keep it alive until the request fails or succeeds
// to prevent cancelling the request.
network::SimpleURLLoader* simple_url_loader_ptr = simple_url_loader.get();
simple_url_loader_ptr->DownloadHeadersOnly(
report_request->url_loader_factory.get(),
base::BindOnce(&InterestGroupManagerImpl::OnOneReportSent,
weak_factory_.GetWeakPtr(), std::move(simple_url_loader),
frame_tree_node_id, std::move(devtools_request_id)));
}
void InterestGroupManagerImpl::OnOneReportSent(
std::unique_ptr<network::SimpleURLLoader> simple_url_loader,
int frame_tree_node_id,
const std::string& devtools_request_id,
scoped_refptr<net::HttpResponseHeaders> response_headers) {
DCHECK_GT(num_active_, 0);
network::URLLoaderCompletionStatus completion_status =
network::URLLoaderCompletionStatus(simple_url_loader->NetError());
if (simple_url_loader->CompletionStatus()) {
completion_status = simple_url_loader->CompletionStatus().value();
}
if (simple_url_loader->ResponseInfo() != nullptr) {
devtools_instrumentation::OnAuctionWorkletNetworkResponseReceived(
frame_tree_node_id, devtools_request_id, devtools_request_id,
simple_url_loader->GetFinalURL(), *simple_url_loader->ResponseInfo());
}
devtools_instrumentation::OnAuctionWorkletNetworkRequestComplete(
frame_tree_node_id, devtools_request_id, completion_status);
base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&InterestGroupManagerImpl::TrySendingOneReport,
weak_factory_.GetWeakPtr()),
reporting_interval_);
}
void InterestGroupManagerImpl::TimeoutReports() {
// TODO(qingxinwu): maybe add UMA metrics to learn how often this happens.
report_requests_.clear();
}
base::OnceClosure
InterestGroupManagerImpl::CreateNotifyInterestGroupAccessedCallback(
InterestGroupObserver::AccessType type,
const url::Origin& owner_origin,
const std::string& name) {
return base::BindOnce(&InterestGroupManagerImpl::NotifyInterestGroupAccessed,
weak_factory_.GetWeakPtr(), type, owner_origin, name);
}
} // namespace content