blob: 6e7d6b526778d11eb30bcdaa17d771e0a026e4b0 [file] [log] [blame]
// Copyright 2025 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_PAGE_VISIT_OBSERVER_H_
#define CONTENT_BROWSER_BTM_BTM_PAGE_VISIT_OBSERVER_H_
#include <deque>
#include <vector>
#include "base/check_deref.h"
#include "base/functional/callback_forward.h"
#include "base/memory/weak_ptr.h"
#include "base/time/clock.h"
#include "base/time/default_clock.h"
#include "base/time/time.h"
#include "content/common/content_export.h"
#include "content/public/browser/btm_redirect_info.h"
#include "content/public/browser/web_contents_observer.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "url/gurl.h"
namespace content {
struct CONTENT_EXPORT BtmPageVisitInfo {
GURL url;
ukm::SourceId source_id;
bool had_active_storage_access = false;
bool received_user_activation = false;
bool had_successful_web_authn_assertion = false;
// Computed based on wall-clock times, so the usual caveat for working with
// wall-clock times applies: the system clock may have been changed during the
// page visit and so the duration may not be positive.
base::TimeDelta visit_duration;
};
struct CONTENT_EXPORT BtmServerRedirectInfo {
GURL url;
ukm::SourceId source_id;
bool did_write_cookies = false;
};
struct CONTENT_EXPORT BtmNavigationInfo {
// Precondition: `navigation_handle.HasCommitted()` must be `true`.
explicit BtmNavigationInfo(NavigationHandle& navigation_handle);
BtmNavigationInfo(BtmNavigationInfo&&);
BtmNavigationInfo& operator=(BtmNavigationInfo&&);
~BtmNavigationInfo();
std::vector<BtmServerRedirectInfo> server_redirects;
bool was_user_initiated;
bool was_renderer_initiated;
ui::PageTransition page_transition;
// The page where the navigation ultimately committed.
GURL destination_url;
ukm::SourceId destination_source_id;
};
// Observes a `WebContents` and reports page visit information to a callback. A
// page visit is defined as the time from when a primary page is committed until
// the next primary page change. Also attempts to attribute late cookie access
// notifications (reports of navigational cookie accesses that are received
// after the navigation has finished) to the appropriate page or redirect.
class CONTENT_EXPORT BtmPageVisitObserver : public WebContentsObserver {
public:
using VisitCallback =
base::RepeatingCallback<void(BtmPageVisitInfo, BtmNavigationInfo)>;
// The arguments to `VisitCallback`.
struct VisitTuple {
BtmPageVisitInfo prev_page;
BtmNavigationInfo navigation;
};
BtmPageVisitObserver(WebContents* web_contents,
VisitCallback callback,
base::Clock* clock = base::DefaultClock::GetInstance());
~BtmPageVisitObserver() override;
// WebContentsObserver overrides:
void DidStartNavigation(NavigationHandle* navigation_handle) override;
void DidRedirectNavigation(NavigationHandle* navigation_handle) override;
void DidFinishNavigation(NavigationHandle* navigation_handle) override;
void NotifyStorageAccessed(RenderFrameHost* render_frame_host,
blink::mojom::StorageTypeAccessed storage_type,
bool blocked) override;
void OnCookiesAccessed(RenderFrameHost* render_frame_host,
const CookieAccessDetails& details) override;
void OnCookiesAccessed(NavigationHandle* navigation_handle,
const CookieAccessDetails& details) override;
void FrameReceivedUserActivation(RenderFrameHost* render_frame_host) override;
void WebAuthnAssertionRequestSucceeded(
RenderFrameHost* render_frame_host) override;
void SetClockForTesting(base::Clock* clock) { clock_ = CHECK_DEREF(clock); }
private:
// Execute the visit callback with a tuple from the pending queue.
void ReportVisit();
// The callback to execute for each page visit.
VisitCallback callback_;
// Metadata on the currently committed page.
BtmPageVisitInfo current_page_;
raw_ref<base::Clock> clock_;
base::Time last_page_change_time_;
// Past page visits that we are holding on to, to see if any late cookie
// access notifications come through for them. A "late" cookie access
// notification is when a navigational cookie access is reported after the
// navigation has finished.
std::deque<VisitTuple> pending_visits_;
base::WeakPtrFactory<BtmPageVisitObserver> weak_factory_{this};
};
} // namespace content
#endif // CONTENT_BROWSER_BTM_BTM_PAGE_VISIT_OBSERVER_H_