#include "content/browser/fenced_frame/fenced_frame.h"
#include "base/notreached.h"
#include "content/browser/devtools/devtools_instrumentation.h"
#include "content/browser/renderer_host/render_frame_proxy_host.h"
#include "content/browser/renderer_host/render_widget_host_view_child_frame.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "net/storage_access_api/status.h"
#include "third_party/blink/public/common/fenced_frame/fenced_frame_utils.h"
#include "third_party/blink/public/common/frame/fenced_frame_sandbox_flags.h"
#include "third_party/blink/public/common/frame/frame_owner_element_type.h"
#include "third_party/blink/public/mojom/navigation/navigation_initiator_activation_and_ad_status.mojom.h"
#include "url/gurl.h"
namespace content {
namespace {
FrameTreeNode* CreateDelegateFrameTreeNode(
RenderFrameHostImpl* owner_render_frame_host) {
return owner_render_frame_host->frame_tree()->AddFrame(
&*owner_render_frame_host,
owner_render_frame_host->GetProcess()->GetDeprecatedID(),
owner_render_frame_host->GetProcess()->GetNextRoutingID(),
mojo::NullAssociatedRemote(),
mojo::NullReceiver(),
nullptr,
mojo::NullAssociatedReceiver(),
blink::mojom::TreeScopeType::kDocument, "", "", true,
blink::LocalFrameToken(), base::UnguessableToken::Create(),
blink::DocumentToken(), blink::FramePolicy(),
blink::mojom::FrameOwnerProperties(), false,
blink::FrameOwnerElementType::kFencedframe,
true);
}
}
FencedFrame::FencedFrame(
base::SafeRef<RenderFrameHostImpl> owner_render_frame_host,
bool was_discarded)
: web_contents_(static_cast<WebContentsImpl*>(
WebContents::FromRenderFrameHost(&*owner_render_frame_host))),
owner_render_frame_host_(owner_render_frame_host),
outer_delegate_frame_tree_node_(
CreateDelegateFrameTreeNode(&*owner_render_frame_host)),
frame_tree_(
std::make_unique<FrameTree>(web_contents_->GetBrowserContext(),
this,
this,
web_contents_,
web_contents_,
web_contents_,
web_contents_,
web_contents_,
web_contents_,
FrameTree::Type::kFencedFrame)) {
if (was_discarded) {
frame_tree_->root()->set_was_discarded();
}
}
FencedFrame::~FencedFrame() {
DCHECK(frame_tree_);
frame_tree_->Shutdown();
frame_tree_.reset();
}
void FencedFrame::Navigate(
const GURL& url,
base::TimeTicks navigation_start_time,
const std::optional<std::u16string>& embedder_shared_storage_context) {
DCHECK_NE(RenderFrameHost::LifecycleState::kPrerendering,
owner_render_frame_host_->GetLifecycleState());
if (!blink::IsValidUrnUuidURL(url) && !blink::IsValidFencedFrameURL(url)) {
bad_message::ReceivedBadMessage(owner_render_frame_host_->GetProcess(),
bad_message::FF_NAVIGATION_INVALID_URL);
return;
}
DCHECK(outer_delegate_frame_tree_node_);
if (outer_delegate_frame_tree_node_->IsInFencedFrameTree()) {
bool is_nested_inside_opaque_ads_fenced_frame =
outer_delegate_frame_tree_node_->GetDeprecatedFencedFrameMode() ==
blink::FencedFrame::DeprecatedFencedFrameMode::kOpaqueAds;
bool is_nested_inside_default_fenced_frame =
!is_nested_inside_opaque_ads_fenced_frame;
if ((is_nested_inside_opaque_ads_fenced_frame &&
!blink::IsValidUrnUuidURL(url)) ||
(is_nested_inside_default_fenced_frame &&
!blink::IsValidFencedFrameURL(url))) {
bad_message::ReceivedBadMessage(
owner_render_frame_host_->GetProcess(),
bad_message::FF_DIFFERENT_MODE_THAN_EMBEDDER);
return;
}
}
if (base::FeatureList::IsEnabled(
blink::features::kFencedFramesLocalUnpartitionedDataAccess)) {
const std::optional<
FencedFrameProperties>& embedder_fenced_frame_properties =
owner_render_frame_host_->frame_tree_node()->GetFencedFrameProperties(
FencedFramePropertiesNodeSource::kFrameTreeRoot);
if (embedder_fenced_frame_properties.has_value() &&
embedder_fenced_frame_properties
->HasDisabledNetworkForCurrentFrameTree()) {
owner_render_frame_host_->AddMessageToConsole(
blink::mojom::ConsoleMessageLevel::kError,
"Embedder-initiated navigations of fenced frames are not allowed "
"after"
" the embedder's network has been disabled.");
return;
}
}
GURL validated_url = url;
owner_render_frame_host_->GetSiteInstance()->GetProcess()->FilterURL(
false, &validated_url);
FrameTreeNode* inner_root = frame_tree_->root();
blink::NavigationDownloadPolicy download_policy;
url::Origin initiator_origin;
blink::mojom::NavigationInitiatorActivationAndAdStatus
initiator_activation_and_ad_status =
blink::mojom::NavigationInitiatorActivationAndAdStatus::
kDidNotStartWithTransientActivation;
inner_root->navigator().NavigateFromFrameProxy(
inner_root->current_frame_host(), validated_url,
nullptr,
content::ChildProcessHost::kInvalidUniqueID, initiator_origin,
std::nullopt,
nullptr, content::Referrer(),
ui::PAGE_TRANSITION_AUTO_SUBFRAME,
true, download_policy, "GET",
nullptr, "",
nullptr,
network::mojom::SourceLocation::New(), false,
false,
std::nullopt, initiator_activation_and_ad_status,
navigation_start_time,
navigation_start_time,
true,
false,
true, false,
false,
net::StorageAccessApiStatus::kNone,
embedder_shared_storage_context);
}
bool FencedFrame::IsHidden() {
return web_contents_->IsHidden();
}
FrameTreeNodeId FencedFrame::GetOuterDelegateFrameTreeNodeId() {
DCHECK(outer_delegate_frame_tree_node_);
return outer_delegate_frame_tree_node_->frame_tree_node_id();
}
RenderFrameHostImpl* FencedFrame::GetProspectiveOuterDocument() {
return nullptr;
}
FrameTree* FencedFrame::LoadingTree() {
CHECK_NE(RenderFrameHostImpl::LifecycleStateImpl::kPrerendering,
owner_render_frame_host_->lifecycle_state());
return web_contents_->LoadingTree();
}
void FencedFrame::SetFocusedFrame(FrameTreeNode* node,
SiteInstanceGroup* source) {
web_contents_->SetFocusedFrame(node, source);
}
FrameTree* FencedFrame::GetOwnedDocumentPictureInPictureFrameTree() {
return nullptr;
}
bool FencedFrame::OnRenderFrameProxyVisibilityChanged(
RenderFrameProxyHost* render_frame_proxy_host,
blink::mojom::FrameVisibility visibility) {
return false;
}
FrameTree* FencedFrame::GetDocumentPictureInPictureOpenerFrameTree() {
return nullptr;
}
RenderFrameProxyHost*
FencedFrame::InitInnerFrameTreeAndReturnProxyToOuterFrameTree(
blink::mojom::RemoteFrameInterfacesFromRendererPtr remote_frame_interfaces,
const blink::RemoteFrameToken& frame_token,
const base::UnguessableToken& devtools_frame_token) {
DCHECK(remote_frame_interfaces);
DCHECK(outer_delegate_frame_tree_node_);
scoped_refptr<SiteInstanceImpl> site_instance =
SiteInstanceImpl::CreateForFencedFrame(
owner_render_frame_host_->GetSiteInstance());
blink::FramePolicy frame_policy;
frame_policy.sandbox_flags = blink::kFencedFrameForcedSandboxFlags;
frame_tree_->Init(site_instance.get(),
false,
"",
nullptr, frame_policy,
devtools_frame_token);
frame_tree_->root()->SetPendingFramePolicy(frame_policy);
web_contents_->NotifySwappedFromRenderManager(
nullptr,
frame_tree_->root()->render_manager()->current_frame_host());
outer_delegate_frame_tree_node_->current_frame_host()
->set_inner_tree_main_frame_tree_node_id(
frame_tree_->root()->frame_tree_node_id());
FrameTreeNode* inner_root = frame_tree_->root();
RenderFrameProxyHost* proxy_host =
inner_root->current_frame_host()
->browsing_context_state()
->CreateOuterDelegateProxy(
owner_render_frame_host_->GetSiteInstance()->group(), inner_root,
frame_token);
proxy_host->BindRemoteFrameInterfaces(
std::move(remote_frame_interfaces->frame),
std::move(remote_frame_interfaces->frame_host_receiver));
inner_root->current_frame_host()->PropagateEmbeddingTokenToParentFrame();
proxy_host->SetRenderFrameProxyCreated(true);
RenderFrameHostManager* inner_render_manager = inner_root->render_manager();
RenderViewHost* rvh =
inner_render_manager->current_frame_host()->GetRenderViewHost();
if (!inner_render_manager->InitRenderView(
inner_render_manager->current_frame_host()
->GetSiteInstance()
->group(),
static_cast<RenderViewHostImpl*>(rvh), nullptr,
std::nullopt)) {
return proxy_host;
}
RenderWidgetHostViewBase* child_rwhv =
inner_render_manager->GetRenderWidgetHostView();
CHECK(child_rwhv);
CHECK(child_rwhv->IsRenderWidgetHostViewChildFrame());
inner_render_manager->SetRWHViewForInnerFrameTree(
static_cast<RenderWidgetHostViewChildFrame*>(child_rwhv));
devtools_instrumentation::FencedFrameCreated(owner_render_frame_host_, this);
return proxy_host;
}
const base::UnguessableToken& FencedFrame::GetDevToolsFrameToken() const {
DCHECK(frame_tree_);
return frame_tree_->GetMainFrame()->GetDevToolsFrameToken();
}
void FencedFrame::NotifyBeforeFormRepostWarningShow() {}
void FencedFrame::NotifyNavigationEntryCommitted(
const LoadCommittedDetails& load_details) {}
void FencedFrame::NotifyNavigationEntryChanged(
const EntryChangedDetails& change_details) {}
void FencedFrame::NotifyNavigationListPruned(
const PrunedDetails& pruned_details) {}
void FencedFrame::NotifyNavigationEntriesDeleted() {}
void FencedFrame::ActivateAndShowRepostFormWarningDialog() {
frame_tree_->controller().CancelPendingReload();
}
bool FencedFrame::ShouldPreserveAbortedURLs() {
return false;
}
void FencedFrame::UpdateOverridingUserAgent() {}
#if BUILDFLAG(ARKWEB_NETWORK_LOAD)
std::string FencedFrame::NotifyNavigationRewriteUrl(
const std::string& original_url,
const std::string& referrer,
int transition_type,
bool is_key_request) { return ""; }
#endif
#if BUILDFLAG(IS_ANDROID)
scoped_refptr<viz::RasterContextProvider>
FencedFrame::GetRasterContextProvider() {
NOTREACHED();
}
gfx::ColorSpace FencedFrame::GetOutputColorSpace(
gfx::ContentColorUsage color_usage,
bool needs_alpha) {
NOTREACHED();
}
#endif
void FencedFrame::DidChangeFramePolicy(const blink::FramePolicy& frame_policy) {
FrameTreeNode* inner_root = frame_tree_->root();
const blink::FramePolicy& current_frame_policy =
inner_root->pending_frame_policy();
inner_root->SetPendingFramePolicy(blink::FramePolicy(
current_frame_policy.sandbox_flags, frame_policy.container_policy,
current_frame_policy.required_document_policy,
frame_policy.deferred_fetch_policy));
}
}