chromium/content/services/auction_worklet/seller_worklet.cc

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/services/auction_worklet/seller_worklet.h"

#include <stdint.h>

#include <cmath>
#include <list>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

#include "base/containers/flat_map.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/memory/scoped_refptr.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/strcat.h"
#include "base/task/bind_post_task.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "base/timer/elapsed_timer.h"
#include "base/trace_event/trace_event.h"
#include "base/types/optional_ref.h"
#include "content/services/auction_worklet/auction_v8_helper.h"
#include "content/services/auction_worklet/auction_v8_logger.h"
#include "content/services/auction_worklet/auction_worklet_util.h"
#include "content/services/auction_worklet/context_recycler.h"
#include "content/services/auction_worklet/direct_from_seller_signals_requester.h"
#include "content/services/auction_worklet/for_debugging_only_bindings.h"
#include "content/services/auction_worklet/private_aggregation_bindings.h"
#include "content/services/auction_worklet/public/cpp/auction_network_events_delegate.h"
#include "content/services/auction_worklet/public/mojom/auction_worklet_service.mojom.h"
#include "content/services/auction_worklet/public/mojom/seller_worklet.mojom.h"
#include "content/services/auction_worklet/real_time_reporting_bindings.h"
#include "content/services/auction_worklet/register_ad_beacon_bindings.h"
#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/trusted_signals.h"
#include "content/services/auction_worklet/webidl_compat.h"
#include "content/services/auction_worklet/worklet_loader.h"
#include "content/services/auction_worklet/worklet_util.h"
#include "gin/converter.h"
#include "gin/dictionary.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/interest_group/ad_auction_currencies.h"
#include "third_party/blink/public/common/interest_group/ad_display_size.h"
#include "third_party/blink/public/common/interest_group/auction_config.h"
#include "third_party/blink/public/mojom/interest_group/interest_group_types.mojom.h"
#include "url/gurl.h"
#include "url/origin.h"
#include "v8/include/v8-context.h"
#include "v8/include/v8-forward.h"
#include "v8/include/v8-object.h"
#include "v8/include/v8-template.h"

