1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241
  242
  243
  244
  245
  246
  247
  248
  249
  250
  251
  252
  253
  254
  255
  256
  257
  258
  259
  260
  261
  262
  263
  264
  265
  266
  267
  268
  269
  270
  271
  272
  273
  274
  275
  276
  277
  278
  279
  280
  281
  282
  283
  284

content / browser / interest_group / ad_auction_service_impl.h [blame]

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

#ifndef CONTENT_BROWSER_INTEREST_GROUP_AD_AUCTION_SERVICE_IMPL_H_
#define CONTENT_BROWSER_INTEREST_GROUP_AD_AUCTION_SERVICE_IMPL_H_

#include <map>
#include <memory>
#include <set>
#include <vector>

#include "base/containers/unique_ptr_adapters.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "base/types/expected.h"
#include "base/uuid.h"
#include "content/browser/fenced_frame/fenced_frame_url_mapping.h"
#include "content/browser/interest_group/auction_nonce_manager.h"
#include "content/browser/interest_group/auction_runner.h"
#include "content/browser/interest_group/auction_worklet_manager.h"
#include "content/browser/interest_group/bidding_and_auction_serializer.h"
#include "content/browser/interest_group/interest_group_auction_reporter.h"
#include "content/common/content_export.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/document_service.h"
#include "content/services/auction_worklet/public/mojom/private_aggregation_request.mojom-forward.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/mojom/client_security_state.mojom.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
#include "third_party/blink/public/common/interest_group/auction_config.h"
#include "third_party/blink/public/mojom/interest_group/ad_auction_service.mojom.h"
#include "third_party/blink/public/mojom/interest_group/interest_group_types.mojom-forward.h"
#include "third_party/blink/public/mojom/parakeet/ad_request.mojom.h"
#include "third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom-forward.h"
#include "url/gurl.h"
#include "url/origin.h"

