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
content / services / auction_worklet / trusted_signals_kvv2_manager.h [blame]
// 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_MANAGER_H_
#define CONTENT_SERVICES_AUCTION_WORKLET_TRUSTED_SIGNALS_KVV2_MANAGER_H_
#include <map>
#include <memory>
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#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/public/mojom/trusted_signals_cache.mojom.h"
#include "content/services/auction_worklet/trusted_signals.h"
#include "content/services/auction_worklet/trusted_signals_kvv2_helper.h"
#include "content/services/auction_worklet/trusted_signals_request_manager.h"
#include "mojo/public/cpp/base/big_buffer.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace auction_worklet {
class AuctionV8Helper;
// Class to manage and parse requests for trusted key-value server version 2
// requests from the browser-side TrustedSignalsCache. Each instance is scoped
// to an AuctionWorkletService, and may be used to fetch results that come from
// different trusted signals URLs, and a single instance may be used by multiple
// BidderWorklets/SellerWorklets.
//
// Callers request signals using a `compression_group_token` provided by the
// browser process. This class merges requests for the same compression group.
// Once the requested compression group has been provided by the browser process
// as a compressed CBOR string, this class decompresses and parses it. It then
// distributes the data to all consumers that requested it, and keeps the parsed
// data cached as long as there's any live consumer of the data, handing it out
// to satisfy new requests.
//
// All fields of all partitions in all requested compression groups are
// currently parsed up front, rather than on first use, so they can safely be
// reused on different V8 threads.
//
// TODO(crbug.com/365957549): Implement some way to not have to parse an entire
// compression group when only limited data is needed from it.
class CONTENT_EXPORT TrustedSignalsKVv2Manager
: public mojom::TrustedSignalsCacheClient {
public:
using Result = TrustedSignals::Result;
using SignalsType = TrustedSignalsKVv2ResponseParser::SignalsType;
using PartitionMapOrError =
TrustedSignalsKVv2ResponseParser::PartitionMapOrError;
using ResultOrError = base::expected<scoped_refptr<Result>, std::string>;
// Use common callback type to make it easy to use both this and a
// TrustedSignalsRequestManager. Once TrustedSignalsRequestManager has been
// removed, may make sense to switch to a callback that takes a ResultOrError
// instead.
using LoadSignalsCallback = TrustedSignalsRequestManager::LoadSignalsCallback;
// Represents a single pending request for TrustedSignals from a consumer.
// Destroying it cancels the request. All live Requests must be destroyed
// before the TrustedSignalsKVv2Manager.
class Request {
public:
Request(Request&) = delete;
Request& operator=(Request&) = delete;
virtual ~Request() = default;
protected:
Request() = default;
};
TrustedSignalsKVv2Manager(
mojo::PendingRemote<mojom::TrustedSignalsCache> trusted_signals_cache,
scoped_refptr<AuctionV8Helper> v8_helper);
TrustedSignalsKVv2Manager(TrustedSignalsKVv2Manager&) = delete;
~TrustedSignalsKVv2Manager() override;
TrustedSignalsKVv2Manager& operator=(TrustedSignalsKVv2Manager&) = delete;
// Requests signals from the cache with `compression_group_token`, and parses
// the `partition_id` partition as `signals_type` signals. The signals for the
// specified partition will asynchronously be passed back to the passed in
// callback.
std::unique_ptr<Request> RequestSignals(
SignalsType signals_type,
base::UnguessableToken compression_group_token,
int partition_id,
LoadSignalsCallback load_signals_callback);
private:
// Private implementation of Request.
class RequestImpl;
// Tracks the data for a particular compression group, and all pending
// Requests associated with it. Created when the first request with a new
// UnguessableToken is received, at which point, the data is requested, and
// destroyed when all Requests associated with it have been destroyed. Once
// the data is received and has been parsed, it's still kept alive to
// distribute the parsed data (or error) to new incoming requests for the same
// compression group.
struct CompressionGroup;
// Map of the IDs identifying each compression group to each CompressionGroup.
using CompressionGroupMap =
std::map<base::UnguessableToken, CompressionGroup>;
// A map of partition IDs to the result of parsing each partition.
using PartitionMap = std::map<int, scoped_refptr<Result>>;
// mojom::TrustedSignalsCacheClient implementation:
void OnSuccess(mojom::TrustedSignalsCompressionScheme compression_scheme,
mojo_base::BigBuffer compression_group_data) override;
void OnError(const std::string& error_message) override;
// Called by OnComplete() once parsing has completed. Distributed the result
// to all waiting requests, and stores it for future incoming requests.
void OnComplete(base::UnguessableToken compression_group_token,
PartitionMapOrError parsed_compression_group_result);
// Closes the Mojo pipe in `compression_group_pipes_` associated with the
// specified CompressionGroup and clears the compression group's
// mojo::ReceiverId. The passed in CompressionGroup must have a live pipe.
void ClosePipe(CompressionGroupMap::iterator compression_group_it);
// Called by RequestImpl when it's destroyed. Removes association between the
// request and the CompressionGroup, destroying the group if it has no more
// associated requests.
void OnRequestDestroyed(RequestImpl* request,
CompressionGroupMap::iterator compression_group_it);
// Retrieves the result for `partition_id` from `compression_group`. Even if
// the compression group was fetched and parsed successfully, may return an
// error if the partition is missing from the group.
static ResultOrError GetResultForPartition(
const CompressionGroup& compression_group,
int partition_id);
// Map of compression group IDs to CompressionGroups. A compression group is
// destroyed when all Requests associated with it have been destroyed.
CompressionGroupMap compression_groups_;
mojo::Remote<mojom::TrustedSignalsCache> trusted_signals_cache_;
// Set of receiver pipes associated with each CompressionGroup that's waiting
// on data.
mojo::ReceiverSet<mojom::TrustedSignalsCacheClient,
CompressionGroupMap::iterator>
compression_group_pipes_;
const scoped_refptr<AuctionV8Helper> v8_helper_;
base::WeakPtrFactory<TrustedSignalsKVv2Manager> weak_ptr_factory_{this};
};
} // namespace auction_worklet
#endif // CONTENT_SERVICES_AUCTION_WORKLET_TRUSTED_SIGNALS_KVV2_MANAGER_H_