blob: 7fd2cad92637619b2ea61f9c55b2133cfa1ae811 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/renderer/render_frame_proxy.h"
#include <stdint.h>
#include <map>
#include <memory>
#include <utility>
#include "base/command_line.h"
#include "base/lazy_instance.h"
#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
#include "content/common/content_switches_internal.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/use_zoom_for_dsf_policy.h"
#include "content/public/renderer/content_renderer_client.h"
#include "content/renderer/agent_scheduling_group.h"
#include "content/renderer/mojo/blink_interface_registry_impl.h"
#include "content/renderer/render_frame_impl.h"
#include "content/renderer/render_thread_impl.h"
#include "content/renderer/render_view_impl.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_message_macros.h"
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "third_party/blink/public/common/frame/frame_policy.h"
#include "third_party/blink/public/common/navigation/impression.h"
#include "third_party/blink/public/common/navigation/navigation_policy.h"
#include "third_party/blink/public/common/permissions_policy/permissions_policy.h"
#include "third_party/blink/public/mojom/frame/frame.mojom.h"
#include "third_party/blink/public/mojom/security_context/insecure_request_policy.mojom.h"
#include "third_party/blink/public/platform/impression_conversions.h"
#include "third_party/blink/public/platform/url_conversion.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_url_request_util.h"
#include "third_party/blink/public/web/web_frame_widget.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_view.h"
#include "ui/gfx/geometry/size_conversions.h"
namespace content {
namespace {
// Facilitates lookup of RenderFrameProxy by routing_id.
typedef std::map<int, RenderFrameProxy*> RoutingIDProxyMap;
static base::LazyInstance<RoutingIDProxyMap>::DestructorAtExit
g_routing_id_proxy_map = LAZY_INSTANCE_INITIALIZER;
// Facilitates lookup of RenderFrameProxy by WebRemoteFrame.
typedef std::map<blink::WebRemoteFrame*, RenderFrameProxy*> FrameProxyMap;
base::LazyInstance<FrameProxyMap>::DestructorAtExit g_frame_proxy_map =
LAZY_INSTANCE_INITIALIZER;
} // namespace
// static
RenderFrameProxy* RenderFrameProxy::CreateProxyToReplaceFrame(
AgentSchedulingGroup& agent_scheduling_group,
RenderFrameImpl* frame_to_replace,
int routing_id,
blink::mojom::TreeScopeType scope,
const blink::RemoteFrameToken& proxy_frame_token) {
CHECK_NE(routing_id, MSG_ROUTING_NONE);
std::unique_ptr<RenderFrameProxy> proxy(
new RenderFrameProxy(agent_scheduling_group, routing_id));
// When a RenderFrame is replaced by a RenderProxy, the WebRemoteFrame should
// always come from WebRemoteFrame::create and a call to WebFrame::swap must
// follow later.
blink::WebRemoteFrame* web_frame = blink::WebRemoteFrame::Create(
scope, proxy.get(), proxy->blink_interface_registry_.get(),
proxy->GetRemoteAssociatedInterfaces(), proxy_frame_token);
proxy->Init(web_frame, frame_to_replace->render_view());
return proxy.release();
}
// static
RenderFrameProxy* RenderFrameProxy::CreateFrameProxy(
AgentSchedulingGroup& agent_scheduling_group,
const blink::RemoteFrameToken& frame_token,
int routing_id,
const base::Optional<blink::FrameToken>& opener_frame_token,
int render_view_routing_id,
int parent_routing_id,
blink::mojom::FrameReplicationStatePtr replicated_state,
const base::UnguessableToken& devtools_frame_token) {
RenderFrameProxy* parent = nullptr;
if (parent_routing_id != MSG_ROUTING_NONE) {
parent = RenderFrameProxy::FromRoutingID(parent_routing_id);
// It is possible that the parent proxy has been detached in this renderer
// process, just as the parent's real frame was creating this child frame.
// In this case, do not create the proxy. See https://crbug.com/568670.
if (!parent)
return nullptr;
}
std::unique_ptr<RenderFrameProxy> proxy(
new RenderFrameProxy(agent_scheduling_group, routing_id));
RenderViewImpl* render_view = nullptr;
blink::WebRemoteFrame* web_frame = nullptr;
blink::WebFrame* opener = nullptr;
if (opener_frame_token)
opener = blink::WebFrame::FromFrameToken(*opener_frame_token);
if (!parent) {
// Create a top level WebRemoteFrame.
render_view = RenderViewImpl::FromRoutingID(render_view_routing_id);
blink::WebView* web_view = render_view->GetWebView();
web_frame = blink::WebRemoteFrame::CreateMainFrame(
web_view, proxy.get(), proxy->blink_interface_registry_.get(),
proxy->GetRemoteAssociatedInterfaces(), frame_token,
devtools_frame_token, opener);
// Root frame proxy has no ancestors to point to their RenderWidget.
// The WebRemoteFrame created here was already attached to the Page as its
// main frame, so we can call WebView's DidAttachRemoteMainFrame().
web_view->DidAttachRemoteMainFrame();
} else {
// Create a frame under an existing parent. The parent is always expected
// to be a RenderFrameProxy, because navigations initiated by local frames
// should not wind up here.
web_frame = parent->web_frame()->CreateRemoteChild(
replicated_state->scope,
blink::WebString::FromUTF8(replicated_state->name),
replicated_state->frame_policy,
replicated_state->frame_owner_element_type, proxy.get(),
proxy->blink_interface_registry_.get(),
proxy->GetRemoteAssociatedInterfaces(), frame_token,
devtools_frame_token, opener);
render_view = parent->render_view();
}
proxy->Init(web_frame, render_view);
// Initialize proxy's WebRemoteFrame with the security origin and other
// replicated information.
// TODO(dcheng): Calling this when parent_routing_id != MSG_ROUTING_NONE is
// mostly redundant, since we already pass the name and sandbox flags in
// createLocalChild(). We should update the Blink interface so it also takes
// the origin. Then it will be clear that the replication call is only needed
// for the case of setting up a main frame proxy.
proxy->SetReplicatedState(std::move(replicated_state));
return proxy.release();
}
RenderFrameProxy* RenderFrameProxy::CreateProxyForPortal(
AgentSchedulingGroup& agent_scheduling_group,
RenderFrameImpl* parent,
int proxy_routing_id,
const blink::RemoteFrameToken& frame_token,
const base::UnguessableToken& devtools_frame_token,
const blink::WebElement& portal_element) {
auto proxy = base::WrapUnique(
new RenderFrameProxy(agent_scheduling_group, proxy_routing_id));
blink::WebRemoteFrame* web_frame = blink::WebRemoteFrame::CreateForPortal(
blink::mojom::TreeScopeType::kDocument, proxy.get(),
proxy->blink_interface_registry_.get(),
proxy->GetRemoteAssociatedInterfaces(), frame_token, devtools_frame_token,
portal_element);
proxy->Init(web_frame, parent->render_view());
return proxy.release();
}
// static
RenderFrameProxy* RenderFrameProxy::FromRoutingID(int32_t routing_id) {
RoutingIDProxyMap* proxies = g_routing_id_proxy_map.Pointer();
auto it = proxies->find(routing_id);
return it == proxies->end() ? NULL : it->second;
}
// static
RenderFrameProxy* RenderFrameProxy::FromWebFrame(
blink::WebRemoteFrame* web_frame) {
// TODO(dcheng): Turn this into a DCHECK() if it doesn't crash on canary.
CHECK(web_frame);
auto iter = g_frame_proxy_map.Get().find(web_frame);
if (iter != g_frame_proxy_map.Get().end()) {
RenderFrameProxy* proxy = iter->second;
DCHECK_EQ(web_frame, proxy->web_frame());
return proxy;
}
// Reaching this is not expected: this implies that the |web_frame| in
// question is not managed by the content API, or the associated
// RenderFrameProxy is already deleted--in which case, it's not safe to touch
// |web_frame|.
NOTREACHED();
return nullptr;
}
RenderFrameProxy::RenderFrameProxy(AgentSchedulingGroup& agent_scheduling_group,
int routing_id)
: agent_scheduling_group_(agent_scheduling_group),
routing_id_(routing_id) {
std::pair<RoutingIDProxyMap::iterator, bool> result =
g_routing_id_proxy_map.Get().insert(std::make_pair(routing_id_, this));
CHECK(result.second) << "Inserting a duplicate item.";
agent_scheduling_group_.AddRoute(routing_id_, this);
blink_interface_registry_ = std::make_unique<BlinkInterfaceRegistryImpl>(
binder_registry_.GetWeakPtr(), associated_interfaces_.GetWeakPtr());
}
RenderFrameProxy::~RenderFrameProxy() {
CHECK(!web_frame_);
agent_scheduling_group_.RemoveRoute(routing_id_);
g_routing_id_proxy_map.Get().erase(routing_id_);
}
void RenderFrameProxy::Init(blink::WebRemoteFrame* web_frame,
RenderViewImpl* render_view) {
CHECK(web_frame);
CHECK(render_view);
web_frame_ = web_frame;
render_view_ = render_view;
std::pair<FrameProxyMap::iterator, bool> result =
g_frame_proxy_map.Get().insert(std::make_pair(web_frame_, this));
CHECK(result.second) << "Inserted a duplicate item.";
}
void RenderFrameProxy::SetReplicatedState(
blink::mojom::FrameReplicationStatePtr state) {
DCHECK(web_frame_);
web_frame_->SetReplicatedOrigin(
state->origin, state->has_potentially_trustworthy_unique_origin);
#if DCHECK_IS_ON()
blink::WebSecurityOrigin security_origin_before_sandbox_flags =
web_frame_->GetSecurityOrigin();
#endif
web_frame_->SetReplicatedSandboxFlags(state->active_sandbox_flags);
#if DCHECK_IS_ON()
// If |state->has_potentially_trustworthy_unique_origin| is set,
// - |state->origin| should be unique (this is checked in
// blink::SecurityOrigin::SetUniqueOriginIsPotentiallyTrustworthy() in
// SetReplicatedOrigin()), and thus
// - The security origin is not updated by SetReplicatedSandboxFlags() and
// thus we don't have to apply |has_potentially_trustworthy_unique_origin|
// flag after SetReplicatedSandboxFlags().
if (state->has_potentially_trustworthy_unique_origin)
DCHECK(security_origin_before_sandbox_flags ==
web_frame_->GetSecurityOrigin());
#endif
web_frame_->SetReplicatedName(blink::WebString::FromUTF8(state->name),
blink::WebString::FromUTF8(state->unique_name));
web_frame_->SetReplicatedInsecureRequestPolicy(
state->insecure_request_policy);
web_frame_->SetReplicatedInsecureNavigationsSet(
state->insecure_navigations_set);
web_frame_->SetReplicatedAdFrameType(state->ad_frame_type);
web_frame_->SetReplicatedPermissionsPolicyHeader(
state->permissions_policy_header);
if (state->has_active_user_gesture) {
// TODO(crbug.com/1087963): This should be hearing about sticky activations
// and setting those (as well as the active one?). But the call to
// UpdateUserActivationState sets the transient activation.
web_frame_->UpdateUserActivationState(
blink::mojom::UserActivationUpdateType::kNotifyActivation,
blink::mojom::UserActivationNotificationType::kMedia);
}
web_frame_->SetHadStickyUserActivationBeforeNavigation(
state->has_received_user_gesture_before_nav);
}
std::string RenderFrameProxy::unique_name() const {
DCHECK(web_frame_);
return web_frame_->UniqueName().Utf8();
}
bool RenderFrameProxy::OnMessageReceived(const IPC::Message& msg) {
return false;
}
void RenderFrameProxy::OnAssociatedInterfaceRequest(
const std::string& interface_name,
mojo::ScopedInterfaceEndpointHandle handle) {
if (interface_name == blink::mojom::RemoteFrame::Name_) {
associated_interfaces_.TryBindInterface(interface_name, &handle);
} else if (interface_name == blink::mojom::RemoteMainFrame::Name_) {
associated_interfaces_.TryBindInterface(interface_name, &handle);
}
}
bool RenderFrameProxy::Send(IPC::Message* message) {
return agent_scheduling_group_.Send(message);
}
void RenderFrameProxy::DidStartLoading() {
web_frame_->DidStartLoading();
}
void RenderFrameProxy::FrameDetached(DetachType type) {
web_frame_->Close();
// Remove the entry in the WebFrame->RenderFrameProxy map, as the |web_frame_|
// is no longer valid.
auto it = g_frame_proxy_map.Get().find(web_frame_);
CHECK(it != g_frame_proxy_map.Get().end());
CHECK_EQ(it->second, this);
g_frame_proxy_map.Get().erase(it);
web_frame_ = nullptr;
delete this;
}
blink::AssociatedInterfaceProvider*
RenderFrameProxy::GetRemoteAssociatedInterfaces() {
if (!remote_associated_interfaces_) {
mojo::PendingAssociatedRemote<blink::mojom::AssociatedInterfaceProvider>
remote_interfaces;
agent_scheduling_group_.GetRemoteRouteProvider()->GetRoute(
routing_id_, remote_interfaces.InitWithNewEndpointAndPassReceiver());
remote_associated_interfaces_ =
std::make_unique<blink::AssociatedInterfaceProvider>(
std::move(remote_interfaces),
agent_scheduling_group_.agent_group_scheduler()
.DefaultTaskRunner());
}
return remote_associated_interfaces_.get();
}
} // namespace content