summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.qmake.conf2
-rw-r--r--examples/websockets/echoserver/main.cpp2
-rw-r--r--src/websockets/qsslserver.cpp15
-rw-r--r--src/websockets/qsslserver_p.h6
-rw-r--r--src/websockets/qwebsockethandshakeresponse.cpp24
-rw-r--r--src/websockets/qwebsocketserver.cpp32
-rw-r--r--src/websockets/qwebsocketserver.h3
-rw-r--r--src/websockets/qwebsocketserver_p.cpp50
-rw-r--r--src/websockets/qwebsocketserver_p.h11
-rw-r--r--tests/auto/websockets/qwebsocketserver/tst_qwebsocketserver.cpp185
10 files changed, 297 insertions, 33 deletions
diff --git a/.qmake.conf b/.qmake.conf
index b5e35ea..c6f1702 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -3,4 +3,4 @@ load(qt_build_config)
CONFIG += warning_clean
DEFINES += QT_NO_FOREACH
-MODULE_VERSION = 5.13.1
+MODULE_VERSION = 5.14.0
diff --git a/examples/websockets/echoserver/main.cpp b/examples/websockets/echoserver/main.cpp
index bf9e3c2..f857f0f 100644
--- a/examples/websockets/echoserver/main.cpp
+++ b/examples/websockets/echoserver/main.cpp
@@ -65,7 +65,7 @@ int main(int argc, char *argv[])
parser.addOption(dbgOption);
QCommandLineOption portOption(QStringList() << "p" << "port",
QCoreApplication::translate("main", "Port for echoserver [default: 1234]."),
- QCoreApplication::translate("main", "port"), QLatin1Literal("1234"));
+ QCoreApplication::translate("main", "port"), QLatin1String("1234"));
parser.addOption(portOption);
parser.process(a);
bool debug = parser.isSet(dbgOption);
diff --git a/src/websockets/qsslserver.cpp b/src/websockets/qsslserver.cpp
index 586e520..ec645c9 100644
--- a/src/websockets/qsslserver.cpp
+++ b/src/websockets/qsslserver.cpp
@@ -118,11 +118,11 @@ void QSslServer::incomingConnection(qintptr socket)
connect(pSslSocket, QOverload<const QList<QSslError>&>::of(&QSslSocket::sslErrors),
this, &QSslServer::sslErrors);
connect(pSslSocket, &QSslSocket::encrypted,
- this, &QSslServer::newEncryptedConnection);
+ this, &QSslServer::socketEncrypted);
connect(pSslSocket, &QSslSocket::preSharedKeyAuthenticationRequired,
this, &QSslServer::preSharedKeyAuthenticationRequired);
- addPendingConnection(pSslSocket);
+ Q_EMIT startedEncryptionHandshake(pSslSocket);
pSslSocket->startServerEncryption();
} else {
@@ -131,4 +131,15 @@ void QSslServer::incomingConnection(qintptr socket)
}
}
+void QSslServer::socketEncrypted()
+{
+ QSslSocket *pSslSocket = qobject_cast<QSslSocket *>(sender());
+
+ // We do not add the connection until the encryption handshake is complete.
+ // In case the handshake is aborted, we would be left with a stale
+ // connection in the queue otherwise.
+ addPendingConnection(pSslSocket);
+ Q_EMIT newEncryptedConnection();
+}
+
QT_END_NAMESPACE
diff --git a/src/websockets/qsslserver_p.h b/src/websockets/qsslserver_p.h
index 10f8fea..6283058 100644
--- a/src/websockets/qsslserver_p.h
+++ b/src/websockets/qsslserver_p.h
@@ -59,6 +59,8 @@
QT_BEGIN_NAMESPACE
+class QSslSocket;
+
class QSslServer : public QTcpServer
{
Q_OBJECT
@@ -76,10 +78,14 @@ Q_SIGNALS:
void peerVerifyError(const QSslError &error);
void newEncryptedConnection();
void preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator);
+ void startedEncryptionHandshake(QSslSocket *socket);
protected:
void incomingConnection(qintptr socket) override;
+private slots:
+ void socketEncrypted();
+
private:
QSslConfiguration m_sslConfiguration;
};
diff --git a/src/websockets/qwebsockethandshakeresponse.cpp b/src/websockets/qwebsockethandshakeresponse.cpp
index 2241ca2..383f1bf 100644
--- a/src/websockets/qwebsockethandshakeresponse.cpp
+++ b/src/websockets/qwebsockethandshakeresponse.cpp
@@ -53,7 +53,9 @@
#include <QtCore/QList>
#include <QtCore/QStringBuilder> //for more efficient string concatenation
+#include <algorithm>
#include <functional> //for std::greater
+#include <iterator>
QT_BEGIN_NAMESPACE
@@ -124,6 +126,18 @@ QString QWebSocketHandshakeResponse::calculateAcceptKey(const QString &key) cons
return QString::fromLatin1(hash.toBase64());
}
+template <class T, class Compare>
+static QList<T> listIntersection(QList<T> list1, QList<T> list2, Compare comp)
+{
+ QList<T> result;
+ std::sort(list1.begin(), list1.end(), comp);
+ std::sort(list2.begin(), list2.end(), comp);
+ std::set_intersection(list1.cbegin(), list1.cend(),
+ list2.cbegin(), list2.cend(),
+ std::back_inserter(result), comp);
+ return result;
+}
+
/*!
\internal
*/
@@ -148,15 +162,13 @@ QString QWebSocketHandshakeResponse::getHandshakeResponse(
if (request.isValid()) {
const QString acceptKey = calculateAcceptKey(request.key());
const QList<QString> matchingProtocols =
- supportedProtocols.toSet().intersect(request.protocols().toSet()).toList();
+ listIntersection(supportedProtocols, request.protocols(), std::less<>());
//TODO: extensions must be kept in the order in which they arrive
//cannot use set.intersect() to get the supported extensions
const QList<QString> matchingExtensions =
- supportedExtensions.toSet().intersect(request.extensions().toSet()).toList();
- QList<QWebSocketProtocol::Version> matchingVersions =
- request.versions().toSet().intersect(supportedVersions.toSet()).toList();
- std::sort(matchingVersions.begin(), matchingVersions.end(),
- std::greater<QWebSocketProtocol::Version>()); //sort in descending order
+ listIntersection(supportedExtensions, request.extensions(), std::less<>());
+ const QList<QWebSocketProtocol::Version> matchingVersions =
+ listIntersection(supportedVersions, request.versions(), std::greater<>()); //sort in descending order
if (Q_UNLIKELY(matchingVersions.isEmpty())) {
m_error = QWebSocketProtocol::CloseCodeProtocolError;
diff --git a/src/websockets/qwebsocketserver.cpp b/src/websockets/qwebsocketserver.cpp
index 7790250..9717401 100644
--- a/src/websockets/qwebsocketserver.cpp
+++ b/src/websockets/qwebsocketserver.cpp
@@ -77,6 +77,9 @@
QWebSocketServer only supports version 13 of the WebSocket protocol, as outlined in \l{RFC 6455}.
+ There is a default connection handshake timeout of 10 seconds to avoid denial of service,
+ which can be customized using setHandshakeTimeout().
+
\sa {WebSocket Server Example}, QWebSocket
*/
@@ -350,6 +353,20 @@ int QWebSocketServer::maxPendingConnections() const
}
/*!
+ Returns the handshake timeout for new connections in milliseconds.
+
+ The default is 10 seconds. If a peer uses more time to complete the
+ handshake their connection is closed.
+
+ \sa setHandshakeTimeout()
+ */
+int QWebSocketServer::handshakeTimeout() const
+{
+ Q_D(const QWebSocketServer);
+ return d->handshakeTimeout();
+}
+
+/*!
Returns the next pending connection as a connected QWebSocket object.
QWebSocketServer does not take ownership of the returned QWebSocket object.
It is up to the caller to delete the object explicitly when it will no longer be used,
@@ -574,6 +591,21 @@ void QWebSocketServer::setMaxPendingConnections(int numConnections)
d->setMaxPendingConnections(numConnections);
}
+/*!
+ Sets the handshake timeout for new connections to \a msec milliseconds.
+
+ By default this is set to 10 seconds. If a peer uses more time to
+ complete the handshake, their connection is closed. You can pass a
+ negative value (e.g. -1) to disable the timeout.
+
+ \sa handshakeTimeout()
+ */
+void QWebSocketServer::setHandshakeTimeout(int msec)
+{
+ Q_D(QWebSocketServer);
+ d->setHandshakeTimeout(msec);
+}
+
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
/*!
Sets the socket descriptor this server should use when listening for incoming connections to
diff --git a/src/websockets/qwebsocketserver.h b/src/websockets/qwebsocketserver.h
index 17d5376..dd06448 100644
--- a/src/websockets/qwebsocketserver.h
+++ b/src/websockets/qwebsocketserver.h
@@ -86,6 +86,9 @@ public:
void setMaxPendingConnections(int numConnections);
int maxPendingConnections() const;
+ void setHandshakeTimeout(int msec);
+ int handshakeTimeout() const;
+
quint16 serverPort() const;
QHostAddress serverAddress() const;
QUrl serverUrl() const;
diff --git a/src/websockets/qwebsocketserver_p.cpp b/src/websockets/qwebsocketserver_p.cpp
index 3a38c4b..8225b59 100644
--- a/src/websockets/qwebsocketserver_p.cpp
+++ b/src/websockets/qwebsocketserver_p.cpp
@@ -49,6 +49,7 @@
#include "qwebsocket_p.h"
#include "qwebsocketcorsauthenticator.h"
+#include <QtCore/QTimer>
#include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
#include <QtNetwork/QNetworkProxy>
@@ -73,7 +74,8 @@ QWebSocketServerPrivate::QWebSocketServerPrivate(const QString &serverName,
m_pendingConnections(),
m_error(QWebSocketProtocol::CloseCodeNormal),
m_errorString(),
- m_maxPendingConnections(30)
+ m_maxPendingConnections(30),
+ m_handshakeTimeout(10000)
{}
/*!
@@ -97,6 +99,8 @@ void QWebSocketServerPrivate::init()
QObjectPrivate::connect(pSslServer, &QSslServer::newEncryptedConnection,
this, &QWebSocketServerPrivate::onNewConnection,
Qt::QueuedConnection);
+ QObjectPrivate::connect(pSslServer, &QSslServer::startedEncryptionHandshake,
+ this, &QWebSocketServerPrivate::startHandshakeTimeout);
QObject::connect(pSslServer, &QSslServer::peerVerifyError,
q, &QWebSocketServer::peerVerifyError);
QObject::connect(pSslServer, &QSslServer::sslErrors,
@@ -381,8 +385,12 @@ void QWebSocketServerPrivate::setError(QWebSocketProtocol::CloseCode code, const
*/
void QWebSocketServerPrivate::onNewConnection()
{
- while (m_pTcpServer->hasPendingConnections())
- handleConnection(m_pTcpServer->nextPendingConnection());
+ while (m_pTcpServer->hasPendingConnections()) {
+ QTcpSocket *pTcpSocket = m_pTcpServer->nextPendingConnection();
+ if (Q_LIKELY(pTcpSocket) && m_secureMode == NonSecureMode)
+ startHandshakeTimeout(pTcpSocket);
+ handleConnection(pTcpSocket);
+ }
}
/*!
@@ -390,8 +398,10 @@ void QWebSocketServerPrivate::onNewConnection()
*/
void QWebSocketServerPrivate::onSocketDisconnected()
{
- if (Q_LIKELY(currentSender)) {
- QTcpSocket *pTcpSocket = qobject_cast<QTcpSocket*>(currentSender->sender);
+ Q_Q(QWebSocketServer);
+ QObject *sender = q->sender();
+ if (Q_LIKELY(sender)) {
+ QTcpSocket *pTcpSocket = qobject_cast<QTcpSocket*>(sender);
if (Q_LIKELY(pTcpSocket))
pTcpSocket->deleteLater();
}
@@ -402,10 +412,12 @@ void QWebSocketServerPrivate::onSocketDisconnected()
*/
void QWebSocketServerPrivate::handshakeReceived()
{
- if (Q_UNLIKELY(!currentSender)) {
+ Q_Q(QWebSocketServer);
+ QObject *sender = q->sender();
+ if (Q_UNLIKELY(!sender)) {
return;
}
- QTcpSocket *pTcpSocket = qobject_cast<QTcpSocket*>(currentSender->sender);
+ QTcpSocket *pTcpSocket = qobject_cast<QTcpSocket*>(sender);
if (Q_UNLIKELY(!pTcpSocket)) {
return;
}
@@ -423,7 +435,6 @@ void QWebSocketServerPrivate::handshakeReceived()
}
disconnect(pTcpSocket, &QTcpSocket::readyRead,
this, &QWebSocketServerPrivate::handshakeReceived);
- Q_Q(QWebSocketServer);
bool success = false;
bool isSecure = (m_secureMode == SecureMode);
@@ -460,6 +471,7 @@ void QWebSocketServerPrivate::handshakeReceived()
request,
response);
if (pWebSocket) {
+ finishHandshakeTimeout(pTcpSocket);
addPendingConnection(pWebSocket);
Q_EMIT q->newConnection();
success = true;
@@ -499,4 +511,26 @@ void QWebSocketServerPrivate::handleConnection(QTcpSocket *pTcpSocket) const
}
}
+void QWebSocketServerPrivate::startHandshakeTimeout(QTcpSocket *pTcpSocket)
+{
+ if (m_handshakeTimeout < 0)
+ return;
+
+ QTimer *handshakeTimer = new QTimer(pTcpSocket);
+ handshakeTimer->setSingleShot(true);
+ handshakeTimer->setObjectName(QStringLiteral("handshakeTimer"));
+ QObject::connect(handshakeTimer, &QTimer::timeout, [=]() {
+ pTcpSocket->close();
+ });
+ handshakeTimer->start(m_handshakeTimeout);
+}
+
+void QWebSocketServerPrivate::finishHandshakeTimeout(QTcpSocket *pTcpSocket)
+{
+ if (QTimer *handshakeTimer = pTcpSocket->findChild<QTimer *>(QStringLiteral("handshakeTimer"))) {
+ handshakeTimer->stop();
+ delete handshakeTimer;
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/websockets/qwebsocketserver_p.h b/src/websockets/qwebsocketserver_p.h
index be7744f..1f1cbd9 100644
--- a/src/websockets/qwebsocketserver_p.h
+++ b/src/websockets/qwebsocketserver_p.h
@@ -90,6 +90,9 @@ public:
bool isListening() const;
bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);
int maxPendingConnections() const;
+ int handshakeTimeout() const {
+ return m_handshakeTimeout;
+ }
virtual QWebSocket *nextPendingConnection();
void pauseAccepting();
#ifndef QT_NO_NETWORKPROXY
@@ -101,6 +104,9 @@ public:
QWebSocketProtocol::CloseCode serverError() const;
quint16 serverPort() const;
void setMaxPendingConnections(int numConnections);
+ void setHandshakeTimeout(int msec) {
+ m_handshakeTimeout = msec;
+ }
bool setSocketDescriptor(qintptr socketDescriptor);
qintptr socketDescriptor() const;
@@ -122,6 +128,9 @@ public:
void handleConnection(QTcpSocket *pTcpSocket) const;
+private slots:
+ void startHandshakeTimeout(QTcpSocket *pTcpSocket);
+
private:
QTcpServer *m_pTcpServer;
QString m_serverName;
@@ -130,6 +139,7 @@ private:
QWebSocketProtocol::CloseCode m_error;
QString m_errorString;
int m_maxPendingConnections;
+ int m_handshakeTimeout;
void addPendingConnection(QWebSocket *pWebSocket);
void setErrorFromSocketError(QAbstractSocket::SocketError error,
@@ -138,6 +148,7 @@ private:
void onNewConnection();
void onSocketDisconnected();
void handshakeReceived();
+ void finishHandshakeTimeout(QTcpSocket *pTcpSocket);
};
QT_END_NAMESPACE
diff --git a/tests/auto/websockets/qwebsocketserver/tst_qwebsocketserver.cpp b/tests/auto/websockets/qwebsocketserver/tst_qwebsocketserver.cpp
index 64b2489..442196b 100644
--- a/tests/auto/websockets/qwebsocketserver/tst_qwebsocketserver.cpp
+++ b/tests/auto/websockets/qwebsocketserver/tst_qwebsocketserver.cpp
@@ -28,7 +28,9 @@
#include <QString>
#include <QtTest>
#include <QNetworkProxy>
+#include <QTcpSocket>
#include <QTcpServer>
+#include <QtCore/QScopedPointer>
#ifndef QT_NO_OPENSSL
#include <QtNetwork/qsslpresharedkeyauthenticator.h>
#endif
@@ -113,6 +115,7 @@ private Q_SLOTS:
void tst_serverDestroyedWhileSocketConnected();
void tst_scheme(); // qtbug-55927
void tst_handleConnection();
+ void tst_handshakeTimeout(); // qtbug-63312, qtbug-57026
private:
bool m_shouldSkipUnsupportedIpv6Test;
@@ -387,7 +390,7 @@ void tst_QWebSocketServer::tst_preSharedKey()
QWebSocketServer server(QString(), QWebSocketServer::SecureMode);
bool cipherFound = false;
- const QList<QSslCipher> supportedCiphers = QSslSocket::supportedCiphers();
+ const QList<QSslCipher> supportedCiphers = QSslConfiguration::supportedCiphers();
for (const QSslCipher &cipher : supportedCiphers) {
if (cipher.name() == PSK_CIPHER_WITHOUT_AUTH) {
cipherFound = true;
@@ -573,6 +576,26 @@ void tst_QWebSocketServer::tst_serverDestroyedWhileSocketConnected()
QTRY_COMPARE(socketDisconnectedSpy.count(), 1);
}
+#ifndef QT_NO_SSL
+static void setupSecureServer(QWebSocketServer *secureServer)
+{
+ QSslConfiguration sslConfiguration;
+ QFile certFile(QStringLiteral(":/localhost.cert"));
+ QFile keyFile(QStringLiteral(":/localhost.key"));
+ QVERIFY(certFile.open(QIODevice::ReadOnly));
+ QVERIFY(keyFile.open(QIODevice::ReadOnly));
+ QSslCertificate certificate(&certFile, QSsl::Pem);
+ QSslKey sslKey(&keyFile, QSsl::Rsa, QSsl::Pem);
+ certFile.close();
+ keyFile.close();
+ sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);
+ sslConfiguration.setLocalCertificate(certificate);
+ sslConfiguration.setPrivateKey(sslKey);
+ sslConfiguration.setProtocol(QSsl::TlsV1SslV3);
+ secureServer->setSslConfiguration(sslConfiguration);
+}
+#endif
+
void tst_QWebSocketServer::tst_scheme()
{
if (m_shouldSkipUnsupportedIpv6Test)
@@ -594,20 +617,9 @@ void tst_QWebSocketServer::tst_scheme()
#ifndef QT_NO_SSL
QWebSocketServer secureServer(QString(), QWebSocketServer::SecureMode);
- QSslConfiguration sslConfiguration;
- QFile certFile(QStringLiteral(":/localhost.cert"));
- QFile keyFile(QStringLiteral(":/localhost.key"));
- QVERIFY(certFile.open(QIODevice::ReadOnly));
- QVERIFY(keyFile.open(QIODevice::ReadOnly));
- QSslCertificate certificate(&certFile, QSsl::Pem);
- QSslKey sslKey(&keyFile, QSsl::Rsa, QSsl::Pem);
- certFile.close();
- keyFile.close();
- sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);
- sslConfiguration.setLocalCertificate(certificate);
- sslConfiguration.setPrivateKey(sslKey);
- sslConfiguration.setProtocol(QSsl::TlsV1SslV3);
- secureServer.setSslConfiguration(sslConfiguration);
+ setupSecureServer(&secureServer);
+ if (QTest::currentTestFailed())
+ return;
QSignalSpy secureServerConnectionSpy(&secureServer, SIGNAL(newConnection()));
QVERIFY(secureServer.listen());
@@ -668,6 +680,149 @@ void tst_QWebSocketServer::tst_handleConnection()
QCOMPARE(arguments.first().toString(), QString("hello"));
}
+struct SocketSpy {
+ QTcpSocket *socket;
+ QSignalSpy *disconnectSpy;
+ ~SocketSpy() {
+ delete socket;
+ delete disconnectSpy;
+ }
+};
+
+static void openManyConnections(QList<SocketSpy *> *sockets, quint16 port, int numConnections)
+{
+ for (int i = 0; i < numConnections; i++) {
+ QTcpSocket *c = new QTcpSocket;
+ QSignalSpy *spy = new QSignalSpy(c, &QTcpSocket::disconnected);
+
+ c->connectToHost("127.0.0.1", port);
+
+ sockets->append(new SocketSpy{c, spy});
+ }
+}
+
+// Sum the counts together, for better output on failure (e.g. "FAIL: Actual: 49, Expected: 50")
+static int sumSocketSpyCount(const QList<SocketSpy *> &sockets)
+{
+ return std::accumulate(sockets.cbegin(), sockets.cend(), 0, [](int c, SocketSpy *s) {
+ return c + s->disconnectSpy->count();
+ });
+}
+
+void tst_QWebSocketServer::tst_handshakeTimeout()
+{
+ { // No Timeout
+ QWebSocketServer plainServer(QString(), QWebSocketServer::NonSecureMode);
+ plainServer.setHandshakeTimeout(-1);
+ QSignalSpy plainServerConnectionSpy(&plainServer, SIGNAL(newConnection()));
+
+ QVERIFY(plainServer.listen());
+
+ QWebSocket socket;
+ socket.open(plainServer.serverUrl().toString());
+
+ QTRY_COMPARE(plainServerConnectionSpy.count(), 1);
+ QScopedPointer<QWebSocket> plainServerSocket(plainServer.nextPendingConnection());
+ QVERIFY(!plainServerSocket.isNull());
+
+ plainServer.close();
+ }
+
+ { // Unencrypted
+ QWebSocketServer plainServer(QString(), QWebSocketServer::NonSecureMode);
+ plainServer.setHandshakeTimeout(500);
+ QSignalSpy plainServerConnectionSpy(&plainServer, SIGNAL(newConnection()));
+
+ QVERIFY(plainServer.listen());
+
+ /* QTcpServer has a default of 30 pending connections. The test checks
+ * whether, when that list is full, the connections are dropped after
+ * a timeout and later pending connections are processed. */
+ const int numConnections = 50;
+ QList<SocketSpy *> sockets;
+ auto cleaner = qScopeGuard([&sockets]() { qDeleteAll(sockets); });
+ openManyConnections(&sockets, plainServer.serverPort(), numConnections);
+
+ QCoreApplication::processEvents();
+
+ /* We have 50 plain TCP connections open, that are not proper websockets. */
+ QCOMPARE(plainServerConnectionSpy.count(), 0);
+
+ QWebSocket socket;
+ socket.open(plainServer.serverUrl().toString());
+
+ /* Check that a real websocket will be processed after some non-websocket
+ * TCP connections timeout. */
+ QTRY_COMPARE(plainServerConnectionSpy.count(), 1);
+ QScopedPointer<QWebSocket> plainServerSocket(plainServer.nextPendingConnection());
+ QVERIFY(!plainServerSocket.isNull());
+
+ /* Check that all non websocket connections eventually timeout. */
+ QTRY_COMPARE(sumSocketSpyCount(sockets), numConnections);
+
+ plainServer.close();
+ }
+
+#if QT_CONFIG(ssl)
+ { // Encrypted
+ QWebSocketServer secureServer(QString(), QWebSocketServer::SecureMode);
+ setupSecureServer(&secureServer);
+ if (QTest::currentTestFailed())
+ return;
+ secureServer.setHandshakeTimeout(500);
+
+ QSignalSpy secureServerConnectionSpy(&secureServer, SIGNAL(newConnection()));
+
+ QVERIFY(secureServer.listen());
+
+ const int numConnections = 50;
+ QList<SocketSpy *> sockets;
+ auto cleaner = qScopeGuard([&sockets]() { qDeleteAll(sockets); });
+ openManyConnections(&sockets, secureServer.serverPort(), numConnections);
+
+ QCoreApplication::processEvents();
+ QCOMPARE(secureServerConnectionSpy.count(), 0);
+
+ QWebSocket secureSocket;
+ QSslConfiguration config = secureSocket.sslConfiguration();
+ config.setPeerVerifyMode(QSslSocket::VerifyNone);
+ secureSocket.setSslConfiguration(config);
+
+ secureSocket.open(secureServer.serverUrl().toString());
+
+ QTRY_COMPARE(secureServerConnectionSpy.count(), 1);
+ QScopedPointer<QWebSocket> serverSocket(secureServer.nextPendingConnection());
+ QVERIFY(!serverSocket.isNull());
+
+ QTRY_COMPARE(sumSocketSpyCount(sockets), numConnections);
+
+ secureServer.close();
+ }
+#endif
+
+ { // Ensure properly handshaked connections are not timed out
+ QWebSocketServer plainServer(QString(), QWebSocketServer::NonSecureMode);
+ plainServer.setHandshakeTimeout(250);
+ QSignalSpy plainServerConnectionSpy(&plainServer, SIGNAL(newConnection()));
+
+ QVERIFY(plainServer.listen());
+
+ QWebSocket socket;
+ QSignalSpy socketConnectedSpy(&socket, &QWebSocket::connected);
+ QSignalSpy socketDisconnectedSpy(&socket, &QWebSocket::disconnected);
+ socket.open(plainServer.serverUrl().toString());
+
+ QTRY_COMPARE(plainServerConnectionSpy.count(), 1);
+ QTRY_COMPARE(socketConnectedSpy.count(), 1);
+
+ QEventLoop loop;
+ QTimer::singleShot(500, &loop, &QEventLoop::quit);
+ loop.exec();
+
+ QCOMPARE(socketDisconnectedSpy.count(), 0);
+ }
+}
+
QTEST_MAIN(tst_QWebSocketServer)
#include "tst_qwebsocketserver.moc"