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
|
// 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_FENCED_FRAME_FENCED_FRAME_URL_MAPPING_H_
#define CONTENT_BROWSER_FENCED_FRAME_FENCED_FRAME_URL_MAPPING_H_
#include <map>
#include <optional>
#include <set>
#include <string>
#include <vector>
#include "base/containers/flat_map.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "content/browser/fenced_frame/fenced_frame_config.h"
#include "content/browser/fenced_frame/fenced_frame_reporter.h"
#include "content/common/content_export.h"
#include "url/gurl.h"
namespace blink {
struct AdDescriptor;
struct AdSize;
} // namespace blink
namespace content {
class FencedFrameURLMappingTestPeer;
using SharedStorageReportingMap = base::flat_map<std::string, ::GURL>;
// Keeps a mapping of fenced frames URN:UUID and URL. Also keeps a set of
// pending mapped URN:UUIDs to support asynchronous mapping. See
// https://github.com/WICG/fenced-frame/blob/master/explainer/opaque_src.md
// TODO(crbug.com/40252330): Add methods for:
// 1. generating the pending config.
// 2. finalizing the pending config.
class CONTENT_EXPORT FencedFrameURLMapping {
public:
// The runURLSelectionOperation's url mapping result. It contains the mapped
// url, the `SharedStorageBudgetMetadata`, and a FencedFrameReporter.
struct CONTENT_EXPORT SharedStorageURNMappingResult {
GURL mapped_url;
SharedStorageBudgetMetadata budget_metadata;
scoped_refptr<FencedFrameReporter> fenced_frame_reporter;
SharedStorageURNMappingResult();
SharedStorageURNMappingResult(
GURL mapped_url,
SharedStorageBudgetMetadata budget_metadata,
scoped_refptr<FencedFrameReporter> fenced_frame_reporter);
~SharedStorageURNMappingResult();
};
class MappingResultObserver {
public:
virtual ~MappingResultObserver() = default;
// Called as soon as the URN mapping decision is made.
//
// On success, `properties` will be populated with the properties bound to
// the urn:uuid.
virtual void OnFencedFrameURLMappingComplete(
const std::optional<FencedFrameProperties>& properties) = 0;
};
FencedFrameURLMapping();
~FencedFrameURLMapping();
FencedFrameURLMapping(FencedFrameURLMapping&) = delete;
FencedFrameURLMapping& operator=(FencedFrameURLMapping&) = delete;
// Imports URN to URL mappings from passed in mapping. Generally only called
// once per PendingAdComponentsMap, on the mapping associated with a frame
// being navigated to a URN. Calling this twice with the same
// PendingAdComponentsMap on the same FencedFrameURLMapping will do nothing.
void ImportPendingAdComponents(
const std::vector<std::pair<GURL, FencedFrameConfig>>& components);
// Move pending mapped `urn_uuid` from `pending_urn_uuid_to_url_map_` to
// `urn_uuid_to_url_map_`. Then assign ad auction data as well as an ordered
// list of ad component URLs, provided by a bidder running an auction, to the
// entry associated with the `urn_uuid` and its associated
// `FencedFrameConfig`. These will to be made available to any fenced frame
// that gets navigated to the URN encapsulated inside the
// `RedactedFencedFrameConfig` that is returned from this method. Either this
// config or the internal URN inside of it is returned to script via the
// InterestGroup API. They used to perform the fenced frame navigation.
//
// `on_navigate_callback` should be run on navigation to `urn_uuid`.
//
// See https://github.com/WICG/turtledove/blob/main/FLEDGE.md
blink::FencedFrame::RedactedFencedFrameConfig
AssignFencedFrameURLAndInterestGroupInfo(
const GURL& urn_uuid,
std::optional<blink::AdSize> container_size,
const blink::AdDescriptor& ad_descriptor,
AdAuctionData auction_data,
base::RepeatingClosure on_navigate_callback,
std::vector<blink::AdDescriptor> ad_component_descriptors,
scoped_refptr<FencedFrameReporter> fenced_frame_reporter = nullptr);
// Generate a URN that is not yet mapped to a URL.
// * For Shared Storage, it will be returned by
// `sharedStorage.runURLSelectionOperation` before the URL selection decision
// is made.
// * For FLEDGE, it will be moved from `pending_urn_uuid_to_url_map_` to
// `urn_uuid_to_url_map_` when ad auction completes. Info provided by auction
// bidder will be assigned using `AssignFencedFrameURLAndInterestGroupInfo`.
//
// This method will fail and return std::nullopt if number of
// mappings has reached limit. Ad auction and `selectURL()` will be terminated
// up front and an error will be reported.
std::optional<GURL> GeneratePendingMappedURN();
// Register an observer for `urn_uuid`. The observer will be notified with the
// mapping result and will be auto unregistered. If `urn_uuid` already exists
// in `urn_uuid_to_url_map_`, or if it is not recognized at all, the observer
// will be notified synchronously; if the mapping is pending (i.e. `urn_uuid`
// exists in `pending_urn_uuid_to_url_map_`), the observer will be notified
// asynchronously as soon as when the mapping decision is made.
void ConvertFencedFrameURNToURL(const GURL& urn_uuid,
MappingResultObserver* observer);
// Explicitly unregister the observer for `urn_uuid`. This is only needed if
// the observer is going to become invalid and the mapping is still pending.
void RemoveObserverForURN(const GURL& urn_uuid,
MappingResultObserver* observer);
// Called when the shared storage mapping decision is made for `urn_uuid`.
// Should only be invoked on a `urn_uuid` pending to be mapped. This method
// will trigger the observers' OnFencedFrameURLMappingComplete() method
// associated with the `urn_uuid`, unregister those observers, and move the
// `urn_uuid` from `pending_urn_uuid_to_url_map_` to `urn_uuid_to_url_map_`.
// If the resolved URL is fenced-frame-compatible, the return value is the
// populated fenced frame config. It is used to notify the observers in shared
// storage worklet host manager. Tests can then obtain the populated fenced
// frame configs from the observers.
// Otherwise this method returns an std::nullopt.
std::optional<FencedFrameConfig> OnSharedStorageURNMappingResultDetermined(
const GURL& urn_uuid,
const SharedStorageURNMappingResult& mapping_result);
// Adds a mapping for |url| to a URN:UUID that will be generated by this
// function. Should only be invoked with a valid URL which is one of the
// "potentially trustworthy URLs".
// Mapping will not be added and return std::nullopt if number of mappings
// has reached limit. Enforcing a limit on number of mappings prevents
// excessive memory consumption.
// `fenced_frame_reporter` will contain a `FencedFrameReporter` to associate
// with the created URN. It may be nullptr.
std::optional<GURL> AddFencedFrameURLForTesting(
const GURL& url,
scoped_refptr<FencedFrameReporter> fenced_frame_reporter = nullptr);
// Erases the urn_uuid_to_url_map_ and the pending_urn_uuid_to_url_map_.
void ClearMapForTesting();
// Return the `SharedStorageBudgetMetadata` associated with `urn_uuid`, or
// nullptr if there's no metadata associated (i.e. `urn_uuid` was not
// originated from shared storage). Precondition: `urn_uuid` exists in
// `urn_uuid_to_url_map_`.
//
// This method will be called during the lifetime of a `NavigationRequest`
// object, to associate the budget metadata to each relevant committed
// document. A non-null returned pointer will stay valid during the
// `FencedFrameURLMapping`'s (thus the page's) lifetime, and a page will
// outlive any `NavigationRequest` occurring in fenced frames in the page,
// thus it's safe for a `NavigationRequest` to store a pointer to this.
SharedStorageBudgetMetadata* GetSharedStorageBudgetMetadataForTesting(
const GURL& urn_uuid);
// Modifies the true URL from a URN by replacing substrings specified in the
// replacements map. The true URLs for any component ads associated with this
// URN will also have substrings substituted. This function will be removed
// once all FLEDGE auctions switch to using fenced frames.
// TODO(crbug.com/40199055): Remove this function when we remove support for
// showing FLEDGE ads in iframes.
void SubstituteMappedURL(
const GURL& urn_uuid,
const std::vector<std::pair<std::string, std::string>>& substitutions);
private:
friend class FencedFrameURLMappingTestPeer;
using UrnUuidToUrlMap = std::map<GURL, FencedFrameConfig>;
// The maximum number of urn mappings.
static constexpr size_t kMaxUrnMappingSize = 65536;
// Adds an entry to `urn_uuid_to_url_map_` for `url`, generating a unique URN
// as the key. Insertion fails if number of entries has reached the limit.
std::optional<UrnUuidToUrlMap::iterator> AddMappingForUrl(const GURL& url);
bool IsMapped(const GURL& urn_uuid) const;
bool IsPendingMapped(const GURL& urn_uuid) const;
// Return true if number of mappings in `urn_uuid_to_url_map_` and
// `pending_urn_uuid_to_url_map_` has reached the limit specified as
// `kMaxUrnMappingSize`.
bool IsFull() const;
// The URNs that are already mapped to URLs, along with their mapping info.
UrnUuidToUrlMap urn_uuid_to_url_map_;
// The URNs that are not yet mapped to URLs, along with the associated
// observers to be notified when the mapping decision is made.
std::map<GURL, std::set<raw_ptr<MappingResultObserver>>>
pending_urn_uuid_to_url_map_;
};
} // namespace content
#endif // CONTENT_BROWSER_FENCED_FRAME_FENCED_FRAME_URL_MAPPING_H_
|