mirror of
https://github.com/QuasarApp/qthttpserver.git
synced 2025-05-09 08:09:33 +00:00
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>
This commit is contained in:
parent
73175545e6
commit
f04a6809b1
@ -4,6 +4,7 @@ INCLUDEPATH += .
|
||||
QT = network core-private
|
||||
|
||||
qtHaveModule(websockets): QT += websockets-private
|
||||
qtConfig(ssl): QT += sslserver
|
||||
|
||||
HEADERS += \
|
||||
qthttpserverglobal.h \
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -1,4 +1,11 @@
|
||||
TEMPLATE = subdirs
|
||||
|
||||
QT = network
|
||||
|
||||
SUBDIRS = \
|
||||
httpserver
|
||||
|
||||
qtConfig(ssl) {
|
||||
SUBDIRS += sslserver
|
||||
httpserver.depends = sslserver
|
||||
}
|
||||
|
73
src/sslserver/qsslserver.cpp
Normal file
73
src/sslserver/qsslserver.cpp
Normal file
@ -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
|
62
src/sslserver/qsslserver.h
Normal file
62
src/sslserver/qsslserver.h
Normal file
@ -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
|
46
src/sslserver/qsslserver_p.h
Normal file
46
src/sslserver/qsslserver_p.h
Normal file
@ -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
|
49
src/sslserver/qtsslserverglobal.h
Normal file
49
src/sslserver/qtsslserverglobal.h
Normal file
@ -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
|
14
src/sslserver/sslserver.pro
Normal file
14
src/sslserver/sslserver.pro
Normal file
@ -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)
|
@ -1,3 +1,4 @@
|
||||
%modules = ( # path to module name map
|
||||
"QtHttpServer" => "$basedir/src/httpserver",
|
||||
"QtSslServer" => "$basedir/src/sslserver",
|
||||
);
|
||||
|
@ -1,5 +1,7 @@
|
||||
TEMPLATE = subdirs
|
||||
|
||||
QT = network
|
||||
|
||||
SUBDIRS = \
|
||||
cmake \
|
||||
qabstracthttpserver \
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user