blob: 94c9b8cc0c13b22bb091fe5e4f17a61e1d273eeb [file] [log] [blame]
// Copyright 2023 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/fenced_frame/fenced_frame_reporter.h"
#include <functional>
#include <map>
#include <memory>
#include <string>
#include <type_traits>
#include <utility>
#include "base/memory/scoped_refptr.h"
#include "base/strings/string_piece.h"
#include "base/test/scoped_feature_list.h"
#include "content/browser/attribution_reporting/attribution_manager.h"
#include "content/browser/attribution_reporting/test/mock_attribution_data_host_manager.h"
#include "content/browser/attribution_reporting/test/mock_attribution_manager.h"
#include "content/browser/interest_group/test_interest_group_private_aggregation_manager.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/browser/storage_partition_impl.h"
#include "content/public/browser/browser_context.h"
#include "content/public/common/content_features.h"
#include "content/public/test/test_renderer_host.h"
#include "content/services/auction_worklet/public/mojom/private_aggregation_request.mojom.h"
#include "net/base/isolation_info.h"
#include "net/base/network_isolation_key.h"
#include "net/http/http_request_headers.h"
#include "services/network/public/cpp/attribution_reporting_runtime_features.h"
#include "services/network/public/cpp/data_element.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_url_loader_factory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/fenced_frame/redacted_fenced_frame_config.h"
#include "third_party/blink/public/mojom/private_aggregation/aggregatable_report.mojom.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace content {
namespace {
using ::testing::_;
using PrivateAggregationRequests =
FencedFrameReporter::PrivateAggregationRequests;
const auction_worklet::mojom::PrivateAggregationRequestPtr
kPrivateAggregationRequest =
auction_worklet::mojom::PrivateAggregationRequest::New(
auction_worklet::mojom::AggregatableReportContribution::
NewHistogramContribution(
blink::mojom::AggregatableReportHistogramContribution::New(
/*bucket=*/1,
/*value=*/2)),
blink::mojom::AggregationServiceMode::kDefault,
blink::mojom::DebugModeDetails::New());
const auction_worklet::mojom::PrivateAggregationRequestPtr
kPrivateAggregationRequest2 =
auction_worklet::mojom::PrivateAggregationRequest::New(
auction_worklet::mojom::AggregatableReportContribution::
NewHistogramContribution(
blink::mojom::AggregatableReportHistogramContribution::New(
/*bucket=*/3,
/*value=*/4)),
blink::mojom::AggregationServiceMode::kDefault,
blink::mojom::DebugModeDetails::New());
// Helper to avoid excess boilerplate.
template <typename... Ts>
auto ElementsAreRequests(Ts&... requests) {
static_assert(
std::conjunction<std::is_same<
std::remove_const_t<Ts>,
auction_worklet::mojom::PrivateAggregationRequestPtr>...>::value);
// Need to use `std::ref` as `mojo::StructPtr`s are move-only.
return testing::UnorderedElementsAre(testing::Eq(std::ref(requests))...);
}
class FencedFrameReporterTest : public RenderViewHostTestHarness {
public:
FencedFrameReporterTest() {
scoped_feature_list_.InitAndEnableFeature(
features::kAttributionFencedFrameReportingBeacon);
}
scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory() {
return test_url_loader_factory_.GetSafeWeakWrapper();
}
AttributionManager* attribution_manager() {
return AttributionManager::FromBrowserContext(browser_context());
}
void SetUp() override {
RenderViewHostTestHarness::SetUp();
NavigateAndCommit(request_initiator_);
}
void ValidateRequest(const network::ResourceRequest& request,
const GURL& expected_url,
const std::string& event_data) {
EXPECT_EQ(request.url, expected_url);
EXPECT_EQ(request.mode, network::mojom::RequestMode::kCors);
EXPECT_EQ(request.request_initiator,
url::Origin::Create(request_initiator_));
EXPECT_EQ(request.credentials_mode, network::mojom::CredentialsMode::kOmit);
EXPECT_EQ(request.method, net::HttpRequestHeaders::kPostMethod);
EXPECT_TRUE(request.trusted_params->isolation_info.network_isolation_key()
.IsTransient());
std::string content_type;
ASSERT_TRUE(request.headers.GetHeader(net::HttpRequestHeaders::kContentType,
&content_type));
EXPECT_EQ(content_type, "text/plain;charset=UTF-8");
ASSERT_TRUE(request.request_body);
ASSERT_EQ(request.request_body->elements()->size(), 1u);
ASSERT_EQ((*request.request_body->elements())[0].type(),
network::DataElement::Tag::kBytes);
EXPECT_EQ((*request.request_body->elements())[0]
.As<network::DataElementBytes>()
.AsStringPiece(),
event_data);
}
protected:
RenderFrameHostImpl* main_rfh_impl() {
return static_cast<RenderFrameHostImpl*>(main_rfh());
}
void ShutDownAttributionManager() {
auto* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
partition->OverrideAttributionManagerForTesting(
/*attribution_manager=*/nullptr);
}
network::TestURLLoaderFactory test_url_loader_factory_;
const GURL request_initiator_{"https://initiator.test/"};
const GURL report_destination_{"https://report_destination.test"};
const GURL report_destination2_{"https://report_destination2.test"};
const GURL report_destination3_{"https://report_destination3.test"};
const url::Origin main_frame_origin_ =
url::Origin::Create(request_initiator_);
const url::Origin report_destination_origin_ =
url::Origin::Create(report_destination_);
TestInterestGroupPrivateAggregationManager private_aggregation_manager_{
main_frame_origin_};
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
// ReportingDestination has no map.
TEST_F(FencedFrameReporterTest, NoReportNoMap) {
scoped_refptr<FencedFrameReporter> reporter =
FencedFrameReporter::CreateForSharedStorage(
shared_url_loader_factory(), attribution_manager(),
/*reporting_url_map=*/{{"event_type", report_destination_}});
std::string error_message;
// A Shared Storage FencedFrameReporter has no map for FLEDGE destinations.
EXPECT_FALSE(reporter->SendReport(
"event_type", "event_data",
blink::FencedFrame::ReportingDestination::kBuyer, main_rfh_impl(),
network::AttributionReportingRuntimeFeatures(), error_message));
EXPECT_EQ(error_message,
"This frame did not register reporting metadata for destination "
"'Buyer'.");
EXPECT_FALSE(reporter->SendReport(
"event_type", "event_data",
blink::FencedFrame::ReportingDestination::kSeller, main_rfh_impl(),
network::AttributionReportingRuntimeFeatures(), error_message));
EXPECT_EQ(error_message,
"This frame did not register reporting metadata for destination "
"'Seller'.");
EXPECT_FALSE(reporter->SendReport(
"event_type", "event_data",
blink::FencedFrame::ReportingDestination::kDirectSeller, main_rfh_impl(),
network::AttributionReportingRuntimeFeatures(), error_message));
EXPECT_EQ(error_message,
"This frame did not register reporting metadata for destination "
"'ComponentSeller'.");
EXPECT_FALSE(reporter->SendReport(
"event_type", "event_data",
blink::FencedFrame::ReportingDestination::kComponentSeller,
main_rfh_impl(), network::AttributionReportingRuntimeFeatures(),
error_message));
EXPECT_EQ(error_message,
"This frame did not register reporting metadata for destination "
"'ComponentSeller'.");
// A FLEDGE FencedFrameReporter has no map for Shared Storage.
reporter = FencedFrameReporter::CreateForFledge(
shared_url_loader_factory(), attribution_manager(),
/*direct_seller_is_seller=*/false, &private_aggregation_manager_,
main_frame_origin_,
/*winner_origin=*/report_destination_origin_);
EXPECT_FALSE(reporter->SendReport(
"event_type", "event_data",
blink::FencedFrame::ReportingDestination::kSharedStorageSelectUrl,
main_rfh_impl(), network::AttributionReportingRuntimeFeatures(),
error_message));
EXPECT_EQ(error_message,
"This frame did not register reporting metadata for destination "
"'SharedStorageSelectUrl'.");
// No requests should have been made.
EXPECT_EQ(test_url_loader_factory_.NumPending(), 0);
}
// ReportingDestination has an empty map.
TEST_F(FencedFrameReporterTest, NoReportEmptyMap) {
scoped_refptr<FencedFrameReporter> reporter =
FencedFrameReporter::CreateForSharedStorage(shared_url_loader_factory(),
attribution_manager(),
/*reporting_url_map=*/{});
std::string error_message;
EXPECT_FALSE(reporter->SendReport(
"event_type", "event_data",
blink::FencedFrame::ReportingDestination::kSharedStorageSelectUrl,
main_rfh_impl(), network::AttributionReportingRuntimeFeatures(),
error_message));
EXPECT_EQ(error_message,
"This frame did not register reporting metadata for destination "
"'SharedStorageSelectUrl'.");
// No requests should have been made.
EXPECT_EQ(test_url_loader_factory_.NumPending(), 0);
}
// Non-empty reporting URL map, but passed in event type isn't registered.
TEST_F(FencedFrameReporterTest, NoReportEventTypeNotRegistered) {
scoped_refptr<FencedFrameReporter> reporter =
FencedFrameReporter::CreateForSharedStorage(
shared_url_loader_factory(), attribution_manager(),
/*reporting_url_map=*/
{{"registered_event_type", report_destination_}});
std::string error_message;
EXPECT_FALSE(reporter->SendReport(
"unregistered_event_type", "event_data",
blink::FencedFrame::ReportingDestination::kSharedStorageSelectUrl,
main_rfh_impl(), network::AttributionReportingRuntimeFeatures(),
error_message));
EXPECT_EQ(
error_message,
"This frame did not register reporting url for destination "
"'SharedStorageSelectUrl' and event_type 'unregistered_event_type'.");
// No requests should have been made.
EXPECT_EQ(test_url_loader_factory_.NumPending(), 0);
}
// Event types map to disallowed URLs (empty URLs, non-HTTP/HTTPS URLs).
TEST_F(FencedFrameReporterTest, NoReportBadUrl) {
scoped_refptr<FencedFrameReporter> reporter =
FencedFrameReporter::CreateForSharedStorage(
shared_url_loader_factory(), attribution_manager(),
/*reporting_url_map=*/
{{"no_url", GURL()},
{"data_url", GURL("data:,only http is allowed")}});
std::string error_message;
EXPECT_FALSE(reporter->SendReport(
"no_url", "event_data",
blink::FencedFrame::ReportingDestination::kSharedStorageSelectUrl,
main_rfh_impl(), network::AttributionReportingRuntimeFeatures(),
error_message));
EXPECT_EQ(error_message,
"This frame registered invalid reporting url for destination "
"'SharedStorageSelectUrl' and event_type 'no_url'.");
EXPECT_FALSE(reporter->SendReport(
"data_url", "event_data",
blink::FencedFrame::ReportingDestination::kSharedStorageSelectUrl,
main_rfh_impl(), network::AttributionReportingRuntimeFeatures(),
error_message));
EXPECT_EQ(error_message,
"This frame registered invalid reporting url for destination "
"'SharedStorageSelectUrl' and event_type 'data_url'.");
// No requests should have been made.
EXPECT_EQ(test_url_loader_factory_.NumPending(), 0);
}
TEST_F(FencedFrameReporterTest, SendReports) {
scoped_refptr<FencedFrameReporter> reporter =
FencedFrameReporter::CreateForSharedStorage(
shared_url_loader_factory(), attribution_manager(),
/*reporting_url_map=*/
{{"event_type", report_destination_},
{"event_type2", report_destination2_}});
// Make a report.
std::string error_message;
EXPECT_TRUE(reporter->SendReport(
"event_type", "event_data",
blink::FencedFrame::ReportingDestination::kSharedStorageSelectUrl,
main_rfh_impl(), network::AttributionReportingRuntimeFeatures(),
error_message));
EXPECT_EQ(test_url_loader_factory_.NumPending(), 1);
ValidateRequest((*test_url_loader_factory_.pending_requests())[0].request,
report_destination_, "event_data");
// Make another report to the same URL with different data. Should also
// succeed.
EXPECT_TRUE(reporter->SendReport(
"event_type", "event_data2",
blink::FencedFrame::ReportingDestination::kSharedStorageSelectUrl,
main_rfh_impl(), network::AttributionReportingRuntimeFeatures(),
error_message));
EXPECT_EQ(test_url_loader_factory_.NumPending(), 2);
ValidateRequest((*test_url_loader_factory_.pending_requests())[1].request,
report_destination_, "event_data2");
// Make a report using another event type.
EXPECT_TRUE(reporter->SendReport(
"event_type2", "event_data3",
blink::FencedFrame::ReportingDestination::kSharedStorageSelectUrl,
main_rfh_impl(), network::AttributionReportingRuntimeFeatures(),
error_message));
EXPECT_EQ(test_url_loader_factory_.NumPending(), 3);
ValidateRequest((*test_url_loader_factory_.pending_requests())[2].request,
report_destination2_, "event_data3");
}
// Test reports in the FLEDGE case, where reporting URL maps are received before
// SendReport() calls.
TEST_F(FencedFrameReporterTest, SendFledgeReportsAfterMapsReceived) {
scoped_refptr<FencedFrameReporter> reporter =
FencedFrameReporter::CreateForFledge(
shared_url_loader_factory(), attribution_manager(),
/*direct_seller_is_seller=*/false, &private_aggregation_manager_,
main_frame_origin_,
/*winner_origin=*/report_destination_origin_);
// Receive all mappings.
reporter->OnUrlMappingReady(
blink::FencedFrame::ReportingDestination::kSeller,
/*reporting_url_map=*/{{"event_type", report_destination_}});
reporter->OnUrlMappingReady(
blink::FencedFrame::ReportingDestination::kComponentSeller,
/*reporting_url_map=*/{{"event_type", report_destination2_}});
reporter->OnUrlMappingReady(
blink::FencedFrame::ReportingDestination::kBuyer,
/*reporting_url_map=*/{{"event_type", report_destination3_}});
EXPECT_EQ(test_url_loader_factory_.NumPending(), 0);
// Make reports. Each should be sent immediately.
std::string error_message;
EXPECT_TRUE(reporter->SendReport(
"event_type", "event_data",
blink::FencedFrame::ReportingDestination::kSeller, main_rfh_impl(),
network::AttributionReportingRuntimeFeatures(), error_message));
EXPECT_EQ(test_url_loader_factory_.NumPending(), 1);
ValidateRequest((*test_url_loader_factory_.pending_requests())[0].request,
report_destination_, "event_data");
EXPECT_TRUE(reporter->SendReport(
"event_type", "event_data",
blink::FencedFrame::ReportingDestination::kComponentSeller,
main_rfh_impl(), network::AttributionReportingRuntimeFeatures(),
error_message));
EXPECT_EQ(test_url_loader_factory_.NumPending(), 2);
ValidateRequest((*test_url_loader_factory_.pending_requests())[1].request,
report_destination2_, "event_data");
EXPECT_TRUE(reporter->SendReport(
"event_type", "event_data",
blink::FencedFrame::ReportingDestination::kBuyer, main_rfh_impl(),
network::AttributionReportingRuntimeFeatures(), error_message));
EXPECT_EQ(test_url_loader_factory_.NumPending(), 3);
ValidateRequest((*test_url_loader_factory_.pending_requests())[2].request,
report_destination3_, "event_data");
EXPECT_TRUE(reporter->SendReport(
"event_type", "event_data",
blink::FencedFrame::ReportingDestination::kDirectSeller, main_rfh_impl(),
network::AttributionReportingRuntimeFeatures(), error_message));
EXPECT_EQ(test_url_loader_factory_.NumPending(), 4);
ValidateRequest((*test_url_loader_factory_.pending_requests())[3].request,
report_destination2_, "event_data");
}
// Test reports in the FLEDGE case, where reporting URL maps are received after
// SendReport() calls.
TEST_F(FencedFrameReporterTest, SendReportsFledgeBeforeMapsReceived) {
scoped_refptr<FencedFrameReporter> reporter =
FencedFrameReporter::CreateForFledge(
shared_url_loader_factory(), attribution_manager(),
/*direct_seller_is_seller=*/true, &private_aggregation_manager_,
main_frame_origin_,
/*winner_origin=*/report_destination_origin_);
// Make reports. They should be queued, since mappings haven't been received
// yet.
std::string error_message;
EXPECT_TRUE(reporter->SendReport(
"event_type", "event_data",
blink::FencedFrame::ReportingDestination::kSeller, main_rfh_impl(),
network::AttributionReportingRuntimeFeatures(), error_message));
EXPECT_TRUE(reporter->SendReport(
"event_type", "event_data",
blink::FencedFrame::ReportingDestination::kComponentSeller,
main_rfh_impl(), network::AttributionReportingRuntimeFeatures(),
error_message));
EXPECT_TRUE(reporter->SendReport(
"event_type", "event_data",
blink::FencedFrame::ReportingDestination::kBuyer, main_rfh_impl(),
network::AttributionReportingRuntimeFeatures(), error_message));
EXPECT_TRUE(reporter->SendReport(
"event_type", "event_data",
blink::FencedFrame::ReportingDestination::kDirectSeller, main_rfh_impl(),
network::AttributionReportingRuntimeFeatures(), error_message));
EXPECT_EQ(test_url_loader_factory_.NumPending(), 0);
// Each report should be sent as its mapping is received.
reporter->OnUrlMappingReady(
blink::FencedFrame::ReportingDestination::kSeller,
/*reporting_url_map=*/{{"event_type", report_destination_}});
EXPECT_EQ(test_url_loader_factory_.NumPending(), 2);
ValidateRequest((*test_url_loader_factory_.pending_requests())[0].request,
report_destination_, "event_data");
// This one is from the "DirectSeller" destination, which was aliased to
// kSeller.
ValidateRequest((*test_url_loader_factory_.pending_requests())[1].request,
report_destination_, "event_data");
reporter->OnUrlMappingReady(
blink::FencedFrame::ReportingDestination::kComponentSeller,
/*reporting_url_map=*/{{"event_type", report_destination2_}});
EXPECT_EQ(test_url_loader_factory_.NumPending(), 3);
ValidateRequest((*test_url_loader_factory_.pending_requests())[2].request,
report_destination2_, "event_data");
reporter->OnUrlMappingReady(
blink::FencedFrame::ReportingDestination::kBuyer,
/*reporting_url_map=*/{{"event_type", report_destination3_}});
EXPECT_EQ(test_url_loader_factory_.NumPending(), 4);
ValidateRequest((*test_url_loader_factory_.pending_requests())[3].request,
report_destination3_, "event_data");
}
// Test reports in the FLEDGE case, where reporting URL maps are received after
// SendReport() calls, but no reports are sent because of errors (bad URL, no
// URL, missing event types). No error messages are generated in this case
// because there's nowhere to pass them
TEST_F(FencedFrameReporterTest, SendFledgeReportsBeforeMapsReceivedWithErrors) {
auto attribution_data_host_manager =
std::make_unique<MockAttributionDataHostManager>();
auto* mock_attribution_data_host_manager =
attribution_data_host_manager.get();
auto mock_manager = std::make_unique<MockAttributionManager>();
mock_manager->SetDataHostManager(std::move(attribution_data_host_manager));
static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition())
->OverrideAttributionManagerForTesting(std::move(mock_manager));
// `AttributionDataHostManager` is notified for the errors.
EXPECT_CALL(*mock_attribution_data_host_manager,
NotifyFencedFrameReportingBeaconData(_, _, _, /*headers=*/nullptr,
/*is_final_response=*/true))
.Times(3);
scoped_refptr<FencedFrameReporter> reporter =
FencedFrameReporter::CreateForFledge(
shared_url_loader_factory(), attribution_manager(),
/*direct_seller_is_seller=*/false, &private_aggregation_manager_,
main_frame_origin_,
/*winner_origin=*/report_destination_origin_);
// SendReport() is called, and then a mapping is received that doesn't have
// the report's event type. No request should be made.
std::string error_message;
EXPECT_TRUE(reporter->SendReport(
"event_type2", "event_data",
blink::FencedFrame::ReportingDestination::kSeller, main_rfh_impl(),
network::AttributionReportingRuntimeFeatures(), error_message));
reporter->OnUrlMappingReady(
blink::FencedFrame::ReportingDestination::kSeller,
/*reporting_url_map=*/{{"event_type", report_destination_}});
EXPECT_EQ(test_url_loader_factory_.NumPending(), 0);
// SendReport() is called, and then a mapping is received that maps the
// report's event type to a data URL. No request should be made.
EXPECT_TRUE(reporter->SendReport(
"event_type", "event_data",
blink::FencedFrame::ReportingDestination::kComponentSeller,
main_rfh_impl(), network::AttributionReportingRuntimeFeatures(),
error_message));
reporter->OnUrlMappingReady(
blink::FencedFrame::ReportingDestination::kComponentSeller,
/*reporting_url_map=*/{
{"event_type", GURL("data:,only http is allowed")}});
EXPECT_EQ(test_url_loader_factory_.NumPending(), 0);
// SendReport() is called, and then a mapping is received with an empty map.
// No request should be made.
EXPECT_TRUE(reporter->SendReport(
"event_type", "event_data",
blink::FencedFrame::ReportingDestination::kBuyer, main_rfh_impl(),
network::AttributionReportingRuntimeFeatures(), error_message));
reporter->OnUrlMappingReady(blink::FencedFrame::ReportingDestination::kBuyer,
/*reporting_url_map=*/{});
EXPECT_EQ(test_url_loader_factory_.NumPending(), 0);
}
// Test reports in the FLEDGE case, where reporting URL map is never received.
TEST_F(FencedFrameReporterTest, SendFledgeReportsNoMapReceived) {
auto attribution_data_host_manager =
std::make_unique<MockAttributionDataHostManager>();
auto* mock_attribution_data_host_manager =
attribution_data_host_manager.get();
auto mock_manager = std::make_unique<MockAttributionManager>();
mock_manager->SetDataHostManager(std::move(attribution_data_host_manager));
static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition())
->OverrideAttributionManagerForTesting(std::move(mock_manager));
// `AttributionDataHostManager` is notified for the pending events.
EXPECT_CALL(*mock_attribution_data_host_manager,
NotifyFencedFrameReportingBeaconData(_, _, _, /*headers=*/nullptr,
/*is_final_response=*/true));
{
scoped_refptr<FencedFrameReporter> reporter =
FencedFrameReporter::CreateForFledge(
shared_url_loader_factory(), attribution_manager(),
/*direct_seller_is_seller=*/false, &private_aggregation_manager_,
main_frame_origin_,
/*winner_origin=*/report_destination_origin_);
// SendReport() is called, but a mapping is never received.
std::string error_message;
EXPECT_TRUE(reporter->SendReport(
"event_type2", "event_data",
blink::FencedFrame::ReportingDestination::kSeller, main_rfh_impl(),
network::AttributionReportingRuntimeFeatures(), error_message));
EXPECT_EQ(test_url_loader_factory_.NumPending(), 0);
}
}
// Test sending non-reserved private aggregation requests, when events from
// fenced frame is received after FLEDGE non-reserved PA requests are ready.
TEST_F(FencedFrameReporterTest, FledgeEventsReceivedAfterRequestsReady) {
scoped_refptr<FencedFrameReporter> reporter =
FencedFrameReporter::CreateForFledge(
shared_url_loader_factory(), attribution_manager(),
/*direct_seller_is_seller=*/false, &private_aggregation_manager_,
main_frame_origin_,
/*winner_origin=*/report_destination_origin_);
// Receive all non-reserved private aggregation requests.
std::map<std::string, PrivateAggregationRequests>
private_aggregation_event_map;
private_aggregation_event_map["event_type"].push_back(
kPrivateAggregationRequest.Clone());
private_aggregation_event_map["event_type2"].push_back(
kPrivateAggregationRequest2.Clone());
std::map<std::string, PrivateAggregationRequests>
private_aggregation_event_map2;
private_aggregation_event_map2["event_type"].push_back(
kPrivateAggregationRequest2.Clone());
private_aggregation_event_map2["event_type3"].push_back(
kPrivateAggregationRequest2.Clone());
reporter->OnForEventPrivateAggregationRequestsReceived(
std::move(private_aggregation_event_map));
reporter->OnForEventPrivateAggregationRequestsReceived(
std::move(private_aggregation_event_map2));
// Reporter received private_aggregation_event_map.
EXPECT_THAT(
reporter->GetPrivateAggregationEventMapForTesting(),
testing::UnorderedElementsAre(
testing::Pair("event_type",
ElementsAreRequests(kPrivateAggregationRequest,
kPrivateAggregationRequest2)),
testing::Pair("event_type2",
ElementsAreRequests(kPrivateAggregationRequest2)),
testing::Pair("event_type3",
ElementsAreRequests(kPrivateAggregationRequest2))));
// No event received from fenced frame yet, so no PA request gets sent.
EXPECT_TRUE(
private_aggregation_manager_.TakePrivateAggregationRequests().empty());
// Each call to SendPrivateAggregationRequestsForEvent() should send
// corresponding PA requests immediately, and the entry for the event type
// should be removed from reporter's private_aggregation_event_map.
reporter->SendPrivateAggregationRequestsForEvent("event_type");
EXPECT_THAT(private_aggregation_manager_.TakePrivateAggregationRequests(),
testing::UnorderedElementsAre(testing::Pair(
report_destination_origin_,
ElementsAreRequests(kPrivateAggregationRequest,
kPrivateAggregationRequest2))));
EXPECT_THAT(
reporter->GetPrivateAggregationEventMapForTesting(),
testing::UnorderedElementsAre(
testing::Pair("event_type2",
ElementsAreRequests(kPrivateAggregationRequest2)),
testing::Pair("event_type3",
ElementsAreRequests(kPrivateAggregationRequest2))));
reporter->SendPrivateAggregationRequestsForEvent("event_type2");
EXPECT_THAT(private_aggregation_manager_.TakePrivateAggregationRequests(),
testing::UnorderedElementsAre(testing::Pair(
report_destination_origin_,
ElementsAreRequests(kPrivateAggregationRequest2))));
EXPECT_THAT(
reporter->GetPrivateAggregationEventMapForTesting(),
testing::UnorderedElementsAre(testing::Pair(
"event_type3", ElementsAreRequests(kPrivateAggregationRequest2))));
// Private aggregation requests for "event_type" has already been sent and
// cleared, so no more such requests for the type to send when receiving it
// again.
reporter->SendPrivateAggregationRequestsForEvent("event_type");
EXPECT_THAT(private_aggregation_manager_.TakePrivateAggregationRequests(),
testing::UnorderedElementsAre());
// No private aggregation requests for "event_type4", so there's no effect
// when "event_type4" is received.
reporter->SendPrivateAggregationRequestsForEvent("event_type4");
EXPECT_THAT(private_aggregation_manager_.TakePrivateAggregationRequests(),
testing::UnorderedElementsAre());
}
// Test sending non-reserved private aggregation requests, when events from
// fenced frame is received before FLEDGE non-reserved PA requests are ready.
TEST_F(FencedFrameReporterTest, FledgeEventsReceivedBeforeRequestsReady) {
scoped_refptr<FencedFrameReporter> reporter =
FencedFrameReporter::CreateForFledge(
shared_url_loader_factory(), attribution_manager(),
/*direct_seller_is_seller=*/false, &private_aggregation_manager_,
main_frame_origin_,
/*winner_origin=*/report_destination_origin_);
// Calls SendPrivateAggregationRequestsForEvent() with event types. The event
// types should be queued, since non-reserved private aggregation requests
// haven't been received yet.
reporter->SendPrivateAggregationRequestsForEvent("event_type");
reporter->SendPrivateAggregationRequestsForEvent("event_type");
reporter->SendPrivateAggregationRequestsForEvent("event_type3");
// ReceivedPaEvents is a std::set, so duplicate event types are only stored
// once.
EXPECT_THAT(reporter->GetReceivedPaEventsForTesting(),
testing::UnorderedElementsAre("event_type", "event_type3"));
EXPECT_TRUE(
private_aggregation_manager_.TakePrivateAggregationRequests().empty());
// Receive all non-reserved private aggregation requests.
std::map<std::string, PrivateAggregationRequests>
private_aggregation_event_map;
private_aggregation_event_map["event_type"].push_back(
kPrivateAggregationRequest.Clone());
private_aggregation_event_map["event_type2"].push_back(
kPrivateAggregationRequest2.Clone());
reporter->OnForEventPrivateAggregationRequestsReceived(
std::move(private_aggregation_event_map));
// `received_pa_events_` is kept, in case needed for new private aggregation
// requests from reportWin().
EXPECT_THAT(reporter->GetReceivedPaEventsForTesting(),
testing::UnorderedElementsAre("event_type", "event_type3"));
// All pending pa events' PA requests in private_aggregation_event_map should
// be sent after private_aggregation_event_map is ready.
EXPECT_THAT(private_aggregation_manager_.TakePrivateAggregationRequests(),
testing::UnorderedElementsAre(testing::Pair(
report_destination_origin_,
ElementsAreRequests(kPrivateAggregationRequest))));
// Calling SendPrivateAggregationRequestsForEvent() should send
// corresponding PA requests immediately.
reporter->SendPrivateAggregationRequestsForEvent("event_type2");
EXPECT_THAT(private_aggregation_manager_.TakePrivateAggregationRequests(),
testing::UnorderedElementsAre(testing::Pair(
report_destination_origin_,
ElementsAreRequests(kPrivateAggregationRequest2))));
// Although requests for "event_type2" are sent immediately, still store
// "event_type2" in reporter's `received_pa_events_`, so that further
// received PA requests of the type can still be triggered.
EXPECT_THAT(reporter->GetReceivedPaEventsForTesting(),
testing::UnorderedElementsAre("event_type", "event_type3",
"event_type2"));
// Private aggregation requests for "event_type" has already been sent and
// cleared, so no more such requests for the type to sends.
reporter->SendPrivateAggregationRequestsForEvent("event_type");
EXPECT_THAT(private_aggregation_manager_.TakePrivateAggregationRequests(),
testing::UnorderedElementsAre());
// Receive more non-reserved private aggregation requests. It happens when
// reportWin() completes and then
// OnForEventPrivateAggregationRequestsReceived() is called.
std::map<std::string, PrivateAggregationRequests>
private_aggregation_event_map2;
private_aggregation_event_map2["event_type"].push_back(
kPrivateAggregationRequest2.Clone());
private_aggregation_event_map2["event_type2"].push_back(
kPrivateAggregationRequest.Clone());
// We expect two calls to `SendHistogramReport()` given the two events.
private_aggregation_manager_.set_allow_multiple_calls_per_origin(true);
reporter->OnForEventPrivateAggregationRequestsReceived(
std::move(private_aggregation_event_map2));
// Requests for both event types are sent immediately since there were such
// pending PA events.
EXPECT_THAT(private_aggregation_manager_.TakePrivateAggregationRequests(),
testing::UnorderedElementsAre(testing::Pair(
report_destination_origin_,
ElementsAreRequests(kPrivateAggregationRequest,
kPrivateAggregationRequest2))));
}
// FencedFrameReporter's `private_aggregation_manager` is nullptr but fenced
// frame sends events unexpectedly. This could happen if the renderer is
// compromised. Should just ignore the events.
TEST_F(FencedFrameReporterTest, FledgeEventsReceivedUnexpectedly) {
scoped_refptr<FencedFrameReporter> reporter =
FencedFrameReporter::CreateForFledge(
shared_url_loader_factory(), attribution_manager(),
/*direct_seller_is_seller=*/false,
/*private_aggregation_manager=*/nullptr, main_frame_origin_,
/*winner_origin=*/report_destination_origin_);
// Calls SendPrivateAggregationRequestsForEvent() with "event_type".
// "event_type" should be ignored and not be queued.
reporter->SendPrivateAggregationRequestsForEvent("event_type");
EXPECT_TRUE(reporter->GetReceivedPaEventsForTesting().empty());
EXPECT_TRUE(
private_aggregation_manager_.TakePrivateAggregationRequests().empty());
}
TEST_F(FencedFrameReporterTest, AttributionManagerShutDown_NoCrash) {
EXPECT_TRUE(attribution_manager());
scoped_refptr<FencedFrameReporter> reporter =
FencedFrameReporter::CreateForSharedStorage(
shared_url_loader_factory(), attribution_manager(),
/*reporting_url_map=*/
{{"event_type", report_destination_}});
// Make a report.
std::string error_message;
EXPECT_TRUE(reporter->SendReport(
"event_type", "event_data",
blink::FencedFrame::ReportingDestination::kSharedStorageSelectUrl,
main_rfh_impl(), network::AttributionReportingRuntimeFeatures(),
error_message));
EXPECT_EQ(test_url_loader_factory_.NumPending(), 1);
ValidateRequest((*test_url_loader_factory_.pending_requests())[0].request,
report_destination_, "event_data");
ShutDownAttributionManager();
EXPECT_FALSE(attribution_manager());
EXPECT_TRUE(test_url_loader_factory_.SimulateResponseForPendingRequest(
report_destination_.spec(), ""));
}
} // namespace
} // namespace content