Commit 89eb5791 authored by Eric Lawrence's avatar Eric Lawrence Committed by Commit Bot

Log external handler invocations to the console

Previously, failing to invoke an external protocol handler ('foo://bar')
would fail silently if the protocol was not registered or if the user
gesture requirement was not met. This limitation made it difficult for
web developers to troubleshoot such situations. This CL emits errors to
the Developer Tools console when the protocol handler is not registered,
is forbidden, or is temporarily blocked pending a user-gesture.
Similarly, if an external handler is launched, an informational log
entry is added.

Bug: 1096610
Change-Id: Ie562d0c030f138f7e5ac0a09576ba73a79de3971
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2252848Reviewed-by: default avatarMatt Giuca <mgiuca@chromium.org>
Commit-Queue: Eric Lawrence [MSFT] <ericlaw@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#782007}
parent d1b93008
...@@ -112,6 +112,19 @@ void RunExternalProtocolDialogWithDelegate( ...@@ -112,6 +112,19 @@ void RunExternalProtocolDialogWithDelegate(
has_user_gesture, initiating_origin); has_user_gesture, initiating_origin);
return; return;
} }
#if defined(OS_MACOSX) || defined(OS_WIN)
// If the Shell does not have a registered name for the protocol,
// attempting to invoke the protocol will fail.
if (shell_integration::GetApplicationNameForProtocol(url).empty()) {
web_contents->GetMainFrame()->AddMessageToConsole(
blink::mojom::ConsoleMessageLevel::kError,
"Failed to launch '" + url.possibly_invalid_spec() +
"' because the scheme does not have a registered handler.");
return;
}
#endif
ExternalProtocolHandler::RunExternalProtocolDialog( ExternalProtocolHandler::RunExternalProtocolDialog(
url, web_contents, page_transition, has_user_gesture, initiating_origin); url, web_contents, page_transition, has_user_gesture, initiating_origin);
} }
...@@ -130,6 +143,10 @@ void LaunchUrlWithoutSecurityCheckWithDelegate( ...@@ -130,6 +143,10 @@ void LaunchUrlWithoutSecurityCheckWithDelegate(
if (!web_contents) if (!web_contents)
return; return;
web_contents->GetMainFrame()->AddMessageToConsole(
blink::mojom::ConsoleMessageLevel::kInfo,
"Launched external handler for '" + url.possibly_invalid_spec() + "'.");
platform_util::OpenExternal( platform_util::OpenExternal(
Profile::FromBrowserContext(web_contents->GetBrowserContext()), url); Profile::FromBrowserContext(web_contents->GetBrowserContext()), url);
...@@ -391,6 +408,11 @@ void ExternalProtocolHandler::LaunchUrl( ...@@ -391,6 +408,11 @@ void ExternalProtocolHandler::LaunchUrl(
escaped_url.scheme(), base::OptionalOrNullptr(initiating_origin), escaped_url.scheme(), base::OptionalOrNullptr(initiating_origin),
g_external_protocol_handler_delegate, profile); g_external_protocol_handler_delegate, profile);
if (block_state == BLOCK) { if (block_state == BLOCK) {
web_contents->GetMainFrame()->AddMessageToConsole(
blink::mojom::ConsoleMessageLevel::kError,
"Not allowed to launch '" + url.possibly_invalid_spec() + "'" +
(g_accept_requests ? "." : " because a user gesture is required."));
if (g_external_protocol_handler_delegate) if (g_external_protocol_handler_delegate)
g_external_protocol_handler_delegate->BlockRequest(); g_external_protocol_handler_delegate->BlockRequest();
return; return;
......
...@@ -71,3 +71,41 @@ IN_PROC_BROWSER_TEST_F(ExternalProtocolHandlerBrowserTest, ...@@ -71,3 +71,41 @@ IN_PROC_BROWSER_TEST_F(ExternalProtocolHandlerBrowserTest,
observer.Wait(); observer.Wait();
EXPECT_EQ(browser()->tab_strip_model()->count(), 1); EXPECT_EQ(browser()->tab_strip_model()->count(), 1);
} }
IN_PROC_BROWSER_TEST_F(ExternalProtocolHandlerBrowserTest,
ProtocolLaunchEmitsConsoleLog) {
#if defined(OS_WIN)
// On Win 7 the protocol is registered to be handled by Chrome and thus never
// reaches the ExternalProtocolHandler so we skip the test. For
// more info see installer/util/shell_util.cc:GetShellIntegrationEntries
if (base::win::GetVersion() < base::win::Version::WIN8)
return;
#endif
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
content::WebContentsConsoleObserver observer(web_contents);
observer.SetPattern("Launched external handler for 'mailto:test@site.test'.");
ASSERT_TRUE(
ExecJs(web_contents, "window.open('mailto:test@site.test', '_self');"));
observer.Wait();
ASSERT_EQ(1u, observer.messages().size());
}
IN_PROC_BROWSER_TEST_F(ExternalProtocolHandlerBrowserTest,
ProtocolFailureEmitsConsoleLog) {
// Only on Mac and Windows is there a way for Chromium to know whether a
// protocol handler is registered ahead of time.
#if defined(OS_MACOSX) || defined(OS_WIN)
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
content::WebContentsConsoleObserver observer(web_contents);
observer.SetPattern("Failed to launch 'does.not.exist:failure'*");
ASSERT_TRUE(
ExecJs(web_contents, "window.open('does.not.exist:failure', '_self');"));
observer.Wait();
ASSERT_EQ(1u, observer.messages().size());
#endif
}
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