namespace content {

class InterestGroupManagerImpl;
class PrivateAggregationManager;
class ReconnectableURLLoaderFactory;
class RenderFrameHost;
class RenderFrameHostImpl;
struct BiddingAndAuctionServerKey;

// Implements the AdAuctionService service called by Blink code.
class CONTENT_EXPORT AdAuctionServiceImpl final
    : public DocumentService<blink::mojom::AdAuctionService>,
      public AuctionWorkletManager::Delegate {
 public:
  // Factory method for creating an instance of this interface that is
  // bound to the lifetime of the frame or receiver (whichever is shorter).
  static void CreateMojoService(
      RenderFrameHost* render_frame_host,
      mojo::PendingReceiver<blink::mojom::AdAuctionService> receiver);

  // blink::mojom::AdAuctionService.
  void JoinInterestGroup(const blink::InterestGroup& group,
                         JoinInterestGroupCallback callback) override;
  void LeaveInterestGroup(const url::Origin& owner,
                          const std::string& name,
                          LeaveInterestGroupCallback callback) override;
  void LeaveInterestGroupForDocument() override;
  void ClearOriginJoinedInterestGroups(
      const url::Origin& owner,
      const std::vector<std::string>& interest_groups_to_keep,
      ClearOriginJoinedInterestGroupsCallback callback) override;
  void UpdateAdInterestGroups() override;
  void RunAdAuction(
      const blink::AuctionConfig& config,
      mojo::PendingReceiver<blink::mojom::AbortableAdAuction> abort_receiver,
      RunAdAuctionCallback callback) override;
  void DeprecatedGetURLFromURN(
      const GURL& urn_url,
      bool send_reports,
      DeprecatedGetURLFromURNCallback callback) override;
  void DeprecatedReplaceInURN(
      const GURL& urn_url,
      const std::vector<blink::AuctionConfig::AdKeywordReplacement>&
          replacements,
      DeprecatedReplaceInURNCallback callback) override;
  void GetInterestGroupAdAuctionData(
      const url::Origin& seller,
      const std::optional<url::Origin>& coordinator,
      blink::mojom::AuctionDataConfigPtr config,
      GetInterestGroupAdAuctionDataCallback callback) override;
  void CreateAdRequest(blink::mojom::AdRequestConfigPtr config,
                       CreateAdRequestCallback callback) override;
  void FinalizeAd(const std::string& ads_guid,
                  const blink::AuctionConfig& config,
                  FinalizeAdCallback callback) override;

  scoped_refptr<network::SharedURLLoaderFactory>
  GetRefCountedTrustedURLLoaderFactory();

  // AuctionWorkletManager::Delegate implementation:
  network::mojom::URLLoaderFactory* GetFrameURLLoaderFactory() override;
  network::mojom::URLLoaderFactory* GetTrustedURLLoaderFactory() override;
  void PreconnectSocket(
      const GURL& url,
      const net::NetworkAnonymizationKey& network_anonymization_key) override;
  RenderFrameHostImpl* GetFrame() override;
  scoped_refptr<SiteInstance> GetFrameSiteInstance() override;
  network::mojom::ClientSecurityStatePtr GetClientSecurityState() override;
  std::optional<std::string> GetCookieDeprecationLabel() override;
  void GetBiddingAndAuctionServerKey(
      const std::optional<url::Origin>& coordinator,
      base::OnceCallback<void(base::expected<BiddingAndAuctionServerKey,
                                             std::string>)> callback) override;

  using DocumentService::origin;
  using DocumentService::render_frame_host;

 private:
  using ReporterList = std::list<std::unique_ptr<InterestGroupAuctionReporter>>;

  class BiddingAndAuctionDataConstructionState {
   public:
    BiddingAndAuctionDataConstructionState();
    BiddingAndAuctionDataConstructionState(
        BiddingAndAuctionDataConstructionState&& other);
    ~BiddingAndAuctionDataConstructionState();

    base::TimeTicks start_time;  // time used for metrics
    std::unique_ptr<BiddingAndAuctionServerKey> key;
    std::unique_ptr<BiddingAndAuctionData> data;
    base::Uuid request_id;
    url::Origin seller;
    std::optional<url::Origin> coordinator;
    base::Time timestamp;  // timestamp to include in the request.
    blink::mojom::AuctionDataConfigPtr config;
    GetInterestGroupAdAuctionDataCallback callback;
  };

  // `render_frame_host` must not be null, and DocumentService guarantees
  // `this` will not outlive the `render_frame_host`.
  AdAuctionServiceImpl(
      RenderFrameHost& render_frame_host,
      mojo::PendingReceiver<blink::mojom::AdAuctionService> receiver);

  // `this` can only be destroyed by DocumentService.
  ~AdAuctionServiceImpl() override;

  // Checks if a join or leave interest group is allowed to be sent from the
  // current renderer. If not, returns false and invokes
  // ReportBadMessageAndDeleteThis().
  bool JoinOrLeaveApiAllowedFromRenderer(const url::Origin& owner,
                                         const char* invoked_method);

  // Checks if `feature` is enabled for the frame, and returns true if so, and
  // false if not. Additionally, if the feature is enabled, prints a warning to
  // the console if the feature would not be enabled if the default state of the
  // feature across cross-origin frames were switched to disabled instead of
  // enabled.
  bool IsPermissionPolicyEnabledAndWarnIfNeeded(
      blink::mojom::PermissionsPolicyFeature feature,
      const char* method);

  // Returns true if `origin` is allowed to perform the specified
  // `interest_group_api_operation` in this frame. Must be called on worklet /
  // interest group origins before using them in any interest group API.
  bool IsInterestGroupAPIAllowed(ContentBrowserClient::InterestGroupApiOperation
                                     interest_group_api_operation,
                                 const url::Origin& origin) const;

  // Deletes `auction`.
  void OnAuctionComplete(
      RunAdAuctionCallback callback,
      GURL urn_uuid,
      AuctionRunner* auction,
      bool aborted_by_script,
      std::optional<blink::InterestGroupKey> winning_group_key,
      std::optional<blink::AdSize> requested_ad_size,
      std::optional<blink::AdDescriptor> ad_descriptor,
      std::vector<blink::AdDescriptor> ad_component_descriptors,
      std::vector<std::string> errors,
      std::unique_ptr<InterestGroupAuctionReporter> reporter,
      bool contained_server_auction,
      bool contained_on_device_auction,
      AuctionResult result);

  void OnReporterComplete(ReporterList::iterator reporter_it);

  void MaybeLogPrivateAggregationFeatures(
      const std::vector<auction_worklet::mojom::PrivateAggregationRequestPtr>&
          private_aggregation_requests);

  // On failing to fetch ad auction data, call the first callback in
  // ba_data_callbacks_ & start loading the next following request in
  // ba_data_callbacks_.
  void ReturnEmptyGetInterestGroupAdAuctionDataCallback(const std::string& msg);
  void LoadAuctionDataAndKeyForNextQueuedRequest();
  void OnGotAuctionData(base::Uuid request_id, BiddingAndAuctionData data);
  void OnGotBiddingAndAuctionServerKey(
      base::Uuid request_id,
      base::expected<BiddingAndAuctionServerKey, std::string> maybe_key);
  void OnGotAuctionDataAndKey(base::Uuid request_id);

  InterestGroupManagerImpl& GetInterestGroupManager() const;

  url::Origin GetTopWindowOrigin() const;

  void CreateUnderlyingTrustedURLLoaderFactory(
      mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory);

  AdAuctionPageData* GetAdAuctionPageData();

  // For each buyer in `config`, preconnect to its origin and bidding signals
  // origin if the origins have been cached from previous interest group joins
  // or auctions. This function needs to be called separately to preconnect to
  // origins for `config`'s component auctions. Returns the number of buyers
  // that were preconnected.
  size_t PreconnectToBuyerOrigins(const blink::AuctionConfig& config);

  // To avoid race conditions associated with top frame navigations (mentioned
  // in document_service.h), we need to save the values of the main frame
  // URL and origin in the constructor.
  const url::Origin main_frame_origin_;
  const GURL main_frame_url_;

  mojo::Remote<network::mojom::URLLoaderFactory> frame_url_loader_factory_;

  // A URLLoaderFactory connecting to the underlying factory created by
  // CreateUnderlyingTrustedURLLoaderFactory(), with reconnecting support. This
  // can be used for reporting requests, which might happen after the frame is
  // destroyed.
  scoped_refptr<ReconnectableURLLoaderFactory>
      ref_counted_trusted_url_loader_factory_;

  // Used to create AuctionMetricsRecorders, which store data needed to record
  // UKM. This must be before `auction_worklet_manager_`, since worklet owners
  // may keep references to the AuctionMetricsRecorders owned by the
  // `auction_metrics_recorder_manager_`.
  AuctionMetricsRecorderManager auction_metrics_recorder_manager_;

  // This must be before `auctions_`, since auctions may own references to
  // worklets it manages.
  AuctionWorkletManager auction_worklet_manager_;

  // Manages auction nonces issued by prior calls to CreateAuctionNonce,
  // which are used by subsequent calls to RunAdAuction.
  AuctionNonceManager auction_nonce_manager_;

  // Use a map instead of a list so can remove entries without destroying them.
  // TODO(mmenke): Switch to std::set() and use extract() once that's allowed.
  std::map<AuctionRunner*, std::unique_ptr<AuctionRunner>> auctions_;
  ReporterList reporters_;

  // Safe to keep as it will outlive the associated `RenderFrameHost` and
  // therefore `this`, being tied to the lifetime of the `StoragePartition`.
  const raw_ptr<PrivateAggregationManager> private_aggregation_manager_;

  // Whether a UseCounter has already been logged for usage of the Private
  // Aggregation API in general, the extended Private Aggregation API and the
  // Private Aggregation API's enableDebugMode(), respectively.
  bool has_logged_private_aggregation_web_features_ = false;
  bool has_logged_extended_private_aggregation_web_feature_ = false;
  bool has_logged_private_aggregation_enable_debug_mode_web_feature_ = false;
  bool has_logged_private_aggregation_filtering_id_web_feature_ = false;

  // Track the state of GetInterestGroupAdAuctionData calls. One request will be
  // handled at a time (the first in the queue). The first
  // BiddingAndAuctionDataConstructionState's data and key will be edited in
  // place as they are loaded.
  base::queue<BiddingAndAuctionDataConstructionState> ba_data_callbacks_;

  // True if a feature is currently enabled, but would be disabled if the
  // default policy for the feature were switched to EnableForSelf. Lazily
  // populated.
  std::map<blink::mojom::PermissionsPolicyFeature, bool>
      should_warn_about_feature_;

  base::WeakPtrFactory<AdAuctionServiceImpl> weak_ptr_factory_{this};
};

}  // namespace content

#endif  // CONTENT_BROWSER_INTEREST_GROUP_AD_AUCTION_SERVICE_IMPL_H_