From 551b83b280bf83137e0c8ceefad59558bfe9e03e Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Mon, 14 Jun 2021 16:11:54 +0200 Subject: Stop using Widgets in WebEngineCore tests With QWebEnginePage in Core we can now make the core tests core-only. Add the same times moves tests from widgets that only uses core classes. Change-Id: I67a25b534912d9a0891e16b0419f0db9bf434e92 Reviewed-by: Peter Varga (cherry picked from commit b8c48ee53009365a39d9dde1f6773048ec5ee4a0) Reviewed-by: Qt Cherry-pick Bot --- tests/auto/core/CMakeLists.txt | 6 + tests/auto/core/certificateerror/CMakeLists.txt | 23 + .../core/certificateerror/certificateerror.pro | 3 + .../core/certificateerror/resources/server.key | 27 + .../core/certificateerror/resources/server.pem | 41 + .../core/certificateerror/tst_certificateerror.cpp | 136 +++ tests/auto/core/core.pro | 7 +- tests/auto/core/devtools/CMakeLists.txt | 7 + tests/auto/core/devtools/devtools.pro | 1 + tests/auto/core/devtools/tst_devtools.cpp | 87 ++ tests/auto/core/origins/CMakeLists.txt | 45 + tests/auto/core/origins/origins.pro | 8 + .../core/origins/resources/createObjectURL.html | 11 + .../core/origins/resources/dedicatedWorker.html | 19 + .../auto/core/origins/resources/dedicatedWorker.js | 1 + .../auto/core/origins/resources/mixedSchemes.html | 31 + .../origins/resources/mixedSchemesWithCsp.html | 32 + .../core/origins/resources/mixedSchemes_frame.html | 11 + tests/auto/core/origins/resources/mixedXHR.html | 19 + tests/auto/core/origins/resources/mixedXHR.txt | 1 + tests/auto/core/origins/resources/redirect.css | 8 + tests/auto/core/origins/resources/redirect.html | 10 + .../auto/core/origins/resources/serviceWorker.html | 18 + tests/auto/core/origins/resources/serviceWorker.js | 1 + .../auto/core/origins/resources/sharedWorker.html | 19 + tests/auto/core/origins/resources/sharedWorker.js | 6 + .../auto/core/origins/resources/subdir/frame2.html | 10 + .../auto/core/origins/resources/subdir/index.html | 26 + .../auto/core/origins/resources/subdir_frame1.html | 10 + tests/auto/core/origins/resources/viewSource.html | 9 + tests/auto/core/origins/resources/websocket.html | 23 + tests/auto/core/origins/tst_origins.cpp | 958 +++++++++++++++++++++ tests/auto/core/origins/tst_origins.qrc | 22 + .../auto/core/qwebenginecookiestore/CMakeLists.txt | 2 +- tests/auto/core/qwebenginesettings/BLACKLIST | 2 + tests/auto/core/qwebenginesettings/CMakeLists.txt | 9 + .../core/qwebenginesettings/qwebenginesettings.pro | 2 + .../qwebenginesettings/tst_qwebenginesettings.cpp | 198 +++++ .../qwebengineurlrequestinterceptor/CMakeLists.txt | 2 +- tests/auto/core/tests.pri | 2 +- 40 files changed, 1848 insertions(+), 5 deletions(-) create mode 100644 tests/auto/core/certificateerror/CMakeLists.txt create mode 100644 tests/auto/core/certificateerror/certificateerror.pro create mode 100644 tests/auto/core/certificateerror/resources/server.key create mode 100644 tests/auto/core/certificateerror/resources/server.pem create mode 100644 tests/auto/core/certificateerror/tst_certificateerror.cpp create mode 100644 tests/auto/core/devtools/CMakeLists.txt create mode 100644 tests/auto/core/devtools/devtools.pro create mode 100644 tests/auto/core/devtools/tst_devtools.cpp create mode 100644 tests/auto/core/origins/CMakeLists.txt create mode 100644 tests/auto/core/origins/origins.pro create mode 100644 tests/auto/core/origins/resources/createObjectURL.html create mode 100644 tests/auto/core/origins/resources/dedicatedWorker.html create mode 100644 tests/auto/core/origins/resources/dedicatedWorker.js create mode 100644 tests/auto/core/origins/resources/mixedSchemes.html create mode 100644 tests/auto/core/origins/resources/mixedSchemesWithCsp.html create mode 100644 tests/auto/core/origins/resources/mixedSchemes_frame.html create mode 100644 tests/auto/core/origins/resources/mixedXHR.html create mode 100644 tests/auto/core/origins/resources/mixedXHR.txt create mode 100644 tests/auto/core/origins/resources/redirect.css create mode 100644 tests/auto/core/origins/resources/redirect.html create mode 100644 tests/auto/core/origins/resources/serviceWorker.html create mode 100644 tests/auto/core/origins/resources/serviceWorker.js create mode 100644 tests/auto/core/origins/resources/sharedWorker.html create mode 100644 tests/auto/core/origins/resources/sharedWorker.js create mode 100644 tests/auto/core/origins/resources/subdir/frame2.html create mode 100644 tests/auto/core/origins/resources/subdir/index.html create mode 100644 tests/auto/core/origins/resources/subdir_frame1.html create mode 100644 tests/auto/core/origins/resources/viewSource.html create mode 100644 tests/auto/core/origins/resources/websocket.html create mode 100644 tests/auto/core/origins/tst_origins.cpp create mode 100644 tests/auto/core/origins/tst_origins.qrc create mode 100644 tests/auto/core/qwebenginesettings/BLACKLIST create mode 100644 tests/auto/core/qwebenginesettings/CMakeLists.txt create mode 100644 tests/auto/core/qwebenginesettings/qwebenginesettings.pro create mode 100644 tests/auto/core/qwebenginesettings/tst_qwebenginesettings.cpp (limited to 'tests/auto/core') diff --git a/tests/auto/core/CMakeLists.txt b/tests/auto/core/CMakeLists.txt index ee2f010d0..0d2340188 100644 --- a/tests/auto/core/CMakeLists.txt +++ b/tests/auto/core/CMakeLists.txt @@ -1,5 +1,11 @@ add_subdirectory(qwebenginecookiestore) +add_subdirectory(qwebenginesettings) add_subdirectory(qwebengineurlrequestinterceptor) +add_subdirectory(origins) +if(NOT boot2qt) + add_subdirectory(devtools) +endif() if(QT_FEATURE_ssl) add_subdirectory(qwebengineclientcertificatestore) + add_subdirectory(certificateerror) endif() diff --git a/tests/auto/core/certificateerror/CMakeLists.txt b/tests/auto/core/certificateerror/CMakeLists.txt new file mode 100644 index 000000000..57801e195 --- /dev/null +++ b/tests/auto/core/certificateerror/CMakeLists.txt @@ -0,0 +1,23 @@ +include(../../httpserver/httpserver.cmake) +include(../../util/util.cmake) + +qt_internal_add_test(tst_certificateerror + SOURCES + tst_certificateerror.cpp + LIBRARIES + Qt::WebEngineCore + Test::HttpServer + Test::Util +) + +set(tst_certificateerror_resource_files + "resources/server.pem" + "resources/server.key" +) + +qt_internal_add_resource(tst_certificateerror "tst_certificateerror" + PREFIX + "/" + FILES + ${tst_certificateerror_resource_files} +) diff --git a/tests/auto/core/certificateerror/certificateerror.pro b/tests/auto/core/certificateerror/certificateerror.pro new file mode 100644 index 000000000..73ba7515b --- /dev/null +++ b/tests/auto/core/certificateerror/certificateerror.pro @@ -0,0 +1,3 @@ +include(../tests.pri) +include(../../shared/https.pri) +QT *= core-private diff --git a/tests/auto/core/certificateerror/resources/server.key b/tests/auto/core/certificateerror/resources/server.key new file mode 100644 index 000000000..9bf87aee3 --- /dev/null +++ b/tests/auto/core/certificateerror/resources/server.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAqAygFPG5ILLb3G51D0OIN4Kpm5t3Oh1nByTnvi1kMz+sCBBd +CSugt4NnKkB6kiGtMEsrEm1/xg8Bkfbpet3v3+jAidRpjvCISqy3Z9D1cgCFM46h +iob/AvLZpqITiAgsU4fJ4auuIKhFplIGrIKMv2gK8haoBGBoRUD1RM+irwjEr6TN +XTQt2Ap+Ouxs53NLPhAOgumpfzzRR8/Umbhen+G5MhH+XTzzreiClz2V6A79ePJj +y1uQ8NJ79feOOWBDRizRDWwxsnNd24GjkpvcaTwafiK6Vdqeub+XTtiB5RPal2on +Cj0TQDcnaacecl/zmUWsIFNkNJWDcd3/vEdyOQIDAQABAoIBAQCW93icOCdim6tu +FIDu7HEjxSsPUpPCToWu4lWaAHcinxGx0NlzkpD4K4DzcSdrvfszBmQ0UtBVokd7 +1IAdU+HZmePWLk+CDM2zoAPHrO3Cs3r2PS0cIHhZMsearcG0E/uWMseHB08PoXuo +lcnPEhzVGueyYe4guGcTx+5PGeUBLf+fJcEc3rIQnT2LYulM2aqBZSQM3jRUaPYs +F0awDpCNwajW/Bt2VB14Pr+H5MJ+WSznFCqW7SolBkqDGfKckXPSHgX6xZ0y7VCI +MM8vwlVI4mPkaHvSQMSI8vS4Qh+SGQCSs/AuuNLjjPoz1YotV3Ih4YbLj6BjFP2g +CrqzT6VNAoGBANOHmsqE0nRkLzonTDrMdla5b0TjTxwtNM5DjLgJa6UBBqPe+1Lv +JFoBP9bIfYDRWZOZrxXItfMmM43nK/ST6Xqgx1IpHUCLKVr2pA9RXrP+m4oawfgn +frW212fHibeOYiLy+DaQXQ0VRFxsc/VbwKVyVlMEcNg3N93x2E67M7vjAoGBAMtg +7wDa+5gjwuyNr7LKkp5VDTmtKQhoDtg4sw6MSQSMF6fJT9Z4kGTZ23+G85/LsM/k +iXbceabGJ0CQJvGn6oW4dI2Ut2c2nCNVbQCxJ6Nyn/yW7bRLShMnwXvbGAVxVUax +5ohJPZGJ8ar2CP76A0bkvm2Nwylq2gp6Y8h7+iwzAoGBAKizwfQ6sk45iKDsrpNG +dir8gY2DbJigRTksDpLIkJ1skAspz295YpiV3oBCLjYKwVJCg6zwAo0FrqBB+oB5 +ZwByMgWI3NeZJUZy5q2Ay/Lp4MroRELR3PC3/lu6fE90szgEZ4m84TmJ+Jdtt527 +q41H/yj+pbELePb95vIDw2LZAoGBAJBZ+MmupCzUFSI5Xp+UUIS48W4ijaE92mt1 +swF8aMcleBTLOjOL11D9oGHfs0OUG6czGq6WxnGs62dT6ZBUEo1e4rsq9xH3HNOn +anq3Qt8sGIn7xjPVzHnUGeyDEYWrb0+CLZJGCcEnG7SwdKolYfYLnW281Oysvp35 +SKGf/W0pAoGAa2+sZmhb1mpGAf6Bi4z+uym/6qOJmG6CnrBSM9e/r8nujwFVkCYF +3iz48qx3GbuliO6za8aM1drX2u8KWp1uP5KzwYvtW5SfpQ1eusFblHEYQQNRcKLT +j/wZBXnU961eMKkkTe2XsPirO8rVhVmxuFLqT/aEPffcragQFFIGOEQ= +-----END RSA PRIVATE KEY----- diff --git a/tests/auto/core/certificateerror/resources/server.pem b/tests/auto/core/certificateerror/resources/server.pem new file mode 100644 index 000000000..a201ed08e --- /dev/null +++ b/tests/auto/core/certificateerror/resources/server.pem @@ -0,0 +1,41 @@ +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIUFZEIIzeR7lEA10rb14w7MfhP87MwDQYJKoZIhvcNAQEL +BQAwWjELMAkGA1UEBhMCREUxDzANBgNVBAgMBkJlcmxpbjEPMA0GA1UEBwwGQmVy +bGluMRUwEwYDVQQKDAxUaGVRdENvbXBhbnkxEjAQBgNVBAsMCXdlYmVuZ2luZTAe +Fw0yMTA1MTAyMTM1MTJaFw0yMjA1MTAyMTM1MTJaMGAxCzAJBgNVBAYTAkRFMQ8w +DQYDVQQIDAZCZXJsaW4xDzANBgNVBAcMBkJlcmxpbjEVMBMGA1UECgwMVGhlUXRD +b21wYW55MRgwFgYDVQQDDA93ZWJlbmdpbmUucXQuaW8wggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQCoDKAU8bkgstvcbnUPQ4g3gqmbm3c6HWcHJOe+LWQz +P6wIEF0JK6C3g2cqQHqSIa0wSysSbX/GDwGR9ul63e/f6MCJ1GmO8IhKrLdn0PVy +AIUzjqGKhv8C8tmmohOICCxTh8nhq64gqEWmUgasgoy/aAryFqgEYGhFQPVEz6Kv +CMSvpM1dNC3YCn467Gznc0s+EA6C6al/PNFHz9SZuF6f4bkyEf5dPPOt6IKXPZXo +Dv148mPLW5Dw0nv19445YENGLNENbDGyc13bgaOSm9xpPBp+IrpV2p65v5dO2IHl +E9qXaicKPRNANydppx5yX/OZRawgU2Q0lYNx3f+8R3I5AgMBAAGjMzAxMBoGA1Ud +EQQTMBGCD3dlYmVuZ2luZS5xdC5pbzATBgNVHSUEDDAKBggrBgEFBQcDATANBgkq +hkiG9w0BAQsFAAOCAQEAjThKpP0sBv1vEmaqBc1wTu//7RHmFcoStTt3scADzb2C +9gjOVC4NzxBneLkv01444Z1p/Iiu/ZZ+VKu7aJElJgnBWEisYwJ09t3cdZRA0UY7 +XRvTVAqV0OlsB1Jn0afE+aTLGjWo+jSYzua0O+NK74e23p9jkdSmXxH9w0FB/oyM +FGIOFnnfP0+QR4ZVvAGk2H60tBHQKmCM6b87TiD4GQIfOghCQWH+qJYSuyGu4hkE +uis+n1KHHhed3GIJOHpm7gt1C9qtjcp1nOpv0ycQjfc9CGvr02BcQjhMeO65hX0A +TvCgKN9/XMFv5jwwjjPCL12GBhwnN2k9hM/tEYpe2A== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDOzCCAiMCFDwWg4NZxCplj3qyBxAUTi1wmj4jMA0GCSqGSIb3DQEBCwUAMFox +CzAJBgNVBAYTAkRFMQ8wDQYDVQQIDAZCZXJsaW4xDzANBgNVBAcMBkJlcmxpbjEV +MBMGA1UECgwMVGhlUXRDb21wYW55MRIwEAYDVQQLDAl3ZWJlbmdpbmUwHhcNMjEw +NTEwMjEzMTE4WhcNMjIwNTEwMjEzMTE4WjBaMQswCQYDVQQGEwJERTEPMA0GA1UE +CAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4xFTATBgNVBAoMDFRoZVF0Q29tcGFu +eTESMBAGA1UECwwJd2ViZW5naW5lMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAuc/8xVrfSzOsI6kYul+o1QIPBh1I86eQm1PhTBDMAAPHuzyPaEMgBkn2 +XAUmvkynGpNioaJDU2ndV2fBHvsoeQCdNNmjFTe1rKYjrN6U2X5KoYSzN93TOYzK +aR38fEFx+w4qV76nnxSjYtGNe9z74GrfWFMdDQ0NJKzvaO4gaZ+OOg0OzWy4MJQ0 +aINo3UV55Y7Nt92AxFweiuHucKu+rjf3BX7n0Af/Tcs2c84f0R3HA7euReSibVvX +f33eHLRKwu2bvDjXiUzOdkxBn9GTo6Q09LyY6wDG0ZdWnyCKj3NBQKBVrq+bs3Q0 +ATsWhj/PvYlZhhZh4EOlqYOhCpwv4wIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCC +pLSFGJcG0zhHW+2A6ogmpn2tA8gKUZx7f0J1nwgPEoAXQqWQv/299ZtmWfMKHUkk +ygG4u80C87wWPH42XWXo/KDrP9iYzoqAvtqbRuPG9PAxefQ/JUSnuhikA51g9+Mu +IDKKKSI+y/JW9u0Qo77fp/5n2DaFn5B+pBYvn/xLfaEa9bRdJMTEMsElGbPBzMZd +I/7X6B78X6Ow5TuRKSeZA7E1AZ/+e5A4Hj65bLAugoSKz3zaS0dV26LwAo18c2zP +TqtwHyIVj4QCoI6Z694q9KH4Pkml3fz8VSkk+MvZMWapvUhHu/DneTgqGbp9POYg +nx6oWME6idhnvN6DljxB +-----END CERTIFICATE----- diff --git a/tests/auto/core/certificateerror/tst_certificateerror.cpp b/tests/auto/core/certificateerror/tst_certificateerror.cpp new file mode 100644 index 000000000..74c7e3bd4 --- /dev/null +++ b/tests/auto/core/certificateerror/tst_certificateerror.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include + +#include +#include +#include +#include + +#include + +class tst_CertificateError : public QObject +{ + Q_OBJECT +public: + tst_CertificateError() { } + +private Q_SLOTS: + void handleError_data(); + void handleError(); +}; + +struct PageWithCertificateErrorHandler : QWebEnginePage +{ + Q_OBJECT + +public: + PageWithCertificateErrorHandler(bool defer, bool accept, QObject *p = nullptr) + : QWebEnginePage(p), deferError(defer), acceptCertificate(accept) + , loadSpy(this, &QWebEnginePage::loadFinished) + { + connect(this, &PageWithCertificateErrorHandler::certificateError, + this, &PageWithCertificateErrorHandler::onCertificateError); + } + + bool deferError, acceptCertificate; + + QSignalSpy loadSpy; + QScopedPointer error; + +public Q_SLOTS: + void onCertificateError(QWebEngineCertificateError e) + { + error.reset(new QWebEngineCertificateError(e)); + if (deferError) { + error->defer(); + return; + } + + if (acceptCertificate) + error->acceptCertificate(); + else + error->rejectCertificate(); + } +}; + +void tst_CertificateError::handleError_data() +{ + QTest::addColumn("deferError"); + QTest::addColumn("acceptCertificate"); + QTest::addColumn("expectedContent"); + QTest::addRow("Reject") << false << false << QString(); + QTest::addRow("DeferReject") << true << false << QString(); + QTest::addRow("DeferAccept") << true << true << "TEST"; +} + +void tst_CertificateError::handleError() +{ + HttpsServer server(":/resources/server.pem",":/resources/server.key"); + server.setExpectError(true); + QVERIFY(server.start()); + + connect(&server, &HttpsServer::newRequest, [&] (HttpReqRep *rr) { + rr->setResponseBody(QByteArrayLiteral("TEST")); + rr->sendResponse(); + }); + + QFETCH(bool, deferError); + QFETCH(bool, acceptCertificate); + QFETCH(QString, expectedContent); + + PageWithCertificateErrorHandler page(deferError, acceptCertificate); + page.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false); + + page.setUrl(server.url()); + QTRY_VERIFY(page.error); + QVERIFY(page.error->isOverridable()); + auto chain = page.error->certificateChain(); + QCOMPARE(chain.size(), 2); + QCOMPARE(chain[0].serialNumber(), "15:91:08:23:37:91:ee:51:00:d7:4a:db:d7:8c:3b:31:f8:4f:f3:b3"); + QCOMPARE(chain[1].serialNumber(), "3c:16:83:83:59:c4:2a:65:8f:7a:b2:07:10:14:4e:2d:70:9a:3e:23"); + + if (deferError) { + QCOMPARE(page.loadSpy.count(), 0); + QCOMPARE(toPlainTextSync(&page), QString()); + + if (acceptCertificate) + page.error->acceptCertificate(); + else + page.error->rejectCertificate(); + + page.error.reset(); + } + QTRY_COMPARE_WITH_TIMEOUT(page.loadSpy.count(), 1, 30000); + QCOMPARE(page.loadSpy.takeFirst().value(0).toBool(), acceptCertificate); + QCOMPARE(toPlainTextSync(&page), expectedContent); +} + +QTEST_MAIN(tst_CertificateError) +#include diff --git a/tests/auto/core/core.pro b/tests/auto/core/core.pro index 1dc5e052c..23b25bd97 100644 --- a/tests/auto/core/core.pro +++ b/tests/auto/core/core.pro @@ -3,7 +3,10 @@ QT_FOR_CONFIG += network-private SUBDIRS += \ qwebenginecookiestore \ - qwebengineurlrequestinterceptor + qwebenginesettings \ + qwebengineurlrequestinterceptor \ + devtools \ + origins -qtConfig(ssl): SUBDIRS += qwebengineclientcertificatestore +qtConfig(ssl): SUBDIRS += certificateerror qwebengineclientcertificatestore diff --git a/tests/auto/core/devtools/CMakeLists.txt b/tests/auto/core/devtools/CMakeLists.txt new file mode 100644 index 000000000..fd8d850f0 --- /dev/null +++ b/tests/auto/core/devtools/CMakeLists.txt @@ -0,0 +1,7 @@ +qt_internal_add_test(tst_devtools + SOURCES + tst_devtools.cpp + LIBRARIES + Qt::WebEngineCore +) + diff --git a/tests/auto/core/devtools/devtools.pro b/tests/auto/core/devtools/devtools.pro new file mode 100644 index 000000000..e99c7f493 --- /dev/null +++ b/tests/auto/core/devtools/devtools.pro @@ -0,0 +1 @@ +include(../tests.pri) diff --git a/tests/auto/core/devtools/tst_devtools.cpp b/tests/auto/core/devtools/tst_devtools.cpp new file mode 100644 index 000000000..3026b3931 --- /dev/null +++ b/tests/auto/core/devtools/tst_devtools.cpp @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include + +class tst_DevTools : public QObject { + Q_OBJECT + +private Q_SLOTS: + void attachAndDestroyPageFirst(); + void attachAndDestroyInspectorFirst(); +}; + +void tst_DevTools::attachAndDestroyPageFirst() +{ + // External inspector + manual destruction of page first + QWebEnginePage* page = new QWebEnginePage(); + QWebEnginePage* inspector = new QWebEnginePage(); + + QSignalSpy spy(page, &QWebEnginePage::loadFinished); + page->load(QUrl("data:text/plain,foobarbaz")); + QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 12000); + + inspector->setInspectedPage(page); + page->triggerAction(QWebEnginePage::InspectElement); + + // This is deliberately racy: + QTest::qWait(10); + + delete page; + delete inspector; +} + +void tst_DevTools::attachAndDestroyInspectorFirst() +{ + // External inspector + manual destruction of inspector first + QWebEnginePage* page = new QWebEnginePage(); + QWebEnginePage* inspector = new QWebEnginePage(); + inspector->setInspectedPage(page); + + QSignalSpy spy(page, &QWebEnginePage::loadFinished); + page->setHtml(QStringLiteral("

FOO BAR!

")); + QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 12000); + + page->triggerAction(QWebEnginePage::InspectElement); + + delete inspector; + + page->triggerAction(QWebEnginePage::InspectElement); + + // This is deliberately racy: + QTest::qWait(10); + + delete page; +} + + +QTEST_MAIN(tst_DevTools) + +#include "tst_devtools.moc" diff --git a/tests/auto/core/origins/CMakeLists.txt b/tests/auto/core/origins/CMakeLists.txt new file mode 100644 index 000000000..a044ea2ef --- /dev/null +++ b/tests/auto/core/origins/CMakeLists.txt @@ -0,0 +1,45 @@ +include(../../httpserver/httpserver.cmake) +include(../../util/util.cmake) + +qt_internal_add_test(tst_origins + SOURCES + tst_origins.cpp + LIBRARIES + Qt::WebEngineCore + Test::HttpServer + Test::Util +) + +set(tst_origins_resource_files + "resources/createObjectURL.html" + "resources/dedicatedWorker.html" + "resources/dedicatedWorker.js" + "resources/mixedSchemes.html" + "resources/mixedSchemesWithCsp.html" + "resources/mixedSchemes_frame.html" + "resources/mixedXHR.html" + "resources/mixedXHR.txt" + "resources/serviceWorker.html" + "resources/serviceWorker.js" + "resources/sharedWorker.html" + "resources/sharedWorker.js" + "resources/subdir/frame2.html" + "resources/subdir/index.html" + "resources/subdir_frame1.html" + "resources/viewSource.html" + "resources/websocket.html" +) + +qt_internal_add_resource(tst_origins "tst_origins" + PREFIX + "/" + FILES + ${tst_origins_resource_files} +) + +qt_internal_extend_target(tst_origins CONDITION QT_FEATURE_webengine_webchannel AND TARGET Qt::WebSockets + DEFINES + WEBSOCKETS + LIBRARIES + Qt::WebSockets +) diff --git a/tests/auto/core/origins/origins.pro b/tests/auto/core/origins/origins.pro new file mode 100644 index 000000000..6cf0b2b92 --- /dev/null +++ b/tests/auto/core/origins/origins.pro @@ -0,0 +1,8 @@ +include(../tests.pri) +include(../../shared/http.pri) + +qtConfig(webengine-webchannel):qtHaveModule(websockets) { + QT += websockets + DEFINES += WEBSOCKETS +} + diff --git a/tests/auto/core/origins/resources/createObjectURL.html b/tests/auto/core/origins/resources/createObjectURL.html new file mode 100644 index 000000000..133f636bb --- /dev/null +++ b/tests/auto/core/origins/resources/createObjectURL.html @@ -0,0 +1,11 @@ + + + + createObjectURL + + + + diff --git a/tests/auto/core/origins/resources/dedicatedWorker.html b/tests/auto/core/origins/resources/dedicatedWorker.html new file mode 100644 index 000000000..cb4f14e73 --- /dev/null +++ b/tests/auto/core/origins/resources/dedicatedWorker.html @@ -0,0 +1,19 @@ + + + + dedicatedWorker + + + + diff --git a/tests/auto/core/origins/resources/dedicatedWorker.js b/tests/auto/core/origins/resources/dedicatedWorker.js new file mode 100644 index 000000000..2631939d7 --- /dev/null +++ b/tests/auto/core/origins/resources/dedicatedWorker.js @@ -0,0 +1 @@ +onmessage = (e) => { postMessage(e.data + 1); }; diff --git a/tests/auto/core/origins/resources/mixedSchemes.html b/tests/auto/core/origins/resources/mixedSchemes.html new file mode 100644 index 000000000..c73e9ecdc --- /dev/null +++ b/tests/auto/core/origins/resources/mixedSchemes.html @@ -0,0 +1,31 @@ + + + + Mixed + + + + + + diff --git a/tests/auto/core/origins/resources/mixedSchemesWithCsp.html b/tests/auto/core/origins/resources/mixedSchemesWithCsp.html new file mode 100644 index 000000000..ad7cbeeb7 --- /dev/null +++ b/tests/auto/core/origins/resources/mixedSchemesWithCsp.html @@ -0,0 +1,32 @@ + + + + + Mixed + + + + + + diff --git a/tests/auto/core/origins/resources/mixedSchemes_frame.html b/tests/auto/core/origins/resources/mixedSchemes_frame.html new file mode 100644 index 000000000..00c20ba37 --- /dev/null +++ b/tests/auto/core/origins/resources/mixedSchemes_frame.html @@ -0,0 +1,11 @@ + + + + Mixed - Frame + + + + diff --git a/tests/auto/core/origins/resources/mixedXHR.html b/tests/auto/core/origins/resources/mixedXHR.html new file mode 100644 index 000000000..3dfd90006 --- /dev/null +++ b/tests/auto/core/origins/resources/mixedXHR.html @@ -0,0 +1,19 @@ + + + + Mixed + + + + + diff --git a/tests/auto/core/origins/resources/mixedXHR.txt b/tests/auto/core/origins/resources/mixedXHR.txt new file mode 100644 index 000000000..b5754e203 --- /dev/null +++ b/tests/auto/core/origins/resources/mixedXHR.txt @@ -0,0 +1 @@ +ok \ No newline at end of file diff --git a/tests/auto/core/origins/resources/redirect.css b/tests/auto/core/origins/resources/redirect.css new file mode 100644 index 000000000..41d7560cc --- /dev/null +++ b/tests/auto/core/origins/resources/redirect.css @@ -0,0 +1,8 @@ +@font-face { + font-family: 'MyWebFont'; + src: url('redirect1:/resources/Akronim-Regular.woff2') format('woff2'); +} + +body { + font-family: 'MyWebFont', Fallback, sans-serif; +} diff --git a/tests/auto/core/origins/resources/redirect.html b/tests/auto/core/origins/resources/redirect.html new file mode 100644 index 000000000..04948e14b --- /dev/null +++ b/tests/auto/core/origins/resources/redirect.html @@ -0,0 +1,10 @@ + + + + redirect + + + + Text + + diff --git a/tests/auto/core/origins/resources/serviceWorker.html b/tests/auto/core/origins/resources/serviceWorker.html new file mode 100644 index 000000000..27890c98f --- /dev/null +++ b/tests/auto/core/origins/resources/serviceWorker.html @@ -0,0 +1,18 @@ + + + + serviceWorker + + + + diff --git a/tests/auto/core/origins/resources/serviceWorker.js b/tests/auto/core/origins/resources/serviceWorker.js new file mode 100644 index 000000000..40a8c178f --- /dev/null +++ b/tests/auto/core/origins/resources/serviceWorker.js @@ -0,0 +1 @@ +/* empty */ diff --git a/tests/auto/core/origins/resources/sharedWorker.html b/tests/auto/core/origins/resources/sharedWorker.html new file mode 100644 index 000000000..8b5a0a794 --- /dev/null +++ b/tests/auto/core/origins/resources/sharedWorker.html @@ -0,0 +1,19 @@ + + + + sharedWorker + + + + diff --git a/tests/auto/core/origins/resources/sharedWorker.js b/tests/auto/core/origins/resources/sharedWorker.js new file mode 100644 index 000000000..60ef93a5f --- /dev/null +++ b/tests/auto/core/origins/resources/sharedWorker.js @@ -0,0 +1,6 @@ +onconnect = function(e) { + let port = e.ports[0]; + port.onmessage = function(e) { + port.postMessage(e.data + 1); + }; +}; diff --git a/tests/auto/core/origins/resources/subdir/frame2.html b/tests/auto/core/origins/resources/subdir/frame2.html new file mode 100644 index 000000000..3a2f664ca --- /dev/null +++ b/tests/auto/core/origins/resources/subdir/frame2.html @@ -0,0 +1,10 @@ + + + + Subdir - Frame 2 + + + + diff --git a/tests/auto/core/origins/resources/subdir/index.html b/tests/auto/core/origins/resources/subdir/index.html new file mode 100644 index 000000000..9c5d5d782 --- /dev/null +++ b/tests/auto/core/origins/resources/subdir/index.html @@ -0,0 +1,26 @@ + + + + Subdir + + + + + + + + + + + + diff --git a/tests/auto/core/origins/resources/subdir_frame1.html b/tests/auto/core/origins/resources/subdir_frame1.html new file mode 100644 index 000000000..63973f2f4 --- /dev/null +++ b/tests/auto/core/origins/resources/subdir_frame1.html @@ -0,0 +1,10 @@ + + + + Subdir - Frame 1 + + + + diff --git a/tests/auto/core/origins/resources/viewSource.html b/tests/auto/core/origins/resources/viewSource.html new file mode 100644 index 000000000..977074c74 --- /dev/null +++ b/tests/auto/core/origins/resources/viewSource.html @@ -0,0 +1,9 @@ + + + + viewSource + + +

