summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSylvain Garcia <garcia.6l20@gmail.com>2019-09-26 14:27:07 +0200
committerSylvain Garcia <garcia.6l20@gmail.com>2019-10-04 17:16:09 +0200
commitf04a6809b1d83bb7c0ae0f42251d3a31510f1be9 (patch)
tree37ba38933e9d671faab80980df06190809b61daa
parent73175545e69cc5f07a7a1447a6b8c4c74d9795c8 (diff)
HTTPS support
Added new `QAbstractHttpServer::sslSetup` which enables HTTPS usage. Added new `QSslServer` which inherits from `QTcpServer` and configures incoming TCP clients to use SSL. [ChangeLog][QHttpServer][Https support] Https support added to QAbstractHttpServer class Change-Id: I536cf48b86b246e3f4b9d960f793b93670afe06f Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io> Reviewed-by: Guy Poizat <gerrit.qt@gmail.com> Reviewed-by: Mikhail Svetkin <mikhail.svetkin@gmail.com>
-rw-r--r--src/httpserver/httpserver.pro1
-rw-r--r--src/httpserver/qabstracthttpserver.cpp29
-rw-r--r--src/httpserver/qabstracthttpserver.h12
-rw-r--r--src/httpserver/qabstracthttpserver_p.h5
-rw-r--r--src/src.pro7
-rw-r--r--src/sslserver/qsslserver.cpp73
-rw-r--r--src/sslserver/qsslserver.h62
-rw-r--r--src/sslserver/qsslserver_p.h46
-rw-r--r--src/sslserver/qtsslserverglobal.h49
-rw-r--r--src/sslserver/sslserver.pro14
-rw-r--r--sync.profile1
-rw-r--r--tests/auto/auto.pro2
-rw-r--r--tests/auto/qhttpserver/tst_qhttpserver.cpp261
13 files changed, 512 insertions, 50 deletions
diff --git a/src/httpserver/httpserver.pro b/src/httpserver/httpserver.pro
index 1ba716b..20f567f 100644
--- a/src/httpserver/httpserver.pro
+++ b/src/httpserver/httpserver.pro
@@ -4,6 +4,7 @@ INCLUDEPATH += .
QT = network core-private
qtHaveModule(websockets): QT += websockets-private
+qtConfig(ssl): QT += sslserver
HEADERS += \
qthttpserverglobal.h \
diff --git a/src/httpserver/qabstracthttpserver.cpp b/src/httpserver/qabstracthttpserver.cpp
index 1ccd91d..26e6e97 100644
--- a/src/httpserver/qabstracthttpserver.cpp
+++ b/src/httpserver/qabstracthttpserver.cpp
@@ -148,11 +148,20 @@ QAbstractHttpServer::QAbstractHttpServer(QAbstractHttpServerPrivate &dd, QObject
*/
int QAbstractHttpServer::listen(const QHostAddress &address, quint16 port)
{
+#if QT_CONFIG(ssl)
+ Q_D(QAbstractHttpServer);
+ QTcpServer *tcpServer = d->sslEnabled ? new QSslServer(d->sslConfiguration, this)
+ : new QTcpServer(this);
+#else
auto tcpServer = new QTcpServer(this);
+#endif
const auto listening = tcpServer->listen(address, port);
if (listening) {
bind(tcpServer);
return tcpServer->serverPort();
+ } else {
+ qCCritical(lcHttpServer, "listen failed: %s",
+ tcpServer->errorString().toStdString().c_str());
}
delete tcpServer;
@@ -254,4 +263,24 @@ QHttpServerResponder QAbstractHttpServer::makeResponder(const QHttpServerRequest
return QHttpServerResponder(request, socket);
}
+#if QT_CONFIG(ssl)
+void QAbstractHttpServer::sslSetup(const QSslCertificate &certificate,
+ const QSslKey &privateKey,
+ QSsl::SslProtocol protocol)
+{
+ QSslConfiguration conf;
+ conf.setLocalCertificate(certificate);
+ conf.setPrivateKey(privateKey);
+ conf.setProtocol(protocol);
+ sslSetup(conf);
+}
+
+void QAbstractHttpServer::sslSetup(const QSslConfiguration &sslConfiguration)
+{
+ Q_D(QAbstractHttpServer);
+ d->sslConfiguration = sslConfiguration;
+ d->sslEnabled = true;
+}
+#endif
+
QT_END_NAMESPACE
diff --git a/src/httpserver/qabstracthttpserver.h b/src/httpserver/qabstracthttpserver.h
index 6b59115..ffcdc2a 100644
--- a/src/httpserver/qabstracthttpserver.h
+++ b/src/httpserver/qabstracthttpserver.h
@@ -36,6 +36,12 @@
#include <QtNetwork/qhostaddress.h>
+#if QT_CONFIG(ssl)
+#include <QtSslServer/qsslserver.h>
+#include <QSslCertificate>
+#include <QSslKey>
+#endif
+
QT_BEGIN_NAMESPACE
class QHttpServerRequest;
@@ -57,6 +63,12 @@ public:
void bind(QTcpServer *server = nullptr);
QVector<QTcpServer *> servers() const;
+#if QT_CONFIG(ssl)
+ void sslSetup(const QSslCertificate &certificate, const QSslKey &privateKey,
+ QSsl::SslProtocol protocol = QSsl::SecureProtocols);
+ void sslSetup(const QSslConfiguration &sslConfiguration);
+#endif
+
Q_SIGNALS:
void missingHandler(const QHttpServerRequest &request, QTcpSocket *socket);
diff --git a/src/httpserver/qabstracthttpserver_p.h b/src/httpserver/qabstracthttpserver_p.h
index 69732ff..2c02b19 100644
--- a/src/httpserver/qabstracthttpserver_p.h
+++ b/src/httpserver/qabstracthttpserver_p.h
@@ -70,6 +70,11 @@ public:
void handleNewConnections();
void handleReadyRead(QTcpSocket *socket,
QHttpServerRequest *request);
+
+#if QT_CONFIG(ssl)
+ QSslConfiguration sslConfiguration;
+ bool sslEnabled = false;
+#endif
};
QT_END_NAMESPACE
diff --git a/src/src.pro b/src/src.pro
index 68d9ed3..7a4c276 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -1,4 +1,11 @@
TEMPLATE = subdirs
+QT = network
+
SUBDIRS = \
httpserver
+
+qtConfig(ssl) {
+ SUBDIRS += sslserver
+ httpserver.depends = sslserver
+}
diff --git a/src/sslserver/qsslserver.cpp b/src/sslserver/qsslserver.cpp
new file mode 100644
index 0000000..b22cadb
--- /dev/null
+++ b/src/sslserver/qsslserver.cpp
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Sylvain Garcia <garcia.6l20@gmail.com>.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtHttpServer module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** 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 <private/qsslserver_p.h>
+
+#include <QtCore/qloggingcategory.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcSS, "qt.sslserver");
+
+QSslServer::QSslServer(QObject *parent):
+ QTcpServer (QAbstractSocket::TcpSocket, *new QSslServerPrivate, parent)
+{
+}
+
+QSslServer::QSslServer(const QSslConfiguration &sslConfiguration,
+ QObject *parent):
+ QTcpServer (QAbstractSocket::TcpSocket, *new QSslServerPrivate, parent)
+{
+ Q_D(QSslServer);
+ d->sslConfiguration = sslConfiguration;
+}
+
+void QSslServer::incomingConnection(qintptr handle)
+{
+ Q_D(QSslServer);
+ QSslSocket *socket = new QSslSocket(this);
+ connect(socket, QOverload<const QList<QSslError>&>::of(&QSslSocket::sslErrors),
+ [this, socket](const QList<QSslError> &errors) {
+ for (auto &err: errors)
+ qCCritical(lcSS) << err;
+ Q_EMIT sslErrors(socket, errors);
+ });
+ socket->setSocketDescriptor(handle);
+ socket->setSslConfiguration(d->sslConfiguration);
+ socket->startServerEncryption();
+
+ addPendingConnection(socket);
+}
+
+void QSslServer::setSslConfiguration(const QSslConfiguration &sslConfiguration)
+{
+ Q_D(QSslServer);
+ d->sslConfiguration = sslConfiguration;
+}
+QT_END_NAMESPACE
diff --git a/src/sslserver/qsslserver.h b/src/sslserver/qsslserver.h
new file mode 100644
index 0000000..13b01d1
--- /dev/null
+++ b/src/sslserver/qsslserver.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Sylvain Garcia <garcia.6l20@gmail.com>.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtHttpServer module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** 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$
+**
+****************************************************************************/
+
+#ifndef QSSLSERVER_H
+#define QSSLSERVER_H
+
+#include <QtSslServer/qtsslserverglobal.h>
+
+#include <QtNetwork/qtcpserver.h>
+#include <QtNetwork/qsslconfiguration.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSslServerPrivate;
+class Q_SSLSERVER_EXPORT QSslServer : public QTcpServer
+{
+ Q_OBJECT
+public:
+ QSslServer(QObject *parent = nullptr);
+ QSslServer(const QSslConfiguration &sslConfiguration, QObject *parent = nullptr);
+
+ void setSslConfiguration(const QSslConfiguration &sslConfiguration);
+
+Q_SIGNALS:
+ void sslErrors(QSslSocket *socket, const QList<QSslError> &errors);
+
+protected:
+ void incomingConnection(qintptr handle) override final;
+
+private:
+ Q_DECLARE_PRIVATE(QSslServer)
+};
+
+QT_END_NAMESPACE
+
+#endif // QSSLSERVER_HPP
diff --git a/src/sslserver/qsslserver_p.h b/src/sslserver/qsslserver_p.h
new file mode 100644
index 0000000..4556c3d
--- /dev/null
+++ b/src/sslserver/qsslserver_p.h
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Sylvain Garcia <garcia.6l20@gmail.com>.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtHttpServer module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** 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$
+**
+****************************************************************************/
+
+#ifndef QSSLSERVER_P_H
+#define QSSLSERVER_P_H
+
+#include <QtSslServer/qsslserver.h>
+
+#include <private/qtcpserver_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSslServerPrivate: public QTcpServerPrivate {
+public:
+ QSslConfiguration sslConfiguration;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSSLSERVER_P_H
diff --git a/src/sslserver/qtsslserverglobal.h b/src/sslserver/qtsslserverglobal.h
new file mode 100644
index 0000000..8f9b55d
--- /dev/null
+++ b/src/sslserver/qtsslserverglobal.h
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Sylvain Garcia <garcia.6l20@gmail.com>.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtHttpServer module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** 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 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** 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$
+**
+****************************************************************************/
+
+#ifndef QTSSLSERVERGLOBAL_H
+#define QTSSLSERVERGLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_STATIC
+# if defined(QT_BUILD_SSLSERVER_LIB)
+# define Q_SSLSERVER_EXPORT Q_DECL_EXPORT
+# else
+# define Q_SSLSERVER_EXPORT Q_DECL_IMPORT
+# endif
+#else
+# define Q_SSLSERVER_EXPORT
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QTSSLSERVERGLOBAL_H
diff --git a/src/sslserver/sslserver.pro b/src/sslserver/sslserver.pro
new file mode 100644
index 0000000..6d09233
--- /dev/null
+++ b/src/sslserver/sslserver.pro
@@ -0,0 +1,14 @@
+TARGET = QtSslServer
+INCLUDEPATH += .
+
+QT = network network-private core-private
+
+HEADERS += \
+ qsslserver.h \
+ qtsslserverglobal.h \
+ qsslserver_p.h
+
+SOURCES += \
+ qsslserver.cpp
+
+load(qt_module)
diff --git a/sync.profile b/sync.profile
index b4dfb24..80eeaf9 100644
--- a/sync.profile
+++ b/sync.profile
@@ -1,3 +1,4 @@
%modules = ( # path to module name map
"QtHttpServer" => "$basedir/src/httpserver",
+ "QtSslServer" => "$basedir/src/sslserver",
);
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
index 473a337..af38d7a 100644
--- a/tests/auto/auto.pro
+++ b/tests/auto/auto.pro
@@ -1,5 +1,7 @@
TEMPLATE = subdirs
+QT = network
+
SUBDIRS = \
cmake \
qabstracthttpserver \
diff --git a/tests/auto/qhttpserver/tst_qhttpserver.cpp b/tests/auto/qhttpserver/tst_qhttpserver.cpp
index a0a437c..ef5290e 100644
--- a/tests/auto/qhttpserver/tst_qhttpserver.cpp
+++ b/tests/auto/qhttpserver/tst_qhttpserver.cpp
@@ -51,6 +51,41 @@
#include <QtNetwork/qnetworkreply.h>
#include <QtNetwork/qnetworkrequest.h>
+
+static const char g_privateKey[] = R"(-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDykG51ZjNJra8iS27g3DJojH1qG8C3Z+Avo5U6Qz6NkOsjvr22
+gXqOS4uwVUXdCAKxsP0Wwn2zGz5vxGpLPVKtbAmaqHYZuipMG/Qun3t+QYBgR+9t
+lmHdI8TNP2Om8stDO5uQyBH7DcMjPyIgpfc8fBoNLhCn4oC2n6JK9EMuhQIDAQAB
+AoGAUHTLzrEJjgTINI3kxz0Ck18WMl3mPG9+Ew8lbl/jnb1V4VNhReoIpq40NVbz
+h28ixaG5MRVt8Dy3Jwd1YmOCylHSujdFQ2u0pcHFmERgDS2bOMwMTRoFOj2qgMGS
+9SM+iXlPY5AQY8nEg7rLjMSfaC/8Hq4RXpkj4PeHh6N7AzkCQQD++HzM3xBr+Gvh
+zco9Kt8IiKNlfeiA5gUQq1UPJzcWIEgW1Tgr5UzMUOcZ0HfYwhqL3+wMhzN4sba+
+1plB1QRXAkEA84sfM0jm9BRSqtYTPlhsYAmuPjeo24Pxel8ijEkToAu0ppEC6AQ3
+zfwZD0ISgaWQ7af5TN/RCsoNVX79twP6gwJBANbtB+Z6shERm38ARdZB6Tf8ViAb
+fn4JZ4OhqVXYrKrOE3aLzYnTBGXGXMh53kytcksuOoBlB5JZ274Kj63arokCQFPo
+9xMAZzJpXiImJ/MvHAfqzfH501/ukeCLrqeO9ggKgG9zPwEZkvCRj0DGjwHEPa7k
+VOy7oJaLDxUJ7/iCkmkCQQCtTLsvDbGH4tyFK5VIPJbUcccIib+dTzSTeONdUxKL
+Yk+C6o7OpaUWX+ikp4Ow/6iHOAgXaeA2OolDer/NspUy
+-----END RSA PRIVATE KEY-----)";
+
+static const char g_certificate[] = R"(-----BEGIN CERTIFICATE-----
+MIICrjCCAhegAwIBAgIUcuXjCSkJ2+v/Rqv/UHThTRGFlpswDQYJKoZIhvcNAQEL
+BQAwaDELMAkGA1UEBhMCRlIxDzANBgNVBAgMBkZyYW5jZTERMA8GA1UEBwwIR3Jl
+bm9ibGUxFjAUBgNVBAoMDVF0Q29udHJpYnV0b3IxHTAbBgNVBAMMFHFodHRwc3Nl
+cnZlcnRlc3QuY29tMCAXDTE5MDkyNjA4NTc1MloYDzIyNTUwMzEzMDg1NzUyWjBo
+MQswCQYDVQQGEwJGUjEPMA0GA1UECAwGRnJhbmNlMREwDwYDVQQHDAhHcmVub2Js
+ZTEWMBQGA1UECgwNUXRDb250cmlidXRvcjEdMBsGA1UEAwwUcWh0dHBzc2VydmVy
+dGVzdC5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPKQbnVmM0mtryJL
+buDcMmiMfWobwLdn4C+jlTpDPo2Q6yO+vbaBeo5Li7BVRd0IArGw/RbCfbMbPm/E
+aks9Uq1sCZqodhm6Kkwb9C6fe35BgGBH722WYd0jxM0/Y6byy0M7m5DIEfsNwyM/
+IiCl9zx8Gg0uEKfigLafokr0Qy6FAgMBAAGjUzBRMB0GA1UdDgQWBBTDMYCcl2jz
+UUWByEzTj5Ew/LWkeDAfBgNVHSMEGDAWgBTDMYCcl2jzUUWByEzTj5Ew/LWkeDAP
+BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4GBAMNupAOXoBih6RvuAn3w
+W8jOIZfkn5CMYdbUSndY/Wrt4p07M8r9uFPWG4bXSwG6n9Nzl75X9b0ka/jqPjQ3
+X769simPygCblBp2xwE6w14aHEBx4kcF1p2QbC1vHynszJxyVLvHqUjuJwVAoPrM
+Imy6LOiw2tRTHPsj7UH16M6C
+-----END CERTIFICATE-----)";
+
QT_BEGIN_NAMESPACE
class QueryRequireRouterRule : public QHttpServerRouterRule
@@ -101,6 +136,8 @@ private:
private:
QHttpServer httpserver;
QString urlBase;
+ QString sslUrlBase;
+ QNetworkAccessManager networkAccessManager;
};
struct CustomArg {
@@ -243,7 +280,52 @@ void tst_QHttpServer::initTestCase()
return resp;
});
- urlBase = QStringLiteral("http://localhost:%1%2").arg(httpserver.listen());
+ int port = httpserver.listen();
+ if (port < 0)
+ qCritical() << "Http server listen failed";
+
+ urlBase = QStringLiteral("http://localhost:%1%2").arg(port);
+
+#if QT_CONFIG(ssl)
+ httpserver.sslSetup(QSslCertificate(g_certificate),
+ QSslKey(g_privateKey, QSsl::Rsa));
+
+ port = httpserver.listen();
+ if (port < 0)
+ qCritical() << "Http server listen failed";
+
+ sslUrlBase = QStringLiteral("https://localhost:%1%2").arg(port);
+
+ QList<QSslError> expectedSslErrors;
+
+// Non-OpenSSL backends are not able to report a specific error code
+// for self-signed certificates.
+#ifndef QT_NO_OPENSSL
+# define FLUKE_CERTIFICATE_ERROR QSslError::SelfSignedCertificate
+#else
+# define FLUKE_CERTIFICATE_ERROR QSslError::CertificateUntrusted
+#endif
+
+ expectedSslErrors.append(QSslError(FLUKE_CERTIFICATE_ERROR,
+ QSslCertificate(g_certificate)));
+ expectedSslErrors.append(QSslError(QSslError::HostNameMismatch,
+ QSslCertificate(g_certificate)));
+
+ connect(&networkAccessManager, &QNetworkAccessManager::sslErrors,
+ [expectedSslErrors](QNetworkReply *reply,
+ const QList<QSslError> &errors) {
+ for (const auto &error: errors) {
+ for (const auto &expectedError: expectedSslErrors) {
+ if (error.error() != expectedError.error() ||
+ error.certificate() != expectedError.certificate()) {
+ qCritical() << "Got unexpected ssl error:"
+ << error << error.certificate();
+ }
+ }
+ }
+ reply->ignoreSslErrors(expectedSslErrors);
+ });
+#endif
}
void tst_QHttpServer::routeGet_data()
@@ -254,177 +336,207 @@ void tst_QHttpServer::routeGet_data()
QTest::addColumn<QString>("body");
QTest::addRow("hello world")
- << "/"
+ << urlBase.arg("/")
<< 200
<< "text/plain"
<< "Hello world get";
QTest::addRow("test msg")
- << "/test"
+ << urlBase.arg("/test")
<< 200
<< "text/html"
<< "test msg";
QTest::addRow("not found")
- << "/not-found"
+ << urlBase.arg("/not-found")
<< 404
<< "application/x-empty"
<< "";
QTest::addRow("arg:int")
- << "/page/10"
+ << urlBase.arg("/page/10")
<< 200
<< "text/plain"
<< "page: 10";
QTest::addRow("arg:-int")
- << "/page/-10"
+ << urlBase.arg("/page/-10")
<< 200
<< "text/plain"
<< "page: -10";
QTest::addRow("arg:uint")
- << "/page/10/detail"
+ << urlBase.arg("/page/10/detail")
<< 200
<< "text/plain"
<< "page: 10 detail";
QTest::addRow("arg:-uint")
- << "/page/-10/detail"
+ << urlBase.arg("/page/-10/detail")
<< 404
<< "application/x-empty"
<< "";
QTest::addRow("arg:string")
- << "/user/test"
+ << urlBase.arg("/user/test")
<< 200
<< "text/plain"
<< "test";
QTest::addRow("arg:string")
- << "/user/test test ,!a+."
+ << urlBase.arg("/user/test test ,!a+.")
<< 200
<< "text/plain"
<< "test test ,!a+.";
QTest::addRow("arg:string,ba")
- << "/user/james/bond"
+ << urlBase.arg("/user/james/bond")
<< 200
<< "text/plain"
<< "james-bond";
QTest::addRow("arg:url")
- << "/test/api/v0/cmds?val=1"
+ << urlBase.arg("/test/api/v0/cmds?val=1")
<< 200
<< "text/plain"
<< "path: api/v0/cmds";
QTest::addRow("arg:float 5.1")
- << "/api/v5.1"
+ << urlBase.arg("/api/v5.1")
<< 200
<< "text/plain"
<< "api 5.1v";
QTest::addRow("arg:float 5.")
- << "/api/v5."
+ << urlBase.arg("/api/v5.")
<< 200
<< "text/plain"
<< "api 5v";
QTest::addRow("arg:float 6.0")
- << "/api/v6.0"
+ << urlBase.arg("/api/v6.0")
<< 200
<< "text/plain"
<< "api 6v";
QTest::addRow("arg:float,uint")
- << "/api/v5.1/user/10"
+ << urlBase.arg("/api/v5.1/user/10")
<< 200
<< "text/plain"
<< "api 5.1v, user id - 10";
QTest::addRow("arg:float,uint,query")
- << "/api/v5.2/user/11/settings?role=admin" << 200
+ << urlBase.arg("/api/v5.2/user/11/settings?role=admin")
+ << 200
<< "text/plain"
<< "api 5.2v, user id - 11, set settings role=admin#''";
// The fragment isn't actually sent via HTTP (it's information for the user agent)
QTest::addRow("arg:float,uint, query+fragment")
- << "/api/v5.2/user/11/settings?role=admin#tag"
- << 200 << "text/plain"
+ << urlBase.arg("/api/v5.2/user/11/settings?role=admin#tag")
+ << 200
+ << "text/plain"
<< "api 5.2v, user id - 11, set settings role=admin#''";
QTest::addRow("custom route rule")
- << "/custom/15"
+ << urlBase.arg("/custom/15")
<< 404
<< "application/x-empty"
<< "";
QTest::addRow("custom route rule + query")
- << "/custom/10?key=11&g=1"
+ << urlBase.arg("/custom/10?key=11&g=1")
<< 200
<< "text/plain"
<< "Custom router rule: 10, key=11";
QTest::addRow("custom route rule + query key req")
- << "/custom/10?g=1&key=12"
+ << urlBase.arg("/custom/10?g=1&key=12")
<< 200
<< "text/plain"
<< "Custom router rule: 10, key=12";
QTest::addRow("post-and-get, get")
- << "/post-and-get"
+ << urlBase.arg("/post-and-get")
<< 200
<< "text/plain"
<< "Hello world get";
QTest::addRow("invalid-rule-method, get")
- << "/invalid-rule-method"
+ << urlBase.arg("/invalid-rule-method")
<< 404
<< "application/x-empty"
<< "";
QTest::addRow("check custom type, data=1")
- << "/check-custom-type/1"
+ << urlBase.arg("/check-custom-type/1")
<< 200
<< "text/plain"
<< "data = 1";
QTest::addRow("any, get")
- << "/any"
+ << urlBase.arg("/any")
<< 200
<< "text/plain"
<< "Get";
QTest::addRow("response from html file")
- << "/file/text.html"
+ << urlBase.arg("/file/text.html")
<< 200
<< "text/html"
<< "<html></html>";
QTest::addRow("response from json file")
- << "/file/application.json"
+ << urlBase.arg("/file/application.json")
<< 200
<< "application/json"
<< "{ \"key\": \"value\" }";
QTest::addRow("json-object")
- << "/json-object/"
+ << urlBase.arg("/json-object/")
<< 200
<< "application/json"
<< "{\"property\":\"test\",\"value\":1}";
QTest::addRow("json-array")
- << "/json-array/"
+ << urlBase.arg("/json-array/")
<< 200
<< "application/json"
<< "[1,\"2\",{\"name\":\"test\"}]";
QTest::addRow("chunked")
- << "/chunked/"
+ << urlBase.arg("/chunked/")
<< 200
<< "text/plain"
<< "part 1 of the message, part 2 of the message";
+
+#if QT_CONFIG(ssl)
+
+ QTest::addRow("hello world, ssl")
+ << sslUrlBase.arg("/")
+ << 200
+ << "text/plain"
+ << "Hello world get";
+
+ QTest::addRow("post-and-get, get, ssl")
+ << sslUrlBase.arg("/post-and-get")
+ << 200
+ << "text/plain"
+ << "Hello world get";
+
+ QTest::addRow("invalid-rule-method, get, ssl")
+ << sslUrlBase.arg("/invalid-rule-method")
+ << 404
+ << "application/x-empty"
+ << "";
+
+ QTest::addRow("check custom type, data=1, ssl")
+ << sslUrlBase.arg("/check-custom-type/1")
+ << 200
+ << "text/plain"
+ << "data = 1";
+
+#endif // QT_CONFIG(ssl)
}
void tst_QHttpServer::routeGet()
@@ -434,15 +546,15 @@ void tst_QHttpServer::routeGet()
QFETCH(QString, type);
QFETCH(QString, body);
- QNetworkAccessManager networkAccessManager;
- const QUrl requestUrl(urlBase.arg(url));
- auto reply = networkAccessManager.get(QNetworkRequest(requestUrl));
+ auto reply = networkAccessManager.get(QNetworkRequest(url));
QTRY_VERIFY(reply->isFinished());
QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader), type);
QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), code);
QCOMPARE(reply->readAll().trimmed(), body);
+
+ reply->deleteLater();
}
void tst_QHttpServer::routeKeepAlive()
@@ -458,7 +570,6 @@ void tst_QHttpServer::routeKeepAlive()
.arg(static_cast<int>(req.method()));
});
- QNetworkAccessManager networkAccessManager;
QNetworkRequest request(urlBase.arg("/keep-alive"));
request.setRawHeader(QByteArray("Connection"), QByteArray("keep-alive"));
@@ -506,28 +617,28 @@ void tst_QHttpServer::routePost_data()
QTest::addColumn<QString>("body");
QTest::addRow("hello world")
- << "/"
+ << urlBase.arg("/")
<< 200
<< "text/plain"
<< ""
<< "Hello world post";
QTest::addRow("post-and-get, post")
- << "/post-and-get"
+ << urlBase.arg("/post-and-get")
<< 200
<< "text/plain"
<< ""
<< "Hello world post";
QTest::addRow("any, post")
- << "/any"
+ << urlBase.arg("/any")
<< 200
<< "text/plain"
<< ""
<< "Post";
QTest::addRow("post-body")
- << "/post-body"
+ << urlBase.arg("/post-body")
<< 200
<< "text/plain"
<< "some post data"
@@ -538,11 +649,43 @@ void tst_QHttpServer::routePost_data()
body.append(QString::number(i));
QTest::addRow("post-body - huge body, chunk test")
- << "/post-body"
+ << urlBase.arg("/post-body")
<< 200
<< "text/plain"
<< body
<< body;
+
+#if QT_CONFIG(ssl)
+
+ QTest::addRow("post-and-get, post, ssl")
+ << sslUrlBase.arg("/post-and-get")
+ << 200
+ << "text/plain"
+ << ""
+ << "Hello world post";
+
+ QTest::addRow("any, post, ssl")
+ << sslUrlBase.arg("/any")
+ << 200
+ << "text/plain"
+ << ""
+ << "Post";
+
+ QTest::addRow("post-body, ssl")
+ << sslUrlBase.arg("/post-body")
+ << 200
+ << "text/plain"
+ << "some post data"
+ << "some post data";
+
+ QTest::addRow("post-body - huge body, chunk test, ssl")
+ << sslUrlBase.arg("/post-body")
+ << 200
+ << "text/plain"
+ << body
+ << body;
+
+#endif // QT_CONFIG(ssl)
}
void tst_QHttpServer::routePost()
@@ -553,8 +696,7 @@ void tst_QHttpServer::routePost()
QFETCH(QString, data);
QFETCH(QString, body);
- QNetworkAccessManager networkAccessManager;
- QNetworkRequest request(QUrl(urlBase.arg(url)));
+ QNetworkRequest request(url);
if (data.size()) {
request.setHeader(QNetworkRequest::ContentTypeHeader,
QHttpServerLiterals::contentTypeTextHtml());
@@ -567,6 +709,8 @@ void tst_QHttpServer::routePost()
QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader), type);
QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), code);
QCOMPARE(reply->readAll(), body);
+
+ reply->deleteLater();
}
void tst_QHttpServer::routeDelete_data()
@@ -577,16 +721,32 @@ void tst_QHttpServer::routeDelete_data()
QTest::addColumn<QString>("data");
QTest::addRow("post-and-get, delete")
- << "/post-and-get"
+ << urlBase.arg("/post-and-get")
<< 404
<< "application/x-empty"
<< "";
QTest::addRow("any, delete")
- << "/any"
+ << urlBase.arg("/any")
<< 200
<< "text/plain"
<< "Delete";
+
+#if QT_CONFIG(ssl)
+
+ QTest::addRow("post-and-get, delete, ssl")
+ << sslUrlBase.arg("/post-and-get")
+ << 404
+ << "application/x-empty"
+ << "";
+
+ QTest::addRow("any, delete, ssl")
+ << sslUrlBase.arg("/any")
+ << 200
+ << "text/plain"
+ << "Delete";
+
+#endif // QT_CONFIG(ssl)
}
void tst_QHttpServer::routeDelete()
@@ -596,19 +756,18 @@ void tst_QHttpServer::routeDelete()
QFETCH(QString, type);
QFETCH(QString, data);
- QNetworkAccessManager networkAccessManager;
- const QUrl requestUrl(urlBase.arg(url));
- auto reply = networkAccessManager.deleteResource(QNetworkRequest(requestUrl));
+ auto reply = networkAccessManager.deleteResource(QNetworkRequest(url));
QTRY_VERIFY(reply->isFinished());
QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader), type);
QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), code);
+
+ reply->deleteLater();
}
void tst_QHttpServer::routeExtraHeaders()
{
- QNetworkAccessManager networkAccessManager;
const QUrl requestUrl(urlBase.arg("/extra-headers"));
auto reply = networkAccessManager.get(QNetworkRequest(requestUrl));
@@ -669,8 +828,8 @@ void tst_QHttpServer::checkRouteLambdaCapture()
return msg;
});
- QNetworkAccessManager networkAccessManager;
- checkReply(networkAccessManager.get(QNetworkRequest(QUrl(urlBase.arg("/capture-this/")))),
+ checkReply(networkAccessManager.get(
+ QNetworkRequest(QUrl(urlBase.arg("/capture-this/")))),
urlBase);
if (QTest::currentTestFailed())
return;
@@ -688,6 +847,8 @@ void tst_QHttpServer::checkReply(QNetworkReply *reply, const QString &response)
QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader), "text/plain");
QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
QCOMPARE(reply->readAll(), response);
+
+ reply->deleteLater();
};
QT_END_NAMESPACE