Commit 841c2e84 authored by Ehsan Karamad's avatar Ehsan Karamad Committed by Commit Bot

[ MimeHandlerView ] Cleaning up MimeHandlerViewEmbedder when disallowed

The process of creating MimeHandlerView is:
  * Navigation to resource starts
  * MimeHandlerViewEmbedder is created
  * HTMLPlugInElement::UpdatePlugin is called
  * MimeHandlerViewContainerManager is notified
  * HTMLPlugInElement creates a frame
  * MimeHandlerViewEmbedder observes the new frame and attaches
    GuestView, and destroys itself.

These steps are legitimately disturbed when the embedder is not
authorized to load plugins (e.g., in <webview> when using permissions).
In such cases, the update from HTMLPlugInElement does not reach the
MimeHandlerViewContainerManager and also a plugin frame is not created.
Therefore, MimeHandlerViewEmbedder does not get destroyed.

This CL will change the update process so that even for blocked plugins
the MHVCM is notified (of the failure) which gives it a chance to notify
the browser in turn and clean up the MimeHandlerViewEmbedder.

In line with the change, the test:
  WebViewPluginTest.TestLoadPluginInternalResource
is modified to assert no MimeHandlerViewEmbedders are lying around.

Bug: 967045
Change-Id: Ic63a980883240fe8098a4ee8d5e3ae3b9cc46415
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1629071Reviewed-by: default avatarKaran Bhatia <karandeepb@chromium.org>
Reviewed-by: default avatarLei Zhang <thestig@chromium.org>
Reviewed-by: default avatarEhsan Karamad <ekaramad@chromium.org>
Reviewed-by: default avatarKen Buchanan <kenrb@chromium.org>
Reviewed-by: default avatarJames MacLean <wjmaclean@chromium.org>
Commit-Queue: Ehsan Karamad <ekaramad@chromium.org>
Cr-Commit-Position: refs/heads/master@{#663982}
parent 85ea958a
...@@ -92,6 +92,7 @@ ...@@ -92,6 +92,7 @@
#include "extensions/browser/api/declarative_webrequest/webrequest_constants.h" #include "extensions/browser/api/declarative_webrequest/webrequest_constants.h"
#include "extensions/browser/api/extensions_api_client.h" #include "extensions/browser/api/extensions_api_client.h"
#include "extensions/browser/app_window/native_app_window.h" #include "extensions/browser/app_window/native_app_window.h"
#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_embedder.h"
#include "extensions/browser/guest_view/web_view/web_view_guest.h" #include "extensions/browser/guest_view/web_view/web_view_guest.h"
#include "extensions/common/extension.h" #include "extensions/common/extension.h"
#include "extensions/common/extensions_client.h" #include "extensions/common/extensions_client.h"
...@@ -3341,7 +3342,13 @@ IN_PROC_BROWSER_TEST_F(WebViewPluginTest, TestLoadPluginInternalResource) { ...@@ -3341,7 +3342,13 @@ IN_PROC_BROWSER_TEST_F(WebViewPluginTest, TestLoadPluginInternalResource) {
true); true);
TestHelper("testPluginLoadInternalResource", "web_view/shim", NO_TEST_SERVER); TestHelper("testPluginLoadInternalResource", "web_view/shim", NO_TEST_SERVER);
// Sanity check to ensure no GuestView was created.
for (auto* guest_wc : GetEmbedderWebContents()->GetInnerWebContents()) {
EXPECT_FALSE(extensions::MimeHandlerViewEmbedder::Get(
guest_wc->GetMainFrame()->GetFrameTreeNodeId()));
}
} }
#endif // BUILDFLAG(ENABLE_PLUGINS) #endif // BUILDFLAG(ENABLE_PLUGINS)
class WebViewCaptureTest : public WebViewTest { class WebViewCaptureTest : public WebViewTest {
......
...@@ -613,15 +613,18 @@ bool ChromeContentRendererClient::IsPluginHandledExternally( ...@@ -613,15 +613,18 @@ bool ChromeContentRendererClient::IsPluginHandledExternally(
// necessary here (see https://crbug.com/965747). For now, returning false // necessary here (see https://crbug.com/965747). For now, returning false
// should take us to CreatePlugin after HTMLPlugInElement which is called // should take us to CreatePlugin after HTMLPlugInElement which is called
// through HTMLPlugInElement::LoadPlugin code path. // through HTMLPlugInElement::LoadPlugin code path.
if ((plugin_info->status != chrome::mojom::PluginStatus::kAllowed && if (plugin_info->status != chrome::mojom::PluginStatus::kAllowed &&
plugin_info->status != plugin_info->status !=
chrome::mojom::PluginStatus::kPlayImportantContent) || chrome::mojom::PluginStatus::kPlayImportantContent) {
!ChromeExtensionsRendererClient::MaybeCreateMimeHandlerView( // We could get here when a MimeHandlerView is loaded inside a <webview>
plugin_element, original_url, plugin_info->actual_mime_type, // which is using permissions API (see WebViewPluginTests).
plugin_info->plugin)) { ChromeExtensionsRendererClient::DidBlockMimeHandlerViewForDisallowedPlugin(
plugin_element);
return false; return false;
} }
return true; return ChromeExtensionsRendererClient::MaybeCreateMimeHandlerView(
plugin_element, original_url, plugin_info->actual_mime_type,
plugin_info->plugin);
#else #else
return false; return false;
#endif #endif
......
...@@ -318,6 +318,16 @@ ChromeExtensionsRendererClient::CreateBrowserPluginDelegate( ...@@ -318,6 +318,16 @@ ChromeExtensionsRendererClient::CreateBrowserPluginDelegate(
original_url); original_url);
} }
// static
void ChromeExtensionsRendererClient::DidBlockMimeHandlerViewForDisallowedPlugin(
const blink::WebElement& plugin_element) {
extensions::MimeHandlerViewContainerManager::Get(
content::RenderFrame::FromWebFrame(
plugin_element.GetDocument().GetFrame()),
true /* create_if_does_not_exist */)
->DidBlockMimeHandlerViewForDisallowedPlugin(plugin_element);
}
// static // static
bool ChromeExtensionsRendererClient::MaybeCreateMimeHandlerView( bool ChromeExtensionsRendererClient::MaybeCreateMimeHandlerView(
const blink::WebElement& plugin_element, const blink::WebElement& plugin_element,
......
...@@ -93,6 +93,8 @@ class ChromeExtensionsRendererClient ...@@ -93,6 +93,8 @@ class ChromeExtensionsRendererClient
const content::WebPluginInfo& info, const content::WebPluginInfo& info,
const std::string& mime_type, const std::string& mime_type,
const GURL& original_url); const GURL& original_url);
static void DidBlockMimeHandlerViewForDisallowedPlugin(
const blink::WebElement& plugin_element);
static bool MaybeCreateMimeHandlerView( static bool MaybeCreateMimeHandlerView(
const blink::WebElement& plugin_element, const blink::WebElement& plugin_element,
const GURL& resource_url, const GURL& resource_url,
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_registry.h"
#include "extensions/browser/guest_view/mime_handler_view/mime_handler_stream_manager.h" #include "extensions/browser/guest_view/mime_handler_view/mime_handler_stream_manager.h"
#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_constants.h" #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_constants.h"
#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_embedder.h"
#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h" #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
#include "extensions/browser/guest_view/web_view/web_view_content_script_manager.h" #include "extensions/browser/guest_view/web_view/web_view_content_script_manager.h"
#include "extensions/browser/guest_view/web_view/web_view_guest.h" #include "extensions/browser/guest_view/web_view/web_view_guest.h"
...@@ -126,6 +127,22 @@ void ExtensionsGuestViewMessageFilter::CreateMimeHandlerViewGuest( ...@@ -126,6 +127,22 @@ void ExtensionsGuestViewMessageFilter::CreateMimeHandlerViewGuest(
false)); false));
} }
void ExtensionsGuestViewMessageFilter::ReadyToCreateMimeHandlerView(
int32_t render_frame_id,
bool success) {
if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
base::PostTaskWithTraits(
FROM_HERE, {content::BrowserThread::UI},
base::BindOnce(
&ExtensionsGuestViewMessageFilter::ReadyToCreateMimeHandlerView,
this, render_frame_id, success));
return;
}
auto* rfh =
content::RenderFrameHost::FromID(render_process_id_, render_frame_id);
if (auto* mhve = MimeHandlerViewEmbedder::Get(rfh->GetFrameTreeNodeId()))
mhve->ReadyToCreateMimeHandlerView(success);
}
void ExtensionsGuestViewMessageFilter::CreateMimeHandlerViewGuestOnUIThread( void ExtensionsGuestViewMessageFilter::CreateMimeHandlerViewGuestOnUIThread(
int render_frame_id, int render_frame_id,
const std::string& view_id, const std::string& view_id,
......
...@@ -82,6 +82,8 @@ class ExtensionsGuestViewMessageFilter ...@@ -82,6 +82,8 @@ class ExtensionsGuestViewMessageFilter
int32_t element_instance_id, int32_t element_instance_id,
const gfx::Size& element_size, const gfx::Size& element_size,
mime_handler::BeforeUnloadControlPtr before_unload_control) override; mime_handler::BeforeUnloadControlPtr before_unload_control) override;
void ReadyToCreateMimeHandlerView(int32_t render_frame_id,
bool success) override;
void CreateMimeHandlerViewGuestOnUIThread( void CreateMimeHandlerViewGuestOnUIThread(
int32_t render_frame_id, int32_t render_frame_id,
......
...@@ -33,6 +33,17 @@ EmbedderMap* GetMimeHandlerViewEmbeddersMap() { ...@@ -33,6 +33,17 @@ EmbedderMap* GetMimeHandlerViewEmbeddersMap() {
} }
} // namespace } // namespace
// static
MimeHandlerViewEmbedder* MimeHandlerViewEmbedder::Get(
int32_t frame_tree_node_id) {
const auto& map = *GetMimeHandlerViewEmbeddersMap();
auto it = map.find(frame_tree_node_id);
if (it == map.cend())
return nullptr;
return it->second.get();
}
// static
void MimeHandlerViewEmbedder::Create(int32_t frame_tree_node_id, void MimeHandlerViewEmbedder::Create(int32_t frame_tree_node_id,
const GURL& resource_url, const GURL& resource_url,
const std::string& mime_type, const std::string& mime_type,
...@@ -96,6 +107,13 @@ void MimeHandlerViewEmbedder::RenderFrameCreated( ...@@ -96,6 +107,13 @@ void MimeHandlerViewEmbedder::RenderFrameCreated(
render_frame_host_->GetLastCommittedURL() != resource_url_) { render_frame_host_->GetLastCommittedURL() != resource_url_) {
return; return;
} }
if (!ready_to_create_mime_handler_view_) {
// Renderer notifies the browser about creating MimeHandlerView right after
// HTMLPlugInElement::RequestObject, which is before the plugin element is
// navigated.
GetMimeHandlerViewEmbeddersMap()->erase(frame_tree_node_id_);
return;
}
outer_contents_frame_tree_node_id_ = render_frame_host->GetFrameTreeNodeId(); outer_contents_frame_tree_node_id_ = render_frame_host->GetFrameTreeNodeId();
element_instance_id_ = render_frame_host->GetRoutingID(); element_instance_id_ = render_frame_host->GetRoutingID();
// This suggests that a same-origin child frame is created under the // This suggests that a same-origin child frame is created under the
...@@ -185,4 +203,12 @@ MimeHandlerViewEmbedder::GetContainerManager() { ...@@ -185,4 +203,12 @@ MimeHandlerViewEmbedder::GetContainerManager() {
} }
return container_manager_.get(); return container_manager_.get();
} }
void MimeHandlerViewEmbedder::ReadyToCreateMimeHandlerView(
bool ready_to_create_mime_handler_view) {
ready_to_create_mime_handler_view_ = ready_to_create_mime_handler_view;
if (!ready_to_create_mime_handler_view_)
GetMimeHandlerViewEmbeddersMap()->erase(frame_tree_node_id_);
}
} // namespace extensions } // namespace extensions
...@@ -32,6 +32,10 @@ namespace extensions { ...@@ -32,6 +32,10 @@ namespace extensions {
//. - the embedder or the <iframe> are removed from DOM. //. - the embedder or the <iframe> are removed from DOM.
class MimeHandlerViewEmbedder : public content::WebContentsObserver { class MimeHandlerViewEmbedder : public content::WebContentsObserver {
public: public:
// Returns the instances associated with an ongoing navigation in a frame
// identified by |frame_tree_node_id|.
static MimeHandlerViewEmbedder* Get(int32_t frame_tree_node_id);
static void Create(int32_t frame_tree_node_id, static void Create(int32_t frame_tree_node_id,
const GURL& resource_url, const GURL& resource_url,
const std::string& mime_type, const std::string& mime_type,
...@@ -46,6 +50,8 @@ class MimeHandlerViewEmbedder : public content::WebContentsObserver { ...@@ -46,6 +50,8 @@ class MimeHandlerViewEmbedder : public content::WebContentsObserver {
void DidStartNavigation(content::NavigationHandle* handle) override; void DidStartNavigation(content::NavigationHandle* handle) override;
void ReadyToCommitNavigation(content::NavigationHandle* handle) override; void ReadyToCommitNavigation(content::NavigationHandle* handle) override;
void ReadyToCreateMimeHandlerView(bool result);
private: private:
MimeHandlerViewEmbedder(int32_t frame_tree_node_id, MimeHandlerViewEmbedder(int32_t frame_tree_node_id,
const GURL& resource_url, const GURL& resource_url,
...@@ -82,6 +88,8 @@ class MimeHandlerViewEmbedder : public content::WebContentsObserver { ...@@ -82,6 +88,8 @@ class MimeHandlerViewEmbedder : public content::WebContentsObserver {
const std::string internal_id_; const std::string internal_id_;
bool ready_to_create_mime_handler_view_ = false;
base::WeakPtrFactory<MimeHandlerViewEmbedder> weak_factory_; base::WeakPtrFactory<MimeHandlerViewEmbedder> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(MimeHandlerViewEmbedder); DISALLOW_COPY_AND_ASSIGN(MimeHandlerViewEmbedder);
......
...@@ -30,6 +30,13 @@ interface GuestView { ...@@ -30,6 +30,13 @@ interface GuestView {
int32 element_instance_id, int32 element_instance_id,
gfx.mojom.Size element_size, gfx.mojom.Size element_size,
extensions.mime_handler.BeforeUnloadControl? before_unload_control); extensions.mime_handler.BeforeUnloadControl? before_unload_control);
// Notifies the browser whether or not now is a good time to start loading the
// MimeHandlerView. |routing_id| identifies the embedder frame. If |success|
// is false, then MimeHandlerViewEmbedder should destroy itself. When
// |success| is true the MimeHandlerViewEmbedder should proceed with attaching
// the GuestView.
ReadyToCreateMimeHandlerView(int32 routing_id, bool success);
}; };
// An interface implemented by the renderer which is used for creating a // An interface implemented by the renderer which is used for creating a
......
...@@ -145,6 +145,11 @@ PostMessageSupport::Delegate* PostMessageSupport::Delegate::FromWebLocalFrame( ...@@ -145,6 +145,11 @@ PostMessageSupport::Delegate* PostMessageSupport::Delegate::FromWebLocalFrame(
return mime_handlers.front(); return mime_handlers.front();
} }
// static
mojom::GuestView* MimeHandlerViewContainerBase::GuestView() {
return GetGuestView();
}
// static // static
std::vector<MimeHandlerViewContainerBase*> std::vector<MimeHandlerViewContainerBase*>
MimeHandlerViewContainerBase::FromRenderFrame( MimeHandlerViewContainerBase::FromRenderFrame(
......
...@@ -46,6 +46,8 @@ class MimeHandlerViewContainerBase : public blink::WebAssociatedURLLoaderClient, ...@@ -46,6 +46,8 @@ class MimeHandlerViewContainerBase : public blink::WebAssociatedURLLoaderClient,
~MimeHandlerViewContainerBase() override; ~MimeHandlerViewContainerBase() override;
static mojom::GuestView* GuestView();
// TODO(ekaramad): Remove this and make MimeHandlerViewContainerManager of // TODO(ekaramad): Remove this and make MimeHandlerViewContainerManager of
// |render_frame| hold on to the list of MimeHandlerViewContainerBase. // |render_frame| hold on to the list of MimeHandlerViewContainerBase.
static std::vector<MimeHandlerViewContainerBase*> FromRenderFrame( static std::vector<MimeHandlerViewContainerBase*> FromRenderFrame(
......
...@@ -109,6 +109,18 @@ bool MimeHandlerViewContainerManager::CreateFrameContainer( ...@@ -109,6 +109,18 @@ bool MimeHandlerViewContainerManager::CreateFrameContainer(
return true; return true;
} }
void MimeHandlerViewContainerManager::
DidBlockMimeHandlerViewForDisallowedPlugin(
const blink::WebElement& plugin_element) {
if (IsManagedByContainerManager(plugin_element)) {
// This is the one injected by HTML string. Return true so that the
// HTMLPlugInElement creates a child frame to be used as the outer
// WebContents frame.
MimeHandlerViewContainerBase::GuestView()->ReadyToCreateMimeHandlerView(
render_frame()->GetRoutingID(), false);
}
}
v8::Local<v8::Object> MimeHandlerViewContainerManager::GetScriptableObject( v8::Local<v8::Object> MimeHandlerViewContainerManager::GetScriptableObject(
const blink::WebElement& plugin_element, const blink::WebElement& plugin_element,
v8::Isolate* isolate) { v8::Isolate* isolate) {
...@@ -295,6 +307,8 @@ bool MimeHandlerViewContainerManager::IsManagedByContainerManager( ...@@ -295,6 +307,8 @@ bool MimeHandlerViewContainerManager::IsManagedByContainerManager(
base::ToUpperASCII(plugin_element.GetAttribute("internalid").Utf8()) == base::ToUpperASCII(plugin_element.GetAttribute("internalid").Utf8()) ==
internal_id_) { internal_id_) {
plugin_element_ = plugin_element; plugin_element_ = plugin_element;
MimeHandlerViewContainerBase::GuestView()->ReadyToCreateMimeHandlerView(
render_frame()->GetRoutingID(), true);
} }
return plugin_element_ == plugin_element; return plugin_element_ == plugin_element;
} }
......
...@@ -66,6 +66,10 @@ class MimeHandlerViewContainerManager ...@@ -66,6 +66,10 @@ class MimeHandlerViewContainerManager
const GURL& resource_url, const GURL& resource_url,
const std::string& mime_type, const std::string& mime_type,
const content::WebPluginInfo& plugin_info); const content::WebPluginInfo& plugin_info);
// Called to notify about a failed plugin load; this could happen if a
// <webview> with permissions API tries to load a plugin.
void DidBlockMimeHandlerViewForDisallowedPlugin(
const blink::WebElement& plugin_element);
// A wrapper for custom postMessage scripts. There should already be a // A wrapper for custom postMessage scripts. There should already be a
// MimeHandlerViewFrameContainer for |plugin_element|. // MimeHandlerViewFrameContainer for |plugin_element|.
v8::Local<v8::Object> GetScriptableObject( v8::Local<v8::Object> GetScriptableObject(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment