From 8d0bd4b1a18ff886f360e71942f95858b5995ba3 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 24 May 2022 16:56:41 +0200 Subject: Fix local->remote user navigation Specifically allow user initiated navigation of the mainframe. Fixes: QTBUG-103778 Change-Id: I4e3d6b4fb606bd0c3cf66e090fba3c97c8c535b4 Reviewed-by: Michal Klocek (cherry picked from commit 2ba1f04b4589e5883a399b022b7795266c4d4646) Reviewed-by: Qt Cherry-pick Bot --- src/core/net/proxying_url_loader_factory_qt.cpp | 19 ++++++- .../widgets/qwebenginepage/tst_qwebenginepage.cpp | 65 ++++++++++++++++++++++ 2 files changed, 81 insertions(+), 3 deletions(-) diff --git a/src/core/net/proxying_url_loader_factory_qt.cpp b/src/core/net/proxying_url_loader_factory_qt.cpp index 39630cf2d..ba2051d60 100644 --- a/src/core/net/proxying_url_loader_factory_qt.cpp +++ b/src/core/net/proxying_url_loader_factory_qt.cpp @@ -280,10 +280,23 @@ void InterceptedRequest::Restart() // Check if non-local access is allowed if (!allow_remote_ && remote_access_) { - target_client_->OnComplete(network::URLLoaderCompletionStatus(net::ERR_NETWORK_ACCESS_DENIED)); - delete this; - return; + bool granted_special_access = false; + switch (ui::PageTransition(request_.transition_type)) { + case ui::PAGE_TRANSITION_LINK: + case ui::PAGE_TRANSITION_TYPED: + if (blink::mojom::ResourceType(request_.resource_type) == blink::mojom::ResourceType::kMainFrame && request_.has_user_gesture) + granted_special_access = true; // allow normal explicit navigation + break; + default: + break; + } + if (!granted_special_access) { + target_client_->OnComplete(network::URLLoaderCompletionStatus(net::ERR_NETWORK_ACCESS_DENIED)); + delete this; + return; + } } + // Check if local access is allowed if (!allow_local_ && local_access_) { bool granted_special_access = false; diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp index 227f33c17..32f866810 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp @@ -257,6 +257,8 @@ private Q_SLOTS: void testChooseFilesParameters(); void fileSystemAccessDialog(); + void localToRemoteNavigation(); + private: static QPoint elementCenter(QWebEnginePage *page, const QString &id); static bool isFalseJavaScriptResult(QWebEnginePage *page, const QString &javaScript); @@ -328,6 +330,14 @@ void tst_QWebEnginePage::initTestCase() QWebEngineUrlScheme echo("echo"); echo.setSyntax(QWebEngineUrlScheme::Syntax::Path); QWebEngineUrlScheme::registerScheme(echo); + + QWebEngineUrlScheme local("local"); + local.setFlags(QWebEngineUrlScheme::LocalScheme); + QWebEngineUrlScheme::registerScheme(local); + + QWebEngineUrlScheme remote("remote"); + remote.setFlags(QWebEngineUrlScheme::CorsEnabled); + QWebEngineUrlScheme::registerScheme(remote); } void tst_QWebEnginePage::cleanupTestCase() @@ -5010,6 +5020,61 @@ void tst_QWebEnginePage::isSafeRedirect() spy.clear(); } +class LocalRemoteUrlSchemeHandler : public QWebEngineUrlSchemeHandler +{ +public: + LocalRemoteUrlSchemeHandler(QObject *parent = nullptr) + : QWebEngineUrlSchemeHandler(parent) + { + } + ~LocalRemoteUrlSchemeHandler() = default; + + void requestStarted(QWebEngineUrlRequestJob *job) override + { + QBuffer *buffer = new QBuffer(job); + buffer->setData("Click link"); + job->reply("text/html", buffer); + loaded = true; + } + bool loaded = false; +}; + +void tst_QWebEnginePage::localToRemoteNavigation() +{ + LocalRemoteUrlSchemeHandler local; + LocalRemoteUrlSchemeHandler remote; + QWebEngineProfile profile; + profile.installUrlSchemeHandler("local", &local); + profile.installUrlSchemeHandler("remote", &remote); + + QWebEnginePage page(&profile); + QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool))); + QWebEngineView view; + view.resize(640, 480); + view.show(); + view.setPage(&page); + page.setUrl(QUrl("local://test.html")); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + QTRY_COMPARE_WITH_TIMEOUT(loadSpy.count(), 1, 20000); + QVERIFY(local.loaded); + + // Should navigate: + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, elementCenter(&page, "link")); + QTRY_COMPARE_WITH_TIMEOUT(loadSpy.count(), 2, 20000); + QVERIFY(remote.loaded); + local.loaded = false; + remote.loaded = false; + + page.setUrl(QUrl("local://test.html")); + QTRY_COMPARE_WITH_TIMEOUT(loadSpy.count(), 3, 20000); + QVERIFY(local.loaded && !remote.loaded); + + // Should not navigate: + page.runJavaScript(QStringLiteral("document.getElementById(\"link\").click()")); + QTest::qWait(500); + QVERIFY(!remote.loaded); +} + static QByteArrayList params = {QByteArrayLiteral("--use-fake-device-for-media-stream")}; W_QTEST_MAIN(tst_QWebEnginePage, params) -- cgit v1.2.3