From efee223d7ff6e0e30fb9d9dff1536936922d4a03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCri=20Valdmann?= Date: Mon, 29 Apr 2019 15:51:58 +0200 Subject: Q(Quick)WebEngineProfile: Update list of internal schemes Disallow installing handler for "about" and everything in kStandardURLSchemes of url/url_util.cc. Except for "gopher" which is used in tests. Suppress warning about custom schemes for "gopher" since it's not a custom scheme. Also lowercase the scheme in urlSchemeHandler() and removeUrlSchemeHandler(). Change-Id: I72b06d4fa6433882019405a0d600a593c8971bf1 Reviewed-by: Allan Sandfeld Jensen --- src/core/profile_adapter.cpp | 41 ++++++++++++++++++++-- src/core/profile_adapter.h | 2 +- src/webengine/api/qquickwebengineprofile.cpp | 32 ++--------------- src/webenginewidgets/api/qwebengineprofile.cpp | 32 ++--------------- .../qwebengineprofile/tst_qwebengineprofile.cpp | 41 ++++++++++++++++++++++ 5 files changed, 84 insertions(+), 64 deletions(-) diff --git a/src/core/profile_adapter.cpp b/src/core/profile_adapter.cpp index 1b946949a..b04fa0d46 100644 --- a/src/core/profile_adapter.cpp +++ b/src/core/profile_adapter.cpp @@ -44,6 +44,7 @@ #include "content/public/browser/browsing_data_remover.h" #include "content/public/browser/download_manager.h" +#include "api/qwebengineurlscheme.h" #include "content_client_qt.h" #include "download_manager_delegate_qt.h" #include "net/url_request_context_getter_qt.h" @@ -440,16 +441,50 @@ bool ProfileAdapter::removeCustomUrlSchemeHandler(QWebEngineUrlSchemeHandler *ha QWebEngineUrlSchemeHandler *ProfileAdapter::takeCustomUrlSchemeHandler(const QByteArray &scheme) { - QWebEngineUrlSchemeHandler *handler = m_customUrlSchemeHandlers.take(scheme); + QWebEngineUrlSchemeHandler *handler = m_customUrlSchemeHandlers.take(scheme.toLower()); if (handler) updateCustomUrlSchemeHandlers(); return handler; } -void ProfileAdapter::addCustomUrlSchemeHandler(const QByteArray &scheme, QWebEngineUrlSchemeHandler *handler) +bool ProfileAdapter::addCustomUrlSchemeHandler(const QByteArray &scheme, QWebEngineUrlSchemeHandler *handler) { - m_customUrlSchemeHandlers.insert(scheme, handler); + static const QSet blacklist{ + QByteArrayLiteral("about"), + QByteArrayLiteral("blob"), + QByteArrayLiteral("data"), + QByteArrayLiteral("javascript"), + QByteArrayLiteral("qrc"), + // See also kStandardURLSchemes in url/url_util.cc (through url::IsStandard below) + }; + + static const QSet whitelist{ + QByteArrayLiteral("gopher"), + }; + + const QByteArray canonicalScheme = scheme.toLower(); + bool standardSyntax = url::IsStandard(canonicalScheme.data(), url::Component(0, canonicalScheme.size())); + bool customScheme = QWebEngineUrlScheme::schemeByName(canonicalScheme) != QWebEngineUrlScheme(); + bool blacklisted = blacklist.contains(canonicalScheme) || (standardSyntax && !customScheme); + bool whitelisted = whitelist.contains(canonicalScheme); + + if (blacklisted && !whitelisted) { + qWarning("Cannot install a URL scheme handler overriding internal scheme: %s", scheme.constData()); + return false; + } + + if (m_customUrlSchemeHandlers.value(canonicalScheme, handler) != handler) { + qWarning("URL scheme handler already installed for the scheme: %s", scheme.constData()); + return false; + } + + if (!whitelisted && !customScheme) + qWarning("Please register the custom scheme '%s' via QWebEngineUrlScheme::registerScheme() " + "before installing the custom scheme handler.", scheme.constData()); + + m_customUrlSchemeHandlers.insert(canonicalScheme, handler); updateCustomUrlSchemeHandlers(); + return true; } void ProfileAdapter::clearCustomUrlSchemeHandlers() diff --git a/src/core/profile_adapter.h b/src/core/profile_adapter.h index 7ed5c13f5..e92fb524b 100644 --- a/src/core/profile_adapter.h +++ b/src/core/profile_adapter.h @@ -179,7 +179,7 @@ public: const QHash &customUrlSchemeHandlers() const; const QList customUrlSchemes() const; void clearCustomUrlSchemeHandlers(); - void addCustomUrlSchemeHandler(const QByteArray &, QWebEngineUrlSchemeHandler *); + bool addCustomUrlSchemeHandler(const QByteArray &, QWebEngineUrlSchemeHandler *); bool removeCustomUrlSchemeHandler(QWebEngineUrlSchemeHandler *); QWebEngineUrlSchemeHandler *takeCustomUrlSchemeHandler(const QByteArray &); UserResourceControllerHost *userResourceController(); diff --git a/src/webengine/api/qquickwebengineprofile.cpp b/src/webengine/api/qquickwebengineprofile.cpp index 73577a04c..f77f376aa 100644 --- a/src/webengine/api/qquickwebengineprofile.cpp +++ b/src/webengine/api/qquickwebengineprofile.cpp @@ -847,20 +847,7 @@ void QQuickWebEngineProfile::setRequestInterceptor(QWebEngineUrlRequestIntercept const QWebEngineUrlSchemeHandler *QQuickWebEngineProfile::urlSchemeHandler(const QByteArray &scheme) const { const Q_D(QQuickWebEngineProfile); - if (d->profileAdapter()->customUrlSchemeHandlers().contains(scheme)) - return d->profileAdapter()->customUrlSchemeHandlers().value(scheme); - return 0; -} - -static bool checkInternalScheme(const QByteArray &scheme) -{ - static QSet internalSchemes; - if (internalSchemes.isEmpty()) { - internalSchemes << QByteArrayLiteral("qrc") << QByteArrayLiteral("data") << QByteArrayLiteral("blob") - << QByteArrayLiteral("http") << QByteArrayLiteral("https") << QByteArrayLiteral("ftp") - << QByteArrayLiteral("javascript"); - } - return internalSchemes.contains(scheme); + return d->profileAdapter()->customUrlSchemeHandlers().value(scheme.toLower()); } /*! @@ -873,23 +860,8 @@ void QQuickWebEngineProfile::installUrlSchemeHandler(const QByteArray &scheme, Q { Q_D(QQuickWebEngineProfile); Q_ASSERT(handler); - QByteArray canonicalScheme = scheme.toLower(); - if (checkInternalScheme(canonicalScheme)) { - qWarning("Cannot install a URL scheme handler overriding internal scheme: %s", scheme.constData()); - return; - } - - if (d->profileAdapter()->customUrlSchemeHandlers().contains(canonicalScheme)) { - if (d->profileAdapter()->customUrlSchemeHandlers().value(canonicalScheme) != handler) - qWarning("URL scheme handler already installed for the scheme: %s", scheme.constData()); + if (!d->profileAdapter()->addCustomUrlSchemeHandler(scheme, handler)) return; - } - - if (QWebEngineUrlScheme::schemeByName(canonicalScheme) == QWebEngineUrlScheme()) - qWarning("Please register the custom scheme '%s' via QWebEngineUrlScheme::registerScheme() " - "before installing the custom scheme handler.", scheme.constData()); - - d->profileAdapter()->addCustomUrlSchemeHandler(canonicalScheme, handler); connect(handler, SIGNAL(_q_destroyedUrlSchemeHandler(QWebEngineUrlSchemeHandler*)), this, SLOT(destroyedUrlSchemeHandler(QWebEngineUrlSchemeHandler*))); } diff --git a/src/webenginewidgets/api/qwebengineprofile.cpp b/src/webenginewidgets/api/qwebengineprofile.cpp index 929c2aaa1..c8aafa0e8 100644 --- a/src/webenginewidgets/api/qwebengineprofile.cpp +++ b/src/webenginewidgets/api/qwebengineprofile.cpp @@ -688,20 +688,7 @@ QWebEngineSettings *QWebEngineProfile::settings() const const QWebEngineUrlSchemeHandler *QWebEngineProfile::urlSchemeHandler(const QByteArray &scheme) const { const Q_D(QWebEngineProfile); - if (d->profileAdapter()->customUrlSchemeHandlers().contains(scheme)) - return d->profileAdapter()->customUrlSchemeHandlers().value(scheme); - return 0; -} - -static bool checkInternalScheme(const QByteArray &scheme) -{ - static QSet internalSchemes; - if (internalSchemes.isEmpty()) { - internalSchemes << QByteArrayLiteral("qrc") << QByteArrayLiteral("data") << QByteArrayLiteral("blob") - << QByteArrayLiteral("http") << QByteArrayLiteral("https") << QByteArrayLiteral("ftp") - << QByteArrayLiteral("javascript"); - } - return internalSchemes.contains(scheme); + return d->profileAdapter()->customUrlSchemeHandlers().value(scheme.toLower()); } /*! @@ -716,23 +703,8 @@ void QWebEngineProfile::installUrlSchemeHandler(const QByteArray &scheme, QWebEn { Q_D(QWebEngineProfile); Q_ASSERT(handler); - QByteArray canonicalScheme = scheme.toLower(); - if (checkInternalScheme(canonicalScheme)) { - qWarning("Cannot install a URL scheme handler overriding internal scheme: %s", scheme.constData()); - return; - } - - if (d->profileAdapter()->customUrlSchemeHandlers().contains(canonicalScheme)) { - if (d->profileAdapter()->customUrlSchemeHandlers().value(canonicalScheme) != handler) - qWarning("URL scheme handler already installed for the scheme: %s", scheme.constData()); + if (!d->profileAdapter()->addCustomUrlSchemeHandler(scheme, handler)) return; - } - - if (QWebEngineUrlScheme::schemeByName(canonicalScheme) == QWebEngineUrlScheme()) - qWarning("Please register the custom scheme '%s' via QWebEngineUrlScheme::registerScheme() " - "before installing the custom scheme handler.", scheme.constData()); - - d->profileAdapter()->addCustomUrlSchemeHandler(canonicalScheme, handler); connect(handler, SIGNAL(_q_destroyedUrlSchemeHandler(QWebEngineUrlSchemeHandler*)), this, SLOT(destroyedUrlSchemeHandler(QWebEngineUrlSchemeHandler*))); } diff --git a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp index 2a4e2d533..3fc8fb45a 100644 --- a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp +++ b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp @@ -55,6 +55,7 @@ private Q_SLOTS: void urlSchemeHandlerFailRequest(); void urlSchemeHandlerFailOnRead(); void urlSchemeHandlerStreaming(); + void urlSchemeHandlerInstallation(); void customUserAgent(); void httpAcceptLanguage(); void downloadItem(); @@ -466,6 +467,46 @@ void tst_QWebEngineProfile::urlSchemeHandlerStreaming() QCOMPARE(toPlainTextSync(view.page()), QString::fromLatin1(result)); } +void tst_QWebEngineProfile::urlSchemeHandlerInstallation() +{ + FailingUrlSchemeHandler handler; + QWebEngineProfile profile; + + // Builtin schemes that *cannot* be overridden. + for (auto scheme : { "about", "blob", "data", "javascript", "qrc", "https", "http", "file", + "ftp", "wss", "ws", "filesystem", "FileSystem" }) { + QTest::ignoreMessage( + QtWarningMsg, + QRegularExpression("Cannot install a URL scheme handler overriding internal scheme.*")); + profile.installUrlSchemeHandler(scheme, &handler); + QCOMPARE(profile.urlSchemeHandler(scheme), nullptr); + } + + // Builtin schemes that *can* be overridden. + for (auto scheme : { "gopher", "GOPHER" }) { + profile.installUrlSchemeHandler(scheme, &handler); + QCOMPARE(profile.urlSchemeHandler(scheme), &handler); + profile.removeUrlScheme(scheme); + } + + // Other schemes should be registered with QWebEngineUrlScheme first, but + // handler installation still succeeds to preserve backwards compatibility. + QTest::ignoreMessage( + QtWarningMsg, + QRegularExpression("Please register the custom scheme.*")); + profile.installUrlSchemeHandler("tst", &handler); + QCOMPARE(profile.urlSchemeHandler("tst"), &handler); + + // Existing handler cannot be overridden. + FailingUrlSchemeHandler handler2; + QTest::ignoreMessage( + QtWarningMsg, + QRegularExpression("URL scheme handler already installed.*")); + profile.installUrlSchemeHandler("tst", &handler2); + QCOMPARE(profile.urlSchemeHandler("tst"), &handler); + profile.removeUrlScheme("tst"); +} + void tst_QWebEngineProfile::customUserAgent() { QString defaultUserAgent = QWebEngineProfile::defaultProfile()->httpUserAgent(); -- cgit v1.2.3