Commit 9c87118e authored by Kevin McNee's avatar Kevin McNee Committed by Commit Bot

Ensure script context in subframes where webview needs definition

If a frame has guest view custom elements defined, then any iframes also
need the definition or else a webview in an iframe will not be
initialized. If the iframe contains a script element, a script context
will be created which allows for the definition of the custom element in
the iframe. If there are no script elements, then no script context is
created, so the custom element definition is not available.

We make the ForceMainWorldInitialization setting available so that
extension code can force the creation of a script context for any
subframe of a frame which has access to guest view custom element
definitions.

Bug: 788914
Change-Id: Ibdd7c321b6e67dbe913f3deb2307406102d7b44a
Reviewed-on: https://chromium-review.googlesource.com/828045
Commit-Queue: Kevin McNee <mcnee@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarDevlin <rdevlin.cronin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#531744}
parent cb819123
...@@ -661,12 +661,18 @@ class WebViewTestBase : public extensions::PlatformAppBrowserTest { ...@@ -661,12 +661,18 @@ class WebViewTestBase : public extensions::PlatformAppBrowserTest {
ExtensionTestMessageListener done_listener("TEST_PASSED", false); ExtensionTestMessageListener done_listener("TEST_PASSED", false);
done_listener.set_failure_message("TEST_FAILED"); done_listener.set_failure_message("TEST_FAILED");
if (!content::ExecuteScript( // Note that domAutomationController may not exist for some tests so we
embedder_web_contents, // must use the async version of ExecuteScript.
base::StringPrintf("runTest('%s')", test_name.c_str()))) { content::ExecuteScriptAsync(
LOG(ERROR) << "UNABLE TO START TEST."; embedder_web_contents,
return; base::StringPrintf("try { "
} " runTest('%s'); "
"} catch (e) { "
" console.log('UNABLE TO START TEST.'); "
" console.log(e); "
" chrome.test.sendMessage('TEST_FAILED'); "
"}",
test_name.c_str()));
ASSERT_TRUE(done_listener.WaitUntilSatisfied()); ASSERT_TRUE(done_listener.WaitUntilSatisfied());
} }
...@@ -3683,27 +3689,6 @@ IN_PROC_BROWSER_TEST_P(WebViewTest, LoadWebviewInaccessibleResource) { ...@@ -3683,27 +3689,6 @@ IN_PROC_BROWSER_TEST_P(WebViewTest, LoadWebviewInaccessibleResource) {
EXPECT_EQ(foo_url, web_view_contents->GetLastCommittedURL()); EXPECT_EQ(foo_url, web_view_contents->GetLastCommittedURL());
} }
// Tests that a webview inside an iframe can load and that it is destroyed when
// the iframe is detached.
IN_PROC_BROWSER_TEST_P(WebViewTest, LoadWebviewInsideIframe) {
TestHelper("testLoadWebviewInsideIframe",
"web_view/load_webview_inside_iframe", NEEDS_TEST_SERVER);
// WebContents is leaked when using BrowserPlugin.
if (!base::FeatureList::IsEnabled(::features::kGuestViewCrossProcessFrames))
return;
content::WebContentsDestroyedWatcher watcher(
GetGuestViewManager()->GetLastGuestCreated());
// Remove the iframe.
EXPECT_TRUE(content::ExecuteScript(
GetEmbedderWebContents(), "document.querySelector('iframe').remove()"));
// Wait for guest to be destroyed.
watcher.Wait();
}
// Makes sure that a webview will display correctly after reloading it after a // Makes sure that a webview will display correctly after reloading it after a
// crash. // crash.
IN_PROC_BROWSER_TEST_P(WebViewTest, ReloadAfterCrash) { IN_PROC_BROWSER_TEST_P(WebViewTest, ReloadAfterCrash) {
...@@ -3736,6 +3721,58 @@ IN_PROC_BROWSER_TEST_P(WebViewTest, ReloadAfterCrash) { ...@@ -3736,6 +3721,58 @@ IN_PROC_BROWSER_TEST_P(WebViewTest, ReloadAfterCrash) {
WaitForChildFrameSurfaceReady(GetGuestWebContents()->GetMainFrame()); WaitForChildFrameSurfaceReady(GetGuestWebContents()->GetMainFrame());
} }
// The presence of DomAutomationController interferes with these tests, so we
// disable it.
class WebViewTestNoDomAutomationController : public WebViewTest {
public:
~WebViewTestNoDomAutomationController() override {}
void SetUpInProcessBrowserTestFixture() override {
WebViewTest::SetUpInProcessBrowserTestFixture();
// DomAutomationController is added in BrowserTestBase::SetUp, so we need
// to remove it here instead of in SetUpCommandLine.
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
base::CommandLine new_command_line(command_line->GetProgram());
base::CommandLine::SwitchMap switches = command_line->GetSwitches();
switches.erase(switches::kDomAutomationController);
for (const auto& s : switches)
new_command_line.AppendSwitchNative(s.first, s.second);
*command_line = new_command_line;
}
};
INSTANTIATE_TEST_CASE_P(WebViewTests,
WebViewTestNoDomAutomationController,
testing::Bool());
// Tests that a webview inside an iframe can load and that it is destroyed when
// the iframe is detached.
// We need to disable DomAutomationController because it forces the creation of
// a script context. We want to test that we handle the case where there is no
// script context for the iframe. See crbug.com/788914
IN_PROC_BROWSER_TEST_P(WebViewTestNoDomAutomationController,
LoadWebviewInsideIframe) {
TestHelper("testLoadWebviewInsideIframe",
"web_view/load_webview_inside_iframe", NEEDS_TEST_SERVER);
ASSERT_TRUE(GetGuestViewManager()->GetLastGuestCreated());
// WebContents is leaked when using BrowserPlugin.
if (!base::FeatureList::IsEnabled(::features::kGuestViewCrossProcessFrames))
return;
content::WebContentsDestroyedWatcher watcher(
GetGuestViewManager()->GetLastGuestCreated());
// Remove the iframe.
content::ExecuteScriptAsync(GetEmbedderWebContents(),
"document.querySelector('iframe').remove()");
// Wait for guest to be destroyed.
watcher.Wait();
}
IN_PROC_BROWSER_TEST_P(WebViewAccessibilityTest, LoadWebViewAccessibility) { IN_PROC_BROWSER_TEST_P(WebViewAccessibilityTest, LoadWebViewAccessibility) {
LoadAppWithGuest("web_view/focus_accessibility"); LoadAppWithGuest("web_view/focus_accessibility");
content::WebContents* web_contents = GetFirstAppWindowWebContents(); content::WebContents* web_contents = GetFirstAppWindowWebContents();
......
...@@ -6,6 +6,12 @@ ...@@ -6,6 +6,12 @@
--> -->
<html> <html>
<body> <body>
<!--
* Do not include any scripts in this file as that would create a script
* context for the iframe. We want to test that the browser ensures the
* creation of a script context so that this webview is recognized as a
* custom element.
-->
<webview></webview> <webview></webview>
</body> </body>
</html> </html>
...@@ -18,13 +18,20 @@ function testLoadWebviewInsideIframe() { ...@@ -18,13 +18,20 @@ function testLoadWebviewInsideIframe() {
var iframe = document.querySelector('iframe'); var iframe = document.querySelector('iframe');
var webview = iframe.contentDocument.querySelector('webview'); var webview = iframe.contentDocument.querySelector('webview');
webview.addEventListener('loadstop', function () { if (webview.contentWindow === undefined) {
window.addEventListener('message', function (e) { window.console.log('The webview was not initialized.');
if(e.data == 'TEST_PASSED') { chrome.test.sendMessage('TEST_FAILED');
chrome.test.sendMessage('TEST_PASSED'); return;
} else { }
chrome.test.sendMessage('TEST_FAILED');
}}); webview.addEventListener('loadstop', function() {
window.addEventListener('message', function(e) {
if (e.data == 'TEST_PASSED') {
chrome.test.sendMessage('TEST_PASSED');
} else {
chrome.test.sendMessage('TEST_FAILED');
}
});
webview.contentWindow.postMessage('TEST_START', '*'); webview.contentWindow.postMessage('TEST_START', '*');
}); });
......
...@@ -112,6 +112,7 @@ ...@@ -112,6 +112,7 @@
#include "third_party/WebKit/public/web/WebScopedUserGesture.h" #include "third_party/WebKit/public/web/WebScopedUserGesture.h"
#include "third_party/WebKit/public/web/WebScriptController.h" #include "third_party/WebKit/public/web/WebScriptController.h"
#include "third_party/WebKit/public/web/WebSecurityPolicy.h" #include "third_party/WebKit/public/web/WebSecurityPolicy.h"
#include "third_party/WebKit/public/web/WebSettings.h"
#include "third_party/WebKit/public/web/WebView.h" #include "third_party/WebKit/public/web/WebView.h"
#include "ui/base/layout.h" #include "ui/base/layout.h"
#include "ui/base/resource/resource_bundle.h" #include "ui/base/resource/resource_bundle.h"
...@@ -1408,6 +1409,17 @@ void Dispatcher::RequireGuestViewModules(ScriptContext* context) { ...@@ -1408,6 +1409,17 @@ void Dispatcher::RequireGuestViewModules(ScriptContext* context) {
module_system->Require("guestViewIframeContainer"); module_system->Require("guestViewIframeContainer");
} }
if (requires_guest_view_module) {
// If a frame has guest view custom elements defined, we need to make sure
// the custom elements are also defined in subframes. The subframes will
// need a scripting context which we will need to forcefully create if
// the subframe doesn't otherwise have any scripts.
context->web_frame()
->View()
->GetSettings()
->SetForceMainWorldInitialization(true);
}
// The "guestViewDeny" module must always be loaded last. It registers // The "guestViewDeny" module must always be loaded last. It registers
// error-providing custom elements for the GuestView types that are not // error-providing custom elements for the GuestView types that are not
// available, and thus all of those types must have been checked and loaded // available, and thus all of those types must have been checked and loaded
......
...@@ -71,6 +71,10 @@ void WebSettingsImpl::SetFixedFontFamily(const WebString& font, ...@@ -71,6 +71,10 @@ void WebSettingsImpl::SetFixedFontFamily(const WebString& font,
settings_->NotifyGenericFontFamilyChange(); settings_->NotifyGenericFontFamilyChange();
} }
void WebSettingsImpl::SetForceMainWorldInitialization(bool enabled) {
settings_->SetForceMainWorldInitialization(enabled);
}
void WebSettingsImpl::SetForcePreloadNoneForMediaElements(bool enabled) { void WebSettingsImpl::SetForcePreloadNoneForMediaElements(bool enabled) {
settings_->SetForcePreloadNoneForMediaElements(enabled); settings_->SetForcePreloadNoneForMediaElements(enabled);
} }
......
...@@ -94,6 +94,7 @@ class CORE_EXPORT WebSettingsImpl final : public WebSettings { ...@@ -94,6 +94,7 @@ class CORE_EXPORT WebSettingsImpl final : public WebSettings {
UScriptCode = USCRIPT_COMMON) override; UScriptCode = USCRIPT_COMMON) override;
void SetFixedFontFamily(const WebString&, void SetFixedFontFamily(const WebString&,
UScriptCode = USCRIPT_COMMON) override; UScriptCode = USCRIPT_COMMON) override;
void SetForceMainWorldInitialization(bool) override;
void SetForcePreloadNoneForMediaElements(bool) override; void SetForcePreloadNoneForMediaElements(bool) override;
void SetForceZeroLayoutHeight(bool) override; void SetForceZeroLayoutHeight(bool) override;
void SetFullscreenSupported(bool) override; void SetFullscreenSupported(bool) override;
......
...@@ -185,6 +185,7 @@ class WebSettings { ...@@ -185,6 +185,7 @@ class WebSettings {
UScriptCode = USCRIPT_COMMON) = 0; UScriptCode = USCRIPT_COMMON) = 0;
virtual void SetFixedFontFamily(const WebString&, virtual void SetFixedFontFamily(const WebString&,
UScriptCode = USCRIPT_COMMON) = 0; UScriptCode = USCRIPT_COMMON) = 0;
virtual void SetForceMainWorldInitialization(bool) = 0;
virtual void SetForcePreloadNoneForMediaElements(bool) = 0; virtual void SetForcePreloadNoneForMediaElements(bool) = 0;
virtual void SetForceZeroLayoutHeight(bool) = 0; virtual void SetForceZeroLayoutHeight(bool) = 0;
virtual void SetFullscreenSupported(bool) = 0; virtual void SetFullscreenSupported(bool) = 0;
......
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