From f7949df24319cda7363aed354ca6d60dc6512788 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 8 Apr 2019 09:58:08 +0200 Subject: tst_QUrl: Fix left-over temporary directory on Windows The test changes the current directory to the test directory in fromUserInputWithCwd(), but did not restore it, causing: Totals 898 passed, 0 failed, 1 skipped, 0 blacklisted, 368ms ********* Finished testing of tst_QUrl ********* QTemporaryDir Unable to remove "C:\\TEMP\\tst_qurl-ryVxqu" most likely due to the presence of read-only files. Restore the old directory at the end to fix this. Change-Id: I62669868f3c6d97dd38ebac76515428c14b7e1e7 Reviewed-by: David Faure --- tests/auto/corelib/io/qurl/tst_qurl.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'tests/auto') diff --git a/tests/auto/corelib/io/qurl/tst_qurl.cpp b/tests/auto/corelib/io/qurl/tst_qurl.cpp index 4f173d2dfd..d697dae9dd 100644 --- a/tests/auto/corelib/io/qurl/tst_qurl.cpp +++ b/tests/auto/corelib/io/qurl/tst_qurl.cpp @@ -47,6 +47,7 @@ class tst_QUrl : public QObject private slots: void initTestCase(); + void cleanupTestCase(); void effectiveTLDs_data(); void effectiveTLDs(); void getSetCheck(); @@ -188,6 +189,7 @@ private slots: private: void testThreadingHelper(); + const QString m_currentPath = QDir::currentPath(); QTemporaryDir m_tempDir; }; @@ -196,6 +198,12 @@ void tst_QUrl::initTestCase() QVERIFY2(m_tempDir.isValid(), qPrintable(m_tempDir.errorString())); } +void tst_QUrl::cleanupTestCase() +{ + // Restore working directory changed in fromUserInputWithCwd() + QDir::setCurrent(m_currentPath); +} + // Testing get/set functions void tst_QUrl::getSetCheck() { -- cgit v1.2.3 From 4b445481c37836e2870a5717e05d575398341483 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Thu, 28 Mar 2019 16:14:59 +0100 Subject: tst_http2 - extend 'singleRequest' test case MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit to test different h2 modes: "h2c" (clear text with protocol upgrade), "h2" (encrypted, negotiating via ALPN extension), "h2-direct" (encrypted, no ALPN), "h2c-direct" (plain text, no protocol upgrade). This patch-set is an amendment to the recent fix in the protocol handler where we were crashing in "h2c-direct" mode. Change-Id: I3ff5ed1396a59b72b59a95f927d404ccd202d0b8 Reviewed-by: Timur Pocheptsov Reviewed-by: MÃ¥rten Nordheim --- tests/auto/network/access/http2/http2srv.cpp | 55 +++++++++------- tests/auto/network/access/http2/http2srv.h | 15 ++++- tests/auto/network/access/http2/tst_http2.cpp | 93 +++++++++++++++++++++------ 3 files changed, 119 insertions(+), 44 deletions(-) (limited to 'tests/auto') diff --git a/tests/auto/network/access/http2/http2srv.cpp b/tests/auto/network/access/http2/http2srv.cpp index 6e2220fa67..5a99d4e50c 100644 --- a/tests/auto/network/access/http2/http2srv.cpp +++ b/tests/auto/network/access/http2/http2srv.cpp @@ -76,11 +76,15 @@ void fill_push_header(const HttpHeader &originalRequest, HttpHeader &promisedReq } -Http2Server::Http2Server(bool h2c, const Http2::RawSettings &ss, const Http2::RawSettings &cs) - : serverSettings(ss), - expectedClientSettings(cs), - clearTextHTTP2(h2c) +Http2Server::Http2Server(H2Type type, const Http2::RawSettings &ss, const Http2::RawSettings &cs) + : connectionType(type), + serverSettings(ss), + expectedClientSettings(cs) { +#if !QT_CONFIG(ssl) + Q_ASSERT(type != H2Type::h2Alpn && type != H2Type::h2Direct); +#endif + responseBody = "\n" "\n" "Sample \"Hello, World\" Application\n" @@ -129,15 +133,15 @@ void Http2Server::redirectOpenStream(quint16 port) targetPort = port; } +bool Http2Server::isClearText() const +{ + return connectionType == H2Type::h2c || connectionType == H2Type::h2cDirect; +} + void Http2Server::startServer() { -#ifdef QT_NO_SSL - // Let the test fail with timeout. - if (!clearTextHTTP2) - return; -#endif if (listen()) { - if (clearTextHTTP2) + if (isClearText()) authority = QStringLiteral("127.0.0.1:%1").arg(serverPort()).toLatin1(); emit serverStarted(serverPort()); } @@ -146,7 +150,7 @@ void Http2Server::startServer() bool Http2Server::sendProtocolSwitchReply() { Q_ASSERT(socket); - Q_ASSERT(clearTextHTTP2 && upgradeProtocol); + Q_ASSERT(connectionType == H2Type::h2c); // The first and the last HTTP/1.1 response we send: const char response[] = "HTTP/1.1 101 Switching Protocols\r\n" "Connection: Upgrade\r\n" @@ -262,25 +266,28 @@ void Http2Server::sendWINDOW_UPDATE(quint32 streamID, quint32 delta) void Http2Server::incomingConnection(qintptr socketDescriptor) { - if (clearTextHTTP2) { + if (isClearText()) { socket.reset(new QTcpSocket); const bool set = socket->setSocketDescriptor(socketDescriptor); Q_ASSERT(set); // Stop listening: close(); - upgradeProtocol = true; + upgradeProtocol = connectionType == H2Type::h2c; QMetaObject::invokeMethod(this, "connectionEstablished", Qt::QueuedConnection); } else { -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) socket.reset(new QSslSocket); QSslSocket *sslSocket = static_cast(socket.data()); - // Add HTTP2 as supported protocol: - auto conf = QSslConfiguration::defaultConfiguration(); - auto protos = conf.allowedNextProtocols(); - protos.prepend(QSslConfiguration::ALPNProtocolHTTP2); - conf.setAllowedNextProtocols(protos); - sslSocket->setSslConfiguration(conf); + + if (connectionType == H2Type::h2Alpn) { + // Add HTTP2 as supported protocol: + auto conf = QSslConfiguration::defaultConfiguration(); + auto protos = conf.allowedNextProtocols(); + protos.prepend(QSslConfiguration::ALPNProtocolHTTP2); + conf.setAllowedNextProtocols(protos); + sslSocket->setSslConfiguration(conf); + } // SSL-related setup ... sslSocket->setPeerVerifyMode(QSslSocket::VerifyNone); sslSocket->setProtocol(QSsl::TlsV1_2OrLater); @@ -299,7 +306,7 @@ void Http2Server::incomingConnection(qintptr socketDescriptor) connect(sslSocket, SIGNAL(encrypted()), this, SLOT(connectionEstablished())); sslSocket->startServerEncryption(); #else - Q_UNREACHABLE(); + Q_ASSERT(0); #endif } } @@ -377,7 +384,7 @@ void Http2Server::connectionEstablished() { using namespace Http2; - if (testingGOAWAY && !clearTextHTTP2) + if (testingGOAWAY && !isClearText()) return triggerGOAWAYEmulation(); // For clearTextHTTP2 we first have to respond with 'protocol switch' @@ -392,7 +399,7 @@ void Http2Server::connectionEstablished() waitingClientSettings = false; settingsSent = false; - if (clearTextHTTP2) { + if (connectionType == H2Type::h2c) { requestLine.clear(); // Now we have to handle HTTP/1.1 request. We use Get/Post in our test, // so set requestType to something unsupported: @@ -818,7 +825,7 @@ void Http2Server::sendResponse(quint32 streamID, bool emptyBody) Q_ASSERT(targetPort); header.push_back({":status", "308"}); const QString url("%1://localhost:%2/"); - header.push_back({"location", url.arg(clearTextHTTP2 ? QStringLiteral("http") : QStringLiteral("https"), + header.push_back({"location", url.arg(isClearText() ? QStringLiteral("http") : QStringLiteral("https"), QString::number(targetPort)).toLatin1()}); } else { diff --git a/tests/auto/network/access/http2/http2srv.h b/tests/auto/network/access/http2/http2srv.h index ae3f084fdc..4ef4b25101 100644 --- a/tests/auto/network/access/http2/http2srv.h +++ b/tests/auto/network/access/http2/http2srv.h @@ -62,21 +62,32 @@ public: Q_DECLARE_PRIVATE(Http11Reply) }; +enum class H2Type { + h2Alpn, // Secure connection, ALPN to negotiate h2. + h2c, // Clear text with protocol upgrade. + h2Direct, // Secure connection, ALPN not supported. + h2cDirect, // Clear text direct +}; + class Http2Server : public QTcpServer { Q_OBJECT public: - Http2Server(bool clearText, const Http2::RawSettings &serverSettings, + + Http2Server(H2Type type, const Http2::RawSettings &serverSettings, const Http2::RawSettings &clientSettings); ~Http2Server(); + // To be called before server started: void enablePushPromise(bool enabled, const QByteArray &path = QByteArray()); void setResponseBody(const QByteArray &body); void emulateGOAWAY(int timeout); void redirectOpenStream(quint16 targetPort); + bool isClearText() const; + // Invokables, since we can call them from the main thread, // but server (can) work on its own thread. Q_INVOKABLE void startServer(); @@ -129,6 +140,7 @@ private: QScopedPointer socket; + H2Type connectionType = H2Type::h2Alpn; // Connection preface: bool waitingClientPreface = false; bool waitingClientSettings = false; @@ -170,7 +182,6 @@ private: quint32 streamRecvWindowSize = Http2::defaultSessionWindowSize; QByteArray responseBody; - bool clearTextHTTP2 = false; bool pushPromiseEnabled = false; quint32 lastPromisedStream = 0; QByteArray pushPath; diff --git a/tests/auto/network/access/http2/tst_http2.cpp b/tests/auto/network/access/http2/tst_http2.cpp index 52e98c1fc1..9ca7c892f7 100644 --- a/tests/auto/network/access/http2/tst_http2.cpp +++ b/tests/auto/network/access/http2/tst_http2.cpp @@ -59,6 +59,9 @@ const bool clearTextHTTP2 = false; const bool clearTextHTTP2 = true; #endif +Q_DECLARE_METATYPE(H2Type) +Q_DECLARE_METATYPE(QNetworkRequest::Attribute) + QT_BEGIN_NAMESPACE class tst_Http2 : public QObject @@ -69,6 +72,7 @@ public: ~tst_Http2(); private slots: // Tests: + void singleRequest_data(); void singleRequest(); void multipleRequests(); void flowControlClientSide(); @@ -100,13 +104,13 @@ private: // small payload. void runEventLoop(int ms = 5000); void stopEventLoop(); - Http2Server *newServer(const Http2::RawSettings &serverSettings, + Http2Server *newServer(const Http2::RawSettings &serverSettings, H2Type connectionType, const Http2::ProtocolParameters &clientSettings = {}); // Send a get or post request, depending on a payload (empty or not). void sendRequest(int streamNumber, QNetworkRequest::Priority priority = QNetworkRequest::NormalPriority, const QByteArray &payload = QByteArray()); - QUrl requestUrl() const; + QUrl requestUrl(H2Type connnectionType) const; quint16 serverPort = 0; QThread *workerThread = nullptr; @@ -143,6 +147,11 @@ struct ServerDeleter using ServerPtr = QScopedPointer; +H2Type defaultConnectionType() +{ + return clearTextHTTP2 ? H2Type::h2c : H2Type::h2Alpn; +} + } // unnamed namespace tst_Http2::tst_Http2() @@ -164,25 +173,59 @@ tst_Http2::~tst_Http2() } } +void tst_Http2::singleRequest_data() +{ + QTest::addColumn("h2Attribute"); + QTest::addColumn("connectionType"); + + // 'Clear text' that should always work, either via the protocol upgrade + // or as direct. + QTest::addRow("h2c-upgrade") << QNetworkRequest::HTTP2AllowedAttribute << H2Type::h2c; + QTest::addRow("h2c-direct") << QNetworkRequest::Http2DirectAttribute << H2Type::h2cDirect; + + if (!clearTextHTTP2) { + // Qt with TLS where TLS-backend supports ALPN. + QTest::addRow("h2-ALPN") << QNetworkRequest::HTTP2AllowedAttribute << H2Type::h2Alpn; + } + +#if QT_CONFIG(ssl) + QTest::addRow("h2-direct") << QNetworkRequest::Http2DirectAttribute << H2Type::h2Direct; +#endif +} + void tst_Http2::singleRequest() { clearHTTP2State(); +#if QT_CONFIG(securetransport) + // Normally on macOS we use plain text only for SecureTransport + // does not support ALPN on the server side. With 'direct encrytped' + // we have to use TLS sockets (== private key) and thus suppress a + // keychain UI asking for permission to use a private key. + // Our CI has this, but somebody testing locally - will have a problem. + qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", QByteArray("1")); + auto envRollback = qScopeGuard([](){ + qunsetenv("QT_SSL_USE_TEMPORARY_KEYCHAIN"); + }); +#endif + serverPort = 0; nRequests = 1; - ServerPtr srv(newServer(defaultServerSettings)); + QFETCH(const H2Type, connectionType); + ServerPtr srv(newServer(defaultServerSettings, connectionType)); QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection); runEventLoop(); QVERIFY(serverPort != 0); - auto url = requestUrl(); + auto url = requestUrl(connectionType); url.setPath("/index.html"); QNetworkRequest request(url); - request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, QVariant(true)); + QFETCH(const QNetworkRequest::Attribute, h2Attribute); + request.setAttribute(h2Attribute, QVariant(true)); auto reply = manager.get(request); connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished); @@ -207,7 +250,7 @@ void tst_Http2::multipleRequests() serverPort = 0; nRequests = 10; - ServerPtr srv(newServer(defaultServerSettings)); + ServerPtr srv(newServer(defaultServerSettings, defaultConnectionType())); QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection); @@ -258,7 +301,7 @@ void tst_Http2::flowControlClientSide() manager.setProperty(Http2::http2ParametersPropertyName, QVariant::fromValue(params)); const Http2::RawSettings serverSettings = {{Settings::MAX_CONCURRENT_STREAMS_ID, quint32(3)}}; - ServerPtr srv(newServer(serverSettings, params)); + ServerPtr srv(newServer(serverSettings, defaultConnectionType(), params)); const QByteArray respond(int(Http2::defaultSessionWindowSize * 10), 'x'); @@ -300,7 +343,7 @@ void tst_Http2::flowControlServerSide() const Http2::RawSettings serverSettings = {{Settings::MAX_CONCURRENT_STREAMS_ID, 7}}; - ServerPtr srv(newServer(serverSettings)); + ServerPtr srv(newServer(serverSettings, defaultConnectionType())); const QByteArray payload(int(Http2::defaultSessionWindowSize * 500), 'x'); @@ -335,7 +378,7 @@ void tst_Http2::pushPromise() params.settingsFrameData[Settings::ENABLE_PUSH_ID] = 1; manager.setProperty(Http2::http2ParametersPropertyName, QVariant::fromValue(params)); - ServerPtr srv(newServer(defaultServerSettings, params)); + ServerPtr srv(newServer(defaultServerSettings, defaultConnectionType(), params)); srv->enablePushPromise(true, QByteArray("/script.js")); QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection); @@ -343,7 +386,7 @@ void tst_Http2::pushPromise() QVERIFY(serverPort != 0); - auto url = requestUrl(); + auto url = requestUrl(defaultConnectionType()); url.setPath("/index.html"); QNetworkRequest request(url); @@ -409,14 +452,14 @@ void tst_Http2::goaway() serverPort = 0; nRequests = 3; - ServerPtr srv(newServer(defaultServerSettings)); + ServerPtr srv(newServer(defaultServerSettings, defaultConnectionType())); srv->emulateGOAWAY(responseTimeoutMS); QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection); runEventLoop(); QVERIFY(serverPort != 0); - auto url = requestUrl(); + auto url = requestUrl(defaultConnectionType()); // We have to store these replies, so that we can check errors later. std::vector replies(nRequests); for (int i = 0; i < nRequests; ++i) { @@ -456,7 +499,7 @@ void tst_Http2::earlyResponse() serverPort = 0; nRequests = 1; - ServerPtr targetServer(newServer(defaultServerSettings)); + ServerPtr targetServer(newServer(defaultServerSettings, defaultConnectionType())); QMetaObject::invokeMethod(targetServer.data(), "startServer", Qt::QueuedConnection); runEventLoop(); @@ -466,7 +509,7 @@ void tst_Http2::earlyResponse() const quint16 targetPort = serverPort; serverPort = 0; - ServerPtr redirector(newServer(defaultServerSettings)); + ServerPtr redirector(newServer(defaultServerSettings, defaultConnectionType())); redirector->redirectOpenStream(targetPort); QMetaObject::invokeMethod(redirector.data(), "startServer", Qt::QueuedConnection); @@ -506,11 +549,11 @@ void tst_Http2::stopEventLoop() eventLoop.exitLoop(); } -Http2Server *tst_Http2::newServer(const Http2::RawSettings &serverSettings, +Http2Server *tst_Http2::newServer(const Http2::RawSettings &serverSettings, H2Type connectionType, const Http2::ProtocolParameters &clientSettings) { using namespace Http2; - auto srv = new Http2Server(clearTextHTTP2, serverSettings, + auto srv = new Http2Server(connectionType, serverSettings, clientSettings.settingsFrameData); using Srv = Http2Server; @@ -535,7 +578,7 @@ void tst_Http2::sendRequest(int streamNumber, QNetworkRequest::Priority priority, const QByteArray &payload) { - auto url = requestUrl(); + auto url = requestUrl(defaultConnectionType()); url.setPath(QString("/stream%1.html").arg(streamNumber)); QNetworkRequest request(url); @@ -554,10 +597,24 @@ void tst_Http2::sendRequest(int streamNumber, connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished); } -QUrl tst_Http2::requestUrl() const +QUrl tst_Http2::requestUrl(H2Type connectionType) const { +#if !QT_CONFIG(ssl) + Q_ASSERT(connectionType != H2Type::h2Alpn && connectionType != H2Type::h2Direct); +#endif static auto url = QUrl(QLatin1String(clearTextHTTP2 ? "http://127.0.0.1" : "https://127.0.0.1")); url.setPort(serverPort); + // Clear text may mean no-TLS-at-all or crappy-TLS-without-ALPN. + switch (connectionType) { + case H2Type::h2Alpn: + case H2Type::h2Direct: + url.setScheme(QStringLiteral("https")); + break; + case H2Type::h2c: + case H2Type::h2cDirect: + url.setScheme(QStringLiteral("http")); + break; + } return url; } -- cgit v1.2.3 From 5f2afe18ccb0bbe258d4016ef65218cd3656cac2 Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Tue, 9 Apr 2019 13:38:06 +0200 Subject: Fix QMetaObject::newInstance on non-QObject meta object QMetaObject::newInstance returns a QObject, thus it's not possible to create a new instance of a Q_GADGET using this function. Previously, we returned a non-null QObject pointer for such scenarios, which then leads to crashes when one tries to use it. Now, we check whether the meta object inherits QObject's meta object, and error out early otherwise. Change-Id: I7b1fb6c8d48b3e98161894be2f281a491963345e Reviewed-by: Thiago Macieira --- tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'tests/auto') diff --git a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp index 9855bec520..cfe1443fd3 100644 --- a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp +++ b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp @@ -40,6 +40,13 @@ struct MyStruct int i; }; +class MyGadget +{ + Q_GADGET +public: + Q_INVOKABLE MyGadget() {} +}; + namespace MyNamespace { // Used in tst_QMetaObject::checkScope class MyClass : public QObject @@ -1207,6 +1214,12 @@ void tst_QMetaObject::invokeMetaConstructor() QCOMPARE(obj2->parent(), (QObject*)&obj); QVERIFY(qobject_cast(obj2) != 0); } + // gadget shouldn't return a valid pointer + { + QCOMPARE(MyGadget::staticMetaObject.constructorCount(), 1); + QTest::ignoreMessage(QtWarningMsg, "QMetaObject::newInstance: type MyGadget does not inherit QObject"); + QVERIFY(!MyGadget::staticMetaObject.newInstance()); + } } void tst_QMetaObject::invokeTypedefTypes() -- cgit v1.2.3