blob: 2808a31ad9e12cee794ac511db8ce197ececfbb7 [file] [log] [blame]
// Copyright 2022 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_BTM_BTM_BOUNCE_DETECTOR_H_
#define CONTENT_BROWSER_BTM_BTM_BOUNCE_DETECTOR_H_
#include <memory>
#include <string>
#include <variant>
#include "base/check_deref.h"
#include "base/containers/span.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "base/time/default_clock.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/types/optional_ref.h"
#include "content/browser/btm/btm_service_impl.h"
#include "content/browser/btm/btm_utils.h"
#include "content/browser/btm/cookie_access_filter.h"
#include "content/common/content_export.h"
#include "content/public/browser/allow_service_worker_result.h"
#include "content/public/browser/btm_redirect_info.h"
#include "content/public/browser/cookie_access_details.h"
#include "content/public/browser/dedicated_worker_service.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/navigation_handle_timing.h"
#include "content/public/browser/navigation_handle_user_data.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/shared_worker_service.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "url/gurl.h"
namespace base {
class Clock;
class TickClock;
} // namespace base
namespace url {
class Origin;
}
namespace content {
class WebContents;
using BtmRedirectChainHandler =
base::RepeatingCallback<void(std::vector<BtmRedirectInfoPtr>,
BtmRedirectChainInfoPtr)>;
using BtmIssueHandler =
base::RepeatingCallback<void(std::set<std::string> sites)>;
using Btm3PcSettingsCallback = base::RepeatingCallback<bool()>;
using BtmIssueReportingCallback =
base::RepeatingCallback<void(const std::set<std::string>& sites)>;
// ClientBounceDetectionState is owned by the BtmBounceDetector and stores
// data needed to detect stateful client-side redirects.
class ClientBounceDetectionState {
public:
ClientBounceDetectionState(GURL url,
std::string site,
base::TimeTicks load_time);
ClientBounceDetectionState(const ClientBounceDetectionState& other);
~ClientBounceDetectionState();
// The NavigationHandle's previously committed URL at the time the navigation
// finishes and commits.
GURL previous_url;
std::string current_site;
base::TimeTicks page_load_time;
std::optional<base::Time> last_activation_time;
std::optional<base::Time> last_storage_time;
std::optional<base::Time> last_successful_web_authn_assertion_time;
BtmDataAccessType site_data_access_type = BtmDataAccessType::kUnknown;
};
// Either the URL navigated away from (starting a new chain), or the client-side
// redirect connecting the navigation to the currently-committed chain.
// TODO: crbug.com/324573484 - rename to remove association with DIPS.
using BtmNavigationStart =
std::variant<std::pair<GURL, ukm::SourceId>, BtmRedirectInfoPtr>;
// In case of a client-side redirect loop, we need to impose a limit on the
// stored redirect chain to avoid boundless memory use. Past this limit,
// redirects are trimmed from the front of the list.
constexpr size_t kBtmRedirectChainMax = 1000;
// When checking the history of the current tab for sites following the
// first-party site, this is the maximum number of navigation entries to check.
inline constexpr int kAllSitesFollowingFirstPartyLookbackLength = 10;
// A redirect-chain-in-progress. It grows by calls to Append() and restarts by
// calls to EndChain(). Runs a `BtmRedirectChainHandler` when the chain is
// complete.
//
// TODO: crbug.com/324573484 - rename to remove association with BTM.
class CONTENT_EXPORT BtmRedirectContext {
public:
BtmRedirectContext(BtmRedirectChainHandler handler,
BtmIssueHandler issue_handler,
Btm3PcSettingsCallback are_3pcs_generally_enabled_callback,
const GURL& initial_url,
ukm::SourceId initial_source_id,
size_t redirect_prefix_count);
~BtmRedirectContext();
// Immediately calls the `BtmRedirectChainHandler` for the uncommitted
// navigation. It will take into account the length and initial URL of the
// current chain (without modifying it).
void HandleUncommitted(BtmNavigationStart navigation_start,
std::vector<BtmRedirectInfoPtr> server_redirects);
// Either calls for termination of the in-progress redirect chain, with a
// start of a new one, or extends it, according to the value of
// `navigation_start`.
void AppendCommitted(BtmNavigationStart navigation_start,
std::vector<BtmRedirectInfoPtr> server_redirects,
const GURL& final_url,
ukm::SourceId final_source_id,
bool current_page_has_interaction);
// Terminates the in-progress redirect chain, ending it with `final_url`, and
// passing it to the `BtmRedirectChainHandler` iff the chain is valid. It
// also starts a fresh redirect chain with `final_url` and `final_source_id`
// whilst clearing the state of the terminated chain. NOTE: A chain is valid
// if it has a non-empty `initial_url_`.
void EndChain(GURL final_url,
ukm::SourceId final_source_id,
bool current_page_has_interaction);
// Reports a BTM issue to the inspector (e.g., DevTools).
void ReportIssue(const GURL& final_url);
// Attempts to attribute a late cookie access `op` to a recent redirect with
// URL `url`. A late cookie access is a navigational cookie access for which
// the notification arrives after the navigation has finished. Returns true if
// the cookie access was attributed to a redirect, and false otherwise.
[[nodiscard]] bool AddLateCookieAccess(const GURL& url, CookieOperation op);
size_t size() const { return redirects_.size(); }
const GURL& GetInitialURLForTesting() const { return initial_url_; }
void SetRedirectChainHandlerForTesting(BtmRedirectChainHandler handler) {
handler_ = handler;
}
// Returns the total number of redirects in the chain, including any that
// preceded this chain that should count toward this chain's length.
size_t GetRedirectChainLength() const {
return redirects_.size() + redirect_prefix_count_;
}
const BtmRedirectInfo& operator[](size_t index) const {
return *redirects_.at(index);
}
std::optional<std::pair<size_t, BtmRedirectInfo*>> GetRedirectInfoFromChain(
const std::string& site) const;
// Return whether `site` had a user activation or authentication interaction
// in the current redirect context.
bool SiteHadUserActivationOrAuthn(const std::string& site) const;
// Return all sites that had an interaction in the current redirect context.
std::set<std::string> AllSitesWithUserActivationOrAuthn() const;
// Returns the server redirects from the last navigation. Note that due to
// limitations in C++ the BtmRedirectInfo objects are unavoidably mutable.
// Clients MUST NOT modify them.
base::span<const BtmRedirectInfoPtr>
GetServerRedirectsSinceLastPrimaryPageChange() const;
private:
void AppendClientRedirect(BtmRedirectInfoPtr client_redirect);
void AppendServerRedirects(std::vector<BtmRedirectInfoPtr> server_redirects);
// Evicts the first redirect from the front of the in-progress redirect chain
// if it exceeds its max allowed length of `kBtmRedirectChainMax`, and passes
// any evicted redirects as partial chains to the `BtmRedirectChainHandler`.
void MaybeTrimAndHandlePartialRedirectChain();
BtmRedirectChainHandler handler_;
BtmIssueHandler issue_handler_;
Btm3PcSettingsCallback are_3pcs_generally_enabled_callback_;
// Represents the start of a chain and also indicates the presence of a valid
// chain.
GURL initial_url_;
ukm::SourceId initial_source_id_;
// Whether the initial_url_ had a user activation or web authentication
// interaction while loaded.
bool initial_url_had_interaction_;
// TODO(amaliev): Make redirects_ a circular queue to handle the memory bound
// more gracefully.
std::vector<BtmRedirectInfoPtr> redirects_;
std::set<std::string> redirectors_;
// The number of redirects preceding this chain, that should be counted toward
// this chain's total length. Includes both committed redirects (for an
// uncommitted chain) and trimmed redirects. (Redirects may be trimmed from
// the front of an ongoing chain for memory management.)
size_t redirect_prefix_count_ = 0;
};
// A simplified interface to WebContents and BtmServiceImpl that can be faked
// in tests. Needed to allow unit testing BtmBounceDetector.
//
// TODO: crbug.com/324573484 - rename to remove association with BTM.
class CONTENT_EXPORT BtmBounceDetectorDelegate {
public:
virtual ~BtmBounceDetectorDelegate();
virtual GURL GetLastCommittedURL() const = 0;
virtual ukm::SourceId GetLastCommittedSourceId() const = 0;
virtual void HandleRedirectChain(std::vector<BtmRedirectInfoPtr> redirects,
BtmRedirectChainInfoPtr chain) = 0;
// Report `sites` as redirectors to the inspector (e.g., DevTools).
virtual void ReportRedirectors(std::set<std::string> sites) = 0;
virtual void OnSiteStorageAccessed(const GURL& first_party_url,
CookieOperation op,
bool http_cookie) = 0;
virtual bool Are3PcsGenerallyEnabled() const = 0;
};
// ServerBounceDetectionState gets attached to NavigationHandle (which is a
// SupportsUserData subclass) to store data needed to detect stateful
// server-side redirects.
class CONTENT_EXPORT ServerBounceDetectionState
: public NavigationHandleUserData<ServerBounceDetectionState> {
public:
ServerBounceDetectionState();
~ServerBounceDetectionState() override;
struct ServerRedirectData {
const int http_response_code;
const base::TimeDelta bounce_delay;
const bool was_response_cached;
const GURL destination_url;
};
// A BtmRedirectInfoPtr if the navigation started with a client redirect; a
// UrlAndSourceId otherwise.
BtmNavigationStart navigation_start;
CookieAccessFilter filter;
std::vector<ServerRedirectData> server_redirects;
std::vector<ukm::SourceId> server_redirect_source_ids;
base::TimeTicks last_server_redirect;
private:
explicit ServerBounceDetectionState(NavigationHandle& navigation_handle);
friend NavigationHandleUserData;
NAVIGATION_HANDLE_USER_DATA_KEY_DECL();
};
// A simplified interface to `NavigationHandle` that can be faked in tests.
//
// TODO: crbug.com/324573484 - Rename to remove association with BTM.
// TODO: crbug.com/381687258 - Remove in favor of using `NavigationSimulator` in
// tests.
class CONTENT_EXPORT BtmNavigationHandle {
public:
virtual ~BtmNavigationHandle();
// See NavigationHandle for an explanation of these methods:
const GURL& GetURL() const { return GetRedirectChain().back(); }
virtual ukm::SourceId GetNextPageUkmSourceId() = 0;
virtual const GURL& GetPreviousPrimaryMainFrameURL() const = 0;
virtual bool HasCommitted() const = 0;
virtual const std::vector<GURL>& GetRedirectChain() const = 0;
virtual bool WasResponseCached() = 0;
// Get the HTTP response code from the navigation.
virtual int GetHTTPResponseCode() = 0;
// This method has one important (simplifying) change from
// NavigationHandle::HasUserGesture(): it returns true if the
// navigation was not renderer-initiated.
virtual bool HasUserGesture() const = 0;
// This method doesn't have a direct equivalent in NavigationHandle,
// as it relies on GetInitiatorOrigin(), but returns what is effectively a
// base URL. Also, this returns `about:blank` if the initiator origin is
// unspecified or opaque.
virtual const GURL GetInitiator() const = 0;
// Get a SourceId of type REDIRECT_ID for the index'th URL in the redirect
// chain.
ukm::SourceId GetRedirectSourceId(size_t index);
// Create a ukm::SourceId of type REDIRECT_ID for the given redirector URL.
ukm::SourceId MakeRedirectSourceId(const GURL& url) const;
// Calls ServerBounceDetectionState::GetOrCreateForNavigationHandle(). We
// declare this instead of making BtmNavigationHandle a subclass of
// SupportsUserData, because ServerBounceDetectionState inherits from
// NavigationHandleUserData, whose helper functions only work with actual
// NavigationHandle, not any SupportsUserData.
virtual ServerBounceDetectionState* GetServerState() = 0;
};
// Detects client- and server-side bounces and handles them (currently by
// collecting metrics and storing them in the BtmDatabase).
//
// This class has a communication loop with `RedirectChainDetector`.
// `RedirectChainDetector` owns this class and calls it directly; this class
// then uses the `BtmBounceDetectorDelegate` interface, which
// `RedirectChainDetector` implements, to communicate back to the owning
// `RedirectChainDetector` instance.
//
// TODO: crbug.com/324573484 - rename this to avoid confusion with
// `RedirectChainDetector` and remove its association with BTM.
class CONTENT_EXPORT BtmBounceDetector {
public:
explicit BtmBounceDetector(BtmBounceDetectorDelegate* delegate,
const base::TickClock* tick_clock,
const base::Clock* clock);
~BtmBounceDetector();
BtmBounceDetector(const BtmBounceDetector&) = delete;
BtmBounceDetector& operator=(const BtmBounceDetector&) = delete;
void SetClockForTesting(base::Clock* clock) { clock_ = clock; }
const base::Clock* GetClock() { return clock_.get(); }
// The following methods are based on WebContentsObserver, simplified.
void DidStartNavigation(BtmNavigationHandle* navigation_handle);
void DidRedirectNavigation(BtmNavigationHandle* navigation_handle);
void OnClientSiteDataAccessed(const GURL& url, CookieOperation op);
// Note: `navigation_handle` may be null if this server cookie access is
// associated with a document rather than a navigation.
void OnServerCookiesAccessed(BtmNavigationHandle* navigation_handle,
const GURL& url,
CookieOperation op);
void DidFinishNavigation(BtmNavigationHandle* navigation_handle);
// Only records a new user activation event once per
// |kTimestampUpdateInterval| for a given page.
void OnUserActivation();
// Only records a new Web authn assertion event once per
// |kTimestampUpdateInterval| for a given page.
void WebAuthnAssertionRequestSucceeded();
// Makes a call to process the current chain before its state is destroyed by
// the tab closure.
void BeforeDestruction();
// Use the passed handler instead of
// BtmBounceDetectorDelegate::HandleRedirect().
void SetRedirectChainHandlerForTesting(BtmRedirectChainHandler handler) {
committed_redirect_context_.SetRedirectChainHandlerForTesting(handler);
}
// Returns state for the in-progress redirect chain.
const BtmRedirectContext& CommittedRedirectContext() const {
return committed_redirect_context_;
}
// Attempts to attribute the late cookie access notification `op` to a recent
// redirect by `url` in the current chain. A "late" cookie access is a
// navigational cookie access that is reported after the navigation has
// finished. Returns true if the access was attributed to a redirect, and
// false otherwise.
[[nodiscard]] bool AddLateCookieAccess(GURL url, CookieOperation op) {
bool was_late = committed_redirect_context_.AddLateCookieAccess(url, op);
if (was_late) {
OnServerCookiesAccessed(/*navigation_handle=*/nullptr, url, op);
}
return was_late;
}
// Makes a call to process the current chain on
// `client_bounce_detection_timer_`'s timeout.
void OnClientBounceDetectionTimeout();
private:
// Whether or not the `last_time` timestamp should be updated yet. This is
// used to enforce throttling of timestamp updates, reducing the number of
// writes to the DIPS db.
bool ShouldUpdateTimestamp(base::optional_ref<const base::Time> last_time,
base::Time now);
raw_ptr<const base::TickClock> tick_clock_;
raw_ptr<const base::Clock> clock_;
raw_ptr<BtmBounceDetectorDelegate> delegate_;
std::optional<ClientBounceDetectionState> client_detection_state_;
BtmRedirectContext committed_redirect_context_;
base::RetainingOneShotTimer client_bounce_detection_timer_;
};
// Holds a pointer to a redirect chain, and uses a timer to delay BTM's
// processing of the chain, to give some time for "late" cookie accesses to be
// reported first.
class DelayedChainHandler {
public:
explicit DelayedChainHandler(BtmRedirectChainHandler handler);
~DelayedChainHandler();
void HandleRedirectChain(std::vector<BtmRedirectInfoPtr> redirects,
BtmRedirectChainInfoPtr chain);
[[nodiscard]] bool AddLateCookieAccess(const GURL& url, CookieOperation op);
void HandlePreviousChainNow() {
HandlePreviousChainNowImpl(/*timer_fired=*/false);
}
private:
void HandlePreviousChainNowImpl(bool timer_fired);
BtmRedirectChainHandler handler_;
std::optional<
std::pair<std::vector<BtmRedirectInfoPtr>, BtmRedirectChainInfoPtr>>
prev_chain_pair_;
base::RetainingOneShotTimer timer_;
};
// Attached to a `WebContents` and observes its navigations to detect chains of
// server and client redirects. Notifies `RedirectChainDetector::Observer`s
// when a redirect chain has completed.
//
// TODO: crbug.com/324573485 - move to separate file.
class CONTENT_EXPORT RedirectChainDetector
: public WebContentsObserver,
public WebContentsUserData<RedirectChainDetector>,
public BtmBounceDetectorDelegate {
public:
class Observer : public base::CheckedObserver {
public:
// Called when a navigation has committed and the redirect context has been
// updated. (If you override WebContentsObserver::DidFinishNavigation()
// directly, you could be called before the context has been updated.)
virtual void OnNavigationCommitted(NavigationHandle* navigation_handle) {}
// Called when any redirect chain ends, including ones that end with an
// uncommitted navigation.
virtual void OnRedirectChainEnded(const std::vector<BtmRedirectInfoPtr>&,
const BtmRedirectChainInfo&) {}
// Called before OnRedirectChainEnded() with set of redirector sites in the
// chain, omitting the initial and final sites.
// TODO(rtarpine) - replace with more general purpose method
virtual void ReportRedirectors(const std::set<std::string>& sites) {}
// Called when most types of storage are accessed (including cookies,
// the Web Storage API, IndexedDB, etc). Does not report 3PCs, and
// attributes partitioned storage to the top-level URL.
virtual void OnSiteStorageAccessed(const GURL& first_party_url,
CookieOperation op,
bool http_cookie) {}
};
void AddObserver(Observer* observer);
void RemoveObserver(const Observer* observer);
~RedirectChainDetector() override;
void SetRedirectChainHandlerForTesting(BtmRedirectChainHandler handler) {
detector_.SetRedirectChainHandlerForTesting(handler);
}
// Returns state for the in-progress redirect chain.
const BtmRedirectContext& CommittedRedirectContext() const {
return detector_.CommittedRedirectContext();
}
void SetClockForTesting(base::Clock* clock) {
detector_.SetClockForTesting(clock);
}
private:
explicit RedirectChainDetector(WebContents* web_contents);
// So WebContentsUserData::CreateForWebContents() can call the constructor.
friend class WebContentsUserData<RedirectChainDetector>;
// BtmBounceDetectorDelegate overrides:
GURL GetLastCommittedURL() const override;
ukm::SourceId GetLastCommittedSourceId() const override;
void HandleRedirectChain(std::vector<BtmRedirectInfoPtr> redirects,
BtmRedirectChainInfoPtr chain) override;
void ReportRedirectors(std::set<std::string> sites) override;
void OnSiteStorageAccessed(const GURL& first_party_url,
CookieOperation op,
bool http_cookie) override;
bool Are3PcsGenerallyEnabled() const override;
// End BtmBounceDetectorDelegate overrides.
// Start WebContentsObserver overrides:
void PrimaryPageChanged(Page& page) override;
void DidStartNavigation(NavigationHandle* navigation_handle) override;
void DidRedirectNavigation(NavigationHandle* navigation_handle) override;
// See the `WebContentsObserver` declarations for `OnCookiesAccessed` for when
// this overload is called vs. the other.
void OnCookiesAccessed(RenderFrameHost* render_frame_host,
const CookieAccessDetails& details) override;
// See the `WebContentsObserver` declarations for `OnCookiesAccessed` for when
// this overload is called vs. the other.
void OnCookiesAccessed(NavigationHandle* navigation_handle,
const CookieAccessDetails& details) override;
void NotifyStorageAccessed(RenderFrameHost* render_frame_host,
blink::mojom::StorageTypeAccessed storage_type,
bool blocked) override;
void DidFinishNavigation(NavigationHandle* navigation_handle) override;
void FrameReceivedUserActivation(RenderFrameHost* render_frame_host) override;
void WebAuthnAssertionRequestSucceeded(
RenderFrameHost* render_frame_host) override;
void WebContentsDestroyed() override;
// End WebContentsObserver overrides:
void NotifyOnRedirectChainEnded(std::vector<BtmRedirectInfoPtr> redirects,
BtmRedirectChainInfoPtr chain);
BtmBounceDetector detector_;
DelayedChainHandler delayed_handler_;
base::ObserverList<Observer> observers_;
base::WeakPtrFactory<RedirectChainDetector> weak_factory_{this};
WEB_CONTENTS_USER_DATA_KEY_DECL();
};
// Populates the BTM database with site metadata, which is then used by the
// `BtmService` to identify sites that perform bounce tracking and delete their
// storage.
class CONTENT_EXPORT BtmWebContentsObserver
: public WebContentsObserver,
public WebContentsUserData<BtmWebContentsObserver>,
public SharedWorkerService::Observer,
public DedicatedWorkerService::Observer,
public RedirectChainDetector::Observer {
public:
static void MaybeCreateForWebContents(WebContents* web_contents);
~BtmWebContentsObserver() override;
// Use the passed handler instead of BtmWebContentsObserver::EmitBtmIssue().
void SetIssueReportingCallbackForTesting(BtmIssueReportingCallback callback) {
issue_reporting_callback_ = callback;
}
// TODO(rtarpine): make this take a Clock&.
void SetClockForTesting(base::Clock* clock) {
DCHECK(btm_service_);
btm_service_->storage()
->AsyncCall(&BtmStorage::SetClockForTesting)
.WithArgs(clock);
RedirectChainDetector::FromWebContents(web_contents())
->SetClockForTesting(clock);
clock_ = *clock;
}
private:
BtmWebContentsObserver(WebContents* web_contents,
BtmServiceImpl* dips_service);
// So WebContentsUserData::CreateForWebContents() can call the constructor.
friend class WebContentsUserData<BtmWebContentsObserver>;
// Emits a BTM issue to the inspector (e.g., DevTools).
void EmitBtmIssue(const std::set<std::string>& sites);
void RecordEvent(BtmRecordedEvent event,
const GURL& url,
const base::Time& time);
void OnStatefulBounce(const GURL& final_url);
// Start RedirectChainDetector::Observer overrides:
void ReportRedirectors(const std::set<std::string>& sites) override;
void OnRedirectChainEnded(const std::vector<BtmRedirectInfoPtr>& redirects,
const BtmRedirectChainInfo& chain) override;
void OnSiteStorageAccessed(const GURL& first_party_url,
CookieOperation op,
bool http_cookie) override;
// End RedirectChainDetector::Observer overrides.
// Start WebContentsObserver overrides:
void PrimaryPageChanged(Page& page) override;
void OnServiceWorkerAccessed(RenderFrameHost* render_frame_host,
const GURL& scope,
AllowServiceWorkerResult allowed) override;
void OnServiceWorkerAccessed(NavigationHandle* navigation_handle,
const GURL& scope,
AllowServiceWorkerResult allowed) override;
void FrameReceivedUserActivation(RenderFrameHost* render_frame_host) override;
void WebAuthnAssertionRequestSucceeded(
RenderFrameHost* render_frame_host) override;
void WebContentsDestroyed() override;
// End WebContentsObserver overrides:
// Start SharedWorkerService.Observer overrides:
void OnClientAdded(const blink::SharedWorkerToken& token,
GlobalRenderFrameHostId render_frame_host_id) override;
void OnWorkerCreated(const blink::SharedWorkerToken& token,
int worker_process_id,
const url::Origin& security_origin,
const base::UnguessableToken& dev_tools_token) override {
}
void OnBeforeWorkerDestroyed(const blink::SharedWorkerToken& token) override {
}
void OnClientRemoved(const blink::SharedWorkerToken& token,
GlobalRenderFrameHostId render_frame_host_id) override {}
using SharedWorkerService::Observer::OnFinalResponseURLDetermined;
// End SharedWorkerService.Observer overrides.
// Start DedicatedWorkerService.Observer overrides:
void OnWorkerCreated(const blink::DedicatedWorkerToken& worker_token,
int worker_process_id,
const url::Origin& security_origin,
DedicatedWorkerCreator creator) override;
void OnBeforeWorkerDestroyed(const blink::DedicatedWorkerToken& worker_token,
DedicatedWorkerCreator creator) override {}
void OnFinalResponseURLDetermined(
const blink::DedicatedWorkerToken& worker_token,
const GURL& url) override {}
// End DedicatedWorkerService.Observer overrides.
raw_ptr<RedirectChainDetector> detector_;
// raw_ptr<> is safe here because BtmServiceImpl is a KeyedService,
// associated with the BrowserContext/Profile which will outlive the
// WebContents that BtmWebContentsObserver is observing.
raw_ptr<BtmServiceImpl> btm_service_;
raw_ref<base::Clock> clock_{*base::DefaultClock::GetInstance()};
BtmIssueReportingCallback issue_reporting_callback_;
std::optional<std::string> last_committed_site_;
std::optional<base::Time> last_storage_timestamp_;
std::optional<base::Time> last_interaction_timestamp_;
base::WeakPtrFactory<BtmWebContentsObserver> weak_factory_{this};
WEB_CONTENTS_USER_DATA_KEY_DECL();
};
namespace btm {
ukm::SourceId GetRedirectSourceId(NavigationHandle* navigation_handle,
size_t index);
CONTENT_EXPORT bool IsOrWasInPrimaryPage(RenderFrameHost& render_frame_host);
// Sets the `has_3pc_exception` field of each element of `redirects`.
CONTENT_EXPORT void Populate3PcExceptions(
BrowserContext* browser_context,
WebContents* web_contents,
const GURL& initial_url,
const GURL& final_url,
base::span<BtmRedirectInfoPtr> redirects);
// Checks whether third-party cookies are generally enabled within this browser
// session.
//
// Any bounce tracking mitigations processing should be short-circuited when
// TPCs are enabled by default.
CONTENT_EXPORT bool Are3PcsGenerallyEnabled(BrowserContext* browser_context,
WebContents* web_contents);
} // namespace btm
} // namespace content
#endif // CONTENT_BROWSER_BTM_BTM_BOUNCE_DETECTOR_H_