From 49c0ce8403e5caeb864f66553f122c68a7c975fb Mon Sep 17 00:00:00 2001 From: Viktor Engelmann Date: Mon, 3 Jul 2017 15:51:51 +0200 Subject: Add Setting to allow passing unknown URL schemes to QDesktopServices A new enum UnknownUrlSchemePolicy was added to WebEngineSettings, QWebEngineSettings and QQuickWebEngineSettings. WebContentsDelegate now has a new attribute of that type, which can be read and written through the public APIs Q(Quick)WebEngineSettings::unknownUrlSchemeNavigationPolicy and Q(Quick)WebEngineSettings::setUnknownUrlSchemeNavigationPolicy. This way, one can control, whether URLs with unknown schemes are passed to QDesktopServices. WebContentsAdapterClient::navigationRequested is called on these requests, so this allows more fine-grained control over the schemes and origins, that are allowed. Task-number: QTBUG-58627 Change-Id: Ie81d9503456d63ea1ed5606483254acf437cd8f7 Reviewed-by: Allan Sandfeld Jensen --- .../resource_dispatcher_host_delegate_qt.cpp | 10 ++-- src/core/web_contents_delegate_qt.cpp | 41 +++++++++++-- src/core/web_contents_delegate_qt.h | 2 +- src/core/web_engine_settings.cpp | 18 ++++++ src/core/web_engine_settings.h | 12 ++++ src/webengine/api/qquickwebenginesettings.cpp | 41 +++++++++++++ src/webengine/api/qquickwebenginesettings_p.h | 12 ++++ src/webengine/plugin/plugins.qmltypes | 22 ++++++- src/webenginewidgets/api/qwebenginesettings.cpp | 25 +++++++- src/webenginewidgets/api/qwebenginesettings.h | 10 ++++ .../doc/src/qwebenginesettings_lgpl.qdoc | 35 +++++++++++ .../tst_qwebenginefaviconmanager.cpp | 2 +- .../qwebenginesettings/tst_qwebenginesettings.cpp | 69 ++++++++++++++++++++++ 13 files changed, 282 insertions(+), 17 deletions(-) diff --git a/src/core/renderer_host/resource_dispatcher_host_delegate_qt.cpp b/src/core/renderer_host/resource_dispatcher_host_delegate_qt.cpp index afc2ea8fa..279a03d42 100644 --- a/src/core/renderer_host/resource_dispatcher_host_delegate_qt.cpp +++ b/src/core/renderer_host/resource_dispatcher_host_delegate_qt.cpp @@ -138,7 +138,7 @@ void ResourceDispatcherHostLoginDelegateQt::destroy() static void LaunchURL(const GURL& url, int render_process_id, const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter, - ui::PageTransition page_transition, bool is_main_frame) + ui::PageTransition page_transition, bool is_main_frame, bool has_user_gesture) { Q_UNUSED(render_process_id); Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); @@ -146,16 +146,13 @@ static void LaunchURL(const GURL& url, int render_process_id, if (!webContents) return; WebContentsDelegateQt *contentsDelegate = static_cast(webContents->GetDelegate()); - contentsDelegate->launchExternalURL(toQt(url), page_transition, is_main_frame); + contentsDelegate->launchExternalURL(toQt(url), page_transition, is_main_frame, has_user_gesture); } bool ResourceDispatcherHostDelegateQt::HandleExternalProtocol(const GURL& url, content::ResourceRequestInfo* info) { Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); - // We don't want to launch external applications unless it is based on a user action - if (!info->HasUserGesture()) - return false; content::BrowserThread::PostTask( content::BrowserThread::UI, @@ -164,7 +161,8 @@ bool ResourceDispatcherHostDelegateQt::HandleExternalProtocol(const GURL& url, c info->GetChildID(), info->GetWebContentsGetterForRequest(), info->GetPageTransition(), - info->IsMainFrame()) + info->IsMainFrame(), + info->HasUserGesture()) ); return true; } diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp index ad0e7ad6d..31180a1c1 100644 --- a/src/core/web_contents_delegate_qt.cpp +++ b/src/core/web_contents_delegate_qt.cpp @@ -499,14 +499,45 @@ void WebContentsDelegateQt::requestGeolocationPermission(const QUrl &requestingO extern WebContentsAdapterClient::NavigationType pageTransitionToNavigationType(ui::PageTransition transition); -void WebContentsDelegateQt::launchExternalURL(const QUrl &url, ui::PageTransition page_transition, bool is_main_frame) +void WebContentsDelegateQt::launchExternalURL(const QUrl &url, ui::PageTransition page_transition, bool is_main_frame, bool has_user_gesture) { - int navigationRequestAction = WebContentsAdapterClient::AcceptRequest; - m_viewClient->navigationRequested(pageTransitionToNavigationType(page_transition), url, navigationRequestAction, is_main_frame); + WebEngineSettings *settings = m_viewClient->webEngineSettings(); + bool navigationAllowedByPolicy = false; + bool navigationRequestAccepted = true; + + switch (settings->unknownUrlSchemePolicy()) { + case WebEngineSettings::DisallowUnknownUrlSchemes: + break; + case WebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction: + navigationAllowedByPolicy = has_user_gesture; + break; + case WebEngineSettings::AllowAllUnknownUrlSchemes: + navigationAllowedByPolicy = true; + break; + default: + Q_UNREACHABLE(); + } + + if (navigationAllowedByPolicy) { + int navigationRequestAction = WebContentsAdapterClient::AcceptRequest; + m_viewClient->navigationRequested(pageTransitionToNavigationType(page_transition), url, navigationRequestAction, is_main_frame); + navigationRequestAccepted = navigationRequestAction == WebContentsAdapterClient::AcceptRequest; #ifndef QT_NO_DESKTOPSERVICES - if (navigationRequestAction == WebContentsAdapterClient::AcceptRequest) - QDesktopServices::openUrl(url); + if (navigationRequestAccepted) + QDesktopServices::openUrl(url); #endif + } + + if (!navigationAllowedByPolicy || !navigationRequestAccepted) { + if (!navigationAllowedByPolicy) + didFailLoad(url, 420, QStringLiteral("Launching external protocol forbidden by WebEngineSettings::UnknownUrlSchemePolicy")); + else + didFailLoad(url, 420, QStringLiteral("Launching external protocol suppressed by WebContentsAdapterClient::navigationRequested")); + if (settings->testAttribute(WebEngineSettings::ErrorPageEnabled)) { + EmitLoadStarted(toQt(GURL(content::kUnreachableWebDataURL)), true); + m_viewClient->webContentsAdapter()->load(toQt(GURL(content::kUnreachableWebDataURL))); + } + } } void WebContentsDelegateQt::ShowValidationMessage(content::WebContents *web_contents, const gfx::Rect &anchor_in_root_view, const base::string16 &main_text, const base::string16 &sub_text) diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h index 2e37c498a..dab693780 100644 --- a/src/core/web_contents_delegate_qt.h +++ b/src/core/web_contents_delegate_qt.h @@ -142,7 +142,7 @@ public: void overrideWebPreferences(content::WebContents *, content::WebPreferences*); void allowCertificateError(const QSharedPointer &) ; void requestGeolocationPermission(const QUrl &requestingOrigin); - void launchExternalURL(const QUrl &url, ui::PageTransition page_transition, bool is_main_frame); + void launchExternalURL(const QUrl &url, ui::PageTransition page_transition, bool is_main_frame, bool has_user_gesture); FaviconManager *faviconManager(); void setSavePageInfo(const SavePageInfo &spi) { m_savePageInfo = spi; } diff --git a/src/core/web_engine_settings.cpp b/src/core/web_engine_settings.cpp index 4c944892a..7b9c1225d 100644 --- a/src/core/web_engine_settings.cpp +++ b/src/core/web_engine_settings.cpp @@ -110,6 +110,7 @@ WebEngineSettings::WebEngineSettings(WebEngineSettings *_parentSettings) : m_adapter(0) , m_batchTimer(new BatchTimer(this)) , parentSettings(_parentSettings) + , m_unknownUrlSchemePolicy(WebEngineSettings::InheritedUnknownUrlSchemePolicy) { if (parentSettings) parentSettings->childSettings.insert(this); @@ -212,6 +213,22 @@ QString WebEngineSettings::defaultTextEncoding() const return m_defaultEncoding.isEmpty()? parentSettings->defaultTextEncoding() : m_defaultEncoding; } +void WebEngineSettings::setUnknownUrlSchemePolicy(WebEngineSettings::UnknownUrlSchemePolicy policy) +{ + m_unknownUrlSchemePolicy = policy; +} + +WebEngineSettings::UnknownUrlSchemePolicy WebEngineSettings::unknownUrlSchemePolicy() const +{ + // value InheritedUnknownUrlSchemePolicy means it is taken from parent, if possible. If there + // is no parent, then AllowUnknownUrlSchemesFromUserInteraction (the default behavior) is used. + if (m_unknownUrlSchemePolicy != InheritedUnknownUrlSchemePolicy) + return m_unknownUrlSchemePolicy; + if (parentSettings) + return parentSettings->unknownUrlSchemePolicy(); + return AllowUnknownUrlSchemesFromUserInteraction; +} + void WebEngineSettings::initDefaults() { if (s_defaultAttributes.isEmpty()) { @@ -284,6 +301,7 @@ void WebEngineSettings::initDefaults() } m_defaultEncoding = QStringLiteral("ISO-8859-1"); + m_unknownUrlSchemePolicy = InheritedUnknownUrlSchemePolicy; } void WebEngineSettings::scheduleApply() diff --git a/src/core/web_engine_settings.h b/src/core/web_engine_settings.h index 639d314f3..d4c5e02a8 100644 --- a/src/core/web_engine_settings.h +++ b/src/core/web_engine_settings.h @@ -107,6 +107,14 @@ public: DefaultFixedFontSize }; + // Must match the values from the public API in qwebenginesettings.h. + enum UnknownUrlSchemePolicy { + InheritedUnknownUrlSchemePolicy = 0, + DisallowUnknownUrlSchemes = 1, + AllowUnknownUrlSchemesFromUserInteraction, + AllowAllUnknownUrlSchemes + }; + explicit WebEngineSettings(WebEngineSettings *parentSettings = 0); ~WebEngineSettings(); @@ -129,6 +137,9 @@ public: void setDefaultTextEncoding(const QString &encoding); QString defaultTextEncoding() const; + void setUnknownUrlSchemePolicy(UnknownUrlSchemePolicy policy); + UnknownUrlSchemePolicy unknownUrlSchemePolicy() const; + void initDefaults(); void scheduleApply(); @@ -155,6 +166,7 @@ private: static QHash s_defaultAttributes; static QHash s_defaultFontFamilies; static QHash s_defaultFontSizes; + UnknownUrlSchemePolicy m_unknownUrlSchemePolicy; friend class BatchTimer; friend class WebContentsAdapter; diff --git a/src/webengine/api/qquickwebenginesettings.cpp b/src/webengine/api/qquickwebenginesettings.cpp index 12d313783..44bd308ca 100644 --- a/src/webengine/api/qquickwebenginesettings.cpp +++ b/src/webengine/api/qquickwebenginesettings.cpp @@ -72,6 +72,22 @@ QQuickWebEngineSettings::QQuickWebEngineSettings(QQuickWebEngineSettings *parent QQuickWebEngineSettings::~QQuickWebEngineSettings() { } +/*! + \enum QQuickWebEngineSettings::UnknownUrlSchemePolicy + \since WebEngine 1.6 + + This enum describes how navigation requests to URLs with unknown schemes are handled. + + \value DisallowUnknownUrlSchemes + Disallows all navigation requests to URLs with unknown schemes. + \value AllowUnknownUrlSchemesFromUserInteraction + Allows navigation requests to URLs with unknown schemes that are issued from + user-interaction (like a mouse-click), whereas other navigation requests (for example + from JavaScript) are suppressed. + \value AllowAllUnknownUrlSchemes + Allows all navigation requests to URLs with unknown schemes. +*/ + /*! \qmlproperty bool WebEngineSettings::autoLoadImages @@ -395,6 +411,22 @@ QString QQuickWebEngineSettings::defaultTextEncoding() const return d_ptr->defaultTextEncoding(); } +ASSERT_ENUMS_MATCH(QQuickWebEngineSettings::DisallowUnknownUrlSchemes, WebEngineSettings::DisallowUnknownUrlSchemes) +ASSERT_ENUMS_MATCH(QQuickWebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction, WebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction) +ASSERT_ENUMS_MATCH(QQuickWebEngineSettings::AllowAllUnknownUrlSchemes, WebEngineSettings::AllowAllUnknownUrlSchemes) + +/*! + \qmlproperty WebEngineSettings::UnknownUrlSchemePolicy WebEngineSettings::unknownUrlSchemePolicy + \since QtWebEngine 1.6 + Specifies how navigation requests to URLs with unknown schemes are handled. + + Default is \l{QWebEngineSettings::UnknownUrlSchemePolicy}{WebEngineSettings.AllowUnknownUrlSchemesFromUserInteraction}. +*/ +QQuickWebEngineSettings::UnknownUrlSchemePolicy QQuickWebEngineSettings::unknownUrlSchemePolicy() const +{ + return static_cast(d_ptr->unknownUrlSchemePolicy()); +} + void QQuickWebEngineSettings::setAutoLoadImages(bool on) { bool wasOn = d_ptr->testAttribute(WebEngineSettings::AutoLoadImages); @@ -599,6 +631,15 @@ void QQuickWebEngineSettings::setHideScrollbars(bool on) Q_EMIT hideScrollbarsChanged(); } +void QQuickWebEngineSettings::setUnknownUrlSchemePolicy(QQuickWebEngineSettings::UnknownUrlSchemePolicy policy) +{ + WebEngineSettings::UnknownUrlSchemePolicy oldPolicy = d_ptr->unknownUrlSchemePolicy(); + WebEngineSettings::UnknownUrlSchemePolicy newPolicy = static_cast(policy); + d_ptr->setUnknownUrlSchemePolicy(newPolicy); + if (oldPolicy != newPolicy) + Q_EMIT unknownUrlSchemePolicyChanged(); +} + void QQuickWebEngineSettings::setParentSettings(QQuickWebEngineSettings *parentSettings) { d_ptr->setParentSettings(parentSettings->d_ptr.data()); diff --git a/src/webengine/api/qquickwebenginesettings_p.h b/src/webengine/api/qquickwebenginesettings_p.h index da838f52f..234763ecf 100644 --- a/src/webengine/api/qquickwebenginesettings_p.h +++ b/src/webengine/api/qquickwebenginesettings_p.h @@ -88,8 +88,17 @@ class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineSettings : public QObject { Q_PROPERTY(bool allowGeolocationOnInsecureOrigins READ allowGeolocationOnInsecureOrigins WRITE setAllowGeolocationOnInsecureOrigins NOTIFY allowGeolocationOnInsecureOriginsChanged REVISION 4 FINAL) Q_PROPERTY(bool allowWindowActivationFromJavaScript READ allowWindowActivationFromJavaScript WRITE setAllowWindowActivationFromJavaScript NOTIFY allowWindowActivationFromJavaScriptChanged REVISION 5 FINAL) Q_PROPERTY(bool hideScrollbars READ hideScrollbars WRITE setHideScrollbars NOTIFY hideScrollbarsChanged REVISION 5 FINAL) + Q_PROPERTY(UnknownUrlSchemePolicy unknownUrlSchemePolicy READ unknownUrlSchemePolicy WRITE setUnknownUrlSchemePolicy NOTIFY unknownUrlSchemePolicyChanged REVISION 5 FINAL) public: + enum UnknownUrlSchemePolicy { + DisallowUnknownUrlSchemes = 1, + AllowUnknownUrlSchemesFromUserInteraction, + AllowAllUnknownUrlSchemes + }; + + Q_ENUM(UnknownUrlSchemePolicy) + ~QQuickWebEngineSettings(); bool autoLoadImages() const; @@ -117,6 +126,7 @@ public: bool allowGeolocationOnInsecureOrigins() const; bool allowWindowActivationFromJavaScript() const; bool hideScrollbars() const; + UnknownUrlSchemePolicy unknownUrlSchemePolicy() const; void setAutoLoadImages(bool on); void setJavascriptEnabled(bool on); @@ -143,6 +153,7 @@ public: void setAllowGeolocationOnInsecureOrigins(bool on); void setAllowWindowActivationFromJavaScript(bool on); void setHideScrollbars(bool on); + void setUnknownUrlSchemePolicy(UnknownUrlSchemePolicy policy); signals: void autoLoadImagesChanged(); @@ -170,6 +181,7 @@ signals: Q_REVISION(4) void allowGeolocationOnInsecureOriginsChanged(); Q_REVISION(5) void allowWindowActivationFromJavaScriptChanged(); Q_REVISION(5) void hideScrollbarsChanged(); + Q_REVISION(5) void unknownUrlSchemePolicyChanged(); private: explicit QQuickWebEngineSettings(QQuickWebEngineSettings *parentSettings = 0); diff --git a/src/webengine/plugin/plugins.qmltypes b/src/webengine/plugin/plugins.qmltypes index 321c462b5..e8ec1fa7a 100644 --- a/src/webengine/plugin/plugins.qmltypes +++ b/src/webengine/plugin/plugins.qmltypes @@ -119,10 +119,11 @@ Module { "QtWebEngine/WebEngineDownloadItem 1.2", "QtWebEngine/WebEngineDownloadItem 1.3", "QtWebEngine/WebEngineDownloadItem 1.4", - "QtWebEngine/WebEngineDownloadItem 1.5" + "QtWebEngine/WebEngineDownloadItem 1.5", + "QtWebEngine/WebEngineDownloadItem 1.6" ] isCreatable: false - exportMetaObjectRevisions: [0, 1, 2, 3, 4] + exportMetaObjectRevisions: [0, 1, 2, 3, 4, 5] Enum { name: "DownloadState" values: { @@ -195,12 +196,18 @@ Module { isReadonly: true } Property { name: "interruptReasonString"; revision: 4; type: "string"; isReadonly: true } + Property { name: "isFinished"; revision: 5; type: "bool"; isReadonly: true } + Property { name: "isPaused"; revision: 5; type: "bool"; isReadonly: true } Signal { name: "savePageFormatChanged"; revision: 2 } Signal { name: "mimeTypeChanged"; revision: 1 } Signal { name: "typeChanged"; revision: 3 } Signal { name: "interruptReasonChanged"; revision: 4 } + Signal { name: "isFinishedChanged"; revision: 5 } + Signal { name: "isPausedChanged"; revision: 5 } Method { name: "accept" } Method { name: "cancel" } + Method { name: "pause" } + Method { name: "resume" } } Component { name: "QQuickWebEngineFileDialogRequest" @@ -514,6 +521,14 @@ Module { ] isCreatable: false exportMetaObjectRevisions: [0, 1, 2, 3, 4, 5] + Enum { + name: "UnknownUrlSchemePolicy" + values: { + "DisallowUnknownUrlSchemes": 1, + "AllowUnknownUrlSchemesFromUserInteraction": 2, + "AllowAllUnknownUrlSchemes": 3 + } + } Property { name: "autoLoadImages"; type: "bool" } Property { name: "javascriptEnabled"; type: "bool" } Property { name: "javascriptCanOpenWindows"; type: "bool" } @@ -538,6 +553,7 @@ Module { Property { name: "allowRunningInsecureContent"; revision: 3; type: "bool" } Property { name: "allowGeolocationOnInsecureOrigins"; revision: 4; type: "bool" } Property { name: "allowWindowActivationFromJavaScript"; revision: 5; type: "bool" } + Property { name: "unknownUrlSchemePolicy"; revision: 5; type: "UnknownUrlSchemePolicy" } Signal { name: "fullScreenSupportEnabledChanged"; revision: 1 } Signal { name: "screenCaptureEnabledChanged"; revision: 2 } Signal { name: "webGLEnabledChanged"; revision: 2 } @@ -549,6 +565,7 @@ Module { Signal { name: "allowRunningInsecureContentChanged"; revision: 3 } Signal { name: "allowGeolocationOnInsecureOriginsChanged"; revision: 4 } Signal { name: "allowWindowActivationFromJavaScriptChanged"; revision: 5 } + Signal { name: "unknownUrlSchemePolicyChanged"; revision: 5 } } Component { name: "QQuickWebEngineSingleton" @@ -892,7 +909,6 @@ Module { Property { name: "audioMuted"; revision: 3; type: "bool" } Property { name: "recentlyAudible"; revision: 3; type: "bool"; isReadonly: true } Property { name: "webChannelWorld"; revision: 3; type: "uint" } - Property { name: "testSupport"; type: "QQuickWebEngineTestSupport"; isPointer: true } Signal { name: "loadingChanged" Parameter { name: "loadRequest"; type: "QQuickWebEngineLoadRequest"; isPointer: true } diff --git a/src/webenginewidgets/api/qwebenginesettings.cpp b/src/webenginewidgets/api/qwebenginesettings.cpp index 439e00590..7696dc960 100644 --- a/src/webenginewidgets/api/qwebenginesettings.cpp +++ b/src/webenginewidgets/api/qwebenginesettings.cpp @@ -182,7 +182,6 @@ void QWebEngineSettings::resetFontSize(QWebEngineSettings::FontSize type) d->resetFontSize(static_cast(type)); } - void QWebEngineSettings::setDefaultTextEncoding(const QString &encoding) { Q_D(QWebEngineSettings); @@ -195,6 +194,30 @@ QString QWebEngineSettings::defaultTextEncoding() const return d->defaultTextEncoding(); } +ASSERT_ENUMS_MATCH(WebEngineSettings::DisallowUnknownUrlSchemes, QWebEngineSettings::DisallowUnknownUrlSchemes) +ASSERT_ENUMS_MATCH(WebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction, QWebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction) +ASSERT_ENUMS_MATCH(WebEngineSettings::AllowAllUnknownUrlSchemes, QWebEngineSettings::AllowAllUnknownUrlSchemes) + +QWebEngineSettings::UnknownUrlSchemePolicy QWebEngineSettings::unknownUrlSchemePolicy() const +{ + Q_D(const QWebEngineSettings); + WebEngineSettings::UnknownUrlSchemePolicy result = d->unknownUrlSchemePolicy(); + Q_ASSERT(result != WebEngineSettings::InheritedUnknownUrlSchemePolicy); + return static_cast(result); +} + +void QWebEngineSettings::setUnknownUrlSchemePolicy(QWebEngineSettings::UnknownUrlSchemePolicy policy) +{ + Q_D(QWebEngineSettings); + d->setUnknownUrlSchemePolicy(static_cast(policy)); +} + +void QWebEngineSettings::resetUnknownUrlSchemePolicy() +{ + Q_D(QWebEngineSettings); + d->setUnknownUrlSchemePolicy(WebEngineSettings::InheritedUnknownUrlSchemePolicy); +} + void QWebEngineSettings::setAttribute(QWebEngineSettings::WebAttribute attr, bool on) { Q_D(QWebEngineSettings); diff --git a/src/webenginewidgets/api/qwebenginesettings.h b/src/webenginewidgets/api/qwebenginesettings.h index 1857e5228..dce86eedb 100644 --- a/src/webenginewidgets/api/qwebenginesettings.h +++ b/src/webenginewidgets/api/qwebenginesettings.h @@ -101,6 +101,12 @@ public: DefaultFixedFontSize }; + enum UnknownUrlSchemePolicy { + DisallowUnknownUrlSchemes = 1, + AllowUnknownUrlSchemesFromUserInteraction, + AllowAllUnknownUrlSchemes + }; + #if QT_DEPRECATED_SINCE(5, 5) static QWebEngineSettings *globalSettings(); #endif @@ -121,6 +127,10 @@ public: void setDefaultTextEncoding(const QString &encoding); QString defaultTextEncoding() const; + UnknownUrlSchemePolicy unknownUrlSchemePolicy() const; + void setUnknownUrlSchemePolicy(UnknownUrlSchemePolicy policy); + void resetUnknownUrlSchemePolicy(); + private: Q_DISABLE_COPY(QWebEngineSettings) typedef ::QtWebEngineCore::WebEngineSettings QWebEngineSettingsPrivate; diff --git a/src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc index e6a94281e..06ed10b30 100644 --- a/src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc +++ b/src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc @@ -168,7 +168,22 @@ \value HideScrollbars Hides scrollbars. Disabled by default. (Added in Qt 5.10) +*/ +/*! + \enum QWebEngineSettings::UnknownUrlSchemePolicy + \since Qt 5.10 + + This enum describes how navigation requests to URLs with unknown schemes are handled. + + \value DisallowUnknownUrlSchemes + Disallows all navigation requests to URLs with unknown schemes. + \value AllowUnknownUrlSchemesFromUserInteraction + Allows navigation requests to URLs with unknown schemes that are issued from + user-interaction (like a mouse-click), whereas other navigation requests (for example + from JavaScript) are suppressed. + \value AllowAllUnknownUrlSchemes + Allows all navigation requests to URLs with unknown schemes. */ /*! @@ -223,6 +238,26 @@ in the profile that the page belongs to. */ +/*! + \fn QWebEngineSettings::UnknownUrlSchemePolicy QWebEngineSettings::unknownUrlSchemePolicy() const + Returns the currently selected policy for handling navigation requests to URLs with + unknown schemes. Default is \l{QWebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction}. + \sa setUnknownUrlSchemePolicy resetUnknownUrlSchemePolicy +*/ + +/*! + \fn void QWebEngineSettings::setUnknownUrlSchemePolicy(QWebEngineSettings::UnknownUrlSchemePolicy policy) + Sets the policy for handling navigation requests to URLs with unknown schemes to \a policy. + Default is \l{QWebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction}. + \sa unknownUrlSchemePolicy resetUnknownUrlSchemePolicy +*/ + +/*! + \fn void QWebEngineSettings::resetUnknownUrlSchemePolicy() + Removes the policy for handling navigation requests to URLs with unknown schemes. + \sa unknownUrlSchemePolicy setUnknownUrlSchemePolicy +*/ + /*! \fn void QWebEngineSettings::setAttribute(WebAttribute attribute, bool on) diff --git a/tests/auto/widgets/qwebenginefaviconmanager/tst_qwebenginefaviconmanager.cpp b/tests/auto/widgets/qwebenginefaviconmanager/tst_qwebenginefaviconmanager.cpp index 38311cad2..710561cce 100644 --- a/tests/auto/widgets/qwebenginefaviconmanager/tst_qwebenginefaviconmanager.cpp +++ b/tests/auto/widgets/qwebenginefaviconmanager/tst_qwebenginefaviconmanager.cpp @@ -238,7 +238,7 @@ void tst_QWebEngineFaviconManager::errorPageEnabled() QUrl url("invalid://url"); m_page->load(url); - QTRY_COMPARE(loadFinishedSpy.count(), 1); + QTRY_COMPARE(loadFinishedSpy.count(), 2); QCOMPARE(iconUrlChangedSpy.count(), 0); QCOMPARE(iconChangedSpy.count(), 0); diff --git a/tests/auto/widgets/qwebenginesettings/tst_qwebenginesettings.cpp b/tests/auto/widgets/qwebenginesettings/tst_qwebenginesettings.cpp index 5cbcf4ec0..09e1b73c9 100644 --- a/tests/auto/widgets/qwebenginesettings/tst_qwebenginesettings.cpp +++ b/tests/auto/widgets/qwebenginesettings/tst_qwebenginesettings.cpp @@ -19,6 +19,8 @@ #include +#include +#include #include #include @@ -29,6 +31,7 @@ private Q_SLOTS: void resetAttributes(); void defaultFontFamily_data(); void defaultFontFamily(); + void unknownUrlSchemePolicy(); }; void tst_QWebEngineSettings::resetAttributes() @@ -85,6 +88,72 @@ void tst_QWebEngineSettings::defaultFontFamily() QVERIFY(!settings->fontFamily(static_cast(fontFamily)).isEmpty()); } + +class AcceptNavigationRequestHandler : public QWebEnginePage +{ +public: + AcceptNavigationRequestHandler(QObject* parent = nullptr) + : QWebEnginePage(parent) + { + } + int acceptNavigationRequestCalls = 0; + bool acceptNavigationRequest(const QUrl &/*url*/, NavigationType /*type*/, bool /*isMainFrame*/) override + { + this->acceptNavigationRequestCalls++; + return false; + } +}; + +void tst_QWebEngineSettings::unknownUrlSchemePolicy() +{ + QWebEngineView view; + AcceptNavigationRequestHandler page; + view.setPage(&page); + view.resize(400, 40); + view.show(); + QTest::qWaitForWindowExposed(&view); + QWebEngineSettings *settings = view.page()->profile()->settings(); + settings->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true); + QSignalSpy loadFinishedSpy(&view, &QWebEngineView::loadFinished); + + 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("testing..."); + } else { // navigation request coming from user interaction + shouldAccept = (2 <= i); // all cases except DisallowUnknownUrlSchemes + view.setHtml("nonexistentscheme://somewhere"); + QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 30000); + // 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); + }); + } + + bool errorPageEnabled = settings->testAttribute(QWebEngineSettings::ErrorPageEnabled); + QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 2 + (errorPageEnabled ? 1 : 0), 30000); + QCOMPARE(page.acceptNavigationRequestCalls, shouldAccept ? 1 : 0); + } +} + QTEST_MAIN(tst_QWebEngineSettings) #include "tst_qwebenginesettings.moc" -- cgit v1.2.3