FLEDGE: Move encodeUtf8/decodeUtf8 to protectedAudience.
object handing of the global object, rather than browserSignals argument to functions, as design doc feedback pointed out that it's otherwise hard to use in frozen context mode to pollyfill TextEncoder/TextDecoder. (Part of https://github.com/WICG/turtledove/issues/961) Bug: 397936915 Change-Id: I084b14072ae8aac8419008410d4ee713191d77e9 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6329720 Commit-Queue: Maks Orlovich <morlovich@chromium.org> Reviewed-by: Russ Hamilton <behamilton@google.com> Cr-Commit-Position: refs/heads/main@{#1429678}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
f2519e8e54
commit
a1c3103818
content
services
auction_worklet
test
third_party/blink/web_tests/external/wpt/fledge/tentative
@ -62,7 +62,6 @@
|
||||
#include "content/services/auction_worklet/set_priority_bindings.h"
|
||||
#include "content/services/auction_worklet/set_priority_signals_override_bindings.h"
|
||||
#include "content/services/auction_worklet/shared_storage_bindings.h"
|
||||
#include "content/services/auction_worklet/text_conversion_helpers.h"
|
||||
#include "content/services/auction_worklet/trusted_signals.h"
|
||||
#include "content/services/auction_worklet/trusted_signals_kvv2_manager.h"
|
||||
#include "content/services/auction_worklet/trusted_signals_request_manager.h"
|
||||
@ -943,11 +942,6 @@ bool BidderWorklet::V8State::SetBrowserSignals(
|
||||
return false;
|
||||
}
|
||||
|
||||
if (base::FeatureList::IsEnabled(features::kFledgeTextConversionHelpers)) {
|
||||
context_recycler.text_conversion_helpers()->ReInitialize(context,
|
||||
browser_signals);
|
||||
}
|
||||
|
||||
if (!context_recycler.report_win_lazy_filler()->FillInObject(
|
||||
browser_signal_modeling_signals, browser_signal_join_count,
|
||||
!is_for_additional_bid
|
||||
@ -1132,6 +1126,10 @@ void BidderWorklet::V8State::ReportWin(
|
||||
v8::Local<v8::Context> context = context_recycler_scope.GetContext();
|
||||
AuctionV8Logger v8_logger(v8_helper_.get(), context);
|
||||
|
||||
// We want this before RunScript, both because it's meant to be visible
|
||||
// to globals, and because we don't want to overwrite existing globals.
|
||||
context_recycler.AddTextConversionHelpers();
|
||||
|
||||
v8::LocalVector<v8::Value> args(isolate);
|
||||
if (!AppendJsonValueOrNull(v8_helper_.get(), context,
|
||||
base::OptionalToPtr(auction_signals_json),
|
||||
@ -1176,7 +1174,6 @@ void BidderWorklet::V8State::ReportWin(
|
||||
}
|
||||
|
||||
context_recycler.AddReportWinBrowserSignalsLazyFiller();
|
||||
context_recycler.AddTextConversionHelpers();
|
||||
|
||||
DeprecatedUrlLazyFiller deprecated_render_url(
|
||||
v8_helper_.get(), &v8_logger, &browser_signal_render_url,
|
||||
@ -1929,10 +1926,6 @@ BidderWorklet::V8State::RunGenerateBidOnce(
|
||||
}
|
||||
|
||||
v8::Local<v8::Object> browser_signals = v8::Object::New(isolate);
|
||||
if (base::FeatureList::IsEnabled(features::kFledgeTextConversionHelpers)) {
|
||||
context_recycler->text_conversion_helpers()->ReInitialize(context,
|
||||
browser_signals);
|
||||
}
|
||||
gin::Dictionary browser_signals_dict(isolate, browser_signals);
|
||||
// TODO(crbug.com/336164429): Construct the fields of browser signals lazily.
|
||||
if (!browser_signals_dict.Set("topWindowHostname",
|
||||
@ -2166,6 +2159,10 @@ BidderWorklet::V8State::CreateContextRecyclerAndRunTopLevelForGenerateBid(
|
||||
v8::Local<v8::Context> context = context_recycler_scope.GetContext();
|
||||
TRACE_EVENT_NESTABLE_ASYNC_END0("fledge", "get_bidder_context", trace_id);
|
||||
|
||||
// We want this before RunScript, both because it's meant to be visible
|
||||
// to globals, and because we don't want to overwrite existing globals.
|
||||
context_recycler->AddTextConversionHelpers();
|
||||
|
||||
v8::Local<v8::UnboundScript> unbound_worklet_script =
|
||||
worklet_script_.Get(v8_helper_->isolate());
|
||||
|
||||
@ -2203,7 +2200,6 @@ BidderWorklet::V8State::CreateContextRecyclerAndRunTopLevelForGenerateBid(
|
||||
context_recycler->AddSetBidBindings();
|
||||
context_recycler->AddSetPriorityBindings();
|
||||
context_recycler->AddSetPrioritySignalsOverrideBindings();
|
||||
context_recycler->AddTextConversionHelpers();
|
||||
context_recycler->AddInterestGroupLazyFiller();
|
||||
context_recycler->AddBiddingBrowserSignalsLazyFiller();
|
||||
|
||||
|
@ -4961,19 +4961,35 @@ TEST_F(BidderWorkletTest, GenerateBidInterestGroupCreativeScanningMetadata) {
|
||||
|
||||
TEST_F(BidderWorkletTest, GenerateBidTextConversions) {
|
||||
RunGenerateBidExpectingExpressionIsTrue(
|
||||
R"(!('encodeUtf8' in browserSignals))");
|
||||
RunGenerateBidExpectingExpressionIsTrue(
|
||||
R"(!('decodeUtf8' in browserSignals))");
|
||||
R"(!('protectedAudience' in globalThis))");
|
||||
}
|
||||
|
||||
TEST_F(BidderWorkletTextConversionsTest, GenerateBidTextConversions) {
|
||||
RunGenerateBidExpectingExpressionIsTrue(R"('encodeUtf8' in browserSignals)");
|
||||
RunGenerateBidExpectingExpressionIsTrue(R"('decodeUtf8' in browserSignals)");
|
||||
RunGenerateBidExpectingExpressionIsTrue(
|
||||
R"('encodeUtf8' in protectedAudience)");
|
||||
RunGenerateBidExpectingExpressionIsTrue(
|
||||
R"('decodeUtf8' in protectedAudience)");
|
||||
|
||||
RunGenerateBidExpectingExpressionIsTrue(
|
||||
"browserSignals.encodeUtf8('A')[0] === 65");
|
||||
"protectedAudience.encodeUtf8('A')[0] === 65");
|
||||
RunGenerateBidExpectingExpressionIsTrue(
|
||||
"browserSignals.decodeUtf8(new Uint8Array([65, 32, 68])) === 'A D'");
|
||||
"protectedAudience.decodeUtf8(new Uint8Array([65, 32, 68])) === 'A D'");
|
||||
}
|
||||
|
||||
// Make sure we don't stomp over an existing user protectedAudience
|
||||
TEST_F(BidderWorkletTextConversionsTest, GenerateBidNoGlobalStomp) {
|
||||
const char kScript[] = R"(
|
||||
function protectedAudience() {
|
||||
return {bid: 1, render:"https://response.test/"};
|
||||
}
|
||||
|
||||
function generateBid() {
|
||||
return protectedAudience();
|
||||
}
|
||||
)";
|
||||
|
||||
RunGenerateBidWithJavascriptExpectingResult(kScript,
|
||||
TestBidBuilder().Build());
|
||||
}
|
||||
|
||||
class BidderWorkletCreativeScanningTest : public BidderWorkletTest {
|
||||
@ -7853,22 +7869,33 @@ TEST_F(BidderWorkletTest, ReportWinTopLevelTimeout) {
|
||||
|
||||
TEST_F(BidderWorkletTest, ReportWinTextConversions) {
|
||||
RunReportWinWithFunctionBodyExpectingResult(
|
||||
"sendReportTo('https://foo.test?' + ('encodeUtf8' in browserSignals))",
|
||||
GURL("https://foo.test/?false"));
|
||||
RunReportWinWithFunctionBodyExpectingResult(
|
||||
"sendReportTo('https://foo.test?' + ('decodeUtf8' in browserSignals))",
|
||||
"sendReportTo('https://foo.test?' + ('protectedAudience' in globalThis))",
|
||||
GURL("https://foo.test/?false"));
|
||||
}
|
||||
|
||||
TEST_F(BidderWorkletTextConversionsTest, ReportWinTextConversions) {
|
||||
RunReportWinWithFunctionBodyExpectingResult(
|
||||
"sendReportTo('https://foo.test?' + ('encodeUtf8' in browserSignals))",
|
||||
"sendReportTo('https://foo.test?' + ('encodeUtf8' in protectedAudience))",
|
||||
GURL("https://foo.test/?true"));
|
||||
RunReportWinWithFunctionBodyExpectingResult(
|
||||
"sendReportTo('https://foo.test?' + ('decodeUtf8' in browserSignals))",
|
||||
"sendReportTo('https://foo.test?' + ('decodeUtf8' in protectedAudience))",
|
||||
GURL("https://foo.test/?true"));
|
||||
}
|
||||
|
||||
// Make sure we don't stomp over an existing user protectedAudience object.
|
||||
TEST_F(BidderWorkletTextConversionsTest, ReportWinNoGlobalStomp) {
|
||||
const char kScript[] = R"(
|
||||
function protectedAudience() {
|
||||
sendReportTo("https://foo.test");
|
||||
}
|
||||
|
||||
function reportWin() {
|
||||
protectedAudience();
|
||||
}
|
||||
)";
|
||||
RunReportWinWithJavascriptExpectingResult(kScript, GURL("https://foo.test"));
|
||||
}
|
||||
|
||||
TEST_F(BidderWorkletTest, SendReportToLongUrl) {
|
||||
// Copying large URLs can cause flaky generateBid() timeouts with the default
|
||||
// value, even on the standard debug bots.
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "content/services/auction_worklet/for_debugging_only_bindings.h"
|
||||
#include "content/services/auction_worklet/private_aggregation_bindings.h"
|
||||
#include "content/services/auction_worklet/private_model_training_bindings.h"
|
||||
#include "content/services/auction_worklet/public/cpp/auction_worklet_features.h"
|
||||
#include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom.h"
|
||||
#include "content/services/auction_worklet/public/mojom/private_aggregation_request.mojom.h"
|
||||
#include "content/services/auction_worklet/public/mojom/real_time_reporting.mojom.h"
|
||||
@ -6143,6 +6144,10 @@ TEST_F(ContextRecyclerTest, RegisterAdMacroBindings) {
|
||||
}
|
||||
|
||||
TEST_F(ContextRecyclerTest, EncodeUtf8) {
|
||||
base::test::ScopedFeatureList scoped_feature_list;
|
||||
scoped_feature_list.InitAndEnableFeature(
|
||||
features::kFledgeTextConversionHelpers);
|
||||
|
||||
const char kScript[] = R"(
|
||||
function assertEq(l, r, label) {
|
||||
if (l !== r)
|
||||
@ -6160,24 +6165,24 @@ TEST_F(ContextRecyclerTest, EncodeUtf8) {
|
||||
}
|
||||
|
||||
function test1() {
|
||||
assertByteArray(encoderObj.encodeUtf8('ABC'),
|
||||
assertByteArray(protectedAudience.encodeUtf8('ABC'),
|
||||
[65, 66, 67]);
|
||||
}
|
||||
|
||||
function test2() {
|
||||
assertByteArray(encoderObj.encodeUtf8('A \u0490'),
|
||||
assertByteArray(protectedAudience.encodeUtf8('A \u0490'),
|
||||
[65, 32, 0xD2, 0x90]);
|
||||
}
|
||||
|
||||
// Unmatched surrogate.
|
||||
function test3() {
|
||||
assertByteArray(encoderObj.encodeUtf8('A\uD800C'),
|
||||
assertByteArray(protectedAudience.encodeUtf8('A\uD800C'),
|
||||
[65, 0xEF, 0xBF, 0xBD, 67]);
|
||||
}
|
||||
|
||||
// Matched surrogate.
|
||||
function test4() {
|
||||
assertByteArray(encoderObj.encodeUtf8('A\uD83D\uDE02C'),
|
||||
assertByteArray(protectedAudience.encodeUtf8('A\uD83D\uDE02C'),
|
||||
[65, 0xF0, 0x9F, 0x98, 0x82, 67]);
|
||||
}
|
||||
|
||||
@ -6186,7 +6191,7 @@ TEST_F(ContextRecyclerTest, EncodeUtf8) {
|
||||
let obj = {
|
||||
toString: () => "ABC"
|
||||
};
|
||||
assertByteArray(encoderObj.encodeUtf8(obj),
|
||||
assertByteArray(protectedAudience.encodeUtf8(obj),
|
||||
[65, 66, 67]);
|
||||
}
|
||||
)";
|
||||
@ -6203,13 +6208,6 @@ TEST_F(ContextRecyclerTest, EncodeUtf8) {
|
||||
for (const char* test : {"test1", "test2", "test3", "test4", "test5"}) {
|
||||
SCOPED_TRACE(test);
|
||||
ContextRecyclerScope scope(context_recycler);
|
||||
v8::Local<v8::Context> context = scope.GetContext();
|
||||
|
||||
v8::Local<v8::Object> obj = v8::Object::New(helper_->isolate());
|
||||
context_recycler.text_conversion_helpers()->ReInitialize(context, obj);
|
||||
context->Global()
|
||||
->Set(context, helper_->CreateStringFromLiteral("encoderObj"), obj)
|
||||
.Check();
|
||||
|
||||
std::vector<std::string> error_msgs;
|
||||
Run(scope, script, test, error_msgs);
|
||||
@ -6218,10 +6216,14 @@ TEST_F(ContextRecyclerTest, EncodeUtf8) {
|
||||
}
|
||||
|
||||
TEST_F(ContextRecyclerTest, EncodeUtf8Failure) {
|
||||
base::test::ScopedFeatureList scoped_feature_list;
|
||||
scoped_feature_list.InitAndEnableFeature(
|
||||
features::kFledgeTextConversionHelpers);
|
||||
|
||||
const char kScript[] = R"(
|
||||
// Not enough arguments.
|
||||
function test1() {
|
||||
encoderObj.encodeUtf8();
|
||||
protectedAudience.encodeUtf8();
|
||||
}
|
||||
|
||||
// String conversion failure.
|
||||
@ -6229,7 +6231,7 @@ TEST_F(ContextRecyclerTest, EncodeUtf8Failure) {
|
||||
let obj = {
|
||||
toString: () => { throw 'ouch' }
|
||||
};
|
||||
encoderObj.encodeUtf8(obj);
|
||||
protectedAudience.encodeUtf8(obj);
|
||||
}
|
||||
)";
|
||||
|
||||
@ -6254,13 +6256,6 @@ TEST_F(ContextRecyclerTest, EncodeUtf8Failure) {
|
||||
for (const auto& test : kTests) {
|
||||
SCOPED_TRACE(test.functionName);
|
||||
ContextRecyclerScope scope(context_recycler);
|
||||
v8::Local<v8::Context> context = scope.GetContext();
|
||||
|
||||
v8::Local<v8::Object> obj = v8::Object::New(helper_->isolate());
|
||||
context_recycler.text_conversion_helpers()->ReInitialize(context, obj);
|
||||
context->Global()
|
||||
->Set(context, helper_->CreateStringFromLiteral("encoderObj"), obj)
|
||||
.Check();
|
||||
|
||||
std::vector<std::string> error_msgs;
|
||||
Run(scope, script, test.functionName, error_msgs);
|
||||
@ -6269,6 +6264,10 @@ TEST_F(ContextRecyclerTest, EncodeUtf8Failure) {
|
||||
}
|
||||
|
||||
TEST_F(ContextRecyclerTest, DecodeUtf8) {
|
||||
base::test::ScopedFeatureList scoped_feature_list;
|
||||
scoped_feature_list.InitAndEnableFeature(
|
||||
features::kFledgeTextConversionHelpers);
|
||||
|
||||
const char kScript[] = R"(
|
||||
function assertEq(l, r, label) {
|
||||
if (l !== r)
|
||||
@ -6286,32 +6285,33 @@ TEST_F(ContextRecyclerTest, DecodeUtf8) {
|
||||
}
|
||||
|
||||
function test1() {
|
||||
assertString(encoderObj.decodeUtf8(new Uint8Array([65, 66, 67])),
|
||||
assertString(protectedAudience.decodeUtf8(new Uint8Array([65, 66, 67])),
|
||||
'ABC');
|
||||
}
|
||||
|
||||
function test2() {
|
||||
assertString(encoderObj.decodeUtf8(new Uint8Array([65, 32, 0xD2, 0x90])),
|
||||
assertString(protectedAudience.decodeUtf8(
|
||||
new Uint8Array([65, 32, 0xD2, 0x90])),
|
||||
'A \u0490');
|
||||
}
|
||||
|
||||
// Broken utf-8 --- gets a replacement character.
|
||||
function test3() {
|
||||
assertString(encoderObj.decodeUtf8(new Uint8Array([65, 32, 0xD2])),
|
||||
assertString(protectedAudience.decodeUtf8(new Uint8Array([65, 32, 0xD2])),
|
||||
'A \uFFFD');
|
||||
}
|
||||
|
||||
// Utf-8 for just a single surrogate. Every byte ended up replaced with a
|
||||
// replacement character.
|
||||
function test4() {
|
||||
assertString(encoderObj.decodeUtf8(new Uint8Array(
|
||||
assertString(protectedAudience.decodeUtf8(new Uint8Array(
|
||||
[65, 32, 0xED, 0xA0, 0x80, 66])),
|
||||
'A \uFFFD\uFFFD\uFFFDB');
|
||||
}
|
||||
|
||||
// Utf-8 for something that requires two Utf-16 characters.
|
||||
function test5() {
|
||||
assertString(encoderObj.decodeUtf8(new Uint8Array(
|
||||
assertString(protectedAudience.decodeUtf8(new Uint8Array(
|
||||
[65, 0xF0, 0x9F, 0x98, 0x82, 67])),
|
||||
'A\uD83D\uDE02C');
|
||||
}
|
||||
@ -6323,9 +6323,9 @@ TEST_F(ContextRecyclerTest, DecodeUtf8) {
|
||||
for (let i = 0; i < fullView.length; ++i)
|
||||
fullView[i] = 65 + i;
|
||||
let partialView = new Uint8Array(buffer, 2, 3);
|
||||
assertString(encoderObj.decodeUtf8(fullView),
|
||||
assertString(protectedAudience.decodeUtf8(fullView),
|
||||
'ABCDEFGH');
|
||||
assertString(encoderObj.decodeUtf8(partialView),
|
||||
assertString(protectedAudience.decodeUtf8(partialView),
|
||||
'CDE');
|
||||
}
|
||||
)";
|
||||
@ -6343,13 +6343,6 @@ TEST_F(ContextRecyclerTest, DecodeUtf8) {
|
||||
{"test1", "test2", "test3", "test4", "test5", "test6"}) {
|
||||
SCOPED_TRACE(test);
|
||||
ContextRecyclerScope scope(context_recycler);
|
||||
v8::Local<v8::Context> context = scope.GetContext();
|
||||
|
||||
v8::Local<v8::Object> obj = v8::Object::New(helper_->isolate());
|
||||
context_recycler.text_conversion_helpers()->ReInitialize(context, obj);
|
||||
context->Global()
|
||||
->Set(context, helper_->CreateStringFromLiteral("encoderObj"), obj)
|
||||
.Check();
|
||||
|
||||
std::vector<std::string> error_msgs;
|
||||
Run(scope, script, test, error_msgs);
|
||||
@ -6358,15 +6351,19 @@ TEST_F(ContextRecyclerTest, DecodeUtf8) {
|
||||
}
|
||||
|
||||
TEST_F(ContextRecyclerTest, DecodeUtf8Failure) {
|
||||
base::test::ScopedFeatureList scoped_feature_list;
|
||||
scoped_feature_list.InitAndEnableFeature(
|
||||
features::kFledgeTextConversionHelpers);
|
||||
|
||||
const char kScript[] = R"(
|
||||
// Not enough arguments.
|
||||
function test1() {
|
||||
encoderObj.decodeUtf8();
|
||||
protectedAudience.decodeUtf8();
|
||||
}
|
||||
|
||||
// Wrong type.
|
||||
function test2() {
|
||||
encoderObj.decodeUtf8([65,66]);
|
||||
protectedAudience.decodeUtf8([65,66]);
|
||||
}
|
||||
)";
|
||||
|
||||
@ -6393,13 +6390,6 @@ TEST_F(ContextRecyclerTest, DecodeUtf8Failure) {
|
||||
for (const auto& test : kTests) {
|
||||
SCOPED_TRACE(test.functionName);
|
||||
ContextRecyclerScope scope(context_recycler);
|
||||
v8::Local<v8::Context> context = scope.GetContext();
|
||||
|
||||
v8::Local<v8::Object> obj = v8::Object::New(helper_->isolate());
|
||||
context_recycler.text_conversion_helpers()->ReInitialize(context, obj);
|
||||
context->Global()
|
||||
->Set(context, helper_->CreateStringFromLiteral("encoderObj"), obj)
|
||||
.Check();
|
||||
|
||||
std::vector<std::string> error_msgs;
|
||||
Run(scope, script, test.functionName, error_msgs);
|
||||
|
@ -49,7 +49,6 @@
|
||||
#include "content/services/auction_worklet/report_bindings.h"
|
||||
#include "content/services/auction_worklet/seller_lazy_filler.h"
|
||||
#include "content/services/auction_worklet/shared_storage_bindings.h"
|
||||
#include "content/services/auction_worklet/text_conversion_helpers.h"
|
||||
#include "content/services/auction_worklet/trusted_signals.h"
|
||||
#include "content/services/auction_worklet/trusted_signals_kvv2_manager.h"
|
||||
#include "content/services/auction_worklet/webidl_compat.h"
|
||||
@ -905,6 +904,10 @@ SellerWorklet::V8State::CreateContextRecyclerAndRunTopLevel(
|
||||
v8::Local<v8::Context> context = context_recycler_scope.GetContext();
|
||||
TRACE_EVENT_NESTABLE_ASYNC_END0("fledge", "get_seller_context", trace_id);
|
||||
|
||||
// We want this before RunScript, both because it's meant to be visible
|
||||
// to globals, and because we don't want to overwrite existing globals.
|
||||
context_recycler->AddTextConversionHelpers();
|
||||
|
||||
v8::Local<v8::UnboundScript> unbound_worklet_script =
|
||||
worklet_script_.Get(v8_helper_->isolate());
|
||||
|
||||
@ -922,7 +925,6 @@ SellerWorklet::V8State::CreateContextRecyclerAndRunTopLevel(
|
||||
permissions_policy_state_->private_aggregation_allowed,
|
||||
/*reserved_once_allowed=*/true);
|
||||
context_recycler->AddRealTimeReportingBindings();
|
||||
context_recycler->AddTextConversionHelpers();
|
||||
if (base::FeatureList::IsEnabled(network::features::kSharedStorageAPI)) {
|
||||
context_recycler->AddSharedStorageBindings(
|
||||
shared_storage_host_remote_.is_bound()
|
||||
@ -1141,10 +1143,6 @@ void SellerWorklet::V8State::ScoreAd(
|
||||
}
|
||||
context_recycler->seller_browser_signals_lazy_filler()->FillInObject(
|
||||
browser_signal_render_url, &ad_components, browser_signals);
|
||||
if (base::FeatureList::IsEnabled(features::kFledgeTextConversionHelpers)) {
|
||||
context_recycler->text_conversion_helpers()->ReInitialize(context,
|
||||
browser_signals);
|
||||
}
|
||||
// TODO(crbug.com/336164429): Construct the fields of browser signals lazily.
|
||||
if (!browser_signals_dict.Set("topWindowHostname",
|
||||
top_window_origin_.host()) ||
|
||||
@ -1680,6 +1678,10 @@ void SellerWorklet::V8State::ReportResult(
|
||||
v8::Local<v8::Context> context = context_recycler_scope.GetContext();
|
||||
AuctionV8Logger v8_logger(v8_helper_.get(), context);
|
||||
|
||||
// We want this before RunScript, both because it's meant to be visible
|
||||
// to globals, and because we don't want to overwrite existing globals.
|
||||
context_recycler.AddTextConversionHelpers();
|
||||
|
||||
v8::LocalVector<v8::Value> args(isolate);
|
||||
|
||||
context_recycler.EnsureAuctionConfigLazyFillers(
|
||||
@ -1703,12 +1705,6 @@ void SellerWorklet::V8State::ReportResult(
|
||||
|
||||
v8::Local<v8::Object> browser_signals = v8::Object::New(isolate);
|
||||
gin::Dictionary browser_signals_dict(isolate, browser_signals);
|
||||
context_recycler.AddTextConversionHelpers();
|
||||
if (base::FeatureList::IsEnabled(features::kFledgeTextConversionHelpers)) {
|
||||
context_recycler.text_conversion_helpers()->ReInitialize(context,
|
||||
browser_signals);
|
||||
}
|
||||
|
||||
context_recycler.AddSellerBrowserSignalsLazyFiller();
|
||||
// Passing null for ad_components here since we do not want creative scanning
|
||||
// info here.
|
||||
|
@ -1951,24 +1951,36 @@ TEST_F(SellerWorkletTest, ScoreAdAdComponentsCreativeScanningMetadata) {
|
||||
|
||||
TEST_F(SellerWorkletTest, ScoreAdTextConversions) {
|
||||
RunScoreAdWithReturnValueExpectingResult(
|
||||
R"('encodeUtf8' in browserSignals? 3 : 2)", 2);
|
||||
RunScoreAdWithReturnValueExpectingResult(
|
||||
R"('decodeUtf8' in browserSignals? 3 : 2)", 2);
|
||||
R"('protectedAudience' in globalThis? 3 : 2)", 2);
|
||||
}
|
||||
|
||||
TEST_F(SellerWorkletTextConversionsTest, ScoreAdTextConversions) {
|
||||
RunScoreAdWithReturnValueExpectingResult(
|
||||
R"('encodeUtf8' in browserSignals? 3 : 2)", 3);
|
||||
R"('encodeUtf8' in protectedAudience? 3 : 2)", 3);
|
||||
RunScoreAdWithReturnValueExpectingResult(
|
||||
R"('decodeUtf8' in browserSignals? 3 : 2)", 3);
|
||||
R"('decodeUtf8' in protectedAudience? 3 : 2)", 3);
|
||||
|
||||
RunScoreAdWithReturnValueExpectingResult("browserSignals.encodeUtf8('A')[0]",
|
||||
65);
|
||||
RunScoreAdWithReturnValueExpectingResult(
|
||||
"browserSignals.decodeUtf8(new Uint8Array([65, 68])) === 'AD' ? 3 : 2",
|
||||
"protectedAudience.encodeUtf8('A')[0]", 65);
|
||||
RunScoreAdWithReturnValueExpectingResult(
|
||||
"protectedAudience.decodeUtf8(new Uint8Array([65, 68])) === 'AD' ? 3 : 2",
|
||||
3);
|
||||
}
|
||||
|
||||
TEST_F(SellerWorkletTextConversionsTest, ScoreAdNoGlobalStomp) {
|
||||
const char kScript[] = R"(
|
||||
function protectedAudience() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
function scoreAd() {
|
||||
return protectedAudience();
|
||||
}
|
||||
|
||||
)";
|
||||
RunScoreAdWithJavascriptExpectingResult(kScript, 5);
|
||||
}
|
||||
|
||||
TEST_F(SellerWorkletTest, ScoreAdBid) {
|
||||
bid_ = 5;
|
||||
RunScoreAdWithReturnValueExpectingResult("bid", 5);
|
||||
@ -3460,26 +3472,38 @@ TEST_F(SellerWorkletTest, ReportResultNoAdComponentsCreativeScanningMetadata) {
|
||||
|
||||
TEST_F(SellerWorkletTest, ReportResultTextConversions) {
|
||||
RunReportResultCreatedScriptExpectingResult(
|
||||
"('encodeUtf8' in browserSignals) ? 2 : 1",
|
||||
/*extra_code=*/std::string(), "1",
|
||||
/*expected_report_url=*/std::nullopt);
|
||||
RunReportResultCreatedScriptExpectingResult(
|
||||
"('decodeUtf8' in browserSignals) ? 2 : 1",
|
||||
"('protectedAudience' in globalThis) ? 2 : 1",
|
||||
/*extra_code=*/std::string(), "1",
|
||||
/*expected_report_url=*/std::nullopt);
|
||||
}
|
||||
|
||||
TEST_F(SellerWorkletTextConversionsTest, ReportResultTextConversions) {
|
||||
RunReportResultCreatedScriptExpectingResult(
|
||||
"('encodeUtf8' in browserSignals) ? 2 : 1",
|
||||
"('encodeUtf8' in protectedAudience) ? 2 : 1",
|
||||
/*extra_code=*/std::string(), "2",
|
||||
/*expected_report_url=*/std::nullopt);
|
||||
RunReportResultCreatedScriptExpectingResult(
|
||||
"('decodeUtf8' in browserSignals) ? 2 : 1",
|
||||
"('decodeUtf8' in protectedAudience) ? 2 : 1",
|
||||
/*extra_code=*/std::string(), "2",
|
||||
/*expected_report_url=*/std::nullopt);
|
||||
}
|
||||
|
||||
TEST_F(SellerWorkletTextConversionsTest, ReportResultNoGlobalStomp) {
|
||||
const char kScript[] = R"(
|
||||
function protectedAudience() {
|
||||
sendReportTo('https://report.test/');
|
||||
}
|
||||
|
||||
function reportResult() {
|
||||
protectedAudience();
|
||||
}
|
||||
)";
|
||||
RunReportResultWithJavascriptExpectingResult(
|
||||
kScript,
|
||||
/*expected_signals_for_winner=*/"null",
|
||||
/*expected_report_url=*/GURL("https://report.test"));
|
||||
}
|
||||
|
||||
TEST_F(SellerWorkletTest, ReportResultTopWindowOrigin) {
|
||||
top_window_origin_ = url::Origin::Create(GURL("https://foo.test/"));
|
||||
RunReportResultCreatedScriptExpectingResult(
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "content/services/auction_worklet/auction_v8_helper.h"
|
||||
#include "content/services/auction_worklet/public/cpp/auction_worklet_features.h"
|
||||
#include "content/services/auction_worklet/webidl_compat.h"
|
||||
#include "v8/include/v8-array-buffer.h"
|
||||
#include "v8/include/v8-exception.h"
|
||||
@ -21,14 +22,10 @@ TextConversionHelpers::TextConversionHelpers(AuctionV8Helper* v8_helper)
|
||||
: v8_helper_(v8_helper) {}
|
||||
|
||||
void TextConversionHelpers::AttachToContext(v8::Local<v8::Context> context) {
|
||||
// We do everything in ReInitialize, since we attach to an object and not
|
||||
// globally.
|
||||
}
|
||||
if (!base::FeatureList::IsEnabled(features::kFledgeTextConversionHelpers)) {
|
||||
return;
|
||||
}
|
||||
|
||||
void TextConversionHelpers::Reset() {}
|
||||
|
||||
void TextConversionHelpers::ReInitialize(v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Object> object) {
|
||||
v8::Local<v8::External> v8_this =
|
||||
v8::External::New(v8_helper_->isolate(), this);
|
||||
v8::Local<v8::Function> encode =
|
||||
@ -37,14 +34,21 @@ void TextConversionHelpers::ReInitialize(v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Function> decode =
|
||||
v8::Function::New(context, &TextConversionHelpers::DecodeUtf8, v8_this)
|
||||
.ToLocalChecked();
|
||||
object
|
||||
v8::Local<v8::Object> pa_object = v8::Object::New(v8_helper_->isolate());
|
||||
context->Global()
|
||||
->Set(context, v8_helper_->CreateStringFromLiteral("protectedAudience"),
|
||||
pa_object)
|
||||
.Check();
|
||||
pa_object
|
||||
->Set(context, v8_helper_->CreateStringFromLiteral("encodeUtf8"), encode)
|
||||
.Check();
|
||||
object
|
||||
pa_object
|
||||
->Set(context, v8_helper_->CreateStringFromLiteral("decodeUtf8"), decode)
|
||||
.Check();
|
||||
}
|
||||
|
||||
void TextConversionHelpers::Reset() {}
|
||||
|
||||
void TextConversionHelpers::EncodeUtf8(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
TextConversionHelpers* bindings = static_cast<TextConversionHelpers*>(
|
||||
|
@ -22,9 +22,6 @@ class CONTENT_EXPORT TextConversionHelpers : public Bindings {
|
||||
void AttachToContext(v8::Local<v8::Context> context) override;
|
||||
void Reset() override;
|
||||
|
||||
void ReInitialize(v8::Local<v8::Context> context,
|
||||
v8::Local<v8::Object> object);
|
||||
|
||||
private:
|
||||
static void EncodeUtf8(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void DecodeUtf8(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
|
@ -212,13 +212,9 @@ function validateBrowserSignals(browserSignals, isGenerateBid) {
|
||||
throw 'Wrong seller ' + browserSignals.seller;
|
||||
if ('topLevelSeller' in browserSignals)
|
||||
throw 'Wrong topLevelSeller ' + browserSignals.topLevelSeller;
|
||||
if (!(browserSignals.decodeUtf8 instanceof Function))
|
||||
throw 'Wrong decodeUtf8';
|
||||
if (!(browserSignals.encodeUtf8 instanceof Function))
|
||||
throw 'Wrong encodeUtf8';
|
||||
|
||||
if (isGenerateBid) {
|
||||
if (Object.keys(browserSignals).length !== 13) {
|
||||
if (Object.keys(browserSignals).length !== 11) {
|
||||
throw 'Wrong number of browser signals fields ' +
|
||||
JSON.stringify(browserSignals);
|
||||
}
|
||||
@ -241,7 +237,7 @@ function validateBrowserSignals(browserSignals, isGenerateBid) {
|
||||
if (browserSignals.multiBidLimit !== 1)
|
||||
throw 'Wrong multiBidLimit ' + browserSignals.multiBidLimit;
|
||||
} else {
|
||||
if (Object.keys(browserSignals).length !== 18) {
|
||||
if (Object.keys(browserSignals).length !== 16) {
|
||||
throw 'Wrong number of browser signals fields ' +
|
||||
JSON.stringify(browserSignals);
|
||||
}
|
||||
|
@ -192,13 +192,9 @@ function validateBrowserSignals(browserSignals, isGenerateBid) {
|
||||
throw 'Wrong seller ' + browserSignals.seller;
|
||||
if (!browserSignals.topLevelSeller.startsWith('https://b.test'))
|
||||
throw 'Wrong topLevelSeller ' + browserSignals.topLevelSeller;
|
||||
if (!(browserSignals.decodeUtf8 instanceof Function))
|
||||
throw 'Wrong decodeUtf8';
|
||||
if (!(browserSignals.encodeUtf8 instanceof Function))
|
||||
throw 'Wrong encodeUtf8';
|
||||
|
||||
if (isGenerateBid) {
|
||||
if (Object.keys(browserSignals).length !== 14) {
|
||||
if (Object.keys(browserSignals).length !== 12) {
|
||||
throw 'Wrong number of browser signals fields ' +
|
||||
JSON.stringify(browserSignals);
|
||||
}
|
||||
@ -221,7 +217,7 @@ function validateBrowserSignals(browserSignals, isGenerateBid) {
|
||||
if (browserSignals.multiBidLimit !== 1)
|
||||
throw 'Wrong multiBidLimit ' + browserSignals.multiBidLimit;
|
||||
} else {
|
||||
if (Object.keys(browserSignals).length !== 19) {
|
||||
if (Object.keys(browserSignals).length !== 17) {
|
||||
throw 'Wrong number of browser signals fields ' +
|
||||
JSON.stringify(browserSignals);
|
||||
}
|
||||
|
@ -171,14 +171,10 @@ function validateBrowserSignals(browserSignals, isScoreAd) {
|
||||
throw 'Wrong renderUrl ' + browserSignals.renderUrl;
|
||||
if (browserSignals.bidCurrency != 'USD')
|
||||
throw 'Wrong bidCurrency ' + browserSignals.bidCurrency;
|
||||
if (!(browserSignals.decodeUtf8 instanceof Function))
|
||||
throw 'Wrong decodeUtf8';
|
||||
if (!(browserSignals.encodeUtf8 instanceof Function))
|
||||
throw 'Wrong encodeUtf8';
|
||||
|
||||
// Fields that vary by method.
|
||||
if (isScoreAd) {
|
||||
if (Object.keys(browserSignals).length !== 14) {
|
||||
if (Object.keys(browserSignals).length !== 12) {
|
||||
throw 'Wrong number of browser signals fields ' +
|
||||
JSON.stringify(browserSignals);
|
||||
}
|
||||
@ -201,7 +197,7 @@ function validateBrowserSignals(browserSignals, isScoreAd) {
|
||||
throw 'Wrong forDebuggingOnlySampling ' +
|
||||
browserSignals.forDebuggingOnlySampling;
|
||||
} else {
|
||||
if (Object.keys(browserSignals).length !== 15) {
|
||||
if (Object.keys(browserSignals).length !== 13) {
|
||||
throw 'Wrong number of browser signals fields ' +
|
||||
JSON.stringify(browserSignals);
|
||||
}
|
||||
|
@ -185,16 +185,12 @@ function validateBrowserSignals(browserSignals, isScoreAd) {
|
||||
throw 'Wrong renderURL ' + browserSignals.renderURL;
|
||||
if (browserSignals.renderUrl !== "https://example.com/render")
|
||||
throw 'Wrong renderUrl ' + browserSignals.renderUrl;
|
||||
if (browserSignals.bidCurrency !== 'CAD')
|
||||
throw 'Wrong bidCurrency ' + browserSignals.bidCurrency;
|
||||
if (!(browserSignals.decodeUtf8 instanceof Function))
|
||||
throw 'Wrong decodeUtf8';
|
||||
if (!(browserSignals.encodeUtf8 instanceof Function))
|
||||
throw 'Wrong encodeUtf8';
|
||||
if (browserSignals.bidCurrency !== 'CAD')
|
||||
throw 'Wrong bidCurrency ' + browserSignals.bidCurrency;
|
||||
|
||||
// Fields that vary by method.
|
||||
if (isScoreAd) {
|
||||
if (Object.keys(browserSignals).length !== 14) {
|
||||
if (Object.keys(browserSignals).length !== 12) {
|
||||
throw 'Wrong number of browser signals fields ' +
|
||||
JSON.stringify(browserSignals);
|
||||
}
|
||||
@ -217,7 +213,7 @@ function validateBrowserSignals(browserSignals, isScoreAd) {
|
||||
throw 'Wrong forDebuggingOnlySampling ' +
|
||||
browserSignals.forDebuggingOnlySampling;
|
||||
} else {
|
||||
if (Object.keys(browserSignals).length !== 13) {
|
||||
if (Object.keys(browserSignals).length !== 11) {
|
||||
throw 'Wrong number of browser signals fields ' +
|
||||
JSON.stringify(browserSignals);
|
||||
}
|
||||
|
@ -193,14 +193,10 @@ function validateBrowserSignals(browserSignals, isScoreAd) {
|
||||
throw 'Wrong dataVersion ' + browserSignals.dataVersion;
|
||||
if (browserSignals.bidCurrency !== 'USD')
|
||||
throw 'Wrong bidCurrency ' + browserSignals.bidCurrency;
|
||||
if (!(browserSignals.decodeUtf8 instanceof Function))
|
||||
throw 'Wrong decodeUtf8';
|
||||
if (!(browserSignals.encodeUtf8 instanceof Function))
|
||||
throw 'Wrong encodeUtf8';
|
||||
|
||||
// Fields that vary by method.
|
||||
if (isScoreAd) {
|
||||
if (Object.keys(browserSignals).length !== 13) {
|
||||
if (Object.keys(browserSignals).length !== 11) {
|
||||
throw 'Wrong number of browser signals fields ' +
|
||||
JSON.stringify(browserSignals);
|
||||
}
|
||||
@ -221,7 +217,7 @@ function validateBrowserSignals(browserSignals, isScoreAd) {
|
||||
throw 'Wrong forDebuggingOnlySampling ' +
|
||||
browserSignals.forDebuggingOnlySampling;
|
||||
} else {
|
||||
if (Object.keys(browserSignals).length !== 12) {
|
||||
if (Object.keys(browserSignals).length !== 10) {
|
||||
throw 'Wrong number of browser signals fields ' +
|
||||
JSON.stringify(browserSignals);
|
||||
}
|
||||
|
@ -51,11 +51,6 @@ subsetTest(promise_test, async test => {
|
||||
// Remove deprecated field, if present.
|
||||
delete browserSignals.prevWins;
|
||||
|
||||
// encode/decode utf-8 are tested separately, and aren't
|
||||
// suitable to equality testing.
|
||||
delete browserSignals.encodeUtf8;
|
||||
delete browserSignals.decodeUtf8;
|
||||
|
||||
if (!deepEquals(browserSignals, expectedBrowserSignals))
|
||||
throw "Unexpected browserSignals: " + JSON.stringify(browserSignals);`
|
||||
});
|
||||
|
@ -97,19 +97,19 @@ async function testConversionException(test, conversionBody) {
|
||||
|
||||
subsetTest(promise_test, async test => {
|
||||
await testConversion(
|
||||
test, `let result = browserSignals.encodeUtf8('ABC\u0490');
|
||||
test, `let result = protectedAudience.encodeUtf8('ABC\u0490');
|
||||
assertByteArray(result, [65, 66, 67, 0xD2, 0x90])`);
|
||||
}, 'encodeUtf8 - basic');
|
||||
|
||||
subsetTest(promise_test, async test => {
|
||||
await testConversion(
|
||||
test, `let result = browserSignals.encodeUtf8('A\uD800C');
|
||||
test, `let result = protectedAudience.encodeUtf8('A\uD800C');
|
||||
assertByteArray(result, [65, 0xEF, 0xBF, 0xBD, 67])`);
|
||||
}, 'encodeUtf8 - mismatched surrogate gets replaced');
|
||||
|
||||
subsetTest(promise_test, async test => {
|
||||
await testConversion(
|
||||
test, `let result = browserSignals.encodeUtf8('A\uD83D\uDE02C');
|
||||
test, `let result = protectedAudience.encodeUtf8('A\uD83D\uDE02C');
|
||||
assertByteArray(result, [65, 0xF0, 0x9F, 0x98, 0x82, 67])`);
|
||||
}, 'encodeUtf8 - surrogate pair combined');
|
||||
|
||||
@ -118,7 +118,7 @@ subsetTest(promise_test, async test => {
|
||||
let obj = {
|
||||
toString: () => "ABC"
|
||||
};
|
||||
let result = browserSignals.encodeUtf8(obj);
|
||||
let result = protectedAudience.encodeUtf8(obj);
|
||||
assertByteArray(result, [65, 66, 67])
|
||||
`;
|
||||
await testConversion(test, conversionBody);
|
||||
@ -126,7 +126,7 @@ subsetTest(promise_test, async test => {
|
||||
|
||||
subsetTest(promise_test, async test => {
|
||||
const conversionBody = `
|
||||
let result = browserSignals.encodeUtf8();
|
||||
let result = protectedAudience.encodeUtf8();
|
||||
`;
|
||||
await testConversionException(test, conversionBody);
|
||||
}, 'encodeUtf8 - not enough arguments');
|
||||
@ -136,7 +136,7 @@ subsetTest(promise_test, async test => {
|
||||
let obj = {
|
||||
toString: () => { throw 'no go' }
|
||||
};
|
||||
let result = browserSignals.encodeUtf8(obj);
|
||||
let result = protectedAudience.encodeUtf8(obj);
|
||||
`;
|
||||
await testConversionException(test, conversionBody);
|
||||
}, 'encodeUtf8 - custom string conversion failure');
|
||||
@ -144,7 +144,7 @@ subsetTest(promise_test, async test => {
|
||||
subsetTest(promise_test, async test => {
|
||||
const conversionBody = `
|
||||
let input = new Uint8Array([65, 66, 0xD2, 0x90, 67]);
|
||||
let result = browserSignals.decodeUtf8(input);
|
||||
let result = protectedAudience.decodeUtf8(input);
|
||||
assertString(result, 'AB\u0490C');
|
||||
`;
|
||||
await testConversion(test, conversionBody);
|
||||
@ -153,7 +153,7 @@ subsetTest(promise_test, async test => {
|
||||
subsetTest(promise_test, async test => {
|
||||
const conversionBody = `
|
||||
let input = new Uint8Array([65, 32, 0xD2]);
|
||||
let result = browserSignals.decodeUtf8(input);
|
||||
let result = protectedAudience.decodeUtf8(input);
|
||||
if (result.indexOf('\uFFFD') === -1)
|
||||
throw 'Should have replacement character';
|
||||
`;
|
||||
@ -163,7 +163,7 @@ subsetTest(promise_test, async test => {
|
||||
subsetTest(promise_test, async test => {
|
||||
const conversionBody = `
|
||||
let input = new Uint8Array([65, 32, 0xED, 0xA0, 0x80, 66]);
|
||||
let result = browserSignals.decodeUtf8(input);
|
||||
let result = protectedAudience.decodeUtf8(input);
|
||||
if (result.indexOf('\uFFFD') === -1)
|
||||
throw 'Should have replacement character';
|
||||
`;
|
||||
@ -173,7 +173,7 @@ subsetTest(promise_test, async test => {
|
||||
subsetTest(promise_test, async test => {
|
||||
const conversionBody = `
|
||||
let input = new Uint8Array([65, 0xF0, 0x9F, 0x98, 0x82, 67]);
|
||||
let result = browserSignals.decodeUtf8(input);
|
||||
let result = protectedAudience.decodeUtf8(input);
|
||||
assertString(result, 'A\uD83D\uDE02C');
|
||||
`;
|
||||
await testConversion(test, conversionBody);
|
||||
@ -186,9 +186,9 @@ subsetTest(promise_test, async test => {
|
||||
for (let i = 0; i < fullView.length; ++i)
|
||||
fullView[i] = 65 + i;
|
||||
let partialView = new Uint8Array(buffer, 2, 3);
|
||||
assertString(browserSignals.decodeUtf8(fullView),
|
||||
assertString(protectedAudience.decodeUtf8(fullView),
|
||||
'ABCDEFGH');
|
||||
assertString(browserSignals.decodeUtf8(partialView),
|
||||
assertString(protectedAudience.decodeUtf8(partialView),
|
||||
'CDE');
|
||||
`;
|
||||
await testConversion(test, conversionBody);
|
||||
@ -196,14 +196,14 @@ subsetTest(promise_test, async test => {
|
||||
|
||||
subsetTest(promise_test, async test => {
|
||||
const conversionBody = `
|
||||
let result = browserSignals.decodeUtf8();
|
||||
let result = protectedAudience.decodeUtf8();
|
||||
`;
|
||||
await testConversionException(test, conversionBody);
|
||||
}, 'decodeUtf8 - not enough arguments');
|
||||
|
||||
subsetTest(promise_test, async test => {
|
||||
const conversionBody = `
|
||||
let result = browserSignals.decodeUtf8([65, 32, 66]);
|
||||
let result = protectedAudience.decodeUtf8([65, 32, 66]);
|
||||
`;
|
||||
await testConversionException(test, conversionBody);
|
||||
}, 'decodeUtf8 - wrong type');
|
||||
|
Reference in New Issue
Block a user