namespace auction_worklet {

namespace {

// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class ScoreAdInput {};

// Checks both types of DirectFromSellerSignals results (subresource bundle
// based and header based) -- at most one of these should be non-null.
//
// Returns the V8 conversion of the in-use version of DirectFromSellerSignals,
// or v8::Null() if both types of DirectFromSellerSignals are null.
v8::Local<v8::Value> GetDirectFromSellerSignals(
    const DirectFromSellerSignalsRequester::Result& subresource_bundle_result,
    const std::optional<std::string>& header_result,
    AuctionV8Helper& v8_helper,
    v8::Local<v8::Context> context,
    std::vector<std::string>& errors) {}

// ### some duplication with same in interest_group_auction.cc
bool IsValidBid(double bid) {}

// Converts `auction_config` back to JSON format, and appends to args.
// Returns true if conversion succeeded.
//
// `auction_config_lazy_fillers` is incoming, and is organized as follows:
//   [0] corresponds to the top-level auction.
//   [1] corresponds to the 0th component auction.
//   [2] corresponds to the 1th component auction.
//   ... and so on.
// where `auction_config_lazy_filler_pos` describes the position the current
// invocation is expected to use; e.g. it's 0 for top-level, and i + 1 for
// i'th component auction.
//
// The resulting object will look something like this (based on example from
// explainer):
//
// {
//  'seller': 'https://www.example-ssp.com/',
//  'decisionLogicURL': 'https://www.example-ssp.com/seller.js',
//  'trustedScoringSignalsURL': ...,
//  'interestGroupBuyers': ['https://www.example-dsp.com', 'https://buyer2.com',
//  ...], 'auctionSignals': {...}, 'sellerSignals': {...}, 'sellerTimeout': 100,
//  `reportingTimeout`: 600,
//  'perBuyerSignals': {'https://www.example-dsp.com': {...},
//                      'https://www.another-buyer.com': {...},
//                       ...},
//  'perBuyerTimeouts': {'https://www.example-dsp.com': 50,
//                       'https://www.another-buyer.com': 200,
//                       '*': 150,
//                       ...},
//  'perBuyerPrioritySignals': {'https://www.example-dsp.com': {...},
//                              'https://www.another-buyer.com': {...},
//                              '*': {...},
//                              ...},
// }
//
// (With many fields filled in on-demand by an AuctionConfigLazyFiller).
bool AppendAuctionConfig(
    AuctionV8Helper* v8_helper,
    AuctionV8Logger* v8_logger,
    v8::Local<v8::Context> context,
    const url::Origin& seller,
    base::optional_ref<const GURL> decision_logic_url,
    base::optional_ref<const GURL> trusted_scoring_signals_url,
    const std::optional<uint16_t> experiment_group_id,
    const blink::AuctionConfig::NonSharedParams&
        auction_ad_config_non_shared_params,
    const std::vector<std::unique_ptr<AuctionConfigLazyFiller>>&
        auction_config_lazy_fillers,
    size_t auction_config_lazy_filler_pos,
    v8::LocalVector<v8::Value>* args) {}

// Adds the top-level/component seller origin from
// `browser_signals_other_seller` to `browser_signals_dict`. Does nothing if
// `browser_signals_other_seller` is null. Returns false on error.
bool AddOtherSeller(
    mojom::ComponentAuctionOtherSeller* browser_signals_other_seller,
    gin::Dictionary& browser_signals_dict) {}

// Converts reject reason string to corresponding mojom enum.
std::optional<mojom::RejectReason> RejectReasonStringToEnum(
    const std::string& reason) {}

// Checks `provided_currency` against both `expected_seller_currency` and
// `component_expect_bid_currency`, formatting an error if needed, with
// `bid_label` identifying the bid being checked.
// Returns true on success.
bool VerifySellerCurrency(
    std::optional<blink::AdCurrency> provided_currency,
    std::optional<blink::AdCurrency> expected_seller_currency,
    std::optional<blink::AdCurrency> component_expect_bid_currency,
    const GURL& script_url,
    std::string_view bid_label,
    std::vector<std::string>& errors_out) {}

std::optional<base::TimeDelta> NullOptIfZero(base::TimeDelta delta) {}

// Check if trusted scoring signals are absent, same-origin, or cross-origin.
SellerWorklet::SignalsOriginRelation ClassifyTrustedSignals(
    const GURL& decision_logic_url,
    const std::optional<url::Origin>& trusted_scoring_signals_origin) {}

// Sets the appropriate field (if any) of `browser_signals` to data version,
// considering the cross-origin validity.
// Returns success/failure.
bool SetDataVersion(
    SellerWorklet::SignalsOriginRelation trusted_signals_relation,
    std::optional<uint32_t> scoring_signals_data_version,
    gin::Dictionary& browser_signals_dict) {}

// Remove worklet latency contributions if the worklet execution time is
// within the threshold.
std::vector<auction_worklet::mojom::RealTimeReportingContributionPtr>
FilterRealtimeContributions(
    std::vector<auction_worklet::mojom::RealTimeReportingContributionPtr>
        real_time_contributions,
    base::TimeDelta elapsed) {}

}  // namespace

SellerWorklet::SellerWorklet(
    std::vector<scoped_refptr<AuctionV8Helper>> v8_helpers,
    std::vector<mojo::PendingRemote<mojom::AuctionSharedStorageHost>>
        shared_storage_hosts,
    bool pause_for_debugger_on_start,
    mojo::PendingRemote<network::mojom::URLLoaderFactory>
        pending_url_loader_factory,
    mojo::PendingRemote<auction_worklet::mojom::AuctionNetworkEventsHandler>
        auction_network_events_handler,
    const GURL& decision_logic_url,
    const std::optional<GURL>& trusted_scoring_signals_url,
    const url::Origin& top_window_origin,
    mojom::AuctionWorkletPermissionsPolicyStatePtr permissions_policy_state,
    std::optional<uint16_t> experiment_group_id,
    GetNextThreadIndexCallback get_next_thread_index_callback)
    :{}

SellerWorklet::~SellerWorklet() {}

std::vector<int> SellerWorklet::context_group_ids_for_testing() const {}

void SellerWorklet::ScoreAd(
    const std::string& ad_metadata_json,
    double bid,
    const std::optional<blink::AdCurrency>& bid_currency,
    const blink::AuctionConfig::NonSharedParams&
        auction_ad_config_non_shared_params,
    const std::optional<GURL>& direct_from_seller_seller_signals,
    const std::optional<std::string>&
        direct_from_seller_seller_signals_header_ad_slot,
    const std::optional<GURL>& direct_from_seller_auction_signals,
    const std::optional<std::string>&
        direct_from_seller_auction_signals_header_ad_slot,
    mojom::ComponentAuctionOtherSellerPtr browser_signals_other_seller,
    const std::optional<blink::AdCurrency>& component_expect_bid_currency,
    const url::Origin& browser_signal_interest_group_owner,
    const GURL& browser_signal_render_url,
    const std::optional<std::string>&
        browser_signal_selected_buyer_and_seller_reporting_id,
    const std::optional<std::string>&
        browser_signal_buyer_and_seller_reporting_id,
    const std::vector<GURL>& browser_signal_ad_components,
    uint32_t browser_signal_bidding_duration_msecs,
    const std::optional<blink::AdSize>& browser_signal_render_size,
    bool browser_signal_for_debugging_only_in_cooldown_or_lockout,
    const std::optional<base::TimeDelta> seller_timeout,
    uint64_t trace_id,
    mojo::PendingRemote<auction_worklet::mojom::ScoreAdClient>
        score_ad_client) {}

void SellerWorklet::SendPendingSignalsRequests() {}

void SellerWorklet::ReportResult(
    const blink::AuctionConfig::NonSharedParams&
        auction_ad_config_non_shared_params,
    const std::optional<GURL>& direct_from_seller_seller_signals,
    const std::optional<std::string>&
        direct_from_seller_seller_signals_header_ad_slot,
    const std::optional<GURL>& direct_from_seller_auction_signals,
    const std::optional<std::string>&
        direct_from_seller_auction_signals_header_ad_slot,
    mojom::ComponentAuctionOtherSellerPtr browser_signals_other_seller,
    const url::Origin& browser_signal_interest_group_owner,
    const std::optional<std::string>&
        browser_signal_buyer_and_seller_reporting_id,
    const std::optional<std::string>&
        browser_signal_selected_buyer_and_seller_reporting_id,
    const GURL& browser_signal_render_url,
    double browser_signal_bid,
    const std::optional<blink::AdCurrency>& browser_signal_bid_currency,
    double browser_signal_desirability,
    double browser_signal_highest_scoring_other_bid,
    const std::optional<blink::AdCurrency>&
        browser_signal_highest_scoring_other_bid_currency,
    auction_worklet::mojom::ComponentAuctionReportResultParamsPtr
        browser_signals_component_auction_report_result_params,
    std::optional<uint32_t> scoring_signals_data_version,
    uint64_t trace_id,
    ReportResultCallback callback) {}

void SellerWorklet::ConnectDevToolsAgent(
    mojo::PendingAssociatedReceiver<blink::mojom::DevToolsAgent> agent,
    uint32_t thread_index) {}

SellerWorklet::ScoreAdTask::ScoreAdTask() = default;
SellerWorklet::ScoreAdTask::~ScoreAdTask() = default;

SellerWorklet::ReportResultTask::ReportResultTask() = default;
SellerWorklet::ReportResultTask::~ReportResultTask() = default;

SellerWorklet::V8State::V8State(
    scoped_refptr<AuctionV8Helper> v8_helper,
    scoped_refptr<AuctionV8Helper::DebugId> debug_id,
    mojo::PendingRemote<mojom::AuctionSharedStorageHost>
        shared_storage_host_remote,
    const GURL& decision_logic_url,
    const std::optional<GURL>& trusted_scoring_signals_url,
    const std::optional<url::Origin>& trusted_scoring_signals_origin,
    const url::Origin& top_window_origin,
    mojom::AuctionWorkletPermissionsPolicyStatePtr permissions_policy_state,
    std::optional<uint16_t> experiment_group_id,
    base::WeakPtr<SellerWorklet> parent)
    :{}

void SellerWorklet::V8State::SetWorkletScript(
    WorkletLoader::Result worklet_script,
    SignalsOriginRelation trusted_signals_relation) {}

void SellerWorklet::V8State::ScoreAd(
    const std::string& ad_metadata_json,
    double bid,
    const std::optional<blink::AdCurrency>& bid_currency,
    const blink::AuctionConfig::NonSharedParams&
        auction_ad_config_non_shared_params,
    DirectFromSellerSignalsRequester::Result
        direct_from_seller_result_seller_signals,
    const std::optional<std::string>&
        direct_from_seller_seller_signals_header_ad_slot,
    DirectFromSellerSignalsRequester::Result
        direct_from_seller_result_auction_signals,
    const std::optional<std::string>&
        direct_from_seller_auction_signals_header_ad_slot,
    scoped_refptr<TrustedSignals::Result> trusted_scoring_signals,
    bool trusted_scoring_signals_fetch_failed,
    mojom::ComponentAuctionOtherSellerPtr browser_signals_other_seller,
    const std::optional<blink::AdCurrency>& component_expect_bid_currency,
    const url::Origin& browser_signal_interest_group_owner,
    const GURL& browser_signal_render_url,
    const std::optional<std::string>&
        browser_signal_selected_buyer_and_seller_reporting_id,
    const std::optional<std::string>&
        browser_signal_buyer_and_seller_reporting_id,
    const std::vector<std::string>& browser_signal_ad_components,
    uint32_t browser_signal_bidding_duration_msecs,
    const std::optional<blink::AdSize>& browser_signal_render_size,
    bool browser_signal_for_debugging_only_in_cooldown_or_lockout,
    const std::optional<base::TimeDelta> seller_timeout,
    uint64_t trace_id,
    base::ScopedClosureRunner cleanup_score_ad_task,
    base::TimeTicks task_enqueued_time,
    ScoreAdCallbackInternal callback) {}

void SellerWorklet::V8State::ReportResult(
    const blink::AuctionConfig::NonSharedParams&
        auction_ad_config_non_shared_params,
    DirectFromSellerSignalsRequester::Result
        direct_from_seller_result_seller_signals,
    const std::optional<std::string>&
        direct_from_seller_seller_signals_header_ad_slot,
    DirectFromSellerSignalsRequester::Result
        direct_from_seller_result_auction_signals,
    const std::optional<std::string>&
        direct_from_seller_auction_signals_header_ad_slot,
    mojom::ComponentAuctionOtherSellerPtr browser_signals_other_seller,
    const url::Origin& browser_signal_interest_group_owner,
    const std::optional<std::string>&
        browser_signal_buyer_and_seller_reporting_id,
    const std::optional<std::string>&
        browser_signal_selected_buyer_and_seller_reporting_id,
    const GURL& browser_signal_render_url,
    double browser_signal_bid,
    const std::optional<blink::AdCurrency>& browser_signal_bid_currency,
    double browser_signal_desirability,
    double browser_signal_highest_scoring_other_bid,
    const std::optional<blink::AdCurrency>&
        browser_signal_highest_scoring_other_bid_currency,
    auction_worklet::mojom::ComponentAuctionReportResultParamsPtr
        browser_signals_component_auction_report_result_params,
    std::optional<uint32_t> scoring_signals_data_version,
    uint64_t trace_id,
    ReportResultCallbackInternal callback) {}

void SellerWorklet::V8State::ConnectDevToolsAgent(
    mojo::PendingAssociatedReceiver<blink::mojom::DevToolsAgent> agent) {}

SellerWorklet::V8State::~V8State() {}

void SellerWorklet::V8State::FinishInit(
    mojo::PendingRemote<mojom::AuctionSharedStorageHost>
        shared_storage_host_remote) {}

// static
void SellerWorklet::V8State::PostResumeToUserThread(
    base::WeakPtr<SellerWorklet> parent,
    scoped_refptr<base::SequencedTaskRunner> user_thread) {}

void SellerWorklet::V8State::PostScoreAdCallbackToUserThreadOnError(
    ScoreAdCallbackInternal callback,
    base::TimeDelta scoring_latency,
    std::vector<std::string> errors,
    PrivateAggregationRequests pa_requests,
    RealTimeReportingContributions real_time_contributions) {}

void SellerWorklet::V8State::PostScoreAdCallbackToUserThread(
    ScoreAdCallbackInternal callback,
    double score,
    mojom::RejectReason reject_reason,
    mojom::ComponentAuctionModifiedBidParamsPtr
        component_auction_modified_bid_params,
    std::optional<double> bid_in_seller_currency,
    std::optional<uint32_t> scoring_signals_data_version,
    std::optional<GURL> debug_loss_report_url,
    std::optional<GURL> debug_win_report_url,
    PrivateAggregationRequests pa_requests,
    RealTimeReportingContributions real_time_contributions,
    base::TimeDelta scoring_latency,
    std::vector<std::string> errors) {}

void SellerWorklet::V8State::PostReportResultCallbackToUserThread(
    ReportResultCallbackInternal callback,
    std::optional<std::string> signals_for_winner,
    std::optional<GURL> report_url,
    base::flat_map<std::string, GURL> ad_beacon_map,
    PrivateAggregationRequests pa_requests,
    base::TimeDelta reporting_latency,
    std::vector<std::string> errors) {}

void SellerWorklet::ResumeIfPaused() {}

void SellerWorklet::Start() {}

void SellerWorklet::OnDownloadComplete(
    std::vector<WorkletLoader::Result> worklet_scripts,
    std::optional<std::string> error_msg) {}

void SellerWorklet::MaybeRecordCodeWait() {}

void SellerWorklet::OnGotCrossOriginTrustedSignalsPermissions(
    std::vector<url::Origin> permit_origins) {}

void SellerWorklet::StartFetchingSignalsForTask(
    ScoreAdTaskList::iterator score_ad_task) {}

void SellerWorklet::OnTrustedScoringSignalsDownloaded(
    ScoreAdTaskList::iterator task,
    scoped_refptr<TrustedSignals::Result> result,
    std::optional<std::string> error_msg) {}

void SellerWorklet::OnScoreAdClientDestroyed(ScoreAdTaskList::iterator task) {}

void SellerWorklet::OnDirectFromSellerSellerSignalsDownloadedScoreAd(
    ScoreAdTaskList::iterator task,
    DirectFromSellerSignalsRequester::Result result) {}

void SellerWorklet::OnDirectFromSellerAuctionSignalsDownloadedScoreAd(
    ScoreAdTaskList::iterator task,
    DirectFromSellerSignalsRequester::Result result) {}

bool SellerWorklet::IsReadyToScoreAd(const ScoreAdTask& task) const {}

void SellerWorklet::ScoreAdIfReady(ScoreAdTaskList::iterator task) {}

void SellerWorklet::DeliverScoreAdCallbackOnUserThread(
    ScoreAdTaskList::iterator task,
    double score,
    mojom::RejectReason reject_reason,
    mojom::ComponentAuctionModifiedBidParamsPtr
        component_auction_modified_bid_params,
    std::optional<double> bid_in_seller_currency,
    std::optional<uint32_t> scoring_signals_data_version,
    std::optional<GURL> debug_loss_report_url,
    std::optional<GURL> debug_win_report_url,
    PrivateAggregationRequests pa_requests,
    RealTimeReportingContributions real_time_contributions,
    base::TimeDelta scoring_latency,
    std::vector<std::string> errors) {}

void SellerWorklet::CleanUpScoreAdTaskOnUserThread(
    ScoreAdTaskList::iterator task) {}

void SellerWorklet::OnDirectFromSellerSellerSignalsDownloadedReportResult(
    ReportResultTaskList::iterator task,
    DirectFromSellerSignalsRequester::Result result) {}

void SellerWorklet::OnDirectFromSellerAuctionSignalsDownloadedReportResult(
    ReportResultTaskList::iterator task,
    DirectFromSellerSignalsRequester::Result result) {}

bool SellerWorklet::IsReadyToReportResult(const ReportResultTask& task) const {}

void SellerWorklet::RunReportResultIfReady(
    ReportResultTaskList::iterator task) {}

void SellerWorklet::DeliverReportResultCallbackOnUserThread(
    ReportResultTaskList::iterator task,
    const std::optional<std::string> signals_for_winner,
    const std::optional<GURL> report_url,
    base::flat_map<std::string, GURL> ad_beacon_map,
    PrivateAggregationRequests pa_requests,
    base::TimeDelta reporting_latency,
    std::vector<std::string> errors) {}

bool SellerWorklet::IsCodeReady() const {}

}  // namespace auction_worklet