Add Trusted Signals Server KVv2 Support - Bidding signal request
Add support to Trusted Signals Server KVv2 for trusted bidding signals request CBOR encoding. Bug: 337917489 Change-Id: I53d8026fa4fa65979fbb8f4437b379d9662f2c9c Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5521862 Reviewed-by: mmenke <mmenke@chromium.org> Commit-Queue: Tianyang Xu <xtlsheep@google.com> Reviewed-by: Daniel Cheng <dcheng@chromium.org> Cr-Commit-Position: refs/heads/main@{#1327732}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
23ed148d73
commit
c0d554350d
@ -86,6 +86,8 @@ source_set("auction_worklet") {
|
||||
"shared_storage_bindings.h",
|
||||
"trusted_signals.cc",
|
||||
"trusted_signals.h",
|
||||
"trusted_signals_kvv2_helper.cc",
|
||||
"trusted_signals_kvv2_helper.h",
|
||||
"trusted_signals_request_manager.cc",
|
||||
"trusted_signals_request_manager.h",
|
||||
"webidl_compat.cc",
|
||||
@ -107,6 +109,7 @@ source_set("auction_worklet") {
|
||||
deps = [
|
||||
":protocol_sources",
|
||||
"//base",
|
||||
"//components/cbor:cbor",
|
||||
"//content:export",
|
||||
"//content/common",
|
||||
"//content/public/common:common_sources",
|
||||
@ -156,6 +159,7 @@ source_set("tests") {
|
||||
"direct_from_seller_signals_requester_unittest.cc",
|
||||
"public/cpp/auction_downloader_unittest.cc",
|
||||
"seller_worklet_unittest.cc",
|
||||
"trusted_signals_kvv2_helper_unittest.cc",
|
||||
"trusted_signals_request_manager_unittest.cc",
|
||||
"trusted_signals_unittest.cc",
|
||||
"webidl_compat_unittest.cc",
|
||||
@ -179,6 +183,7 @@ source_set("tests") {
|
||||
deps = [
|
||||
"//base",
|
||||
"//base/test:test_support",
|
||||
"//components/cbor:cbor",
|
||||
"//content/common:for_content_tests",
|
||||
"//content/public/common:common",
|
||||
"//gin",
|
||||
|
@ -3,6 +3,7 @@
|
||||
# to this service, make sure they're not inadvertently breaking these
|
||||
# isolation requirements. Please thoroughly discuss additions with OWNERS.
|
||||
include_rules = [
|
||||
"+components/cbor",
|
||||
"+gin",
|
||||
"+net",
|
||||
"+services/network/public",
|
||||
|
@ -139,81 +139,6 @@ std::map<std::string, AuctionV8Helper::SerializedValue> ParseChildKeyValueMap(
|
||||
return ParseKeyValueMap(v8_helper, named_object_value.As<v8::Object>(), keys);
|
||||
}
|
||||
|
||||
// Attempts to parse the `priorityVector` value in `v8_per_interest_group_data`,
|
||||
// expecting it to be a string-to-number mapping. Returns the parsed mapping, or
|
||||
// nullopt upon failure to find or parse the field. Any case where
|
||||
// `priorityVector` exists and is an object is considered a success, even if
|
||||
// it's empty, or some/all keys in it are mapped to things other than numbers.
|
||||
std::optional<TrustedSignals::Result::PriorityVector> ParsePriorityVector(
|
||||
AuctionV8Helper* v8_helper,
|
||||
v8::Local<v8::Object> v8_per_interest_group_data) {
|
||||
v8::Local<v8::Value> priority_vector_value;
|
||||
if (!v8_per_interest_group_data
|
||||
->Get(v8_helper->scratch_context(),
|
||||
v8_helper->CreateStringFromLiteral("priorityVector"))
|
||||
.ToLocal(&priority_vector_value) ||
|
||||
!priority_vector_value->IsObject() ||
|
||||
// Arrays are considered objects, so check explicitly for them.
|
||||
priority_vector_value->IsArray()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
v8::Local<v8::Object> priority_vector_object =
|
||||
priority_vector_value.As<v8::Object>();
|
||||
|
||||
v8::Local<v8::Array> priority_vector_keys;
|
||||
if (!priority_vector_object->GetOwnPropertyNames(v8_helper->scratch_context())
|
||||
.ToLocal(&priority_vector_keys)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Put together a list to construct the returned `flat_map` with, since
|
||||
// insertion is O(n) while construction is O(n log n).
|
||||
std::vector<std::pair<std::string, double>> priority_vector_pairs;
|
||||
for (uint32_t i = 0; i < priority_vector_keys->Length(); ++i) {
|
||||
v8::Local<v8::Value> v8_key;
|
||||
std::string key;
|
||||
if (!priority_vector_keys->Get(v8_helper->scratch_context(), i)
|
||||
.ToLocal(&v8_key) ||
|
||||
!v8_key->IsString() ||
|
||||
!gin::ConvertFromV8(v8_helper->isolate(), v8_key, &key)) {
|
||||
continue;
|
||||
}
|
||||
v8::Local<v8::Value> v8_value;
|
||||
double value;
|
||||
if (!priority_vector_object->Get(v8_helper->scratch_context(), v8_key)
|
||||
.ToLocal(&v8_value) ||
|
||||
!v8_value->IsNumber() ||
|
||||
!v8_value->NumberValue(v8_helper->scratch_context()).To(&value)) {
|
||||
continue;
|
||||
}
|
||||
priority_vector_pairs.emplace_back(std::move(key), value);
|
||||
}
|
||||
return TrustedSignals::Result::PriorityVector(
|
||||
std::move(priority_vector_pairs));
|
||||
}
|
||||
|
||||
// Attempts to parse the `updateIfOlderThanMs` value in
|
||||
// `v8_per_interest_group_data`, expecting it to be a double duration in
|
||||
// milliseconds. Returns the time delta, or nullopt upon failure to find or
|
||||
// parse the value.
|
||||
std::optional<base::TimeDelta> ParseUpdateIfOlderThan(
|
||||
AuctionV8Helper* v8_helper,
|
||||
v8::Local<v8::Object> v8_per_interest_group_data) {
|
||||
v8::Local<v8::Value> update_if_older_than_ms_value;
|
||||
double update_if_older_than_ms;
|
||||
if (!v8_per_interest_group_data
|
||||
->Get(v8_helper->scratch_context(),
|
||||
v8_helper->CreateStringFromLiteral("updateIfOlderThanMs"))
|
||||
.ToLocal(&update_if_older_than_ms_value) ||
|
||||
!update_if_older_than_ms_value->IsNumber() ||
|
||||
!update_if_older_than_ms_value->NumberValue(v8_helper->scratch_context())
|
||||
.To(&update_if_older_than_ms)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return base::Milliseconds(update_if_older_than_ms);
|
||||
}
|
||||
|
||||
// Attempts to parse the `perInterestGroupData` value in `v8_object`, extracting
|
||||
// the `priorityVector` fields of all interest group in `interest_group_names`,
|
||||
// along with `updateIfOlderThanMs`, and putting them all in the returned
|
||||
@ -256,13 +181,14 @@ TrustedSignals::Result::PerInterestGroupDataMap ParsePerInterestGroupMap(
|
||||
v8::Local<v8::Object> v8_per_interest_group_data =
|
||||
per_interest_group_data_value.As<v8::Object>();
|
||||
std::optional<TrustedSignals::Result::PriorityVector> priority_vector =
|
||||
ParsePriorityVector(v8_helper, v8_per_interest_group_data);
|
||||
TrustedSignals::ParsePriorityVector(v8_helper,
|
||||
v8_per_interest_group_data);
|
||||
std::optional<base::TimeDelta> update_if_older_than;
|
||||
|
||||
if (base::FeatureList::IsEnabled(
|
||||
features::kInterestGroupUpdateIfOlderThan)) {
|
||||
update_if_older_than =
|
||||
ParseUpdateIfOlderThan(v8_helper, v8_per_interest_group_data);
|
||||
update_if_older_than = TrustedSignals::ParseUpdateIfOlderThan(
|
||||
v8_helper, v8_per_interest_group_data);
|
||||
}
|
||||
if (priority_vector || update_if_older_than) {
|
||||
out.emplace(interest_group_name, TrustedSignals::Result::PerGroupData(
|
||||
@ -526,6 +452,75 @@ std::unique_ptr<TrustedSignals> TrustedSignals::LoadScoringSignals(
|
||||
return trusted_signals;
|
||||
}
|
||||
|
||||
std::optional<TrustedSignals::Result::PriorityVector>
|
||||
TrustedSignals::ParsePriorityVector(
|
||||
AuctionV8Helper* v8_helper,
|
||||
v8::Local<v8::Object> v8_per_interest_group_data) {
|
||||
DCHECK(v8_helper->v8_runner()->RunsTasksInCurrentSequence());
|
||||
v8::Local<v8::Value> priority_vector_value;
|
||||
if (!v8_per_interest_group_data
|
||||
->Get(v8_helper->scratch_context(),
|
||||
v8_helper->CreateStringFromLiteral("priorityVector"))
|
||||
.ToLocal(&priority_vector_value) ||
|
||||
!priority_vector_value->IsObject() ||
|
||||
// Arrays are considered objects, so check explicitly for them.
|
||||
priority_vector_value->IsArray()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
v8::Local<v8::Object> priority_vector_object =
|
||||
priority_vector_value.As<v8::Object>();
|
||||
|
||||
v8::Local<v8::Array> priority_vector_keys;
|
||||
if (!priority_vector_object->GetOwnPropertyNames(v8_helper->scratch_context())
|
||||
.ToLocal(&priority_vector_keys)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Put together a list to construct the returned `flat_map` with, since
|
||||
// insertion is O(n) while construction is O(n log n).
|
||||
std::vector<std::pair<std::string, double>> priority_vector_pairs;
|
||||
for (uint32_t i = 0; i < priority_vector_keys->Length(); ++i) {
|
||||
v8::Local<v8::Value> v8_key;
|
||||
std::string key;
|
||||
if (!priority_vector_keys->Get(v8_helper->scratch_context(), i)
|
||||
.ToLocal(&v8_key) ||
|
||||
!v8_key->IsString() ||
|
||||
!gin::ConvertFromV8(v8_helper->isolate(), v8_key, &key)) {
|
||||
continue;
|
||||
}
|
||||
v8::Local<v8::Value> v8_value;
|
||||
double value;
|
||||
if (!priority_vector_object->Get(v8_helper->scratch_context(), v8_key)
|
||||
.ToLocal(&v8_value) ||
|
||||
!v8_value->IsNumber() ||
|
||||
!v8_value->NumberValue(v8_helper->scratch_context()).To(&value)) {
|
||||
continue;
|
||||
}
|
||||
priority_vector_pairs.emplace_back(std::move(key), value);
|
||||
}
|
||||
return TrustedSignals::Result::PriorityVector(
|
||||
std::move(priority_vector_pairs));
|
||||
}
|
||||
|
||||
std::optional<base::TimeDelta> TrustedSignals::ParseUpdateIfOlderThan(
|
||||
AuctionV8Helper* v8_helper,
|
||||
v8::Local<v8::Object> v8_per_interest_group_data) {
|
||||
DCHECK(v8_helper->v8_runner()->RunsTasksInCurrentSequence());
|
||||
v8::Local<v8::Value> update_if_older_than_ms_value;
|
||||
double update_if_older_than_ms;
|
||||
if (!v8_per_interest_group_data
|
||||
->Get(v8_helper->scratch_context(),
|
||||
v8_helper->CreateStringFromLiteral("updateIfOlderThanMs"))
|
||||
.ToLocal(&update_if_older_than_ms_value) ||
|
||||
!update_if_older_than_ms_value->IsNumber() ||
|
||||
!update_if_older_than_ms_value->NumberValue(v8_helper->scratch_context())
|
||||
.To(&update_if_older_than_ms)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return base::Milliseconds(update_if_older_than_ms);
|
||||
}
|
||||
|
||||
TrustedSignals::TrustedSignals(
|
||||
std::optional<std::set<std::string>> interest_group_names,
|
||||
std::optional<std::set<std::string>> bidding_signals_keys,
|
||||
|
@ -208,6 +208,25 @@ class CONTENT_EXPORT TrustedSignals {
|
||||
scoped_refptr<AuctionV8Helper> v8_helper,
|
||||
LoadSignalsCallback load_signals_callback);
|
||||
|
||||
// Attempts to parse the `priorityVector` value in
|
||||
// `v8_per_interest_group_data`,
|
||||
// expecting it to be a string-to-number mapping. Returns the parsed mapping,
|
||||
// or nullopt upon failure to find or parse the field. Any case where
|
||||
// `priorityVector` exists and is an object is considered a success, even if
|
||||
// it's empty, or some/all keys in it are mapped to things other than numbers.
|
||||
// Must be called on `v8_helper`'s sequence.
|
||||
static std::optional<TrustedSignals::Result::PriorityVector>
|
||||
ParsePriorityVector(AuctionV8Helper* v8_helper,
|
||||
v8::Local<v8::Object> v8_per_interest_group_data);
|
||||
|
||||
// Attempts to parse the `updateIfOlderThanMs` value in
|
||||
// `v8_per_interest_group_data`, expecting it to be a double duration in
|
||||
// milliseconds. Returns the time delta, or nullopt upon failure to find or
|
||||
// parse the value. Must be called on `v8_helper`'s sequence.
|
||||
static std::optional<base::TimeDelta> ParseUpdateIfOlderThan(
|
||||
AuctionV8Helper* v8_helper,
|
||||
v8::Local<v8::Object> v8_per_interest_group_data);
|
||||
|
||||
private:
|
||||
TrustedSignals(
|
||||
std::optional<std::set<std::string>> interest_group_names,
|
||||
|
314
content/services/auction_worklet/trusted_signals_kvv2_helper.cc
Normal file
314
content/services/auction_worklet/trusted_signals_kvv2_helper.cc
Normal file
@ -0,0 +1,314 @@
|
||||
// Copyright 2024 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/services/auction_worklet/trusted_signals_kvv2_helper.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "base/check.h"
|
||||
#include "base/containers/span.h"
|
||||
#include "base/containers/span_writer.h"
|
||||
#include "base/json/json_reader.h"
|
||||
#include "base/memory/scoped_refptr.h"
|
||||
#include "base/numerics/safe_conversions.h"
|
||||
#include "base/strings/strcat.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/types/expected.h"
|
||||
#include "base/types/optional_ref.h"
|
||||
#include "components/cbor/reader.h"
|
||||
#include "components/cbor/values.h"
|
||||
#include "components/cbor/writer.h"
|
||||
#include "content/common/features.h"
|
||||
#include "content/services/auction_worklet/auction_v8_helper.h"
|
||||
#include "content/services/auction_worklet/trusted_signals.h"
|
||||
#include "content/services/auction_worklet/trusted_signals_request_manager.h"
|
||||
#include "url/origin.h"
|
||||
|
||||
namespace auction_worklet {
|
||||
|
||||
namespace {
|
||||
// Constants for POST request body.
|
||||
constexpr std::array<std::string_view, 2> kAcceptCompression = {"none", "gzip"};
|
||||
constexpr size_t kFramingHeaderSize = 5; // bytes
|
||||
|
||||
// Add hardcoded `acceptCompression` to request body.
|
||||
void AddPostRequestConstants(cbor::Value::MapValue& request_map_value) {
|
||||
// acceptCompression
|
||||
cbor::Value::ArrayValue accept_compression(kAcceptCompression.begin(),
|
||||
kAcceptCompression.end());
|
||||
request_map_value.try_emplace(cbor::Value("acceptCompression"),
|
||||
cbor::Value(std::move(accept_compression)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
std::string CreateRequestBody(cbor::Value::MapValue request_map_value) {
|
||||
cbor::Value message(std::move(request_map_value));
|
||||
std::optional<std::vector<uint8_t>> maybe_msg = cbor::Writer::Write(message);
|
||||
CHECK(maybe_msg.has_value());
|
||||
|
||||
// TODO(crbug.com/337917489): Skip padding for now, and will add padding after
|
||||
// end to end tests.
|
||||
std::string request_body;
|
||||
request_body.resize(kFramingHeaderSize + maybe_msg->size());
|
||||
base::SpanWriter writer(
|
||||
base::as_writable_bytes(base::make_span(request_body)));
|
||||
// First byte includes version and compression format. Always set first bytes
|
||||
// to 0x00 because request body is not compressed.
|
||||
writer.WriteU8BigEndian(0x00);
|
||||
writer.WriteU32BigEndian(base::checked_cast<int>(maybe_msg->size()));
|
||||
writer.Write(base::as_bytes(base::make_span(*maybe_msg)));
|
||||
|
||||
return request_body;
|
||||
}
|
||||
|
||||
// Creates a single entry for the "arguments" array of a partition, with a
|
||||
// single tag and a variable number of data values.
|
||||
cbor::Value MakeArgument(std::string_view tag,
|
||||
const std::set<std::string>& data) {
|
||||
cbor::Value::MapValue argument;
|
||||
|
||||
cbor::Value::ArrayValue tags;
|
||||
tags.emplace_back(tag);
|
||||
|
||||
cbor::Value::ArrayValue cbor_data;
|
||||
for (const auto& element : data) {
|
||||
cbor_data.emplace_back(element);
|
||||
}
|
||||
|
||||
argument.emplace(cbor::Value("tags"), cbor::Value(std::move(tags)));
|
||||
argument.emplace(cbor::Value("data"), cbor::Value(std::move(cbor_data)));
|
||||
return cbor::Value(std::move(argument));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TrustedSignalsKVv2RequestHelper::TrustedSignalsKVv2RequestHelper(
|
||||
std::string post_request_body)
|
||||
: post_request_body_(std::move(post_request_body)) {}
|
||||
|
||||
TrustedSignalsKVv2RequestHelper::TrustedSignalsKVv2RequestHelper(
|
||||
TrustedSignalsKVv2RequestHelper&&) = default;
|
||||
|
||||
TrustedSignalsKVv2RequestHelper& TrustedSignalsKVv2RequestHelper::operator=(
|
||||
TrustedSignalsKVv2RequestHelper&&) = default;
|
||||
|
||||
TrustedSignalsKVv2RequestHelper::~TrustedSignalsKVv2RequestHelper() = default;
|
||||
|
||||
std::string TrustedSignalsKVv2RequestHelper::TakePostRequestBody() {
|
||||
return std::move(post_request_body_);
|
||||
}
|
||||
|
||||
TrustedSignalsKVv2RequestHelperBuilder ::
|
||||
~TrustedSignalsKVv2RequestHelperBuilder() = default;
|
||||
|
||||
TrustedSignalsKVv2RequestHelperBuilder::TrustedSignalsKVv2RequestHelperBuilder(
|
||||
std::string hostname,
|
||||
GURL trusted_signals_url,
|
||||
std::optional<int> experiment_group_id)
|
||||
: hostname_(std::move(hostname)),
|
||||
trusted_signals_url_(std::move(trusted_signals_url)),
|
||||
experiment_group_id_(experiment_group_id) {}
|
||||
|
||||
TrustedSignalsKVv2RequestHelperBuilder::Partition::Partition() = default;
|
||||
|
||||
TrustedSignalsKVv2RequestHelperBuilder::Partition::Partition(
|
||||
int partition_id,
|
||||
const std::string& interest_group_name,
|
||||
const std::set<std::string>& bidding_keys,
|
||||
const std::string& hostname,
|
||||
const std::optional<int>& experiment_group_id,
|
||||
std::pair<std::string, std::string> trusted_bidding_signals_slot_size_param)
|
||||
: partition_id(partition_id),
|
||||
interest_group_names({interest_group_name}),
|
||||
bidding_signals_keys(bidding_keys) {
|
||||
additional_params.Set("hostname", hostname);
|
||||
if (experiment_group_id.has_value()) {
|
||||
additional_params.Set("experimentGroupId",
|
||||
base::NumberToString(experiment_group_id.value()));
|
||||
}
|
||||
additional_params.Set(trusted_bidding_signals_slot_size_param.first,
|
||||
trusted_bidding_signals_slot_size_param.second);
|
||||
}
|
||||
|
||||
TrustedSignalsKVv2RequestHelperBuilder::Partition::Partition(Partition&&) =
|
||||
default;
|
||||
|
||||
TrustedSignalsKVv2RequestHelperBuilder::Partition::~Partition() = default;
|
||||
|
||||
TrustedSignalsKVv2RequestHelperBuilder::Partition&
|
||||
TrustedSignalsKVv2RequestHelperBuilder::Partition::operator=(Partition&&) =
|
||||
default;
|
||||
|
||||
TrustedBiddingSignalsKVv2RequestHelperBuilder::
|
||||
TrustedBiddingSignalsKVv2RequestHelperBuilder(
|
||||
const std::string& hostname,
|
||||
const GURL& trusted_signals_url,
|
||||
std::optional<int> experiment_group_id,
|
||||
const std::string& trusted_bidding_signals_slot_size_param)
|
||||
: TrustedSignalsKVv2RequestHelperBuilder(hostname,
|
||||
trusted_signals_url,
|
||||
experiment_group_id) {
|
||||
// Parse trusted bidding signals slot size parameter to a pair, which
|
||||
// parameter key is first and value is second.
|
||||
if (!trusted_bidding_signals_slot_size_param.empty()) {
|
||||
size_t pos = trusted_bidding_signals_slot_size_param.find('=');
|
||||
CHECK_NE(pos, std::string::npos);
|
||||
std::string key = trusted_bidding_signals_slot_size_param.substr(0, pos);
|
||||
std::string value = trusted_bidding_signals_slot_size_param.substr(pos + 1);
|
||||
CHECK(key == "slotSize" || key == "allSlotsRequestedSizes");
|
||||
trusted_bidding_signals_slot_size_param_ = {std::move(key),
|
||||
std::move(value)};
|
||||
}
|
||||
}
|
||||
|
||||
TrustedBiddingSignalsKVv2RequestHelperBuilder::
|
||||
~TrustedBiddingSignalsKVv2RequestHelperBuilder() = default;
|
||||
|
||||
TrustedSignalsKVv2RequestHelperBuilder::IsolationIndex
|
||||
TrustedBiddingSignalsKVv2RequestHelperBuilder::AddTrustedSignalsRequest(
|
||||
base::optional_ref<const std::string> interest_group_name,
|
||||
base::optional_ref<const std::set<std::string>> bidding_keys,
|
||||
base::optional_ref<const url::Origin> interest_group_join_origin,
|
||||
std::optional<blink::mojom::InterestGroup::ExecutionMode> execution_mode) {
|
||||
DCHECK(interest_group_name.has_value());
|
||||
DCHECK(bidding_keys.has_value());
|
||||
DCHECK(interest_group_join_origin.has_value());
|
||||
DCHECK(execution_mode.has_value());
|
||||
|
||||
int partition_id;
|
||||
int compression_group_id;
|
||||
|
||||
// Find or create a compression group.
|
||||
auto join_origin_compression_id_it =
|
||||
join_origin_compression_id_map().find(interest_group_join_origin.value());
|
||||
CompressionGroup* compression_group_ptr;
|
||||
if (join_origin_compression_id_it == join_origin_compression_id_map().end()) {
|
||||
// Create a new compression group keyed by joining origin.
|
||||
compression_group_id = next_compression_group_id();
|
||||
join_origin_compression_id_map().emplace(interest_group_join_origin.value(),
|
||||
compression_group_id);
|
||||
compression_group_ptr =
|
||||
&compression_groups().try_emplace(compression_group_id).first->second;
|
||||
} else {
|
||||
// Found existing compression group.
|
||||
compression_group_id = join_origin_compression_id_it->second;
|
||||
DCHECK_EQ(1u, compression_groups().count(compression_group_id));
|
||||
compression_group_ptr = &compression_groups()[compression_group_id];
|
||||
}
|
||||
|
||||
// Get partition id based on execution mode.
|
||||
auto partition_it = compression_group_ptr->end();
|
||||
if (execution_mode ==
|
||||
blink::InterestGroup::ExecutionMode::kGroupedByOriginMode) {
|
||||
// Put current interest group to the existing "group-by-origin partition
|
||||
// which is always index 0.
|
||||
partition_id = 0;
|
||||
partition_it = compression_group_ptr->find(partition_id);
|
||||
} else {
|
||||
// If execution mode is not `kGroupedByOriginMode`, we assign new partition
|
||||
// start from index 1. To make partition id consecutive, we use compression
|
||||
// group size if there is a "group-by-origin" partition, otherwise use size
|
||||
// plus 1.
|
||||
if (compression_group_ptr->contains(0)) {
|
||||
partition_id = compression_group_ptr->size();
|
||||
} else {
|
||||
partition_id = compression_group_ptr->size() + 1;
|
||||
}
|
||||
DCHECK_EQ(0u, compression_group_ptr->count(partition_id));
|
||||
}
|
||||
|
||||
// Find or create partition.
|
||||
if (partition_it == compression_group_ptr->end()) {
|
||||
Partition new_partition(partition_id, interest_group_name.value(),
|
||||
bidding_keys.value(), hostname(),
|
||||
experiment_group_id(),
|
||||
trusted_bidding_signals_slot_size_param_);
|
||||
compression_group_ptr->emplace(partition_id, std::move(new_partition));
|
||||
} else {
|
||||
// We only reuse the group-by-origin partition.
|
||||
DCHECK_EQ(0, partition_id);
|
||||
DCHECK_EQ(blink::InterestGroup::ExecutionMode::kGroupedByOriginMode,
|
||||
execution_mode.value());
|
||||
partition_it->second.interest_group_names.insert(
|
||||
interest_group_name.value());
|
||||
partition_it->second.bidding_signals_keys.insert(bidding_keys->begin(),
|
||||
bidding_keys->end());
|
||||
}
|
||||
|
||||
return IsolationIndex(compression_group_id, partition_id);
|
||||
}
|
||||
|
||||
TrustedSignalsKVv2RequestHelper
|
||||
TrustedBiddingSignalsKVv2RequestHelperBuilder::Build() {
|
||||
cbor::Value::MapValue request_map_value;
|
||||
AddPostRequestConstants(request_map_value);
|
||||
|
||||
cbor::Value::ArrayValue partition_array;
|
||||
|
||||
for (const auto& group_pair : compression_groups()) {
|
||||
int compression_group_id = group_pair.first;
|
||||
const CompressionGroup& partition_map = group_pair.second;
|
||||
|
||||
for (const auto& partition_pair : partition_map) {
|
||||
const Partition& partition = partition_pair.second;
|
||||
cbor::Value::MapValue partition_cbor_map = BuildMapForPartition(
|
||||
partition, partition.partition_id, compression_group_id);
|
||||
partition_array.emplace_back(partition_cbor_map);
|
||||
}
|
||||
}
|
||||
|
||||
request_map_value.try_emplace(cbor::Value("partitions"),
|
||||
cbor::Value(std::move(partition_array)));
|
||||
std::string request_body = CreateRequestBody(std::move(request_map_value));
|
||||
|
||||
return TrustedSignalsKVv2RequestHelper(std::move(request_body));
|
||||
}
|
||||
|
||||
cbor::Value::MapValue
|
||||
TrustedBiddingSignalsKVv2RequestHelperBuilder::BuildMapForPartition(
|
||||
const Partition& partition,
|
||||
int partition_id,
|
||||
int compression_group_id) {
|
||||
cbor::Value::MapValue partition_cbor_map;
|
||||
|
||||
partition_cbor_map.try_emplace(cbor::Value("id"), cbor::Value(partition_id));
|
||||
partition_cbor_map.try_emplace(cbor::Value("compressionGroupId"),
|
||||
cbor::Value(compression_group_id));
|
||||
|
||||
// metadata
|
||||
cbor::Value::MapValue metadata;
|
||||
for (const auto param : partition.additional_params) {
|
||||
CHECK(param.second.is_string());
|
||||
// TODO(xtlsheep): The slot size param probably will be changed to a new
|
||||
// format in the future. Check if these are still the right types if the
|
||||
// spec is changed.
|
||||
metadata.try_emplace(cbor::Value(param.first),
|
||||
cbor::Value(param.second.GetString()));
|
||||
}
|
||||
partition_cbor_map.try_emplace(cbor::Value("metadata"),
|
||||
cbor::Value(std::move(metadata)));
|
||||
|
||||
cbor::Value::ArrayValue arguments;
|
||||
arguments.emplace_back(
|
||||
MakeArgument("interestGroupNames", partition.interest_group_names));
|
||||
arguments.emplace_back(MakeArgument("keys", partition.bidding_signals_keys));
|
||||
|
||||
partition_cbor_map.try_emplace(cbor::Value("arguments"),
|
||||
cbor::Value(std::move(arguments)));
|
||||
return partition_cbor_map;
|
||||
}
|
||||
|
||||
} // namespace auction_worklet
|
215
content/services/auction_worklet/trusted_signals_kvv2_helper.h
Normal file
215
content/services/auction_worklet/trusted_signals_kvv2_helper.h
Normal file
@ -0,0 +1,215 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CONTENT_SERVICES_AUCTION_WORKLET_TRUSTED_SIGNALS_KVV2_HELPER_H_
|
||||
#define CONTENT_SERVICES_AUCTION_WORKLET_TRUSTED_SIGNALS_KVV2_HELPER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/types/expected.h"
|
||||
#include "base/types/optional_ref.h"
|
||||
#include "components/cbor/values.h"
|
||||
#include "content/common/content_export.h"
|
||||
#include "content/services/auction_worklet/trusted_signals.h"
|
||||
#include "content/services/auction_worklet/trusted_signals_request_manager.h"
|
||||
#include "third_party/blink/public/mojom/interest_group/interest_group_types.mojom.h"
|
||||
#include "url/gurl.h"
|
||||
#include "url/origin.h"
|
||||
|
||||
// Encapsulates the logic for generating trusted signals key-value version 2
|
||||
// requests.
|
||||
// TODO(crbug.com/349651946): Remove after KVv2 is migrated to browser process.
|
||||
|
||||
namespace auction_worklet {
|
||||
|
||||
class CONTENT_EXPORT TrustedSignalsKVv2RequestHelper {
|
||||
public:
|
||||
explicit TrustedSignalsKVv2RequestHelper(std::string post_request_body);
|
||||
|
||||
TrustedSignalsKVv2RequestHelper(TrustedSignalsKVv2RequestHelper&&);
|
||||
TrustedSignalsKVv2RequestHelper& operator=(TrustedSignalsKVv2RequestHelper&&);
|
||||
|
||||
TrustedSignalsKVv2RequestHelper& operator=(
|
||||
const TrustedSignalsKVv2RequestHelper&) = delete;
|
||||
TrustedSignalsKVv2RequestHelper(const TrustedSignalsKVv2RequestHelper&) =
|
||||
delete;
|
||||
|
||||
~TrustedSignalsKVv2RequestHelper();
|
||||
|
||||
std::string TakePostRequestBody();
|
||||
|
||||
private:
|
||||
std::string post_request_body_;
|
||||
};
|
||||
|
||||
// A single-use class within `TrustedSignalsRequestManager` is designed to
|
||||
// gather interest group names, bidding keys, render URLs, and ad component URLs
|
||||
// for trusted bidding or scoring signals. It encodes this information into CBOR
|
||||
// format as the POST request body. All data will be structured into a
|
||||
// `TrustedSignalsKVv2RequestHelper`.
|
||||
//
|
||||
// TODO(crbug.com/337917489): Consider to add a cache for compression group id
|
||||
// to handle missing compression group in response cases.
|
||||
class CONTENT_EXPORT TrustedSignalsKVv2RequestHelperBuilder {
|
||||
public:
|
||||
TrustedSignalsKVv2RequestHelperBuilder& operator=(
|
||||
const TrustedSignalsKVv2RequestHelperBuilder&);
|
||||
TrustedSignalsKVv2RequestHelperBuilder(
|
||||
const TrustedSignalsKVv2RequestHelperBuilder&);
|
||||
|
||||
virtual ~TrustedSignalsKVv2RequestHelperBuilder();
|
||||
|
||||
// Used in trusted signals requests to store the partition and compression
|
||||
// group it belongs to, as partition IDs can be duplicated across multiple
|
||||
// compression groups.
|
||||
struct CONTENT_EXPORT IsolationIndex {
|
||||
int compression_group_id;
|
||||
int partition_id;
|
||||
|
||||
bool operator==(const IsolationIndex& other) const = default;
|
||||
};
|
||||
|
||||
// Build the request helper using the helper builder to construct the POST
|
||||
// body string, noting that the partition IDs will not be sequential.
|
||||
virtual TrustedSignalsKVv2RequestHelper Build() = 0;
|
||||
|
||||
protected:
|
||||
TrustedSignalsKVv2RequestHelperBuilder(
|
||||
std::string hostname,
|
||||
GURL trusted_signals_url,
|
||||
std::optional<int> experiment_group_id);
|
||||
|
||||
// All the data needed to request a particular bidding or scoring signals
|
||||
// partition.
|
||||
struct Partition {
|
||||
Partition();
|
||||
// Create a new partition for bidding signals based on interest group's
|
||||
// name, bidding keys, hostname, experiment group id and slot size
|
||||
// parameter.
|
||||
Partition(int partition_id,
|
||||
const std::string& interest_group_name,
|
||||
const std::set<std::string>& bidding_keys,
|
||||
const std::string& hostname,
|
||||
const std::optional<int>& experiment_group_id,
|
||||
std::pair<std::string, std::string>
|
||||
trusted_bidding_signals_slot_size_param);
|
||||
Partition(Partition&&);
|
||||
~Partition();
|
||||
Partition& operator=(Partition&&);
|
||||
|
||||
int partition_id;
|
||||
|
||||
// Parameters for building a bidding signals URL.
|
||||
std::set<std::string> interest_group_names;
|
||||
std::set<std::string> bidding_signals_keys;
|
||||
|
||||
// Parameters for building a scoring signals URL.
|
||||
std::set<std::string> render_urls;
|
||||
std::set<std::string> ad_component_render_urls;
|
||||
|
||||
// Valid keys are "hostname", "experimentGroupId",
|
||||
// "slotSize", and "allSlotsRequestedSizes".
|
||||
base::Value::Dict additional_params;
|
||||
};
|
||||
|
||||
// A map of partition IDs to partition to indicate a compression group.
|
||||
using CompressionGroup = std::map<int, Partition>;
|
||||
|
||||
std::map<int, CompressionGroup>& compression_groups() {
|
||||
return compression_groups_;
|
||||
}
|
||||
|
||||
std::map<url::Origin, int>& join_origin_compression_id_map() {
|
||||
return join_origin_compression_id_map_;
|
||||
}
|
||||
|
||||
const std::string& hostname() const { return hostname_; }
|
||||
|
||||
const GURL& trusted_signals_url() const { return trusted_signals_url_; }
|
||||
|
||||
const std::optional<int>& experiment_group_id() const {
|
||||
return experiment_group_id_;
|
||||
}
|
||||
|
||||
// Return next compression group id and increase it by 1.
|
||||
int next_compression_group_id() { return next_compression_group_id_++; }
|
||||
|
||||
private:
|
||||
// Build a CBOR map for the partition with the provided data and IDs.
|
||||
virtual cbor::Value::MapValue BuildMapForPartition(
|
||||
const Partition& partition,
|
||||
int partition_id,
|
||||
int compression_group_id) = 0;
|
||||
|
||||
// Multiple partitions are keyed by compression group ID. For the Partition
|
||||
// vector, always place interest groups with the execution mode
|
||||
// group-by-origin in index-0 position, and then expand for other modes at
|
||||
// the end.
|
||||
std::map<int, CompressionGroup> compression_groups_;
|
||||
// Joining origin to compression group id map
|
||||
std::map<url::Origin, int> join_origin_compression_id_map_;
|
||||
|
||||
const std::string hostname_;
|
||||
const GURL trusted_signals_url_;
|
||||
const std::optional<int> experiment_group_id_;
|
||||
|
||||
// Initial id for compression groups.
|
||||
int next_compression_group_id_ = 0;
|
||||
};
|
||||
|
||||
class CONTENT_EXPORT TrustedBiddingSignalsKVv2RequestHelperBuilder
|
||||
: public TrustedSignalsKVv2RequestHelperBuilder {
|
||||
public:
|
||||
TrustedBiddingSignalsKVv2RequestHelperBuilder(
|
||||
const std::string& hostname,
|
||||
const GURL& trusted_signals_url,
|
||||
std::optional<int> experiment_group_id,
|
||||
const std::string& trusted_bidding_signals_slot_size_param);
|
||||
|
||||
TrustedBiddingSignalsKVv2RequestHelperBuilder(
|
||||
const TrustedBiddingSignalsKVv2RequestHelperBuilder&) = delete;
|
||||
TrustedBiddingSignalsKVv2RequestHelperBuilder& operator=(
|
||||
const TrustedBiddingSignalsKVv2RequestHelperBuilder&) = delete;
|
||||
|
||||
~TrustedBiddingSignalsKVv2RequestHelperBuilder() override;
|
||||
|
||||
// TODO(crbug.com/337917489): Consider a better way to handle identical
|
||||
// trusted signals requests (e.g., with the same IG name and bidding keys).
|
||||
// Duplicate requests should be merged with the existing ones, likely
|
||||
// requiring a map to record the isolation index for IG names to avoid
|
||||
// searching in partitions.
|
||||
//
|
||||
// Adds a request for the specified information to the trusted bidding signals
|
||||
// helper builder. Returns the IsolationIndex indicating where the requested
|
||||
// information can be found in the response to the fully assembled request
|
||||
// once it becomes available.
|
||||
IsolationIndex AddTrustedSignalsRequest(
|
||||
base::optional_ref<const std::string> interest_group_name,
|
||||
base::optional_ref<const std::set<std::string>> bidding_keys,
|
||||
base::optional_ref<const url::Origin> interest_group_join_origin,
|
||||
std::optional<blink::mojom::InterestGroup::ExecutionMode> execution_mode);
|
||||
|
||||
TrustedSignalsKVv2RequestHelper Build() override;
|
||||
|
||||
private:
|
||||
cbor::Value::MapValue BuildMapForPartition(const Partition& partition,
|
||||
int partition_id,
|
||||
int compression_group_id) override;
|
||||
|
||||
// Using a pair to store key and value for a trusted bidding signals slot
|
||||
// size parameter. Valid parameter key are "slotSize" or
|
||||
// "allSlotsRequestedSizes"
|
||||
std::pair<std::string, std::string> trusted_bidding_signals_slot_size_param_;
|
||||
};
|
||||
|
||||
} // namespace auction_worklet
|
||||
|
||||
#endif // CONTENT_SERVICES_AUCTION_WORKLET_TRUSTED_SIGNALS_KVV2_HELPER_H_
|
@ -0,0 +1,305 @@
|
||||
// Copyright 2024 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/services/auction_worklet/trusted_signals_kvv2_helper.h"
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
#include <winsock2.h>
|
||||
#else
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
|
||||
#include "base/containers/span.h"
|
||||
#include "base/containers/span_writer.h"
|
||||
#include "base/debug/crash_logging.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "base/test/task_environment.h"
|
||||
#include "base/time/time.h"
|
||||
#include "components/cbor/values.h"
|
||||
#include "components/cbor/writer.h"
|
||||
#include "content/services/auction_worklet/trusted_signals_request_manager.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "third_party/blink/public/common/features.h"
|
||||
#include "url/gurl.h"
|
||||
#include "url/origin.h"
|
||||
#include "v8-context.h"
|
||||
|
||||
namespace auction_worklet {
|
||||
|
||||
namespace {
|
||||
const char kHostName[] = "publisher.test";
|
||||
const int kExperimentGroupId = 12345;
|
||||
const char kTrustedBiddingSignalsSlotSizeParam[] = "slotSize=100,200";
|
||||
const char kTrustedSignalsUrl[] = "https://url.test/";
|
||||
const char kOriginFooUrl[] = "https://foo.test/";
|
||||
const char kOriginBarUrl[] = "https://bar.test/";
|
||||
} // namespace
|
||||
|
||||
TEST(TrustedSignalsKVv2RequestHelperTest,
|
||||
TrustedBiddingSignalsRequestEncoding) {
|
||||
std::unique_ptr<TrustedBiddingSignalsKVv2RequestHelperBuilder>
|
||||
helper_builder =
|
||||
std::make_unique<TrustedBiddingSignalsKVv2RequestHelperBuilder>(
|
||||
kHostName, GURL(kTrustedSignalsUrl), kExperimentGroupId,
|
||||
kTrustedBiddingSignalsSlotSizeParam);
|
||||
|
||||
helper_builder->AddTrustedSignalsRequest(
|
||||
std::string("groupA"), std::set<std::string>{"keyA", "keyAB"},
|
||||
url::Origin::Create(GURL(kOriginFooUrl)),
|
||||
blink::mojom::InterestGroup::ExecutionMode::kGroupedByOriginMode);
|
||||
helper_builder->AddTrustedSignalsRequest(
|
||||
std::string("groupB"), std::set<std::string>{"keyB", "keyAB"},
|
||||
url::Origin::Create(GURL(kOriginFooUrl)),
|
||||
blink::mojom::InterestGroup::ExecutionMode::kGroupedByOriginMode);
|
||||
// Another group in kOriginFooUrl, but with execution mode kCompatibilityMode,
|
||||
// for scenario of multiple partitions with different keys in one compression
|
||||
// group.
|
||||
helper_builder->AddTrustedSignalsRequest(
|
||||
std::string("groupAB"), std::set<std::string>{"key"},
|
||||
url::Origin::Create(GURL(kOriginFooUrl)),
|
||||
blink::mojom::InterestGroup::ExecutionMode::kCompatibilityMode);
|
||||
helper_builder->AddTrustedSignalsRequest(
|
||||
std::string("groupC"), std::set<std::string>{"keyC", "keyCD"},
|
||||
url::Origin::Create(GURL(kOriginBarUrl)),
|
||||
blink::mojom::InterestGroup::ExecutionMode::kGroupedByOriginMode);
|
||||
helper_builder->AddTrustedSignalsRequest(
|
||||
std::string("groupD"), std::set<std::string>{"keyD", "keyCD"},
|
||||
url::Origin::Create(GURL(kOriginBarUrl)),
|
||||
blink::mojom::InterestGroup::ExecutionMode::kGroupedByOriginMode);
|
||||
// Test interest group name is merged into one partition with same joining
|
||||
// origin and kGroupedByOriginMode.
|
||||
helper_builder->AddTrustedSignalsRequest(
|
||||
std::string("groupD"), std::set<std::string>{},
|
||||
url::Origin::Create(GURL(kOriginBarUrl)),
|
||||
blink::mojom::InterestGroup::ExecutionMode::kGroupedByOriginMode);
|
||||
// Test bidding keys are merged into one partition with same joining origin
|
||||
// and kGroupedByOriginMode.
|
||||
helper_builder->AddTrustedSignalsRequest(
|
||||
std::string("groupD"), std::set<std::string>{"keyDD"},
|
||||
url::Origin::Create(GURL(kOriginBarUrl)),
|
||||
blink::mojom::InterestGroup::ExecutionMode::kGroupedByOriginMode);
|
||||
|
||||
TrustedSignalsKVv2RequestHelper helper = helper_builder->Build();
|
||||
|
||||
std::string post_body = helper.TakePostRequestBody();
|
||||
std::vector<uint8_t> body_bytes(post_body.begin(), post_body.end());
|
||||
|
||||
// Use cbor.me to convert from
|
||||
// {
|
||||
// "partitions": [
|
||||
// {
|
||||
// "id": 0,
|
||||
// "metadata": {
|
||||
// "hostname": "publisher.test",
|
||||
// "slotSize": "100,200",
|
||||
// "experimentGroupId": "12345"
|
||||
// },
|
||||
// "arguments": [
|
||||
// {
|
||||
// "data": [
|
||||
// "groupA",
|
||||
// "groupB"
|
||||
// ],
|
||||
// "tags": [
|
||||
// "interestGroupNames"
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// "data": [
|
||||
// "keyA",
|
||||
// "keyAB",
|
||||
// "keyB"
|
||||
// ],
|
||||
// "tags": [
|
||||
// "keys"
|
||||
// ]
|
||||
// }
|
||||
// ],
|
||||
// "compressionGroupId": 0
|
||||
// },
|
||||
// {
|
||||
// "id": 1,
|
||||
// "metadata": {
|
||||
// "hostname": "publisher.test",
|
||||
// "slotSize": "100,200",
|
||||
// "experimentGroupId": "12345"
|
||||
// },
|
||||
// "arguments": [
|
||||
// {
|
||||
// "data": [
|
||||
// "groupAB"
|
||||
// ],
|
||||
// "tags": [
|
||||
// "interestGroupNames"
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// "data": [
|
||||
// "key"
|
||||
// ],
|
||||
// "tags": [
|
||||
// "keys"
|
||||
// ]
|
||||
// }
|
||||
// ],
|
||||
// "compressionGroupId": 0
|
||||
// },
|
||||
// {
|
||||
// "id": 0,
|
||||
// "metadata": {
|
||||
// "hostname": "publisher.test",
|
||||
// "slotSize": "100,200",
|
||||
// "experimentGroupId": "12345"
|
||||
// },
|
||||
// "arguments": [
|
||||
// {
|
||||
// "data": [
|
||||
// "groupC",
|
||||
// "groupD"
|
||||
// ],
|
||||
// "tags": [
|
||||
// "interestGroupNames"
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// "data": [
|
||||
// "keyC",
|
||||
// "keyCD",
|
||||
// "keyD",
|
||||
// "keyDD"
|
||||
// ],
|
||||
// "tags": [
|
||||
// "keys"
|
||||
// ]
|
||||
// }
|
||||
// ],
|
||||
// "compressionGroupId": 1
|
||||
// }
|
||||
// ],
|
||||
// "acceptCompression": [
|
||||
// "none",
|
||||
// "gzip"
|
||||
// ]
|
||||
// }
|
||||
const std::string kExpectedBodyHex =
|
||||
"A26A706172746974696F6E7383A462696400686D65746164617461A368686F73746E616D"
|
||||
"656E7075626C69736865722E7465737468736C6F7453697A65673130302C323030716578"
|
||||
"706572696D656E7447726F7570496465313233343569617267756D656E747382A2646461"
|
||||
"7461826667726F7570416667726F75704264746167738172696E74657265737447726F75"
|
||||
"704E616D6573A2646461746183646B657941656B65794142646B65794264746167738164"
|
||||
"6B65797372636F6D7072657373696F6E47726F7570496400A462696401686D6574616461"
|
||||
"7461A368686F73746E616D656E7075626C69736865722E7465737468736C6F7453697A65"
|
||||
"673130302C323030716578706572696D656E7447726F7570496465313233343569617267"
|
||||
"756D656E747382A26464617461816767726F7570414264746167738172696E7465726573"
|
||||
"7447726F75704E616D6573A2646461746181636B6579647461677381646B65797372636F"
|
||||
"6D7072657373696F6E47726F7570496400A462696400686D65746164617461A368686F73"
|
||||
"746E616D656E7075626C69736865722E7465737468736C6F7453697A65673130302C3230"
|
||||
"30716578706572696D656E7447726F7570496465313233343569617267756D656E747382"
|
||||
"A26464617461826667726F7570436667726F75704464746167738172696E746572657374"
|
||||
"47726F75704E616D6573A2646461746184646B657943656B65794344646B657944656B65"
|
||||
"794444647461677381646B65797372636F6D7072657373696F6E47726F75704964017161"
|
||||
"6363657074436F6D7072657373696F6E82646E6F6E6564677A6970";
|
||||
// Prefix hex for `kExpectedBodyHex` which includes the compression format
|
||||
// code and the length.
|
||||
const std::string kExpectedPrefixHex = "000000025B";
|
||||
|
||||
EXPECT_EQ(base::HexEncode(body_bytes), kExpectedPrefixHex + kExpectedBodyHex);
|
||||
}
|
||||
|
||||
// TODO(crbug.com/337917489): When adding an identical IG, it should use the
|
||||
// existing partition instead of creating a new one. After the implementation,
|
||||
// the EXPECT_EQ() of second IG H should be failed.
|
||||
TEST(TrustedSignalsKVv2RequestHelperTest, TrustedBiddingSignalsIsolationIndex) {
|
||||
// Add the following interest groups:
|
||||
// IG A[join_origin: foo.com, mode: group-by-origin]
|
||||
// IG B[join_origin: foo.com, mode: group-by-origin]
|
||||
// IG C[join_origin: foo.com, mode: compatibility]
|
||||
// IG D[join_origin: foo.com, mode: compatibility]
|
||||
// IG E[join_origin: bar.com, mode: compatibility]
|
||||
// IG F[join_origin: bar.com, mode: group-by-origin]
|
||||
// IG G[join_origin: bar.com, mode: compatibility]
|
||||
// IG H[join_origin: bar.com, mode: compatibility]
|
||||
// IG H, a dulplicate IG, aiming to test how request builder can handle a
|
||||
// identical IG.
|
||||
// will result the following groups: Compression: 0 -
|
||||
// partition 0: A, B
|
||||
// partition 1: C
|
||||
// partition 2: D
|
||||
// Compression: 1 -
|
||||
// partition 0: F
|
||||
// partition 1: E
|
||||
// partition 2: G
|
||||
// partition 3: H
|
||||
// partition 4: H
|
||||
|
||||
std::unique_ptr<TrustedBiddingSignalsKVv2RequestHelperBuilder>
|
||||
helper_builder =
|
||||
std::make_unique<TrustedBiddingSignalsKVv2RequestHelperBuilder>(
|
||||
kHostName, GURL(kTrustedSignalsUrl), kExperimentGroupId,
|
||||
kTrustedBiddingSignalsSlotSizeParam);
|
||||
|
||||
EXPECT_EQ(
|
||||
TrustedSignalsKVv2RequestHelperBuilder::IsolationIndex(0, 0),
|
||||
helper_builder->AddTrustedSignalsRequest(
|
||||
std::string("groupA"), std::set<std::string>{"key"},
|
||||
url::Origin::Create(GURL(kOriginFooUrl)),
|
||||
blink::mojom::InterestGroup::ExecutionMode::kGroupedByOriginMode));
|
||||
EXPECT_EQ(
|
||||
TrustedSignalsKVv2RequestHelperBuilder::IsolationIndex(0, 0),
|
||||
helper_builder->AddTrustedSignalsRequest(
|
||||
std::string("groupB"), std::set<std::string>{"key"},
|
||||
url::Origin::Create(GURL(kOriginFooUrl)),
|
||||
blink::mojom::InterestGroup::ExecutionMode::kGroupedByOriginMode));
|
||||
EXPECT_EQ(
|
||||
TrustedSignalsKVv2RequestHelperBuilder::IsolationIndex(0, 1),
|
||||
helper_builder->AddTrustedSignalsRequest(
|
||||
std::string("groupC"), std::set<std::string>{"key"},
|
||||
url::Origin::Create(GURL(kOriginFooUrl)),
|
||||
blink::mojom::InterestGroup::ExecutionMode::kCompatibilityMode));
|
||||
EXPECT_EQ(
|
||||
TrustedSignalsKVv2RequestHelperBuilder::IsolationIndex(0, 2),
|
||||
helper_builder->AddTrustedSignalsRequest(
|
||||
std::string("groupD"), std::set<std::string>{"key"},
|
||||
url::Origin::Create(GURL(kOriginFooUrl)),
|
||||
blink::mojom::InterestGroup::ExecutionMode::kCompatibilityMode));
|
||||
EXPECT_EQ(
|
||||
TrustedSignalsKVv2RequestHelperBuilder::IsolationIndex(1, 1),
|
||||
helper_builder->AddTrustedSignalsRequest(
|
||||
std::string("groupE"), std::set<std::string>{"key"},
|
||||
url::Origin::Create(GURL(kOriginBarUrl)),
|
||||
blink::mojom::InterestGroup::ExecutionMode::kCompatibilityMode));
|
||||
EXPECT_EQ(
|
||||
TrustedSignalsKVv2RequestHelperBuilder::IsolationIndex(1, 0),
|
||||
helper_builder->AddTrustedSignalsRequest(
|
||||
std::string("groupF"), std::set<std::string>{"key"},
|
||||
url::Origin::Create(GURL(kOriginBarUrl)),
|
||||
blink::mojom::InterestGroup::ExecutionMode::kGroupedByOriginMode));
|
||||
EXPECT_EQ(
|
||||
TrustedSignalsKVv2RequestHelperBuilder::IsolationIndex(1, 2),
|
||||
helper_builder->AddTrustedSignalsRequest(
|
||||
std::string("groupG"), std::set<std::string>{"key"},
|
||||
url::Origin::Create(GURL(kOriginBarUrl)),
|
||||
blink::mojom::InterestGroup::ExecutionMode::kCompatibilityMode));
|
||||
EXPECT_EQ(
|
||||
TrustedSignalsKVv2RequestHelperBuilder::IsolationIndex(1, 3),
|
||||
helper_builder->AddTrustedSignalsRequest(
|
||||
std::string("groupH"), std::set<std::string>{"key"},
|
||||
url::Origin::Create(GURL(kOriginBarUrl)),
|
||||
blink::mojom::InterestGroup::ExecutionMode::kCompatibilityMode));
|
||||
EXPECT_EQ(
|
||||
TrustedSignalsKVv2RequestHelperBuilder::IsolationIndex(1, 4),
|
||||
helper_builder->AddTrustedSignalsRequest(
|
||||
std::string("groupH"), std::set<std::string>{"key"},
|
||||
url::Origin::Create(GURL(kOriginBarUrl)),
|
||||
blink::mojom::InterestGroup::ExecutionMode::kCompatibilityMode));
|
||||
}
|
||||
|
||||
} // namespace auction_worklet
|
Reference in New Issue
Block a user