-
Notifications
You must be signed in to change notification settings - Fork 6.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement the registerProtocolHandler method for ContentShell
This CL implements in the ContentShell the registerProtocolHandler() method as defined in the HTML spec [1] The change is basically making the Shell class implementing the RegisterProtocolHandler method form the WebContentsDelegate public API. Thanks to the change landed in r982488 we have now all the privacy and security checks performed by the browser process in the WebContentsImpl class, so that chrome or any embedder can rely on this logic to ensure the registerProtocolHandler params normalization defined in the spec is complete. Hence, this CL would only have to worry about the registration logic. The ContentShell, as any other embedder, should use its own registry factory. The Chrome's implementation has one, using its own delegate to deal with the OS integration and the user preferences storage. In this CL a new TestProtocolHandlerRegistryFactory class is added in the Custom Handlers component, using the TestProtocolHandlerRegistryDelegate for now. Since the ContentShell's implementation is intended to be used to run Web Platform Tests, I haven't included the permission related logic that is present in the Chrome's implementation. We just call to the OnAcceptRegisterProtocolHandler to perform the handler registration, or OnIgnoreRegisterProtocolHandler if we want to cancel the request (eg, request coming from a Fenced frame) Additionally, it shouldn't make sense to rely on a user-preference storage to provide a persistent handler registration. Given that the goal is to run WPTs, we would just need to use the in-memory data structures to verify the tests. In order to avoid the pref storage, the mentioned testing registry factory pass nullptr as the PrefService pointer. This CL also implements the spec regarding the use of the registered handler. This issue is described in the bug 1292925 and it's needed to pass all the already defined manual tests in the WPT repo [2]. This changes implies the ShellContentBrowserClient class implementing the ContentBrowserClient::CreateURLLoaderThrottles public API, as described in the mentioned bug. Finally, this CL also provides ContentBrowserTest to ensure the method is implemented correctly using the content-shell. These browser tests are a subset of the ones already defined for Chrome. In order to avoid duplication, I've moved some of the test/data support files to the Custom Handlers component. [1] https://html.spec.whatwg.org/multipage/system-state.html#custom-handlers [2] https://wpt.fyi/results/html/webappapis/system-state-and-capabilities/the-navigator-object Bug: 1292925, 1293295 Change-Id: I20619a75124cf7f5fd1a589a80c013fa27ea70d4 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3557297 Reviewed-by: Dominick Ng <dominickn@chromium.org> Reviewed-by: Mike West <mkwst@chromium.org> Reviewed-by: David Benjamin <davidben@chromium.org> Commit-Queue: Javier Fernandez <jfernandez@igalia.com> Cr-Commit-Position: refs/heads/main@{#988671}
- Loading branch information
1 parent
c32fefc
commit 13150a0
Showing
20 changed files
with
483 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
200 changes: 200 additions & 0 deletions
200
components/custom_handlers/protocol_handler_registry_browsertest.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
// Copyright (c) 2022 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 <memory> | ||
#include <string> | ||
|
||
#include "base/scoped_observation.h" | ||
#include "base/strings/utf_string_conversions.h" | ||
#include "base/test/scoped_feature_list.h" | ||
#include "components/custom_handlers/protocol_handler.h" | ||
#include "components/custom_handlers/protocol_handler_registry.h" | ||
#include "components/custom_handlers/simple_protocol_handler_registry_factory.h" | ||
#include "content/public/browser/navigation_controller.h" | ||
#include "content/public/browser/navigation_entry.h" | ||
#include "content/public/browser/web_contents.h" | ||
#include "content/public/common/content_client.h" | ||
#include "content/public/common/content_features.h" | ||
#include "content/public/test/browser_test.h" | ||
#include "content/public/test/browser_test_utils.h" | ||
#include "content/public/test/content_browser_test.h" | ||
#include "content/public/test/content_browser_test_utils.h" | ||
#include "content/public/test/fenced_frame_test_util.h" | ||
#include "content/shell/browser/shell.h" | ||
#include "net/test/embedded_test_server/embedded_test_server.h" | ||
|
||
using content::WebContents; | ||
|
||
namespace { | ||
|
||
using custom_handlers::ProtocolHandlerRegistry; | ||
|
||
class ProtocolHandlerChangeWaiter : public ProtocolHandlerRegistry::Observer { | ||
public: | ||
explicit ProtocolHandlerChangeWaiter(ProtocolHandlerRegistry* registry) { | ||
registry_observation_.Observe(registry); | ||
} | ||
ProtocolHandlerChangeWaiter(const ProtocolHandlerChangeWaiter&) = delete; | ||
ProtocolHandlerChangeWaiter& operator=(const ProtocolHandlerChangeWaiter&) = | ||
delete; | ||
~ProtocolHandlerChangeWaiter() override = default; | ||
|
||
void Wait() { run_loop_.Run(); } | ||
// ProtocolHandlerRegistry::Observer: | ||
void OnProtocolHandlerRegistryChanged() override { run_loop_.Quit(); } | ||
|
||
private: | ||
base::ScopedObservation<custom_handlers::ProtocolHandlerRegistry, | ||
custom_handlers::ProtocolHandlerRegistry::Observer> | ||
registry_observation_{this}; | ||
base::RunLoop run_loop_; | ||
}; | ||
|
||
} // namespace | ||
|
||
namespace custom_handlers { | ||
|
||
class RegisterProtocolHandlerBrowserTest : public content::ContentBrowserTest { | ||
public: | ||
RegisterProtocolHandlerBrowserTest() = default; | ||
|
||
void SetUpOnMainThread() override { | ||
embedded_test_server()->ServeFilesFromSourceDirectory( | ||
"components/test/data/"); | ||
} | ||
|
||
void AddProtocolHandler(const std::string& protocol, const GURL& url) { | ||
ProtocolHandler handler = | ||
ProtocolHandler::CreateProtocolHandler(protocol, url); | ||
ProtocolHandlerRegistry* registry = | ||
SimpleProtocolHandlerRegistryFactory::GetForBrowserContext( | ||
browser_context(), true); | ||
// Fake that this registration is happening on profile startup. Otherwise | ||
// it'll try to register with the OS, which causes DCHECKs on Windows when | ||
// running as admin on Windows 7. | ||
registry->SetIsLoading(true); | ||
registry->OnAcceptRegisterProtocolHandler(handler); | ||
registry->SetIsLoading(true); | ||
ASSERT_TRUE(registry->IsHandledProtocol(protocol)); | ||
} | ||
|
||
void RemoveProtocolHandler(const std::string& protocol, const GURL& url) { | ||
ProtocolHandler handler = | ||
ProtocolHandler::CreateProtocolHandler(protocol, url); | ||
ProtocolHandlerRegistry* registry = | ||
SimpleProtocolHandlerRegistryFactory::GetForBrowserContext( | ||
browser_context(), true); | ||
registry->RemoveHandler(handler); | ||
ASSERT_FALSE(registry->IsHandledProtocol(protocol)); | ||
} | ||
|
||
content::WebContents* web_contents() { return shell()->web_contents(); } | ||
content::BrowserContext* browser_context() { | ||
return web_contents()->GetBrowserContext(); | ||
} | ||
|
||
protected: | ||
content::test::FencedFrameTestHelper& fenced_frame_test_helper() { | ||
return fenced_frame_helper_; | ||
} | ||
|
||
private: | ||
content::test::FencedFrameTestHelper fenced_frame_helper_; | ||
}; | ||
|
||
IN_PROC_BROWSER_TEST_F(RegisterProtocolHandlerBrowserTest, CustomHandler) { | ||
ASSERT_TRUE(embedded_test_server()->Start()); | ||
GURL handler_url = embedded_test_server()->GetURL("/custom_handler.html"); | ||
AddProtocolHandler("news", handler_url); | ||
|
||
ASSERT_TRUE(NavigateToURL(shell(), GURL("news:test"), handler_url)); | ||
|
||
ASSERT_EQ(handler_url, web_contents()->GetLastCommittedURL()); | ||
|
||
// Also check redirects. | ||
GURL redirect_url = | ||
embedded_test_server()->GetURL("/server-redirect?news:test"); | ||
ASSERT_TRUE(NavigateToURL(shell(), redirect_url, handler_url)); | ||
|
||
ASSERT_EQ(handler_url, web_contents()->GetLastCommittedURL()); | ||
} | ||
|
||
// https://crbug.com/178097: Implement registerProtocolHandler on Android | ||
#if !BUILDFLAG(IS_ANDROID) | ||
// FencedFrames can not register to handle any protocols. | ||
IN_PROC_BROWSER_TEST_F(RegisterProtocolHandlerBrowserTest, FencedFrame) { | ||
ASSERT_TRUE(embedded_test_server()->Start()); | ||
ASSERT_TRUE( | ||
NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"))); | ||
|
||
// Create a FencedFrame. | ||
content::RenderFrameHost* fenced_frame_host = | ||
fenced_frame_test_helper().CreateFencedFrame( | ||
web_contents()->GetMainFrame(), | ||
embedded_test_server()->GetURL("/fenced_frames/title1.html")); | ||
ASSERT_TRUE(fenced_frame_host); | ||
|
||
// Ensure the registry is currently empty. | ||
GURL url("web+search:testing"); | ||
ProtocolHandlerRegistry* registry = | ||
SimpleProtocolHandlerRegistryFactory::GetForBrowserContext( | ||
browser_context(), true); | ||
ASSERT_EQ(0u, registry->GetHandlersFor(url.scheme()).size()); | ||
|
||
// Attempt to add an entry. | ||
ProtocolHandlerChangeWaiter waiter(registry); | ||
ASSERT_TRUE(content::ExecuteScript(fenced_frame_host, | ||
"navigator.registerProtocolHandler('web+" | ||
"search', 'test.html?%s', 'test');")); | ||
waiter.Wait(); | ||
|
||
// Ensure the registry is still empty. | ||
ASSERT_EQ(0u, registry->GetHandlersFor(url.scheme()).size()); | ||
} | ||
#endif | ||
|
||
// https://crbug.com/178097: Implement registerProtocolHandler on Android | ||
#if !BUILDFLAG(IS_ANDROID) | ||
class RegisterProtocolHandlerAndServiceWorkerInterceptor | ||
: public RegisterProtocolHandlerBrowserTest { | ||
public: | ||
void SetUpOnMainThread() override { | ||
RegisterProtocolHandlerBrowserTest::SetUpOnMainThread(); | ||
|
||
ASSERT_TRUE(embedded_test_server()->Start()); | ||
|
||
// Navigate to the test page. | ||
ASSERT_TRUE(NavigateToURL( | ||
shell(), embedded_test_server()->GetURL( | ||
"/protocol_handler/service_workers/" | ||
"test_protocol_handler_and_service_workers.html"))); | ||
} | ||
}; | ||
|
||
// TODO(crbug.com/1204127): Fix flakiness. | ||
IN_PROC_BROWSER_TEST_F(RegisterProtocolHandlerAndServiceWorkerInterceptor, | ||
DISABLED_RegisterFetchListenerForHTMLHandler) { | ||
// Register a service worker intercepting requests to the HTML handler. | ||
EXPECT_EQ(true, | ||
content::EvalJs(shell(), "registerFetchListenerForHTMLHandler();")); | ||
|
||
{ | ||
// Register a HTML handler with a user gesture. | ||
ProtocolHandlerRegistry* registry = | ||
SimpleProtocolHandlerRegistryFactory::GetForBrowserContext( | ||
browser_context(), true); | ||
ProtocolHandlerChangeWaiter waiter(registry); | ||
ASSERT_TRUE(content::ExecJs(shell(), "registerHTMLHandler();")); | ||
waiter.Wait(); | ||
} | ||
|
||
// Verify that a page with the registered scheme is managed by the service | ||
// worker, not the HTML handler. | ||
EXPECT_EQ(true, | ||
content::EvalJs(shell(), | ||
"pageWithCustomSchemeHandledByServiceWorker();")); | ||
} | ||
#endif | ||
|
||
} // namespace custom_handlers |
Oops, something went wrong.