blob: fe3ee7a65f6cfb295c999d2bd92ad66df2ab8e7d [file] [log] [blame]
// Copyright 2013 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_RENDERER_HOST_NAVIGATOR_H_
#define CONTENT_BROWSER_RENDERER_HOST_NAVIGATOR_H_
#include <memory>
#include <optional>
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "content/browser/renderer_host/navigation_controller_impl.h"
#include "content/common/content_export.h"
#include "content/common/navigation_client.mojom.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_discard_reason.h"
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "net/storage_access_api/status.h"
#include "third_party/blink/public/common/navigation/impression.h"
#include "third_party/blink/public/mojom/frame/triggering_event_info.mojom-shared.h"
#include "third_party/blink/public/mojom/navigation/navigation_initiator_activation_and_ad_status.mojom.h"
#include "third_party/blink/public/mojom/navigation/navigation_params.mojom-forward.h"
#include "ui/base/window_open_disposition.h"
class GURL;
namespace base {
class TimeTicks;
}
namespace network {
class ResourceRequestBody;
}
namespace content {
class BrowserContext;
class FrameNavigationEntry;
class FrameTree;
class FrameTreeNode;
class NavigationControllerDelegate;
class NavigationEntryImpl;
class NavigationRequest;
class NavigatorDelegate;
class PrefetchedSignedExchangeCache;
class RenderFrameHostImpl;
struct LoadCommittedDetails;
struct UrlInfo;
// Navigator is responsible for performing navigations in nodes of the
// FrameTree. Its lifetime is bound to the FrameTree.
class CONTENT_EXPORT Navigator {
public:
Navigator(BrowserContext* browser_context,
FrameTree& frame_tree,
NavigatorDelegate* delegate,
NavigationControllerDelegate* navigation_controller_delegate);
Navigator(const Navigator&) = delete;
Navigator& operator=(const Navigator&) = delete;
~Navigator();
// This method verifies that a navigation to |url| doesn't commit into a WebUI
// process if it is not allowed to. Callers of this method should take one of
// two actions if the method returns false:
// * When called from browser process logic (e.g. NavigationRequest), this
// indicates issues with the navigation logic and the browser process must
// be terminated to avoid security issues.
// * If the codepath is processing an IPC message from a renderer process,
// then the renderer process is misbehaving and must be terminated.
// TODO(nasko): Remove the is_renderer_initiated_check parameter when callers
// of this method are migrated to use CHECK instead of DumpWithoutCrashing.
[[nodiscard]] static bool CheckWebUIRendererDoesNotDisplayNormalURL(
RenderFrameHostImpl* render_frame_host,
const UrlInfo& url_info,
bool is_renderer_initiated_check);
static bool ShouldIgnoreIncomingRendererRequest(
const NavigationRequest* ongoing_navigation_request,
bool has_user_gesture);
// Returns the delegate of this Navigator.
NavigatorDelegate* GetDelegate();
// Notifications coming from the RenderFrameHosts ----------------------------
// The RenderFrameHostImpl has committed a navigation. The Navigator is
// responsible for resetting |navigation_request| at the end of this method
// and should not attempt to keep it alive. Note: it is possible that
// |navigation_request| is not the NavigationRequest stored in the
// RenderFrameHost that just committed. This happens for example when a
// same-page navigation commits while another navigation is ongoing. The
// Navigator should use the NavigationRequest provided by this method and not
// attempt to access the RenderFrameHost's NavigationsRequests.
void DidNavigate(RenderFrameHostImpl* render_frame_host,
const mojom::DidCommitProvisionalLoadParams& params,
std::unique_ptr<NavigationRequest> navigation_request,
bool was_within_same_document);
// Called on a newly created subframe during a history navigation. The browser
// process looks up the corresponding FrameNavigationEntry for the new frame
// navigates it in the correct process. Returns false if the
// FrameNavigationEntry can't be found or the navigation fails.
bool StartHistoryNavigationInNewSubframe(
RenderFrameHostImpl* render_frame_host,
mojo::PendingAssociatedRemote<mojom::NavigationClient>* navigation_client,
blink::LocalFrameToken initiator_frame_token,
int initiator_process_id,
base::TimeTicks actual_navigation_start);
// Navigation requests -------------------------------------------------------
// Called by the NavigationController to cause the Navigator to navigate to
// |navigation_request|. The NavigationController should be called back with
// RendererDidNavigate on success or DiscardPendingEntry on failure. The
// callbacks should be called in a future iteration of the message loop.
void Navigate(std::unique_ptr<NavigationRequest> request,
ReloadType reload_type);
// The RenderFrameHostImpl has received a request to open a URL with the
// specified |disposition|.
void RequestOpenURL(
RenderFrameHostImpl* render_frame_host,
const GURL& url,
const blink::LocalFrameToken* initiator_frame_token,
int initiator_process_id,
const std::optional<url::Origin>& initiator_origin,
const std::optional<GURL>& initiator_base_url,
const scoped_refptr<network::ResourceRequestBody>& post_body,
const std::string& extra_headers,
const Referrer& referrer,
WindowOpenDisposition disposition,
bool should_replace_current_entry,
bool user_gesture,
blink::mojom::TriggeringEventInfo triggering_event_info,
const std::string& href_translate,
scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory,
const std::optional<blink::Impression>& impression,
bool has_rel_opener);
// Called when a document requests a navigation in another document through a
// `blink::RemoteFrame`. If `method` is "POST", then `post_body` needs to
// specify the request body, otherwise `post_body` should be null.
void NavigateFromFrameProxy(
RenderFrameHostImpl* render_frame_host,
const GURL& url,
const blink::LocalFrameToken* initiator_frame_token,
int initiator_process_id,
const url::Origin& initiator_origin,
const std::optional<GURL>& initiator_base_url,
SiteInstance* source_site_instance,
const Referrer& referrer,
ui::PageTransition page_transition,
bool should_replace_current_entry,
blink::NavigationDownloadPolicy download_policy,
const std::string& method,
scoped_refptr<network::ResourceRequestBody> post_body,
const std::string& extra_headers,
scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory,
network::mojom::SourceLocationPtr source_location,
bool has_user_gesture,
bool is_form_submission,
const std::optional<blink::Impression>& impression,
blink::mojom::NavigationInitiatorActivationAndAdStatus
initiator_activation_and_ad_status,
base::TimeTicks actual_navigation_start_time,
base::TimeTicks navigation_start_time,
bool is_embedder_initiated_fenced_frame_navigation = false,
bool is_unfenced_top_navigation = false,
bool force_new_browsing_instance = false,
bool is_container_initiated = false,
bool has_rel_opener = false,
net::StorageAccessApiStatus storage_access_api_status =
net::StorageAccessApiStatus::kNone,
std::optional<std::u16string> embedder_shared_storage_context =
std::nullopt);
// Called after BeforeUnloadCompleted callback is invoked from the renderer.
// If `frame_tree_node` has a NavigationRequest waiting for the renderer
// response, then the request is either started or canceled, depending on the
// value of `proceed`. If `for_legacy` is true, then this beforeunload flow
// was only used to post a task and no beforeunload handlers were run. If
// `showed_dialog` is true, then a beforeunload dialog was displayed.
void BeforeUnloadCompleted(FrameTreeNode* frame_tree_node,
bool proceed,
const base::TimeTicks& proceed_time,
bool for_legacy,
bool showed_dialog);
// Used to start a new renderer-initiated navigation, following a
// BeginNavigation IPC from the renderer.
void OnBeginNavigation(
FrameTreeNode* frame_tree_node,
blink::mojom::CommonNavigationParamsPtr common_params,
blink::mojom::BeginNavigationParamsPtr begin_params,
scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory,
mojo::PendingAssociatedRemote<mojom::NavigationClient> navigation_client,
scoped_refptr<PrefetchedSignedExchangeCache>
prefetched_signed_exchange_cache,
int initiator_process_id,
mojo::PendingReceiver<mojom::NavigationRendererCancellationListener>
renderer_cancellation_listener);
// Used to restart a navigation that was thought to be same-document in
// cross-document mode.
void RestartNavigationAsCrossDocument(
std::unique_ptr<NavigationRequest> navigation_request);
// Cancels the NavigationRequest owned by |frame_tree_node|. Note that this
// will only cancel NavigationRequests that haven't reached the "pending
// commit" stage yet, as after that the NavigationRequests will no longer be
// owned by the FrameTreeNode.
void CancelNavigation(FrameTreeNode* frame_tree_node,
NavigationDiscardReason reason);
// Called to record the time it took to execute the beforeunload hook for the
// current navigation. See RenderFrameHostImpl::SendBeforeUnload() for details
// on `for_legacy`.
void LogBeforeUnloadTime(base::TimeTicks renderer_before_unload_start_time,
base::TimeTicks renderer_before_unload_end_time,
base::TimeTicks before_unload_sent_time,
bool for_legacy);
// Called to record the time that the RenderFrameHost told the renderer to
// commit the current navigation.
void LogCommitNavigationSent();
// Returns the NavigationController associated with this Navigator.
NavigationControllerImpl& controller() { return controller_; }
const NavigationControllerImpl& controller() const { return controller_; }
void SetWillNavigateFromFrameProxyCallbackForTesting(
const base::RepeatingClosure& callback);
private:
friend class NavigatorTestWithBrowserSideNavigation;
// Holds data used to track browser side navigation metrics.
struct NavigationMetricsData;
void RecordNavigationMetrics(
const LoadCommittedDetails& details,
const mojom::DidCommitProvisionalLoadParams& params,
SiteInstance* site_instance,
const GURL& original_request_url);
// Called when a renderer initiated navigation has started. Returns the
// pending NavigationEntry to be used. Either null or a new one owned
// NavigationController.
NavigationEntryImpl* GetNavigationEntryForRendererInitiatedNavigation(
const blink::mojom::CommonNavigationParams& common_params,
FrameTreeNode* frame_tree_node,
bool override_user_agent);
// Called to record the time it took to execute beforeunload handlers for
// renderer-inititated navigations. It records the time it took to execute
// beforeunload handlers in the renderer process before sending the
// BeginNavigation IPC.
void LogRendererInitiatedBeforeUnloadTime(
base::TimeTicks renderer_before_unload_start_time,
base::TimeTicks renderer_before_unload_end_time);
// The NavigationController that will keep track of session history for all
// RenderFrameHost objects using this Navigator.
NavigationControllerImpl controller_;
// Used to notify the object embedding this Navigator about navigation
// events. Can be nullptr in tests.
raw_ptr<NavigatorDelegate> delegate_;
// Tracks metrics for each navigation.
std::unique_ptr<Navigator::NavigationMetricsData> metrics_data_;
// Called every time NavigateFromFrameProxy() is called.
base::RepeatingClosure will_navigate_from_frame_proxy_callback_for_testing_;
};
} // namespace content
#endif // CONTENT_BROWSER_RENDERER_HOST_NAVIGATOR_H_