diff options
m--------- | src/3rdparty | 0 | ||||
-rw-r--r-- | src/core/content_browser_client_qt.cpp | 67 | ||||
-rw-r--r-- | src/core/content_browser_client_qt.h | 5 | ||||
-rw-r--r-- | src/core/net/network_delegate_qt.cpp | 3 | ||||
-rw-r--r-- | src/core/net/url_request_notification.cpp | 32 | ||||
-rw-r--r-- | src/core/qtwebengine.gni | 1 | ||||
-rw-r--r-- | tests/auto/widgets/schemes/tst_schemes.cpp | 76 |
7 files changed, 121 insertions, 63 deletions
diff --git a/src/3rdparty b/src/3rdparty -Subproject 88a931558e2e960eacccb32483713fcc4bbaf43 +Subproject d61464c1e69fa96a47ab731f0ee4549890ae465 diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp index 29b6e09ed..49617329e 100644 --- a/src/core/content_browser_client_qt.cpp +++ b/src/core/content_browser_client_qt.cpp @@ -49,6 +49,8 @@ #if QT_CONFIG(webengine_spellchecker) #include "chrome/browser/spellchecker/spell_check_host_chrome_impl.h" #endif +#include "components/navigation_interception/intercept_navigation_throttle.h" +#include "components/navigation_interception/navigation_params.h" #include "components/guest_view/browser/guest_view_base.h" #include "components/network_hints/browser/network_hints_message_filter.h" #include "content/browser/renderer_host/render_view_host_delegate.h" @@ -121,6 +123,7 @@ #include "renderer_host/user_resource_controller_host.h" #include "service/service_qt.h" #include "type_conversion.h" +#include "web_contents_adapter_client.h" #include "web_contents_delegate_qt.h" #include "web_engine_context.h" #include "web_engine_library_info.h" @@ -846,6 +849,70 @@ ContentBrowserClientQt::CreateURLLoaderThrottles( return result; } +extern WebContentsAdapterClient::NavigationType pageTransitionToNavigationType(ui::PageTransition transition); + +static bool navigationThrottleCallback(content::WebContents *source, + const navigation_interception::NavigationParams ¶ms) +{ + // We call navigationRequested later in launchExternalUrl for external protocols. + // The is_external_protocol parameter here is not fully accurate though, + // and doesn't know about profile specific custom URL schemes. + ProfileQt *profile = static_cast<ProfileQt *>(source->GetBrowserContext()); + if (params.is_external_protocol() && !profile->profileAdapter()->urlSchemeHandler(toQByteArray(params.url().scheme()))) + return false; + int navigationRequestAction = WebContentsAdapterClient::AcceptRequest; + WebContentsDelegateQt *delegate = static_cast<WebContentsDelegateQt *>(source->GetDelegate()); + WebContentsAdapterClient *client = delegate->adapterClient(); + client->navigationRequested(pageTransitionToNavigationType(params.transition_type()), + toQt(params.url()), + navigationRequestAction, + params.is_main_frame()); + return navigationRequestAction == static_cast<int>(WebContentsAdapterClient::IgnoreRequest); +} + +std::vector<std::unique_ptr<content::NavigationThrottle>> ContentBrowserClientQt::CreateThrottlesForNavigation( + content::NavigationHandle *navigation_handle) +{ + std::vector<std::unique_ptr<content::NavigationThrottle>> throttles; + throttles.push_back(std::make_unique<navigation_interception::InterceptNavigationThrottle>( + navigation_handle, + base::BindRepeating(&navigationThrottleCallback), + navigation_interception::SynchronyMode::kSync)); + return throttles; +} + +bool ContentBrowserClientQt::IsHandledURL(const GURL &url) +{ + static const char *const kProtocolList[] = { + url::kFileScheme, + content::kChromeDevToolsScheme, +#if BUILDFLAG(ENABLE_EXTENSIONS) + extensions::kExtensionScheme, +#endif + content::kChromeUIScheme, + url::kDataScheme, + url::kAboutScheme, +#if !BUILDFLAG(DISABLE_FTP_SUPPORT) + url::kFtpScheme, +#endif // !BUILDFLAG(DISABLE_FTP_SUPPORT) + url::kBlobScheme, + url::kFileSystemScheme, + url::kQrcScheme, + }; + + // We don't check url.IsCustom() here because we don't + // know if the registered protocol is installed in the + // profile that will be used to load the URL. + + const std::string scheme = url.scheme(); + + for (const char *protocol : kProtocolList) { + if (scheme == protocol) + return true; + } + return net::URLRequest::IsHandledProtocol(scheme); +} + std::unique_ptr<content::LoginDelegate> ContentBrowserClientQt::CreateLoginDelegate( const net::AuthChallengeInfo &authInfo, content::WebContents *web_contents, diff --git a/src/core/content_browser_client_qt.h b/src/core/content_browser_client_qt.h index f5b03a8d9..5d8a1519c 100644 --- a/src/core/content_browser_client_qt.h +++ b/src/core/content_browser_client_qt.h @@ -216,6 +216,11 @@ public: const base::RepeatingCallback<content::WebContents *()> &wc_getter, content::NavigationUIData *navigation_ui_data, int frame_tree_node_id) override; + std::vector<std::unique_ptr<content::NavigationThrottle>> CreateThrottlesForNavigation( + content::NavigationHandle *navigation_handle) override; + + bool IsHandledURL(const GURL &url) override; + static std::string getUserAgent(); std::string GetUserAgent() override { return getUserAgent(); } diff --git a/src/core/net/network_delegate_qt.cpp b/src/core/net/network_delegate_qt.cpp index 7d3801ffe..684558abb 100644 --- a/src/core/net/network_delegate_qt.cpp +++ b/src/core/net/network_delegate_qt.cpp @@ -178,8 +178,7 @@ int NetworkDelegateQt::OnBeforeURLRequest(net::URLRequest *request, net::Complet return net::OK; // try to bail out - if (!m_profileIOData->hasPageInterceptors() && (!m_profileIOData->requestInterceptor() || m_profileIOData->isInterceptorDeprecated()) && - !content::IsResourceTypeFrame(resourceType)) + if (!m_profileIOData->hasPageInterceptors() && (!m_profileIOData->requestInterceptor() || m_profileIOData->isInterceptorDeprecated())) return net::OK; auto webContentsGetter = resourceInfo->GetWebContentsGetterForRequest(); diff --git a/src/core/net/url_request_notification.cpp b/src/core/net/url_request_notification.cpp index fa6d61f65..eb48160bf 100644 --- a/src/core/net/url_request_notification.cpp +++ b/src/core/net/url_request_notification.cpp @@ -44,11 +44,12 @@ #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/browser_thread.h" #include "net/url_request/url_request.h" -#include "web_contents_adapter_client.h" -#include "web_contents_view_qt.h" + +#include "api/qwebengineurlrequestinfo_p.h" #include "profile_io_data_qt.h" -#include "qwebengineurlrequestinfo_p.h" #include "type_conversion.h" +#include "web_contents_adapter_client.h" +#include "web_contents_view_qt.h" namespace QtWebEngineCore { @@ -66,11 +67,6 @@ private: const char UserData::key[] = "QtWebEngineCore::URLRequestNotification"; -static content::ResourceType fromQt(QWebEngineUrlRequestInfo::ResourceType resourceType) -{ - return static_cast<content::ResourceType>(resourceType); -} - URLRequestNotification::URLRequestNotification(net::URLRequest *request, bool isMainFrameRequest, GURL *newUrl, QWebEngineUrlRequestInfo &&requestInfo, content::ResourceRequestInfo::WebContentsGetter webContentsGetter, @@ -105,7 +101,6 @@ void URLRequestNotification::notify() content::WebContents *webContents = m_webContentsGetter.Run(); if (webContents) { - if (m_profileAdapter && m_profileAdapter->requestInterceptor()) { QWebEngineUrlRequestInterceptor *interceptor = m_profileAdapter->requestInterceptor(); if (!interceptor->property("deprecated").toBool()) @@ -123,25 +118,6 @@ void URLRequestNotification::notify() result = m_requestInfo.d_ptr->shouldBlockRequest ? net::ERR_BLOCKED_BY_CLIENT : net::OK; // We handle the rest of the changes later when we are back in I/O thread } - - // Only do navigationRequested on MAIN_FRAME and SUB_FRAME resources - if (result == net::OK && content::IsResourceTypeFrame(fromQt(m_requestInfo.resourceType()))) { - int navigationRequestAction = WebContentsAdapterClient::AcceptRequest; - client->navigationRequested(m_requestInfo.navigationType(), - m_requestInfo.requestUrl(), - navigationRequestAction, - m_isMainFrameRequest); - result = net::ERR_FAILED; - switch (static_cast<WebContentsAdapterClient::NavigationRequestAction>(navigationRequestAction)) { - case WebContentsAdapterClient::AcceptRequest: - result = net::OK; - break; - case WebContentsAdapterClient::IgnoreRequest: - result = net::ERR_ABORTED; - break; - } - DCHECK(result != net::ERR_FAILED); - } } // Run the callback on the IO thread. diff --git a/src/core/qtwebengine.gni b/src/core/qtwebengine.gni index cd8514352..b529290c0 100644 --- a/src/core/qtwebengine.gni +++ b/src/core/qtwebengine.gni @@ -20,6 +20,7 @@ deps = [ "//components/cdm/renderer", "//components/error_page/common", "//components/keyed_service/content", + "//components/navigation_interception", "//components/network_hints/browser", "//components/network_hints/common", "//components/network_hints/renderer", diff --git a/tests/auto/widgets/schemes/tst_schemes.cpp b/tests/auto/widgets/schemes/tst_schemes.cpp index 1b6093571..a4a0e34ff 100644 --- a/tests/auto/widgets/schemes/tst_schemes.cpp +++ b/tests/auto/widgets/schemes/tst_schemes.cpp @@ -38,6 +38,7 @@ class tst_Schemes : public QObject Q_OBJECT private Q_SLOTS: + void unknownUrlSchemePolicy_data(); void unknownUrlSchemePolicy(); }; @@ -58,8 +59,27 @@ public: } }; +Q_DECLARE_METATYPE(QWebEngineSettings::UnknownUrlSchemePolicy) + +void tst_Schemes::unknownUrlSchemePolicy_data() +{ + QTest::addColumn<QWebEngineSettings::UnknownUrlSchemePolicy>("policy"); + QTest::addColumn<bool>("userAction"); + QTest::newRow("DisallowUnknownUrlSchemes, script") << QWebEngineSettings::DisallowUnknownUrlSchemes << false; + QTest::newRow("DisallowUnknownUrlSchemes, user") << QWebEngineSettings::DisallowUnknownUrlSchemes << true; + QTest::newRow("AllowUnknownUrlSchemesFromUserInteraction, script") << QWebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction << false; + QTest::newRow("AllowUnknownUrlSchemesFromUserInteraction, user") << QWebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction << true; + QTest::newRow("AllowAllUnknownUrlSchemes, script") << QWebEngineSettings::AllowAllUnknownUrlSchemes << false; + QTest::newRow("AllowAllUnknownUrlSchemes, user") << QWebEngineSettings::AllowAllUnknownUrlSchemes << true; + QTest::newRow("default UnknownUrlSchemePolicy, script") << QWebEngineSettings::UnknownUrlSchemePolicy(0) << false; + QTest::newRow("default UnknownUrlSchemePolicy, user") << QWebEngineSettings::UnknownUrlSchemePolicy(0) << true; +} + void tst_Schemes::unknownUrlSchemePolicy() { + QFETCH(QWebEngineSettings::UnknownUrlSchemePolicy, policy); + QFETCH(bool, userAction); + QWebEngineView view; AcceptNavigationRequestHandler page; QSignalSpy loadFinishedSpy(&page, &QWebEnginePage::loadFinished); @@ -71,41 +91,31 @@ void tst_Schemes::unknownUrlSchemePolicy() settings->setAttribute(QWebEngineSettings::ErrorPageEnabled, true); settings->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true); - QWebEngineSettings::UnknownUrlSchemePolicy policies[6] = {QWebEngineSettings::DisallowUnknownUrlSchemes, - QWebEngineSettings::DisallowUnknownUrlSchemes, - QWebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction, - QWebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction, - QWebEngineSettings::AllowAllUnknownUrlSchemes, - QWebEngineSettings::AllowAllUnknownUrlSchemes}; - // even iterations are for navigation-requests from javascript, - // odd iterations are for navigations-requests from user-interaction - for (int i = 0; i < 8; i++) { - if (i <= 5) - settings->setUnknownUrlSchemePolicy(policies[i]); - else - settings->resetUnknownUrlSchemePolicy(); - loadFinishedSpy.clear(); - page.acceptNavigationRequestCalls = 0; - bool shouldAccept; - - if (i % 2 == 0) { // navigation request coming from javascript - shouldAccept = (4 <= i && i <= 5); // only case AllowAllUnknownUrlSchemes - view.setHtml("<html><script>setTimeout(function(){ window.location.href='nonexistentscheme://somewhere'; }, 10);</script><body>testing...</body></html>"); - } else { // navigation request coming from user interaction - shouldAccept = (2 <= i); // all cases except DisallowUnknownUrlSchemes - view.setHtml("<html><body><a id='nonexlink' href='nonexistentscheme://somewhere'>nonexistentscheme://somewhere</a></body></html>"); - QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 15000); - // focus and trigger the link - view.page()->runJavaScript("document.getElementById('nonexlink').focus();", [&view](const QVariant &result) { - Q_UNUSED(result); - QTest::sendKeyEvent(QTest::Press, view.focusProxy(), Qt::Key_Return, QString("\r"), Qt::NoModifier); - QTest::sendKeyEvent(QTest::Release, view.focusProxy(), Qt::Key_Return, QString("\r"), Qt::NoModifier); - }); - } + if (policy > 0) + settings->setUnknownUrlSchemePolicy(policy); + else + settings->resetUnknownUrlSchemePolicy(); + loadFinishedSpy.clear(); + page.acceptNavigationRequestCalls = 0; + bool shouldAccept; - QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 2, 60000); - QCOMPARE(page.acceptNavigationRequestCalls, shouldAccept ? 1 : 0); + if (!userAction) { // navigation request coming from javascript + shouldAccept = (policy == QWebEngineSettings::AllowAllUnknownUrlSchemes); + view.setHtml("<html><script>setTimeout(function(){ window.location.href='nonexistentscheme://somewhere'; }, 10);</script><body>testing...</body></html>"); + } else { // navigation request coming from user interaction + shouldAccept = (policy != QWebEngineSettings::DisallowUnknownUrlSchemes); + view.setHtml("<html><body><a id='nonexlink' href='nonexistentscheme://somewhere'>nonexistentscheme://somewhere</a></body></html>"); + QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 15000); + // focus and trigger the link + view.page()->runJavaScript("document.getElementById('nonexlink').focus();", [&view](const QVariant &result) { + Q_UNUSED(result); + QTest::sendKeyEvent(QTest::Press, view.focusProxy(), Qt::Key_Return, QString("\r"), Qt::NoModifier); + QTest::sendKeyEvent(QTest::Release, view.focusProxy(), Qt::Key_Return, QString("\r"), Qt::NoModifier); + }); } + + QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 2, 60000); + QCOMPARE(page.acceptNavigationRequestCalls, shouldAccept ? 1 : 0); } QTEST_MAIN(tst_Schemes) |