viewSource

+ + diff --git a/tests/auto/core/origins/resources/websocket.html b/tests/auto/core/origins/resources/websocket.html new file mode 100644 index 000000000..31db66571 --- /dev/null +++ b/tests/auto/core/origins/resources/websocket.html @@ -0,0 +1,23 @@ + + + + WebSocket + + + + + diff --git a/tests/auto/core/origins/tst_origins.cpp b/tests/auto/core/origins/tst_origins.cpp new file mode 100644 index 000000000..a34404a7e --- /dev/null +++ b/tests/auto/core/origins/tst_origins.cpp @@ -0,0 +1,958 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "httpserver.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(WEBSOCKETS) +#include +#include +#include +#endif +#include + +#define QSL QStringLiteral +#define QBAL QByteArrayLiteral + +void registerSchemes() +{ + { + QWebEngineUrlScheme scheme(QBAL("PathSyntax")); + QWebEngineUrlScheme::registerScheme(scheme); + } + + { + QWebEngineUrlScheme scheme(QBAL("PathSyntax-Secure")); + scheme.setFlags(QWebEngineUrlScheme::SecureScheme); + QWebEngineUrlScheme::registerScheme(scheme); + } + + { + QWebEngineUrlScheme scheme(QBAL("PathSyntax-Secure-ServiceWorkersAllowed")); + scheme.setFlags(QWebEngineUrlScheme::SecureScheme | QWebEngineUrlScheme::ServiceWorkersAllowed); + QWebEngineUrlScheme::registerScheme(scheme); + } + + { + QWebEngineUrlScheme scheme(QBAL("PathSyntax-Local")); + scheme.setFlags(QWebEngineUrlScheme::LocalScheme); + QWebEngineUrlScheme::registerScheme(scheme); + } + + { + QWebEngineUrlScheme scheme(QBAL("PathSyntax-LocalAccessAllowed")); + scheme.setFlags(QWebEngineUrlScheme::LocalAccessAllowed); + QWebEngineUrlScheme::registerScheme(scheme); + } + + { + QWebEngineUrlScheme scheme(QBAL("PathSyntax-NoAccessAllowed")); + scheme.setFlags(QWebEngineUrlScheme::NoAccessAllowed); + QWebEngineUrlScheme::registerScheme(scheme); + } + + { + QWebEngineUrlScheme scheme(QBAL("PathSyntax-ServiceWorkersAllowed")); + scheme.setFlags(QWebEngineUrlScheme::ServiceWorkersAllowed); + QWebEngineUrlScheme::registerScheme(scheme); + } + + { + QWebEngineUrlScheme scheme(QBAL("PathSyntax-ViewSourceAllowed")); + scheme.setFlags(QWebEngineUrlScheme::ViewSourceAllowed); + QWebEngineUrlScheme::registerScheme(scheme); + } + + { + QWebEngineUrlScheme scheme(QBAL("HostSyntax")); + scheme.setSyntax(QWebEngineUrlScheme::Syntax::Host); + QWebEngineUrlScheme::registerScheme(scheme); + } + + { + QWebEngineUrlScheme scheme(QBAL("HostSyntax-ContentSecurityPolicyIgnored")); + scheme.setSyntax(QWebEngineUrlScheme::Syntax::Host); + scheme.setFlags(QWebEngineUrlScheme::ContentSecurityPolicyIgnored); + QWebEngineUrlScheme::registerScheme(scheme); + } + + { + QWebEngineUrlScheme scheme(QBAL("HostAndPortSyntax")); + scheme.setSyntax(QWebEngineUrlScheme::Syntax::HostAndPort); + scheme.setDefaultPort(42); + QWebEngineUrlScheme::registerScheme(scheme); + } + + { + QWebEngineUrlScheme scheme(QBAL("HostPortAndUserInformationSyntax")); + scheme.setSyntax(QWebEngineUrlScheme::Syntax::HostPortAndUserInformation); + scheme.setDefaultPort(42); + QWebEngineUrlScheme::registerScheme(scheme); + } + + { + QWebEngineUrlScheme scheme(QBAL("redirect1")); + scheme.setFlags(QWebEngineUrlScheme::CorsEnabled); + QWebEngineUrlScheme::registerScheme(scheme); + } + + { + QWebEngineUrlScheme scheme(QBAL("redirect2")); + scheme.setFlags(QWebEngineUrlScheme::CorsEnabled); + QWebEngineUrlScheme::registerScheme(scheme); + } + + { + QWebEngineUrlScheme scheme(QBAL("cors")); + scheme.setFlags(QWebEngineUrlScheme::CorsEnabled); + QWebEngineUrlScheme::registerScheme(scheme); + } + +} +Q_CONSTRUCTOR_FUNCTION(registerSchemes) + +class TstUrlSchemeHandler final : public QWebEngineUrlSchemeHandler { + Q_OBJECT + +public: + TstUrlSchemeHandler(QWebEngineProfile *profile) + { + profile->installUrlSchemeHandler(QBAL("tst"), this); + + profile->installUrlSchemeHandler(QBAL("PathSyntax"), this); + profile->installUrlSchemeHandler(QBAL("PathSyntax-Secure"), this); + profile->installUrlSchemeHandler(QBAL("PathSyntax-Secure-ServiceWorkersAllowed"), this); + profile->installUrlSchemeHandler(QBAL("PathSyntax-Local"), this); + profile->installUrlSchemeHandler(QBAL("PathSyntax-LocalAccessAllowed"), this); + profile->installUrlSchemeHandler(QBAL("PathSyntax-NoAccessAllowed"), this); + profile->installUrlSchemeHandler(QBAL("PathSyntax-ServiceWorkersAllowed"), this); + profile->installUrlSchemeHandler(QBAL("PathSyntax-ViewSourceAllowed"), this); + profile->installUrlSchemeHandler(QBAL("HostSyntax"), this); + profile->installUrlSchemeHandler(QBAL("HostSyntax-ContentSecurityPolicyIgnored"), this); + profile->installUrlSchemeHandler(QBAL("HostAndPortSyntax"), this); + profile->installUrlSchemeHandler(QBAL("HostPortAndUserInformationSyntax"), this); + profile->installUrlSchemeHandler(QBAL("redirect1"), this); + profile->installUrlSchemeHandler(QBAL("redirect2"), this); + profile->installUrlSchemeHandler(QBAL("cors"), this); + } + + QList &requests() { return m_requests; } + +private: + void requestStarted(QWebEngineUrlRequestJob *job) override + { + QUrl url = job->requestUrl(); + m_requests << url; + + if (url.scheme() == QBAL("redirect1")) { + url.setScheme(QBAL("redirect2")); + job->redirect(url); + return; + } + + QString pathPrefix = QDir(QT_TESTCASE_SOURCEDIR).canonicalPath(); + QString pathSuffix = url.path(); + QFile *file = new QFile(pathPrefix + pathSuffix, job); + if (!file->open(QIODevice::ReadOnly)) { + job->fail(QWebEngineUrlRequestJob::RequestFailed); + return; + } + QByteArray mimeType = QBAL("text/html"); + if (pathSuffix.endsWith(QSL(".js"))) + mimeType = QBAL("application/javascript"); + else if (pathSuffix.endsWith(QSL(".css"))) + mimeType = QBAL("text/css"); + job->reply(mimeType, file); + } + + QList m_requests; +}; + +class tst_Origins final : public QObject { + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + + void jsUrlCanon(); + void jsUrlRelative(); + void jsUrlOrigin(); + void subdirWithAccess(); + void subdirWithoutAccess(); + void fileAccessRemoteUrl_data(); + void fileAccessRemoteUrl(); + void mixedSchemes(); + void mixedSchemesWithCsp(); + void mixedXHR_data(); + void mixedXHR(); +#if defined(WEBSOCKETS) + void webSocket(); +#endif + void dedicatedWorker(); + void sharedWorker(); + void serviceWorker(); + void viewSource(); + void createObjectURL(); + void redirect(); + +private: + bool verifyLoad(const QUrl &url) + { + QSignalSpy spy(m_page, &QWebEnginePage::loadFinished); + m_page->load(url); + [&spy]() { QTRY_VERIFY_WITH_TIMEOUT(!spy.isEmpty(), 90000); }(); + return !spy.isEmpty() && spy.front().value(0).toBool(); + } + + QVariant eval(const QString &code) + { + return evaluateJavaScriptSync(m_page, code); + } + + QWebEngineProfile m_profile; + QWebEnginePage *m_page = nullptr; + TstUrlSchemeHandler *m_handler = nullptr; +}; + +void tst_Origins::initTestCase() +{ + QTest::ignoreMessage( + QtWarningMsg, + QRegularExpression("Please register the custom scheme 'tst'.*")); + + m_handler = new TstUrlSchemeHandler(&m_profile); +} + +void tst_Origins::cleanupTestCase() +{ + QVERIFY(!m_page); + delete m_handler; +} + +void tst_Origins::init() +{ + m_page = new QWebEnginePage(&m_profile, nullptr); +} + +void tst_Origins::cleanup() +{ + delete m_page; + m_page = nullptr; + m_handler->requests().clear(); +} + +// Test URL parsing and canonicalization in Blink. The implementation of this +// part is mostly shared between Blink and Chromium proper. +void tst_Origins::jsUrlCanon() +{ + QVERIFY(verifyLoad(QSL("about:blank"))); + + // Standard schemes are biased towards the authority part. + QCOMPARE(eval(QSL("new URL(\"http:foo/bar\").href")), QVariant(QSL("http://foo/bar"))); + QCOMPARE(eval(QSL("new URL(\"http:/foo/bar\").href")), QVariant(QSL("http://foo/bar"))); + QCOMPARE(eval(QSL("new URL(\"http://foo/bar\").href")), QVariant(QSL("http://foo/bar"))); + QCOMPARE(eval(QSL("new URL(\"http:///foo/bar\").href")), QVariant(QSL("http://foo/bar"))); + + // The file scheme is however a (particularly) special case. +#ifdef Q_OS_WIN + QCOMPARE(eval(QSL("new URL(\"file:foo/bar\").href")), QVariant(QSL("file://foo/bar"))); + QCOMPARE(eval(QSL("new URL(\"file:/foo/bar\").href")), QVariant(QSL("file://foo/bar"))); + QCOMPARE(eval(QSL("new URL(\"file://foo/bar\").href")), QVariant(QSL("file://foo/bar"))); + QCOMPARE(eval(QSL("new URL(\"file:///foo/bar\").href")), QVariant(QSL("file:///foo/bar"))); +#else + QCOMPARE(eval(QSL("new URL(\"file:foo/bar\").href")), QVariant(QSL("file:///foo/bar"))); + QCOMPARE(eval(QSL("new URL(\"file:/foo/bar\").href")), QVariant(QSL("file:///foo/bar"))); + QCOMPARE(eval(QSL("new URL(\"file://foo/bar\").href")), QVariant(QSL("file://foo/bar"))); + QCOMPARE(eval(QSL("new URL(\"file:///foo/bar\").href")), QVariant(QSL("file:///foo/bar"))); +#endif + + // The qrc scheme is a PathSyntax scheme, having only a path and nothing else. + QCOMPARE(eval(QSL("new URL(\"qrc:foo/bar\").href")), QVariant(QSL("qrc:foo/bar"))); + QCOMPARE(eval(QSL("new URL(\"qrc:/foo/bar\").href")), QVariant(QSL("qrc:/foo/bar"))); + QCOMPARE(eval(QSL("new URL(\"qrc://foo/bar\").href")), QVariant(QSL("qrc://foo/bar"))); + QCOMPARE(eval(QSL("new URL(\"qrc:///foo/bar\").href")), QVariant(QSL("qrc:///foo/bar"))); + + // Same for unregistered schemes. + QCOMPARE(eval(QSL("new URL(\"tst:foo/bar\").href")), QVariant(QSL("tst:foo/bar"))); + QCOMPARE(eval(QSL("new URL(\"tst:/foo/bar\").href")), QVariant(QSL("tst:/foo/bar"))); + QCOMPARE(eval(QSL("new URL(\"tst://foo/bar\").href")), QVariant(QSL("tst://foo/bar"))); + QCOMPARE(eval(QSL("new URL(\"tst:///foo/bar\").href")), QVariant(QSL("tst:///foo/bar"))); + + // A HostSyntax scheme is like http without the port & user information. + QCOMPARE(eval(QSL("new URL(\"HostSyntax:foo/bar\").href")), QVariant(QSL("hostsyntax://foo/bar"))); + QCOMPARE(eval(QSL("new URL(\"HostSyntax:foo:42/bar\").href")), QVariant(QSL("hostsyntax://foo/bar"))); + QCOMPARE(eval(QSL("new URL(\"HostSyntax:a:b@foo/bar\").href")), QVariant(QSL("hostsyntax://foo/bar"))); + + // A HostAndPortSyntax scheme is like http without the user information. + QCOMPARE(eval(QSL("new URL(\"HostAndPortSyntax:foo/bar\").href")), + QVariant(QSL("hostandportsyntax://foo/bar"))); + QCOMPARE(eval(QSL("new URL(\"HostAndPortSyntax:foo:41/bar\").href")), + QVariant(QSL("hostandportsyntax://foo:41/bar"))); + QCOMPARE(eval(QSL("new URL(\"HostAndPortSyntax:foo:42/bar\").href")), + QVariant(QSL("hostandportsyntax://foo/bar"))); + QCOMPARE(eval(QSL("new URL(\"HostAndPortSyntax:a:b@foo/bar\").href")), + QVariant(QSL("hostandportsyntax://foo/bar"))); + + // A HostPortAndUserInformationSyntax scheme is exactly like http. + QCOMPARE(eval(QSL("new URL(\"HostPortAndUserInformationSyntax:foo/bar\").href")), + QVariant(QSL("hostportanduserinformationsyntax://foo/bar"))); + QCOMPARE(eval(QSL("new URL(\"HostPortAndUserInformationSyntax:foo:41/bar\").href")), + QVariant(QSL("hostportanduserinformationsyntax://foo:41/bar"))); + QCOMPARE(eval(QSL("new URL(\"HostPortAndUserInformationSyntax:foo:42/bar\").href")), + QVariant(QSL("hostportanduserinformationsyntax://foo/bar"))); + QCOMPARE(eval(QSL("new URL(\"HostPortAndUserInformationSyntax:a:b@foo/bar\").href")), + QVariant(QSL("hostportanduserinformationsyntax://a:b@foo/bar"))); +} + +// Test relative URL resolution. +void tst_Origins::jsUrlRelative() +{ + QVERIFY(verifyLoad(QSL("about:blank"))); + + // Schemes with hosts, like http, work as expected. + QCOMPARE(eval(QSL("new URL('bar', 'http://foo').href")), QVariant(QSL("http://foo/bar"))); + QCOMPARE(eval(QSL("new URL('baz', 'http://foo/bar').href")), QVariant(QSL("http://foo/baz"))); + QCOMPARE(eval(QSL("new URL('baz', 'http://foo/bar/').href")), QVariant(QSL("http://foo/bar/baz"))); + QCOMPARE(eval(QSL("new URL('/baz', 'http://foo/bar/').href")), QVariant(QSL("http://foo/baz"))); + QCOMPARE(eval(QSL("new URL('./baz', 'http://foo/bar/').href")), QVariant(QSL("http://foo/bar/baz"))); + QCOMPARE(eval(QSL("new URL('../baz', 'http://foo/bar/').href")), QVariant(QSL("http://foo/baz"))); + QCOMPARE(eval(QSL("new URL('../../baz', 'http://foo/bar/').href")), QVariant(QSL("http://foo/baz"))); + QCOMPARE(eval(QSL("new URL('//baz', 'http://foo/bar/').href")), QVariant(QSL("http://baz/"))); + + // In the case of schemes without hosts, relative URLs only work if the URL + // starts with a single slash -- and canonicalization does not guarantee + // this. The following cases all fail with TypeErrors. + QCOMPARE(eval(QSL("new URL('bar', 'tst:foo').href")), QVariant()); + QCOMPARE(eval(QSL("new URL('baz', 'tst:foo/bar').href")), QVariant()); + QCOMPARE(eval(QSL("new URL('bar', 'tst://foo').href")), QVariant()); + QCOMPARE(eval(QSL("new URL('bar', 'tst:///foo').href")), QVariant()); + + // However, registered custom schemes have been patched to allow relative + // URLs even without an initial slash. + QCOMPARE(eval(QSL("new URL('bar', 'qrc:foo').href")), QVariant(QSL("qrc:bar"))); + QCOMPARE(eval(QSL("new URL('baz', 'qrc:foo/bar').href")), QVariant(QSL("qrc:foo/baz"))); + QCOMPARE(eval(QSL("new URL('bar', 'qrc://foo').href")), QVariant()); + QCOMPARE(eval(QSL("new URL('bar', 'qrc:///foo').href")), QVariant()); + + // With a slash it works the same as http except 'foo' is part of the path and not the host. + QCOMPARE(eval(QSL("new URL('bar', 'qrc:/foo').href")), QVariant(QSL("qrc:/bar"))); + QCOMPARE(eval(QSL("new URL('bar', 'qrc:/foo/').href")), QVariant(QSL("qrc:/foo/bar"))); + QCOMPARE(eval(QSL("new URL('baz', 'qrc:/foo/bar').href")), QVariant(QSL("qrc:/foo/baz"))); + QCOMPARE(eval(QSL("new URL('baz', 'qrc:/foo/bar/').href")), QVariant(QSL("qrc:/foo/bar/baz"))); + QCOMPARE(eval(QSL("new URL('/baz', 'qrc:/foo/bar/').href")), QVariant(QSL("qrc:/baz"))); + QCOMPARE(eval(QSL("new URL('./baz', 'qrc:/foo/bar/').href")), QVariant(QSL("qrc:/foo/bar/baz"))); + QCOMPARE(eval(QSL("new URL('../baz', 'qrc:/foo/bar/').href")), QVariant(QSL("qrc:/foo/baz"))); + QCOMPARE(eval(QSL("new URL('../../baz', 'qrc:/foo/bar/').href")), QVariant(QSL("qrc:/baz"))); + QCOMPARE(eval(QSL("new URL('../../../baz', 'qrc:/foo/bar/').href")), QVariant(QSL("qrc:/baz"))); + + // If the relative URL begins with >= 2 slashes, then the scheme is treated + // not as a Syntax::Path scheme but as a Syntax::HostPortAndUserInformation + // scheme. + QCOMPARE(eval(QSL("new URL('//baz', 'qrc:/foo/bar/').href")), QVariant(QSL("qrc://baz/"))); + QCOMPARE(eval(QSL("new URL('///baz', 'qrc:/foo/bar/').href")), QVariant(QSL("qrc://baz/"))); +} + +// Test origin serialization in Blink, implemented by blink::KURL and +// blink::SecurityOrigin as opposed to GURL and url::Origin. +void tst_Origins::jsUrlOrigin() +{ + QVERIFY(verifyLoad(QSL("about:blank"))); + + // For network protocols the origin string must include the domain and port. + QCOMPARE(eval(QSL("new URL(\"http://foo.com/page.html\").origin")), QVariant(QSL("http://foo.com"))); + QCOMPARE(eval(QSL("new URL(\"https://foo.com/page.html\").origin")), QVariant(QSL("https://foo.com"))); + + // Even though file URL can also have domains, these are not included in the + // origin string by Chromium. The standard does not specify a value here, + // but suggests 'null' (https://url.spec.whatwg.org/#origin). + QCOMPARE(eval(QSL("new URL(\"file:/etc/passwd\").origin")), QVariant(QSL("file://"))); + QCOMPARE(eval(QSL("new URL(\"file://foo.com/etc/passwd\").origin")), QVariant(QSL("file://"))); + + // Unregistered schemes behave like file. + QCOMPARE(eval(QSL("new URL(\"tst:/banana\").origin")), QVariant(QSL("tst://"))); + QCOMPARE(eval(QSL("new URL(\"tst://foo.com/banana\").origin")), QVariant(QSL("tst://"))); + + // The non-PathSyntax schemes should have hosts and potentially ports. + QCOMPARE(eval(QSL("new URL(\"HostSyntax:foo:41/bar\").origin")), + QVariant(QSL("hostsyntax://foo"))); + QCOMPARE(eval(QSL("new URL(\"HostAndPortSyntax:foo:41/bar\").origin")), + QVariant(QSL("hostandportsyntax://foo:41"))); + QCOMPARE(eval(QSL("new URL(\"HostAndPortSyntax:foo:42/bar\").origin")), + QVariant(QSL("hostandportsyntax://foo"))); + QCOMPARE(eval(QSL("new URL(\"HostPortAndUserInformationSyntax:foo:41/bar\").origin")), + QVariant(QSL("hostportanduserinformationsyntax://foo:41"))); + QCOMPARE(eval(QSL("new URL(\"HostPortAndUserInformationSyntax:foo:42/bar\").origin")), + QVariant(QSL("hostportanduserinformationsyntax://foo"))); + + // A PathSyntax scheme should have a 'universal' origin. + QCOMPARE(eval(QSL("new URL(\"PathSyntax:foo\").origin")), QVariant(QSL("pathsyntax:"))); + QCOMPARE(eval(QSL("new URL(\"qrc:/crysis.css\").origin")), QVariant(QSL("qrc:"))); + QCOMPARE(eval(QSL("new URL(\"qrc://foo.com/crysis.css\").origin")), QVariant(QSL("qrc:"))); + + // The NoAccessAllowed flag forces opaque origins. + QCOMPARE(eval(QSL("new URL(\"PathSyntax-NoAccessAllowed:foo\").origin")), + QVariant(QSL("null"))); +} + +class ScopedAttribute { +public: + ScopedAttribute(QWebEngineSettings *settings, QWebEngineSettings::WebAttribute attribute, bool newValue) + : m_settings(settings) + , m_attribute(attribute) + , m_oldValue(m_settings->testAttribute(m_attribute)) + { + m_settings->setAttribute(m_attribute, newValue); + } + ~ScopedAttribute() + { + m_settings->setAttribute(m_attribute, m_oldValue); + } +private: + QWebEngineSettings *m_settings; + QWebEngineSettings::WebAttribute m_attribute; + bool m_oldValue; +}; + +// Test same-origin policy of file, qrc and custom schemes. +// +// Note the test case involves the main page trying to load an iframe from a +// file that resides in a parent directory. This is just a small detail to +// demonstrate the difference with Firefox where such access is not allowed. +void tst_Origins::subdirWithAccess() +{ + ScopedAttribute sa(m_page->settings(), QWebEngineSettings::LocalContentCanAccessFileUrls, true); + + QVERIFY(verifyLoad("file:" + QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + + "/resources/subdir/index.html")); + QCOMPARE(eval(QSL("msg[0]")), QVariant(QSL("hello"))); + QCOMPARE(eval(QSL("msg[1]")), QVariant(QSL("world"))); + + QVERIFY(verifyLoad(QSL("qrc:/resources/subdir/index.html"))); + QCOMPARE(eval(QSL("msg[0]")), QVariant(QSL("hello"))); + QCOMPARE(eval(QSL("msg[1]")), QVariant(QSL("world"))); + + QVERIFY(verifyLoad(QSL("tst:/resources/subdir/index.html"))); + QCOMPARE(eval(QSL("msg[0]")), QVariant(QSL("hello"))); + QCOMPARE(eval(QSL("msg[1]")), QVariant(QSL("world"))); +} + +// In this variation the LocalContentCanAccessFileUrls attribute is disabled. As +// a result all file URLs will be considered to have unique/opaque origins, that +// is, they are not the 'same origin as' any other origin. +// +// Note that this applies only to file URLs and not qrc or custom schemes. +// +// See also (in Blink): +// - the allow_file_access_from_file_urls option and +// - the blink::SecurityOrigin::BlockLocalAccessFromLocalOrigin() method. +void tst_Origins::subdirWithoutAccess() +{ + ScopedAttribute sa(m_page->settings(), QWebEngineSettings::LocalContentCanAccessFileUrls, false); + + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); + QVERIFY(verifyLoad("file:" + QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + + "/resources/subdir/index.html")); + QCOMPARE(eval(QSL("msg[0]")), QVariant()); + QCOMPARE(eval(QSL("msg[1]")), QVariant()); + + QVERIFY(verifyLoad(QSL("qrc:/resources/subdir/index.html"))); + QCOMPARE(eval(QSL("msg[0]")), QVariant(QSL("hello"))); + QCOMPARE(eval(QSL("msg[1]")), QVariant(QSL("world"))); + + QVERIFY(verifyLoad(QSL("tst:/resources/subdir/index.html"))); + QCOMPARE(eval(QSL("msg[0]")), QVariant(QSL("hello"))); + QCOMPARE(eval(QSL("msg[1]")), QVariant(QSL("world"))); +} + +void tst_Origins::fileAccessRemoteUrl_data() +{ + QTest::addColumn("EnableAccess"); + QTest::addRow("enabled") << true; + QTest::addRow("disabled") << false; +} + +void tst_Origins::fileAccessRemoteUrl() +{ + QFETCH(bool, EnableAccess); + + HttpServer server; + server.setResourceDirs({ QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + "/resources" }); + QVERIFY(server.start()); + + ScopedAttribute sa(m_page->settings(), QWebEngineSettings::LocalContentCanAccessRemoteUrls, EnableAccess); + if (!EnableAccess) + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("blocked by CORS policy"))); + + QVERIFY(verifyLoad("file:" + QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + + "/resources/mixedXHR.html")); + + eval("sendXHR('" + server.url("/mixedXHR.txt").toString() + "')"); + QTRY_COMPARE(eval("result"), (EnableAccess ? QString("ok") : QString("error"))); +} + +// Load the main page over one scheme with an iframe over another scheme. +// +// For file and qrc schemes, the iframe should load but it should not be +// possible for scripts in different frames to interact. +// +// Additionally for unregistered custom schemes and custom schemes without +// LocalAccessAllowed it should not be possible to load an iframe over the +// file: scheme. +void tst_Origins::mixedSchemes() +{ + QVERIFY(verifyLoad("file:" + QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + + "/resources/mixedSchemes.html")); + eval("setIFrameUrl('file:" + QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + + "/resources/mixedSchemes_frame.html')"); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadAndAccess"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); + eval(QSL("setIFrameUrl('qrc:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); + eval(QSL("setIFrameUrl('tst:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + + QVERIFY(verifyLoad(QSL("qrc:/resources/mixedSchemes.html"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); + eval("setIFrameUrl('file:" + QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + + "/resources/mixedSchemes_frame.html')"); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + eval(QSL("setIFrameUrl('qrc:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadAndAccess"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); + eval(QSL("setIFrameUrl('tst:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + + QVERIFY(verifyLoad(QSL("tst:/resources/mixedSchemes.html"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Not allowed to load local resource"))); + eval("setIFrameUrl('file:" + QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + + "/resources/mixedSchemes_frame.html')"); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("cannotLoad"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); + eval(QSL("setIFrameUrl('qrc:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + eval(QSL("setIFrameUrl('tst:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadAndAccess"))); + + QVERIFY(verifyLoad(QSL("PathSyntax:/resources/mixedSchemes.html"))); + eval(QSL("setIFrameUrl('PathSyntax:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadAndAccess"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Not allowed to load local resource"))); + eval(QSL("setIFrameUrl('PathSyntax-Local:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("cannotLoad"))); + eval(QSL("setIFrameUrl('PathSyntax-LocalAccessAllowed:/resources/mixedSchemes_frame.html')")); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); + eval(QSL("setIFrameUrl('PathSyntax-NoAccessAllowed:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + + QVERIFY(verifyLoad(QSL("PathSyntax-LocalAccessAllowed:/resources/mixedSchemes.html"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); + eval(QSL("setIFrameUrl('PathSyntax:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); + eval(QSL("setIFrameUrl('PathSyntax-Local:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + eval(QSL("setIFrameUrl('PathSyntax-LocalAccessAllowed:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadAndAccess"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); + eval(QSL("setIFrameUrl('PathSyntax-NoAccessAllowed:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + + QVERIFY(verifyLoad(QSL("PathSyntax-NoAccessAllowed:/resources/mixedSchemes.html"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); + eval(QSL("setIFrameUrl('PathSyntax:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Not allowed to load local resource"))); + eval(QSL("setIFrameUrl('PathSyntax-Local:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("cannotLoad"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); + eval(QSL("setIFrameUrl('PathSyntax-LocalAccessAllowed:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); + eval(QSL("setIFrameUrl('PathSyntax-NoAccessAllowed:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + + QVERIFY(verifyLoad(QSL("HostSyntax://a/resources/mixedSchemes.html"))); + eval(QSL("setIFrameUrl('HostSyntax://a/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadAndAccess"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); + eval(QSL("setIFrameUrl('HostSyntax://b/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); +} + +// Like mixedSchemes but adds a Content-Security-Policy: frame-src 'none' header. +void tst_Origins::mixedSchemesWithCsp() +{ + QVERIFY(verifyLoad(QSL("HostSyntax://a/resources/mixedSchemesWithCsp.html"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("violates the following Content Security Policy"))); + eval(QSL("setIFrameUrl('HostSyntax://a/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("violates the following Content Security Policy"))); + eval(QSL("setIFrameUrl('HostSyntax://b/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + + QVERIFY(verifyLoad(QSL("HostSyntax-ContentSecurityPolicyIgnored://a/resources/mixedSchemesWithCsp.html"))); + eval(QSL("setIFrameUrl('HostSyntax-ContentSecurityPolicyIgnored://a/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadAndAccess"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); + eval(QSL("setIFrameUrl('HostSyntax-ContentSecurityPolicyIgnored://b/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); +} + +// Load the main page over one scheme, then make an XMLHttpRequest to a +// different scheme. +// +// Cross-origin XMLHttpRequests can only be made to CORS-enabled schemes. These +// include the builtin schemes http, https, data, and chrome, as well as custom +// schemes with the CorsEnabled flag. +void tst_Origins::mixedXHR_data() +{ + QTest::addColumn("url"); + QTest::addColumn("command"); + QTest::addColumn("result"); + QTest::newRow("file->file") << QString("file:" + QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + + "/resources/mixedXHR.html") + << QString("sendXHR('file:" + + QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + + "/resources/mixedXHR.txt')") + << QVariant(QString("ok")); + QTest::newRow("file->qrc") << QString("file:" + QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + + "/resources/mixedXHR.html") + << QString("sendXHR('qrc:/resources/mixedXHR.txt')") + << QVariant(QString("error")); + QTest::newRow("file->tst") << QString("file:" + QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + + "/resources/mixedXHR.html") + << QString("sendXHR('tst:/resources/mixedXHR.txt')") + << QVariant(QString("error")); + QTest::newRow("file->data") << QString("file:" + QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + + "/resources/mixedXHR.html") + << QString("sendXHR('data:,ok')") << QVariant(QString("ok")); + QTest::newRow("file->cors") << QString("file:" + QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + + "/resources/mixedXHR.html") + << QString("sendXHR('cors:/resources/mixedXHR.txt')") + << QVariant(QString("ok")); + + QTest::newRow("qrc->file") << QString("qrc:/resources/mixedXHR.html") + << QString("sendXHR('file:" + + QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + + "/resources/mixedXHR.txt')") + << QVariant(QString("ok")); + QTest::newRow("qrc->qrc") << QString("qrc:/resources/mixedXHR.html") + << QString("sendXHR('qrc:/resources/mixedXHR.txt')") + << QVariant(QString("ok")); + QTest::newRow("qrc->tst") << QString("qrc:/resources/mixedXHR.html") + << QString("sendXHR('tst:/resources/mixedXHR.txt')") + << QVariant(QString("error")); + QTest::newRow("qrc->data") << QString("qrc:/resources/mixedXHR.html") + << QString("sendXHR('data:,ok')") + << QVariant(QString("ok")); + QTest::newRow("qrc->cors") << QString("qrc:/resources/mixedXHR.html") + << QString("sendXHR('cors:/resources/mixedXHR.txt')") + << QVariant(QString("ok")); + + QTest::newRow("tst->file") << QString("tst:/resources/mixedXHR.html") + << QString("sendXHR('file:" + + QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + + "/resources/mixedXHR.txt')") + << QVariant(QString("error")); + QTest::newRow("tst->qrc") << QString("tst:/resources/mixedXHR.html") + << QString("sendXHR('qrc:/resources/mixedXHR.txt')") + << QVariant(QString("error")); + QTest::newRow("tst->tst") << QString("tst:/resources/mixedXHR.html") + << QString("sendXHR('tst:/resources/mixedXHR.txt')") + << QVariant(QString("ok")); + QTest::newRow("tst->data") << QString("tst:/resources/mixedXHR.html") + << QString("sendXHR('data:,ok')") + << QVariant(QString("ok")); + QTest::newRow("tst->cors") << QString("tst:/resources/mixedXHR.html") + << QString("sendXHR('cors:/resources/mixedXHR.txt')") + << QVariant(QString("ok")); + +} + + +void tst_Origins::mixedXHR() +{ + QFETCH(QString, url); + QFETCH(QString, command); + QFETCH(QVariant, result); + + QVERIFY(verifyLoad(url)); + eval(command); + QTRY_COMPARE(eval(QString("result")), result); +} + +#if defined(WEBSOCKETS) +class EchoServer : public QObject { + Q_OBJECT + Q_PROPERTY(QUrl url READ url NOTIFY urlChanged) +public: + EchoServer() : webSocketServer(QSL("EchoServer"), QWebSocketServer::NonSecureMode) + { + connect(&webSocketServer, &QWebSocketServer::newConnection, this, &EchoServer::onNewConnection); + } + + bool listen() + { + if (webSocketServer.listen(QHostAddress::Any)) { + Q_EMIT urlChanged(); + return true; + } + return false; + } + + QUrl url() const + { + return webSocketServer.serverUrl(); + } + +Q_SIGNALS: + void urlChanged(); + +private: + void onNewConnection() + { + QWebSocket *socket = webSocketServer.nextPendingConnection(); + connect(socket, &QWebSocket::textMessageReceived, this, &EchoServer::onTextMessageReceived); + connect(socket, &QWebSocket::disconnected, socket, &QObject::deleteLater); + } + + void onTextMessageReceived(const QString &message) + { + QWebSocket *socket = qobject_cast(sender()); + socket->sendTextMessage(message); + } + + QWebSocketServer webSocketServer; +}; + +// Try opening a WebSocket from pages loaded over various URL schemes. +void tst_Origins::webSocket() +{ + EchoServer echoServer; + QWebChannel channel; + channel.registerObject(QSL("echoServer"), &echoServer); + m_page->setWebChannel(&channel); + QVERIFY(echoServer.listen()); + + QVERIFY(verifyLoad("file:" + QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + + "/resources/websocket.html")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("ok"))); + + QVERIFY(verifyLoad(QSL("qrc:/resources/websocket.html"))); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("ok"))); + + // Unregistered schemes can also open WebSockets (since Chromium 71) + QVERIFY(verifyLoad(QSL("tst:/resources/websocket.html"))); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("ok"))); + + // Even an insecure registered scheme can open WebSockets. + QVERIFY(verifyLoad(QSL("PathSyntax:/resources/websocket.html"))); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("ok"))); +} +#endif +// Create a (Dedicated)Worker. Since dedicated workers can only be accessed from +// one page, there is not much need for security restrictions. +void tst_Origins::dedicatedWorker() +{ + QVERIFY(verifyLoad("file:" + QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + + "/resources/dedicatedWorker.html")); + QTRY_VERIFY(eval(QSL("done")).toBool()); + QCOMPARE(eval(QSL("result")), QVariant(42)); + + QVERIFY(verifyLoad(QSL("qrc:/resources/dedicatedWorker.html"))); + QTRY_VERIFY(eval(QSL("done")).toBool()); + QCOMPARE(eval(QSL("result")), QVariant(42)); + + // Unregistered schemes can also create Workers (since Chromium 71) + QVERIFY(verifyLoad(QSL("tst:/resources/dedicatedWorker.html"))); + QTRY_VERIFY(eval(QSL("done")).toBool()); + QCOMPARE(eval(QSL("result")), QVariant(42)); + + // Even an insecure registered scheme can create Workers. + QVERIFY(verifyLoad(QSL("PathSyntax:/resources/dedicatedWorker.html"))); + QTRY_VERIFY(eval(QSL("done")).toBool()); + QCOMPARE(eval(QSL("result")), QVariant(42)); + + // But not if the NoAccessAllowed flag is set. + QVERIFY(verifyLoad(QSL("PathSyntax-NoAccessAllowed:/resources/dedicatedWorker.html"))); + QTRY_VERIFY(eval(QSL("done")).toBool()); + QVERIFY(eval(QSL("error")).toString() + .contains(QSL("cannot be accessed from origin 'null'"))); +} + +// Create a SharedWorker. Shared workers can be accessed from multiple pages, +// and therefore the same-origin policy applies. +void tst_Origins::sharedWorker() +{ + { + ScopedAttribute sa(m_page->settings(), QWebEngineSettings::LocalContentCanAccessFileUrls, false); + QVERIFY(verifyLoad("file:" + QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + + "/resources/sharedWorker.html")); + QTRY_VERIFY_WITH_TIMEOUT(eval(QSL("done")).toBool(), 10000); + QVERIFY(eval(QSL("error")).toString() + .contains(QSL("cannot be accessed from origin 'null'"))); + } + + { + ScopedAttribute sa(m_page->settings(), QWebEngineSettings::LocalContentCanAccessFileUrls, true); + QVERIFY(verifyLoad("file:" + QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + + "/resources/sharedWorker.html")); + QTRY_VERIFY_WITH_TIMEOUT(eval(QSL("done")).toBool(), 10000); + QCOMPARE(eval(QSL("result")), QVariant(42)); + } + + QVERIFY(verifyLoad(QSL("qrc:/resources/sharedWorker.html"))); + QTRY_VERIFY_WITH_TIMEOUT(eval(QSL("done")).toBool(), 10000); + QCOMPARE(eval(QSL("result")), QVariant(42)); + + // Unregistered schemes should not create SharedWorkers. + + QVERIFY(verifyLoad(QSL("PathSyntax:/resources/sharedWorker.html"))); + QTRY_VERIFY_WITH_TIMEOUT(eval(QSL("done")).toBool(), 10000); + QCOMPARE(eval(QSL("result")), QVariant(42)); + + QVERIFY(verifyLoad(QSL("PathSyntax-NoAccessAllowed:/resources/sharedWorker.html"))); + QTRY_VERIFY_WITH_TIMEOUT(eval(QSL("done")).toBool(), 10000); + QVERIFY(eval(QSL("error")).toString() + .contains(QSL("denied to origin 'null'"))); +} + +// Service workers have to be explicitly enabled for a scheme. +void tst_Origins::serviceWorker() +{ + QVERIFY(verifyLoad("file:" + QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + + "/resources/serviceWorker.html")); + QTRY_VERIFY(eval(QSL("done")).toBool()); + QVERIFY(eval(QSL("error")).toString() + .contains(QSL("The URL protocol of the current origin ('file://') is not supported."))); + + QVERIFY(verifyLoad(QSL("qrc:/resources/serviceWorker.html"))); + QTRY_VERIFY(eval(QSL("done")).toBool()); + QVERIFY(eval(QSL("error")).toString() + .contains(QSL("The URL protocol of the current origin ('qrc:') is not supported."))); + + QVERIFY(verifyLoad(QSL("tst:/resources/serviceWorker.html"))); + QTRY_VERIFY(eval(QSL("done")).toBool()); + QVERIFY(eval(QSL("error")).toString() + .contains(QSL("Cannot read property 'register' of undefined"))); + + QVERIFY(verifyLoad(QSL("PathSyntax:/resources/serviceWorker.html"))); + QTRY_VERIFY(eval(QSL("done")).toBool()); + QVERIFY(eval(QSL("error")).toString() + .contains(QSL("Cannot read property 'register' of undefined"))); + + QVERIFY(verifyLoad(QSL("PathSyntax-Secure:/resources/serviceWorker.html"))); + QTRY_VERIFY(eval(QSL("done")).toBool()); + QVERIFY(eval(QSL("error")).toString() + .contains(QSL("The URL protocol of the current origin ('pathsyntax-secure:') is not supported."))); + + QVERIFY(verifyLoad(QSL("PathSyntax-ServiceWorkersAllowed:/resources/serviceWorker.html"))); + QTRY_VERIFY(eval(QSL("done")).toBool()); + QVERIFY(eval(QSL("error")).toString() + .contains(QSL("Cannot read property 'register' of undefined"))); + + QVERIFY(verifyLoad(QSL("PathSyntax-Secure-ServiceWorkersAllowed:/resources/serviceWorker.html"))); + QTRY_VERIFY(eval(QSL("done")).toBool()); + QCOMPARE(eval(QSL("error")), QVariant()); + + QVERIFY(verifyLoad(QSL("PathSyntax-NoAccessAllowed:/resources/serviceWorker.html"))); + QTRY_VERIFY(eval(QSL("done")).toBool()); + QVERIFY(eval(QSL("error")).toString() + .contains(QSL("Cannot read property 'register' of undefined"))); +} + +// Support for view-source must be enabled explicitly. +void tst_Origins::viewSource() +{ + QVERIFY(verifyLoad("view-source:file:" + QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + + "/resources/viewSource.html")); +#ifdef Q_OS_WIN + QCOMPARE(m_page->requestedUrl().toString(), + "file:///" + QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + + "/resources/viewSource.html"); +#else + QCOMPARE(m_page->requestedUrl().toString(), + "file://" + QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + + "/resources/viewSource.html"); +#endif + + QVERIFY(verifyLoad(QSL("view-source:qrc:/resources/viewSource.html"))); + QCOMPARE(m_page->requestedUrl().toString(), QSL("qrc:/resources/viewSource.html")); + + QVERIFY(verifyLoad(QSL("view-source:tst:/resources/viewSource.html"))); + QCOMPARE(m_page->requestedUrl().toString(), QSL("about:blank")); + + QVERIFY(verifyLoad(QSL("view-source:PathSyntax:/resources/viewSource.html"))); + QCOMPARE(m_page->requestedUrl().toString(), QSL("about:blank")); + + QVERIFY(verifyLoad(QSL("view-source:PathSyntax-ViewSourceAllowed:/resources/viewSource.html"))); + QCOMPARE(m_page->requestedUrl().toString(), QSL("pathsyntax-viewsourceallowed:/resources/viewSource.html")); +} + +void tst_Origins::createObjectURL() +{ + // Legal for registered custom schemes. + QVERIFY(verifyLoad(QSL("qrc:/resources/createObjectURL.html"))); + QVERIFY(eval(QSL("result")).toString().startsWith(QSL("blob:qrc:"))); + + // Also legal for unregistered schemes (since Chromium 71) + QVERIFY(verifyLoad(QSL("tst:/resources/createObjectURL.html"))); + QVERIFY(eval(QSL("result")).toString().startsWith(QSL("blob:tst:"))); +} + +void tst_Origins::redirect() +{ + QVERIFY(verifyLoad(QSL("redirect1:/resources/redirect.html"))); + QTRY_COMPARE(m_handler->requests().size(), 7); + QCOMPARE(m_handler->requests()[0], QUrl(QStringLiteral("redirect1:/resources/redirect.html"))); + QCOMPARE(m_handler->requests()[1], QUrl(QStringLiteral("redirect2:/resources/redirect.html"))); + QCOMPARE(m_handler->requests()[2], QUrl(QStringLiteral("redirect1:/resources/redirect.css"))); + QCOMPARE(m_handler->requests()[3], QUrl(QStringLiteral("redirect2:/resources/redirect.css"))); + QCOMPARE(m_handler->requests()[4], QUrl(QStringLiteral("redirect1:/resources/Akronim-Regular.woff2"))); + QCOMPARE(m_handler->requests()[5], QUrl(QStringLiteral("redirect1:/resources/Akronim-Regular.woff2"))); + QCOMPARE(m_handler->requests()[6], QUrl(QStringLiteral("redirect2:/resources/Akronim-Regular.woff2"))); +} + +QTEST_MAIN(tst_Origins) +#include "tst_origins.moc" diff --git a/tests/auto/core/origins/tst_origins.qrc b/tests/auto/core/origins/tst_origins.qrc new file mode 100644 index 000000000..fcf54aaea --- /dev/null +++ b/tests/auto/core/origins/tst_origins.qrc @@ -0,0 +1,22 @@ + + + + resources/createObjectURL.html + resources/dedicatedWorker.html + resources/dedicatedWorker.js + resources/mixedSchemes.html + resources/mixedSchemesWithCsp.html + resources/mixedSchemes_frame.html + resources/mixedXHR.html + resources/mixedXHR.txt + resources/serviceWorker.html + resources/serviceWorker.js + resources/sharedWorker.html + resources/sharedWorker.js + resources/subdir/frame2.html + resources/subdir/index.html + resources/subdir_frame1.html + resources/viewSource.html + resources/websocket.html + + diff --git a/tests/auto/core/qwebenginecookiestore/CMakeLists.txt b/tests/auto/core/qwebenginecookiestore/CMakeLists.txt index 6125b4f12..33ba5ff1a 100644 --- a/tests/auto/core/qwebenginecookiestore/CMakeLists.txt +++ b/tests/auto/core/qwebenginecookiestore/CMakeLists.txt @@ -5,7 +5,7 @@ qt_internal_add_test(tst_qwebenginecookiestore SOURCES tst_qwebenginecookiestore.cpp LIBRARIES - Qt::WebEngineWidgets + Qt::WebEngineCore Test::HttpServer Test::Util ) diff --git a/tests/auto/core/qwebenginesettings/BLACKLIST b/tests/auto/core/qwebenginesettings/BLACKLIST new file mode 100644 index 000000000..d4a35a76a --- /dev/null +++ b/tests/auto/core/qwebenginesettings/BLACKLIST @@ -0,0 +1,2 @@ +[javascriptClipboard] +ubuntu-20.04 diff --git a/tests/auto/core/qwebenginesettings/CMakeLists.txt b/tests/auto/core/qwebenginesettings/CMakeLists.txt new file mode 100644 index 000000000..7f8b49d1b --- /dev/null +++ b/tests/auto/core/qwebenginesettings/CMakeLists.txt @@ -0,0 +1,9 @@ +include(../../util/util.cmake) + +qt_internal_add_test(tst_qwebenginesettings + SOURCES + tst_qwebenginesettings.cpp + LIBRARIES + Qt::WebEngineCore + Test::Util +) diff --git a/tests/auto/core/qwebenginesettings/qwebenginesettings.pro b/tests/auto/core/qwebenginesettings/qwebenginesettings.pro new file mode 100644 index 000000000..70786e70f --- /dev/null +++ b/tests/auto/core/qwebenginesettings/qwebenginesettings.pro @@ -0,0 +1,2 @@ +include(../tests.pri) +QT *= core-private gui-private diff --git a/tests/auto/core/qwebenginesettings/tst_qwebenginesettings.cpp b/tests/auto/core/qwebenginesettings/tst_qwebenginesettings.cpp new file mode 100644 index 000000000..4220f496b --- /dev/null +++ b/tests/auto/core/qwebenginesettings/tst_qwebenginesettings.cpp @@ -0,0 +1,198 @@ +/* + Copyright (C) 2015 The Qt Company Ltd. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include + +#include + +#include +#include +#include + +#include +#include + +class tst_QWebEngineSettings: public QObject { + Q_OBJECT + +private Q_SLOTS: + void resetAttributes(); + void defaultFontFamily_data(); + void defaultFontFamily(); + void javascriptClipboard_data(); + void javascriptClipboard(); + void setInAcceptNavigationRequest(); +}; + +void tst_QWebEngineSettings::resetAttributes() +{ + QWebEngineProfile profile; + QWebEngineSettings *settings = profile.settings(); + + // Attribute + bool defaultValue = settings->testAttribute(QWebEngineSettings::FullScreenSupportEnabled); + settings->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, !defaultValue); + QCOMPARE(!defaultValue, settings->testAttribute(QWebEngineSettings::FullScreenSupportEnabled)); + settings->resetAttribute(QWebEngineSettings::FullScreenSupportEnabled); + QCOMPARE(defaultValue, settings->testAttribute(QWebEngineSettings::FullScreenSupportEnabled)); + + // Font family + QString defaultFamily = settings->fontFamily(QWebEngineSettings::StandardFont); + QString newFontFamily("PugDog"); + settings->setFontFamily(QWebEngineSettings::StandardFont, newFontFamily); + QCOMPARE(newFontFamily, settings->fontFamily(QWebEngineSettings::StandardFont)); + settings->resetFontFamily(QWebEngineSettings::StandardFont); + QCOMPARE(defaultFamily, settings->fontFamily(QWebEngineSettings::StandardFont)); + + // Font size + int defaultSize = settings->fontSize(QWebEngineSettings::MinimumFontSize); + int newSize = defaultSize + 10; + settings->setFontSize(QWebEngineSettings::MinimumFontSize, newSize); + QCOMPARE(newSize, settings->fontSize(QWebEngineSettings::MinimumFontSize)); + settings->resetFontSize(QWebEngineSettings::MinimumFontSize); + QCOMPARE(defaultSize, settings->fontSize(QWebEngineSettings::MinimumFontSize)); +} + +void tst_QWebEngineSettings::defaultFontFamily_data() +{ + QTest::addColumn("fontFamily"); + + QTest::newRow("StandardFont") << static_cast(QWebEngineSettings::StandardFont); + QTest::newRow("FixedFont") << static_cast(QWebEngineSettings::FixedFont); + QTest::newRow("SerifFont") << static_cast(QWebEngineSettings::SerifFont); + QTest::newRow("SansSerifFont") << static_cast(QWebEngineSettings::SansSerifFont); + QTest::newRow("CursiveFont") << static_cast(QWebEngineSettings::CursiveFont); + QTest::newRow("FantasyFont") << static_cast(QWebEngineSettings::FantasyFont); +} + +void tst_QWebEngineSettings::defaultFontFamily() +{ + QWebEngineProfile profile; + QWebEngineSettings *settings = profile.settings(); + + QFETCH(int, fontFamily); + QVERIFY(!settings->fontFamily(static_cast(fontFamily)).isEmpty()); +} + +void tst_QWebEngineSettings::javascriptClipboard_data() +{ + QTest::addColumn("javascriptCanAccessClipboard"); + QTest::addColumn("javascriptCanPaste"); + QTest::addColumn("copyResult"); + QTest::addColumn("pasteResult"); + + QTest::newRow("default") << false << false << false << false; + QTest::newRow("canCopy") << true << false << true << false; + // paste command requires both permissions + QTest::newRow("canPaste") << false << true << false << false; + QTest::newRow("canCopyAndPaste") << true << true << true << true; +} + +void tst_QWebEngineSettings::javascriptClipboard() +{ + QFETCH(bool, javascriptCanAccessClipboard); + QFETCH(bool, javascriptCanPaste); + QFETCH(bool, copyResult); + QFETCH(bool, pasteResult); + + QWebEnginePage page; + + // check defaults + QCOMPARE(page.settings()->testAttribute(QWebEngineSettings::JavascriptCanAccessClipboard), + false); + QCOMPARE(page.settings()->testAttribute(QWebEngineSettings::JavascriptCanPaste), false); + + // check accessors + page.settings()->setAttribute(QWebEngineSettings::JavascriptCanAccessClipboard, + javascriptCanAccessClipboard); + page.settings()->setAttribute(QWebEngineSettings::JavascriptCanPaste, + javascriptCanPaste); + QCOMPARE(page.settings()->testAttribute(QWebEngineSettings::JavascriptCanAccessClipboard), + javascriptCanAccessClipboard); + QCOMPARE(page.settings()->testAttribute(QWebEngineSettings::JavascriptCanPaste), + javascriptCanPaste); + + QSignalSpy loadFinishedSpy(&page, SIGNAL(loadFinished(bool))); + page.setHtml("" + "" + ""); + QVERIFY(loadFinishedSpy.wait()); + + // make sure that 'OriginalText' is selected + evaluateJavaScriptSync(&page, "document.getElementById('myInput').select()"); + QCOMPARE(evaluateJavaScriptSync(&page, "window.getSelection().toString()").toString(), + QStringLiteral("OriginalText")); + + // Check that the actual settings work by the + // - return value of queryCommandEnabled and + // - return value of execCommand + // - comparing the clipboard / input field + QGuiApplication::clipboard()->clear(); + QCOMPARE(evaluateJavaScriptSync(&page, "document.queryCommandEnabled('copy')").toBool(), + copyResult); + QCOMPARE(evaluateJavaScriptSync(&page, "document.execCommand('copy')").toBool(), copyResult); + QTRY_COMPARE(QGuiApplication::clipboard()->text(), + (copyResult ? QString("OriginalText") : QString())); + + + QGuiApplication::clipboard()->setText("AnotherText"); + QCOMPARE(evaluateJavaScriptSync(&page, "document.queryCommandEnabled('paste')").toBool(), + pasteResult); + QCOMPARE(evaluateJavaScriptSync(&page, "document.execCommand('paste')").toBool(), pasteResult); + QCOMPARE(evaluateJavaScriptSync(&page, "document.getElementById('myInput').value").toString(), + (pasteResult ? QString("AnotherText") : QString("OriginalText"))); +} + +class NavigationRequestOverride : public QWebEnginePage +{ +protected: + bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) override + { + Q_UNUSED(type); + + if (isMainFrame && url.scheme().startsWith("data")) + settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, true); + // TODO: note this setting is flaky, consider settings().commit() + return true; + } +}; + +void tst_QWebEngineSettings::setInAcceptNavigationRequest() +{ + NavigationRequestOverride page; + QSignalSpy loadFinishedSpy(&page, SIGNAL(loadFinished(bool))); + QWebEngineProfile::defaultProfile()->settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, false); + QVERIFY(!page.settings()->testAttribute(QWebEngineSettings::JavascriptEnabled)); + + page.load(QUrl("about:blank")); + QVERIFY(loadFinishedSpy.wait()); + QVERIFY(!page.settings()->testAttribute(QWebEngineSettings::JavascriptEnabled)); + + page.setHtml("" + "" + "" + ""); + QVERIFY(loadFinishedSpy.wait()); + QVERIFY(page.settings()->testAttribute(QWebEngineSettings::JavascriptEnabled)); + QCOMPARE(toPlainTextSync(&page), QStringLiteral("PASS")); +} + +QTEST_MAIN(tst_QWebEngineSettings) + +#include "tst_qwebenginesettings.moc" diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/CMakeLists.txt b/tests/auto/core/qwebengineurlrequestinterceptor/CMakeLists.txt index 96a06c1b9..0f8d90a08 100644 --- a/tests/auto/core/qwebengineurlrequestinterceptor/CMakeLists.txt +++ b/tests/auto/core/qwebengineurlrequestinterceptor/CMakeLists.txt @@ -5,7 +5,7 @@ qt_internal_add_test(tst_qwebengineurlrequestinterceptor SOURCES tst_qwebengineurlrequestinterceptor.cpp LIBRARIES - Qt::WebEngineWidgets + Qt::WebEngineCore Test::HttpServer Test::Util ) diff --git a/tests/auto/core/tests.pri b/tests/auto/core/tests.pri index 59d6c0865..2f34f1735 100644 --- a/tests/auto/core/tests.pri +++ b/tests/auto/core/tests.pri @@ -10,7 +10,7 @@ INCLUDEPATH += $$PWD exists($$_PRO_FILE_PWD_/$${TARGET}.qrc): RESOURCES += $${TARGET}.qrc -QT += testlib network webenginewidgets widgets +QT += testlib network webenginecore # This define is used by some tests to look up resources in the source tree DEFINES += TESTS_SOURCE_DIR=\\\"$$PWD/\\\" -- cgit v1.2.3