| // 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 <set> |
| #include <string> |
| #include <vector> |
| |
| #include "base/callback_forward.h" |
| #include "base/containers/flat_map.h" |
| #include "base/gtest_prod_util.h" |
| #include "base/memory/raw_ptr.h" |
| #include "content/browser/fenced_frame/fenced_frame_config.h" |
| #include "content/common/content_export.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| #include "url/gurl.h" |
| #include "url/origin.h" |
| |
| 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 |
| class CONTENT_EXPORT FencedFrameURLMapping { |
| public: |
| // The runURLSelectionOperation's url mapping result. It contains the mapped |
| // url and the `SharedStorageBudgetMetadata`. |
| struct CONTENT_EXPORT SharedStorageURNMappingResult { |
| GURL mapped_url; |
| SharedStorageBudgetMetadata budget_metadata; |
| SharedStorageReportingMap reporting_map; |
| SharedStorageURNMappingResult(); |
| SharedStorageURNMappingResult(GURL mapped_url, |
| SharedStorageBudgetMetadata budget_metadata, |
| SharedStorageReportingMap reporting_map); |
| ~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 absl::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 assert, |
| // since it will result in adding the same URNs twice to the same mapping. |
| 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`. These will to be made available to |
| // any fenced frame navigated to the returned URN, via the InterestGroup API. |
| // |
| // `on_navigate_callback` should be run on navigation to `urn_uuid`. |
| // |
| // See https://github.com/WICG/turtledove/blob/main/FLEDGE.md |
| void AssignFencedFrameURLAndInterestGroupInfo( |
| const GURL& urn_uuid, |
| const GURL& url, |
| AdAuctionData auction_data, |
| base::RepeatingClosure on_navigate_callback, |
| std::vector<GURL> ad_component_urls, |
| const ReportingMetadata& reporting_metadata = ReportingMetadata()); |
| |
| // 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 absl::nullopt if number of |
| // mappings has reached limit. Ad auction and `selectURL()` will be terminated |
| // up front and an error will be reported. |
| absl::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_`. |
| void 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 absl::nullopt if number of mappings |
| // has reached limit. Enforcing a limit on number of mappings prevents |
| // excessive memory consumption. |
| // `reporting_metadata` will contain a `ReportingMetadata` that populates |
| // any metadata invoked by the worklet using `RegisterAdBeacon`. See |
| // https://github.com/WICG/turtledove/blob/main/Fenced_Frames_Ads_Reporting.md#registeradbeacon |
| absl::optional<GURL> AddFencedFrameURLForTesting( |
| const GURL& url, |
| const ReportingMetadata& reporting_metadata = ReportingMetadata()); |
| |
| // 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/1253118): 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. |
| absl::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_ |