diff options
51 files changed, 504 insertions, 219 deletions
diff --git a/.qmake.conf b/.qmake.conf index b952473..bc074d5 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.11.3 +MODULE_VERSION = 5.12.0 diff --git a/examples/examples.pro b/examples/examples.pro index 158e1ce..ba224f8 100644 --- a/examples/examples.pro +++ b/examples/examples.pro @@ -1,3 +1,3 @@ TEMPLATE = subdirs -SUBDIRS = websockets
\ No newline at end of file +SUBDIRS = websockets diff --git a/examples/websockets/echoserver/echoserver.pro b/examples/websockets/echoserver/echoserver.pro index eacaedc..e84da11 100644 --- a/examples/websockets/echoserver/echoserver.pro +++ b/examples/websockets/echoserver/echoserver.pro @@ -1,5 +1,4 @@ -QT += core websockets -QT -= gui +QT = websockets TARGET = echoserver CONFIG += console diff --git a/examples/websockets/qmlwebsocketclient/qmlwebsocketclient.pro b/examples/websockets/qmlwebsocketclient/qmlwebsocketclient.pro index 37d7823..a67643f 100644 --- a/examples/websockets/qmlwebsocketclient/qmlwebsocketclient.pro +++ b/examples/websockets/qmlwebsocketclient/qmlwebsocketclient.pro @@ -1,4 +1,4 @@ -QT += core qml quick websockets +QT += quick websockets TARGET = qmlwebsocketclient diff --git a/examples/websockets/qmlwebsocketserver/qmlwebsocketserver.pro b/examples/websockets/qmlwebsocketserver/qmlwebsocketserver.pro index 4f1a64f..1f36181 100644 --- a/examples/websockets/qmlwebsocketserver/qmlwebsocketserver.pro +++ b/examples/websockets/qmlwebsocketserver/qmlwebsocketserver.pro @@ -1,4 +1,4 @@ -QT += core qml quick websockets +QT += quick websockets TARGET = qmlwebsocketserver diff --git a/examples/websockets/simplechat/chatserver.h b/examples/websockets/simplechat/chatserver.h index 4a8285b..5e2a094 100644 --- a/examples/websockets/simplechat/chatserver.h +++ b/examples/websockets/simplechat/chatserver.h @@ -62,7 +62,7 @@ class ChatServer : public QObject Q_OBJECT public: explicit ChatServer(quint16 port, QObject *parent = nullptr); - virtual ~ChatServer(); + ~ChatServer() override; private slots: void onNewConnection(); diff --git a/examples/websockets/simplechat/simplechat.pro b/examples/websockets/simplechat/simplechat.pro index df6f248..235ccc0 100644 --- a/examples/websockets/simplechat/simplechat.pro +++ b/examples/websockets/simplechat/simplechat.pro @@ -1,5 +1,4 @@ -QT += core websockets -QT -= gui +QT = websockets TARGET = chatserver CONFIG += console diff --git a/examples/websockets/sslechoclient/sslechoclient.pro b/examples/websockets/sslechoclient/sslechoclient.pro index 925fece..3fa9d9b 100644 --- a/examples/websockets/sslechoclient/sslechoclient.pro +++ b/examples/websockets/sslechoclient/sslechoclient.pro @@ -1,5 +1,4 @@ -QT += core websockets -QT -= gui +QT = websockets TARGET = sslechoclient CONFIG += console diff --git a/examples/websockets/sslechoserver/sslechoserver.h b/examples/websockets/sslechoserver/sslechoserver.h index 8064476..58d1d67 100644 --- a/examples/websockets/sslechoserver/sslechoserver.h +++ b/examples/websockets/sslechoserver/sslechoserver.h @@ -63,7 +63,7 @@ class SslEchoServer : public QObject Q_OBJECT public: explicit SslEchoServer(quint16 port, QObject *parent = nullptr); - virtual ~SslEchoServer(); + ~SslEchoServer() override; private Q_SLOTS: void onNewConnection(); diff --git a/examples/websockets/sslechoserver/sslechoserver.pro b/examples/websockets/sslechoserver/sslechoserver.pro index b1c0528..a214a6d 100644 --- a/examples/websockets/sslechoserver/sslechoserver.pro +++ b/examples/websockets/sslechoserver/sslechoserver.pro @@ -1,5 +1,4 @@ -QT += core websockets -QT -= gui +QT = websockets TARGET = sslechoserver CONFIG += console diff --git a/qtwebsockets.pro b/qtwebsockets.pro index 58c33f2..0dcd45b 100644 --- a/qtwebsockets.pro +++ b/qtwebsockets.pro @@ -1 +1,2 @@ +requires(qtHaveModule(network)) load(qt_parts) diff --git a/src/imports/qmlwebsockets/dependencies.json b/src/imports/qmlwebsockets/dependencies.json new file mode 100644 index 0000000..0d4f101 --- /dev/null +++ b/src/imports/qmlwebsockets/dependencies.json @@ -0,0 +1,2 @@ +[ +] diff --git a/src/imports/qmlwebsockets/plugins.qmltypes b/src/imports/qmlwebsockets/plugins.qmltypes index cbbb628..2fb57cd 100644 --- a/src/imports/qmlwebsockets/plugins.qmltypes +++ b/src/imports/qmlwebsockets/plugins.qmltypes @@ -4,7 +4,7 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -nonrelocatable QtWebSockets 1.1' +// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtWebSockets 1.1' Module { dependencies: [] diff --git a/src/imports/qmlwebsockets/qmlwebsockets.pro b/src/imports/qmlwebsockets/qmlwebsockets.pro index fef47f4..7b6fc86 100644 --- a/src/imports/qmlwebsockets/qmlwebsockets.pro +++ b/src/imports/qmlwebsockets/qmlwebsockets.pro @@ -1,4 +1,4 @@ -QT = core websockets qml qml-private core-private +QT = websockets qml-private core-private TARGETPATH = QtWebSockets @@ -12,8 +12,6 @@ SOURCES += qmlwebsockets_plugin.cpp \ OTHER_FILES += qmldir -DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 - -IMPORT_VERSION = 1.0 +IMPORT_VERSION = 1.1 load(qml_plugin) diff --git a/src/imports/qmlwebsockets/qmlwebsockets_plugin.h b/src/imports/qmlwebsockets/qmlwebsockets_plugin.h index 749d830..0fc9435 100644 --- a/src/imports/qmlwebsockets/qmlwebsockets_plugin.h +++ b/src/imports/qmlwebsockets/qmlwebsockets_plugin.h @@ -42,13 +42,6 @@ #include <QQmlExtensionPlugin> -static void initResources() -{ -#ifdef QT_STATIC - Q_INIT_RESOURCE(qmake_QtWebSockets); -#endif -} - QT_BEGIN_NAMESPACE class QtWebSocketsDeclarativeModule : public QQmlExtensionPlugin @@ -57,7 +50,7 @@ class QtWebSocketsDeclarativeModule : public QQmlExtensionPlugin Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: - QtWebSocketsDeclarativeModule(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); } + QtWebSocketsDeclarativeModule(QObject *parent = 0) : QQmlExtensionPlugin(parent) { } void registerTypes(const char *uri); }; diff --git a/src/imports/qmlwebsockets/qqmlwebsocket.h b/src/imports/qmlwebsockets/qqmlwebsocket.h index 8db435d..e1ffc72 100644 --- a/src/imports/qmlwebsockets/qqmlwebsocket.h +++ b/src/imports/qmlwebsockets/qqmlwebsocket.h @@ -62,7 +62,7 @@ class QQmlWebSocket : public QObject, public QQmlParserStatus public: explicit QQmlWebSocket(QObject *parent = 0); explicit QQmlWebSocket(QWebSocket *socket, QObject *parent = 0); - virtual ~QQmlWebSocket(); + ~QQmlWebSocket() override; enum Status { @@ -94,8 +94,8 @@ Q_SIGNALS: void urlChanged(); public: - void classBegin() Q_DECL_OVERRIDE; - void componentComplete() Q_DECL_OVERRIDE; + void classBegin() override; + void componentComplete() override; private Q_SLOTS: void onError(QAbstractSocket::SocketError error); diff --git a/src/imports/qmlwebsockets/qqmlwebsocketserver.h b/src/imports/qmlwebsockets/qqmlwebsocketserver.h index 5de5b09..98dbfc4 100644 --- a/src/imports/qmlwebsockets/qqmlwebsocketserver.h +++ b/src/imports/qmlwebsockets/qqmlwebsocketserver.h @@ -63,10 +63,10 @@ class QQmlWebSocketServer : public QObject, public QQmlParserStatus public: explicit QQmlWebSocketServer(QObject *parent = Q_NULLPTR); - virtual ~QQmlWebSocketServer(); + ~QQmlWebSocketServer() override; - void classBegin() Q_DECL_OVERRIDE; - void componentComplete() Q_DECL_OVERRIDE; + void classBegin() override; + void componentComplete() override; QUrl url() const; diff --git a/src/imports/qmlwebsockets_compat/qmlwebsockets_compat.pro b/src/imports/qmlwebsockets_compat/qmlwebsockets_compat.pro index a6610b6..fbdf01c 100644 --- a/src/imports/qmlwebsockets_compat/qmlwebsockets_compat.pro +++ b/src/imports/qmlwebsockets_compat/qmlwebsockets_compat.pro @@ -1,6 +1,6 @@ ### Qt 6: Remove support for the old "Qt.WebSockets" QML module. -QT = core websockets qml +QT = websockets qml TARGETPATH = Qt/WebSockets diff --git a/src/websockets/qdefaultmaskgenerator_p.h b/src/websockets/qdefaultmaskgenerator_p.h index 8637ec6..3ad4990 100644 --- a/src/websockets/qdefaultmaskgenerator_p.h +++ b/src/websockets/qdefaultmaskgenerator_p.h @@ -61,11 +61,11 @@ class Q_AUTOTEST_EXPORT QDefaultMaskGenerator : public QMaskGenerator Q_DISABLE_COPY(QDefaultMaskGenerator) public: - explicit QDefaultMaskGenerator(QObject *parent = 0); - virtual ~QDefaultMaskGenerator(); + explicit QDefaultMaskGenerator(QObject *parent = nullptr); + ~QDefaultMaskGenerator() override; - bool seed() Q_DECL_NOEXCEPT Q_DECL_OVERRIDE; - quint32 nextMask() Q_DECL_NOEXCEPT Q_DECL_OVERRIDE; + bool seed() Q_DECL_NOEXCEPT override; + quint32 nextMask() Q_DECL_NOEXCEPT override; }; QT_END_NAMESPACE diff --git a/src/websockets/qmaskgenerator.h b/src/websockets/qmaskgenerator.h index 5cd8144..419daca 100644 --- a/src/websockets/qmaskgenerator.h +++ b/src/websockets/qmaskgenerator.h @@ -51,7 +51,7 @@ class Q_WEBSOCKETS_EXPORT QMaskGenerator : public QObject public: explicit QMaskGenerator(QObject *parent = nullptr); - virtual ~QMaskGenerator(); + ~QMaskGenerator() override; virtual bool seed() = 0; virtual quint32 nextMask() = 0; diff --git a/src/websockets/qsslserver_p.h b/src/websockets/qsslserver_p.h index 4cd0eac..10f8fea 100644 --- a/src/websockets/qsslserver_p.h +++ b/src/websockets/qsslserver_p.h @@ -66,7 +66,7 @@ class QSslServer : public QTcpServer public: explicit QSslServer(QObject *parent = nullptr); - virtual ~QSslServer(); + ~QSslServer() override; void setSslConfiguration(const QSslConfiguration &sslConfiguration); QSslConfiguration sslConfiguration() const; @@ -78,7 +78,7 @@ Q_SIGNALS: void preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator); protected: - virtual void incomingConnection(qintptr socket); + void incomingConnection(qintptr socket) override; private: QSslConfiguration m_sslConfiguration; diff --git a/src/websockets/qwebsocket.cpp b/src/websockets/qwebsocket.cpp index 3472fe4..ade1eb4 100644 --- a/src/websockets/qwebsocket.cpp +++ b/src/websockets/qwebsocket.cpp @@ -297,7 +297,7 @@ QT_BEGIN_NAMESPACE QWebSocket::QWebSocket(const QString &origin, QWebSocketProtocol::Version version, QObject *parent) : - QObject(*(new QWebSocketPrivate(origin, version, this)), parent) + QObject(*(new QWebSocketPrivate(origin, version)), parent) { Q_D(QWebSocket); d->init(); @@ -340,7 +340,7 @@ QAbstractSocket::SocketError QWebSocket::error() const */ QWebSocket::QWebSocket(QTcpSocket *pTcpSocket, QWebSocketProtocol::Version version, QObject *parent) : - QObject(*(new QWebSocketPrivate(pTcpSocket, version, this)), parent) + QObject(*(new QWebSocketPrivate(pTcpSocket, version)), parent) { Q_D(QWebSocket); d->init(); @@ -775,4 +775,17 @@ bool QWebSocket::isValid() const return d->isValid(); } +/*! + \since 5.12 + Returns the number of bytes that are waiting to be written. The bytes are written when control + goes back to the event loop or when flush() is called. + + \sa flush + */ +qint64 QWebSocket::bytesToWrite() const +{ + Q_D(const QWebSocket); + return d->m_pSocket ? d->m_pSocket->bytesToWrite() : 0; +} + QT_END_NAMESPACE diff --git a/src/websockets/qwebsocket.h b/src/websockets/qwebsocket.h index a80c47a..4944689 100644 --- a/src/websockets/qwebsocket.h +++ b/src/websockets/qwebsocket.h @@ -69,7 +69,7 @@ public: explicit QWebSocket(const QString &origin = QString(), QWebSocketProtocol::Version version = QWebSocketProtocol::VersionLatest, QObject *parent = nullptr); - virtual ~QWebSocket(); + ~QWebSocket() override; void abort(); QAbstractSocket::SocketError error() const; @@ -113,6 +113,8 @@ public: QSslConfiguration sslConfiguration() const; #endif + qint64 bytesToWrite() const; + public Q_SLOTS: void close(QWebSocketProtocol::CloseCode closeCode = QWebSocketProtocol::CloseCodeNormal, const QString &reason = QString()); diff --git a/src/websockets/qwebsocket_p.cpp b/src/websockets/qwebsocket_p.cpp index d233b66..8529538 100644 --- a/src/websockets/qwebsocket_p.cpp +++ b/src/websockets/qwebsocket_p.cpp @@ -87,10 +87,8 @@ QWebSocketConfiguration::QWebSocketConfiguration() : /*! \internal */ -QWebSocketPrivate::QWebSocketPrivate(const QString &origin, QWebSocketProtocol::Version version, - QWebSocket *pWebSocket) : +QWebSocketPrivate::QWebSocketPrivate(const QString &origin, QWebSocketProtocol::Version version) : QObjectPrivate(), - q_ptr(pWebSocket), m_pSocket(nullptr), m_errorString(), m_version(version), @@ -120,10 +118,8 @@ QWebSocketPrivate::QWebSocketPrivate(const QString &origin, QWebSocketProtocol:: /*! \internal */ -QWebSocketPrivate::QWebSocketPrivate(QTcpSocket *pTcpSocket, QWebSocketProtocol::Version version, - QWebSocket *pWebSocket) : +QWebSocketPrivate::QWebSocketPrivate(QTcpSocket *pTcpSocket, QWebSocketProtocol::Version version) : QObjectPrivate(), - q_ptr(pWebSocket), m_pSocket(pTcpSocket), m_errorString(pTcpSocket->errorString()), m_version(version), @@ -228,6 +224,8 @@ bool QWebSocketPrivate::flush() return result; } +#ifndef Q_OS_WASM + /*! \internal */ @@ -244,6 +242,8 @@ qint64 QWebSocketPrivate::sendBinaryMessage(const QByteArray &data) return doWriteFrames(data, true); } +#endif + #ifndef QT_NO_SSL /*! \internal @@ -324,6 +324,8 @@ QWebSocket *QWebSocketPrivate::upgradeFrom(QTcpSocket *pTcpSocket, return pWebSocket; } +#ifndef Q_OS_WASM + /*! \internal */ @@ -345,10 +347,10 @@ void QWebSocketPrivate::close(QWebSocketProtocol::CloseCode closeCode, QString r quint32 maskingKey = 0; if (m_mustMask) { maskingKey = generateMaskingKey(); - QWebSocketProtocol::mask(payload.data(), payload.size(), maskingKey); + QWebSocketProtocol::mask(payload.data(), quint64(payload.size()), maskingKey); } QByteArray frame = getFrameHeader(QWebSocketProtocol::OpCodeClose, - payload.size(), maskingKey, true); + quint64(payload.size()), maskingKey, true); Q_ASSERT(payload.length() <= 125); frame.append(payload); @@ -416,7 +418,7 @@ void QWebSocketPrivate::open(const QNetworkRequest &request, bool mask) setErrorString(message); Q_EMIT q->error(QAbstractSocket::UnsupportedSocketOperationError); } else { - QSslSocket *sslSocket = new QSslSocket(q_ptr); + QSslSocket *sslSocket = new QSslSocket(q); m_pSocket = sslSocket; if (Q_LIKELY(m_pSocket)) { m_pSocket->setSocketOption(QAbstractSocket::LowDelayOption, 1); @@ -435,7 +437,7 @@ void QWebSocketPrivate::open(const QNetworkRequest &request, bool mask) #ifndef QT_NO_NETWORKPROXY sslSocket->setProxy(m_configuration.m_proxy); #endif - sslSocket->connectToHostEncrypted(url.host(), url.port(443)); + sslSocket->connectToHostEncrypted(url.host(), quint16(url.port(443))); } else { const QString message = QWebSocket::tr("Out of memory."); setErrorString(message); @@ -445,7 +447,7 @@ void QWebSocketPrivate::open(const QNetworkRequest &request, bool mask) } else #endif if (url.scheme() == QStringLiteral("ws")) { - m_pSocket = new QTcpSocket(q_ptr); + m_pSocket = new QTcpSocket(q); if (Q_LIKELY(m_pSocket)) { m_pSocket->setSocketOption(QAbstractSocket::LowDelayOption, 1); m_pSocket->setSocketOption(QAbstractSocket::KeepAliveOption, 1); @@ -457,7 +459,7 @@ void QWebSocketPrivate::open(const QNetworkRequest &request, bool mask) #ifndef QT_NO_NETWORKPROXY m_pSocket->setProxy(m_configuration.m_proxy); #endif - m_pSocket->connectToHost(url.host(), url.port(80)); + m_pSocket->connectToHost(url.host(), quint16(url.port(80))); } else { const QString message = QWebSocket::tr("Out of memory."); setErrorString(message); @@ -472,6 +474,8 @@ void QWebSocketPrivate::open(const QNetworkRequest &request, bool mask) } } +#endif + /*! \internal */ @@ -482,7 +486,8 @@ void QWebSocketPrivate::ping(const QByteArray &payload) quint32 maskingKey = 0; if (m_mustMask) maskingKey = generateMaskingKey(); - QByteArray pingFrame = getFrameHeader(QWebSocketProtocol::OpCodePing, payloadTruncated.size(), + QByteArray pingFrame = getFrameHeader(QWebSocketProtocol::OpCodePing, + quint64(payloadTruncated.size()), maskingKey, true); if (m_mustMask) QWebSocketProtocol::mask(&payloadTruncated, maskingKey); @@ -710,6 +715,7 @@ QByteArray QWebSocketPrivate::getFrameHeader(QWebSocketProtocol::OpCode opCode, quint64 payloadLength, quint32 maskingKey, bool lastFrame) { + Q_Q(QWebSocket); QByteArray header; bool ok = payloadLength <= 0x7FFFFFFFFFFFFFFFULL; @@ -743,7 +749,7 @@ QByteArray QWebSocketPrivate::getFrameHeader(QWebSocketProtocol::OpCode opCode, } } else { setErrorString(QStringLiteral("WebSocket::getHeader: payload too big!")); - Q_EMIT q_ptr->error(QAbstractSocket::DatagramTooLargeError); + Q_EMIT q->error(QAbstractSocket::DatagramTooLargeError); } return header; @@ -762,7 +768,7 @@ qint64 QWebSocketPrivate::doWriteFrames(const QByteArray &data, bool isBinary) const QWebSocketProtocol::OpCode firstOpCode = isBinary ? QWebSocketProtocol::OpCodeBinary : QWebSocketProtocol::OpCodeText; - int numFrames = data.size() / FRAME_SIZE_IN_BYTES; + int numFrames = data.size() / int(FRAME_SIZE_IN_BYTES); QByteArray tmpData(data); tmpData.detach(); char *payload = tmpData.data(); @@ -775,7 +781,7 @@ qint64 QWebSocketPrivate::doWriteFrames(const QByteArray &data, bool isBinary) if (Q_UNLIKELY(numFrames == 0)) numFrames = 1; quint64 currentPosition = 0; - quint64 bytesLeft = data.size(); + quint64 bytesLeft = quint64(data.size()); for (int i = 0; i < numFrames; ++i) { quint32 maskingKey = 0; @@ -1108,16 +1114,18 @@ void QWebSocketPrivate::processStateChanged(QAbstractSocket::SocketState socketS headers << qMakePair(QString::fromLatin1(key), QString::fromLatin1(m_request.rawHeader(key))); - const QString handshake = - createHandShakeRequest(m_resourceName, - m_request.url().host() - % QStringLiteral(":") - % QString::number(m_request.url().port(port)), - origin(), - QString(), - QString(), - m_key, - headers); + const auto format = QUrl::RemoveScheme | QUrl::RemoveUserInfo + | QUrl::RemovePath | QUrl::RemoveQuery + | QUrl::RemoveFragment | QUrl::RemovePort; + const QString host = m_request.url().toString(format).mid(2); + const QString handshake = createHandShakeRequest(m_resourceName, + host % QStringLiteral(":") + % QString::number(m_request.url().port(port)), + origin(), + QString(), + QString(), + m_key, + headers); if (handshake.isEmpty()) { m_pSocket->abort(); Q_EMIT q->error(QAbstractSocket::ConnectionRefusedError); @@ -1146,8 +1154,6 @@ void QWebSocketPrivate::processStateChanged(QAbstractSocket::SocketState socketS //do nothing //to make C++ compiler happy; break; - default: - break; } } @@ -1185,7 +1191,10 @@ void QWebSocketPrivate::processPing(const QByteArray &data) quint32 maskingKey = 0; if (m_mustMask) maskingKey = generateMaskingKey(); - m_pSocket->write(getFrameHeader(QWebSocketProtocol::OpCodePong, data.size(), maskingKey, true)); + m_pSocket->write(getFrameHeader(QWebSocketProtocol::OpCodePong, + unsigned(data.size()), + maskingKey, + true)); if (data.size() > 0) { QByteArray maskedData = data; if (m_mustMask) diff --git a/src/websockets/qwebsocket_p.h b/src/websockets/qwebsocket_p.h index fd46e0a..fd631d4 100644 --- a/src/websockets/qwebsocket_p.h +++ b/src/websockets/qwebsocket_p.h @@ -64,10 +64,15 @@ #include <QtCore/QTime> #include <private/qobject_p.h> +#include "qwebsocket.h" #include "qwebsocketprotocol.h" #include "qwebsocketdataprocessor_p.h" #include "qdefaultmaskgenerator_p.h" +#ifdef Q_OS_WASM +#include <emscripten/val.h> +#endif + QT_BEGIN_NAMESPACE class QWebSocketHandshakeRequest; @@ -102,9 +107,8 @@ class QWebSocketPrivate : public QObjectPrivate public: Q_DECLARE_PUBLIC(QWebSocket) explicit QWebSocketPrivate(const QString &origin, - QWebSocketProtocol::Version version, - QWebSocket * const pWebSocket); - virtual ~QWebSocketPrivate(); + QWebSocketProtocol::Version version); + ~QWebSocketPrivate() override; void init(); void abort(); @@ -155,11 +159,8 @@ public: void open(const QNetworkRequest &request, bool mask); void ping(const QByteArray &payload); - QWebSocket * const q_ptr; - private: - QWebSocketPrivate(QTcpSocket *pTcpSocket, QWebSocketProtocol::Version version, - QWebSocket *pWebSocket); + QWebSocketPrivate(QTcpSocket *pTcpSocket, QWebSocketProtocol::Version version); void setVersion(QWebSocketProtocol::Version version); void setResourceName(const QString &resourceName); void setRequest(const QNetworkRequest &request); @@ -250,6 +251,9 @@ private: QMap<QString, QString> m_headers; friend class QWebSocketServerPrivate; +#ifdef Q_OS_WASM + emscripten::val socketContext = emscripten::val::null(); +#endif }; QT_END_NAMESPACE diff --git a/src/websockets/qwebsocket_wasm_p.cpp b/src/websockets/qwebsocket_wasm_p.cpp new file mode 100644 index 0000000..2ac61ba --- /dev/null +++ b/src/websockets/qwebsocket_wasm_p.cpp @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebSockets module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or 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.GPL2 and 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwebsocket_p.h" + +#include <QtCore/qcoreapplication.h> + +#include <emscripten.h> +#include <emscripten/bind.h> + +using namespace emscripten; + +static void q_onErrorCallback(val event) +{ + val target = event["target"]; + + QWebSocketPrivate *wsp = reinterpret_cast<QWebSocketPrivate*>(target["data-context"].as<quintptr>()); + Q_ASSERT (wsp); + + emit wsp->q_func()->error(wsp->error()); +} + +static void q_onCloseCallback(val event) +{ + val target = event["target"]; + + QWebSocketPrivate *wsp = reinterpret_cast<QWebSocketPrivate*>(target["data-context"].as<quintptr>()); + Q_ASSERT (wsp); + + emit wsp->q_func()->disconnected(); +} + +static void q_onOpenCallback(val event) +{ + val target = event["target"]; + + QWebSocketPrivate *wsp = reinterpret_cast<QWebSocketPrivate*>(target["data-context"].as<quintptr>()); + Q_ASSERT (wsp); + + emit wsp->q_func()->connected(); +} + +static void q_onIncomingMessageCallback(val event) +{ + val target = event["target"]; + + if (event["data"].typeOf().as<std::string>() == "string") { + QWebSocketPrivate *wsp = reinterpret_cast<QWebSocketPrivate*>(target["data-context"].as<quintptr>()); + Q_ASSERT (wsp); + + const QString message = QString::fromStdString(event["data"].as<std::string>()); + if (!message.isEmpty()) + wsp->q_func()->textMessageReceived(message); + } else { + val reader = val::global("FileReader").new_(); + reader.set("onload", val::module_property("QWebSocketPrivate_readBlob")); + reader.set("data-context", target["data-context"]); + reader.call<void>("readAsArrayBuffer", event["data"]); + } +} + +static void q_readBlob(val event) +{ + val fileReader = event["target"]; + + QWebSocketPrivate *wsp = reinterpret_cast<QWebSocketPrivate*>(fileReader["data-context"].as<quintptr>()); + Q_ASSERT (wsp); + + // Set up source typed array + val result = fileReader["result"]; // ArrayBuffer + val Uint8Array = val::global("Uint8Array"); + val sourceTypedArray = Uint8Array.new_(result); + + // Allocate and set up destination typed array + const size_t size = result["byteLength"].as<size_t>(); + QByteArray buffer(size, Qt::Uninitialized); + + val destinationTypedArray = Uint8Array.new_(val::module_property("HEAPU8")["buffer"], + reinterpret_cast<quintptr>(buffer.data()), size); + destinationTypedArray.call<void>("set", sourceTypedArray); + + wsp->q_func()->binaryMessageReceived(buffer); +} + + +EMSCRIPTEN_BINDINGS(wasm_module) { + function("QWebSocketPrivate_onErrorCallback", q_onErrorCallback); + function("QWebSocketPrivate_onCloseCallback", q_onCloseCallback); + function("QWebSocketPrivate_onOpenCallback", q_onOpenCallback); + function("QWebSocketPrivate_onIncomingMessageCallback", q_onIncomingMessageCallback); + function("QWebSocketPrivate_readBlob", q_readBlob); +} + +qint64 QWebSocketPrivate::sendTextMessage(const QString &message) +{ + socketContext.call<void>("send", message.toStdString()); + return message.length(); +} + +qint64 QWebSocketPrivate::sendBinaryMessage(const QByteArray &data) +{ + socketContext.call<void>("send", + val(typed_memory_view(data.size(), + reinterpret_cast<const unsigned char *> + (data.constData())))); + + return data.length(); +} + +void QWebSocketPrivate::close(QWebSocketProtocol::CloseCode closeCode, QString reason) +{ + Q_Q(QWebSocket); + m_closeCode = closeCode; + m_closeReason = reason; + Q_EMIT q->aboutToClose(); + + socketContext.call<void>("close", static_cast<quint16>(closeCode), + reason.toLatin1().toStdString()); +} + +void QWebSocketPrivate::open(const QNetworkRequest &request, bool mask) +{ + Q_UNUSED(mask) + Q_Q(QWebSocket); + const QUrl url = request.url(); + if (!url.isValid() || url.toString().contains(QStringLiteral("\r\n"))) { + setErrorString(QWebSocket::tr("Invalid URL.")); + Q_EMIT q->error(QAbstractSocket::ConnectionRefusedError); + return; + } + + const std::string urlbytes = url.toString().toStdString(); + + // HTML WebSockets do not support arbitrary request headers, but + // do support the WebSocket protocol header. This header is + // required for some use cases like MQTT. + const std::string protocolHeaderValue = request.rawHeader("Sec-WebSocket-Protocol").toStdString(); + val webSocket = val::global("WebSocket"); + + socketContext = !protocolHeaderValue.empty() + ? webSocket.new_(urlbytes, protocolHeaderValue) + : webSocket.new_(urlbytes); + + socketContext.set("onerror", val::module_property("QWebSocketPrivate_onErrorCallback")); + socketContext.set("onclose", val::module_property("QWebSocketPrivate_onCloseCallback")); + socketContext.set("onopen", val::module_property("QWebSocketPrivate_onOpenCallback")); + socketContext.set("onmessage", val::module_property("QWebSocketPrivate_onIncomingMessageCallback")); + socketContext.set("data-context", val(quintptr(reinterpret_cast<void *>(this)))); +} diff --git a/src/websockets/qwebsocketdataprocessor.cpp b/src/websockets/qwebsocketdataprocessor.cpp index 8070698..4f81222 100644 --- a/src/websockets/qwebsocketdataprocessor.cpp +++ b/src/websockets/qwebsocketdataprocessor.cpp @@ -150,9 +150,9 @@ void QWebSocketDataProcessor::process(QIODevice *pIoDevice) m_opCode = frame.opCode(); m_isFragmented = !frame.isFinalFrame(); } - quint64 messageLength = (quint64)(m_opCode == QWebSocketProtocol::OpCodeText) - ? m_textMessage.length() - : m_binaryMessage.length(); + quint64 messageLength = m_opCode == QWebSocketProtocol::OpCodeText + ? quint64(m_textMessage.length()) + : quint64(m_binaryMessage.length()); if (Q_UNLIKELY((messageLength + quint64(frame.payload().length())) > MAX_MESSAGE_SIZE_IN_BYTES)) { clear(); diff --git a/src/websockets/qwebsocketdataprocessor_p.h b/src/websockets/qwebsocketdataprocessor_p.h index 79881f8..e80a843 100644 --- a/src/websockets/qwebsocketdataprocessor_p.h +++ b/src/websockets/qwebsocketdataprocessor_p.h @@ -70,7 +70,7 @@ class Q_AUTOTEST_EXPORT QWebSocketDataProcessor : public QObject public: explicit QWebSocketDataProcessor(QObject *parent = nullptr); - virtual ~QWebSocketDataProcessor(); + ~QWebSocketDataProcessor() override; static quint64 maxMessageSize(); static quint64 maxFrameSize(); diff --git a/src/websockets/qwebsocketframe.cpp b/src/websockets/qwebsocketframe.cpp index 3be3d28..041302e 100644 --- a/src/websockets/qwebsocketframe.cpp +++ b/src/websockets/qwebsocketframe.cpp @@ -456,7 +456,7 @@ QWebSocketFrame QWebSocketFrame::readFrame(QIODevice *pIoDevice) } else { quint64 bytesAvailable = quint64(pIoDevice->bytesAvailable()); if (bytesAvailable >= payloadLength) { - frame.m_payload = pIoDevice->read(payloadLength); + frame.m_payload = pIoDevice->read(int(payloadLength)); //payloadLength can be safely cast to an integer, //because MAX_FRAME_SIZE_IN_BYTES = MAX_INT if (Q_UNLIKELY(frame.m_payload.length() != int(payloadLength))) { diff --git a/src/websockets/qwebsockethandshakeresponse_p.h b/src/websockets/qwebsockethandshakeresponse_p.h index 2c2c0b1..9a9b883 100644 --- a/src/websockets/qwebsockethandshakeresponse_p.h +++ b/src/websockets/qwebsockethandshakeresponse_p.h @@ -73,7 +73,7 @@ public: const QList<QString> &supportedProtocols, const QList<QString> &supportedExtensions); - virtual ~QWebSocketHandshakeResponse(); + ~QWebSocketHandshakeResponse() override; bool isValid() const; bool canUpgrade() const; diff --git a/src/websockets/qwebsocketprotocol.cpp b/src/websockets/qwebsocketprotocol.cpp index 5cde1a7..df87a93 100644 --- a/src/websockets/qwebsocketprotocol.cpp +++ b/src/websockets/qwebsocketprotocol.cpp @@ -193,7 +193,7 @@ QWebSocketProtocol::Version QWebSocketProtocol::versionFromString(const QString void QWebSocketProtocol::mask(QByteArray *payload, quint32 maskingKey) { Q_ASSERT(payload); - mask(payload->data(), payload->size(), maskingKey); + mask(payload->data(), quint64(payload->size()), maskingKey); } /*! diff --git a/src/websockets/qwebsocketserver.cpp b/src/websockets/qwebsocketserver.cpp index 5111bfd..7790250 100644 --- a/src/websockets/qwebsocketserver.cpp +++ b/src/websockets/qwebsocketserver.cpp @@ -253,11 +253,11 @@ QWebSocketServer::QWebSocketServer(const QString &serverName, SslMode secureMode #ifndef QT_NO_SSL (secureMode == SecureMode) ? QWebSocketServerPrivate::SecureMode : - QWebSocketServerPrivate::NonSecureMode, + QWebSocketServerPrivate::NonSecureMode #else - QWebSocketServerPrivate::NonSecureMode, + QWebSocketServerPrivate::NonSecureMode #endif - this)), parent) + )), parent) { #ifdef QT_NO_SSL Q_UNUSED(secureMode) @@ -574,6 +574,7 @@ void QWebSocketServer::setMaxPendingConnections(int numConnections) d->setMaxPendingConnections(numConnections); } +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) /*! Sets the socket descriptor this server should use when listening for incoming connections to \a socketDescriptor. @@ -582,8 +583,9 @@ void QWebSocketServer::setMaxPendingConnections(int numConnections) The socket is assumed to be in listening state. \sa socketDescriptor(), isListening() + \since 5.3 */ -bool QWebSocketServer::setSocketDescriptor(int socketDescriptor) +bool QWebSocketServer::setSocketDescriptor(qintptr socketDescriptor) { Q_D(QWebSocketServer); return d->setSocketDescriptor(socketDescriptor); @@ -596,12 +598,104 @@ bool QWebSocketServer::setSocketDescriptor(int socketDescriptor) native socket functions. \sa setSocketDescriptor(), isListening() + \since 5.3 + */ +qintptr QWebSocketServer::socketDescriptor() const +{ + Q_D(const QWebSocketServer); + return d->socketDescriptor(); +} + +/*! + \fn QWebSocketServer::nativeDescriptor + \deprecated + + Returns the native socket descriptor the server uses to listen for incoming instructions, + or -1 if the server is not listening. + If the server is using QNetworkProxy, the returned descriptor may not be usable with + native socket functions. + + \sa socketDescriptor(), setSocketDescriptor(), setNativeDescriptor(), isListening() + \since 5.12 + */ +/*! + \fn QWebSocketServer::setNativeDescriptor + \deprecated + + Sets the socket descriptor this server should use when listening for incoming connections to + \a socketDescriptor. + + Returns true if the socket is set successfully; otherwise returns false. + The socket is assumed to be in listening state. + + \sa socketDescriptor(), setSocketDescriptor(), nativeDescriptor(), isListening() + \since 5.12 + */ +#else // ### Qt 6: Remove leftovers +/*! + \deprecated + + Sets the socket descriptor this server should use when listening for incoming connections to + \a socketDescriptor. + + Returns true if the socket is set successfully; otherwise returns false. + The socket is assumed to be in listening state. + + \sa socketDescriptor(), setSocketDescriptor(), nativeDescriptor(), isListening() + \since 5.3 + */ +bool QWebSocketServer::setSocketDescriptor(int socketDescriptor) +{ + return setNativeDescriptor(socketDescriptor); +} + +/*! + \deprecated + + Returns the native socket descriptor the server uses to listen for incoming instructions, + or -1 if the server is not listening. + If the server is using QNetworkProxy, the returned descriptor may not be usable with + native socket functions. + + \sa nativeDescriptor(), setNativeDescriptor(), setSocketDescriptor(), isListening() + \since 5.3 */ int QWebSocketServer::socketDescriptor() const { + return int(nativeDescriptor()); +} + +/*! + Sets the socket descriptor this server should use when listening for incoming connections to + \a socketDescriptor. + + Returns true if the socket is set successfully; otherwise returns false. + The socket is assumed to be in listening state. + + \sa nativeDescriptor(), isListening() + \since 5.12 + */ +bool QWebSocketServer::setNativeDescriptor(qintptr socketDescriptor) +{ + Q_D(QWebSocketServer); + return d->setSocketDescriptor(socketDescriptor); +} + +/*! + Returns the native socket descriptor the server uses to listen for incoming instructions, + or -1 if the server is not listening. + If the server is using QNetworkProxy, the returned descriptor may not be usable with + native socket functions. + + \sa setNativeDescriptor(), isListening() + \since 5.12 + */ +qintptr QWebSocketServer::nativeDescriptor() const +{ Q_D(const QWebSocketServer); return d->socketDescriptor(); } +#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) /*! Returns a list of WebSocket versions that this server is supporting. diff --git a/src/websockets/qwebsocketserver.h b/src/websockets/qwebsocketserver.h index decd7c3..17d5376 100644 --- a/src/websockets/qwebsocketserver.h +++ b/src/websockets/qwebsocketserver.h @@ -76,7 +76,7 @@ public: explicit QWebSocketServer(const QString &serverName, SslMode secureMode, QObject *parent = nullptr); - virtual ~QWebSocketServer(); + ~QWebSocketServer() override; bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0); void close(); @@ -92,8 +92,18 @@ public: SslMode secureMode() const; - bool setSocketDescriptor(int socketDescriptor); - int socketDescriptor() const; +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + bool setSocketDescriptor(qintptr socketDescriptor); + qintptr socketDescriptor() const; + bool setNativeDescriptor(qintptr descriptor) { return setSocketDescriptor(descriptor); } + qintptr nativeDescriptor() const { return socketDescriptor(); } +#else // ### Qt 6: Remove leftovers + Q_DECL_DEPRECATED_X("Use setNativeDescriptor") bool setSocketDescriptor(int socketDescriptor); + Q_DECL_DEPRECATED_X("Use nativeDescriptor") int socketDescriptor() const; + bool setNativeDescriptor(qintptr descriptor); + qintptr nativeDescriptor() const; +#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + bool hasPendingConnections() const; virtual QWebSocket *nextPendingConnection(); diff --git a/src/websockets/qwebsocketserver_p.cpp b/src/websockets/qwebsocketserver_p.cpp index 59b50e7..f3e7eac 100644 --- a/src/websockets/qwebsocketserver_p.cpp +++ b/src/websockets/qwebsocketserver_p.cpp @@ -65,10 +65,8 @@ const int MAX_HEADERLINES = 100; //maximum number of http request hea \internal */ QWebSocketServerPrivate::QWebSocketServerPrivate(const QString &serverName, - QWebSocketServerPrivate::SslMode secureMode, - QWebSocketServer * const pWebSocketServer) : + QWebSocketServerPrivate::SslMode secureMode) : QObjectPrivate(), - q_ptr(pWebSocketServer), m_pTcpServer(nullptr), m_serverName(serverName), m_secureMode(secureMode), @@ -76,17 +74,16 @@ QWebSocketServerPrivate::QWebSocketServerPrivate(const QString &serverName, m_error(QWebSocketProtocol::CloseCodeNormal), m_errorString(), m_maxPendingConnections(30) -{ - Q_ASSERT(pWebSocketServer); -} +{} /*! \internal */ void QWebSocketServerPrivate::init() { + Q_Q(QWebSocketServer); if (m_secureMode == NonSecureMode) { - m_pTcpServer = new QTcpServer(q_ptr); + m_pTcpServer = new QTcpServer(q); if (Q_LIKELY(m_pTcpServer)) QObjectPrivate::connect(m_pTcpServer, &QTcpServer::newConnection, this, &QWebSocketServerPrivate::onNewConnection); @@ -94,24 +91,24 @@ void QWebSocketServerPrivate::init() qFatal("Could not allocate memory for tcp server."); } else { #ifndef QT_NO_SSL - QSslServer *pSslServer = new QSslServer(q_ptr); + QSslServer *pSslServer = new QSslServer(q); m_pTcpServer = pSslServer; if (Q_LIKELY(m_pTcpServer)) { QObjectPrivate::connect(pSslServer, &QSslServer::newEncryptedConnection, this, &QWebSocketServerPrivate::onNewConnection, Qt::QueuedConnection); QObject::connect(pSslServer, &QSslServer::peerVerifyError, - q_ptr, &QWebSocketServer::peerVerifyError); + q, &QWebSocketServer::peerVerifyError); QObject::connect(pSslServer, &QSslServer::sslErrors, - q_ptr, &QWebSocketServer::sslErrors); + q, &QWebSocketServer::sslErrors); QObject::connect(pSslServer, &QSslServer::preSharedKeyAuthenticationRequired, - q_ptr, &QWebSocketServer::preSharedKeyAuthenticationRequired); + q, &QWebSocketServer::preSharedKeyAuthenticationRequired); } #else qFatal("SSL not supported on this platform."); #endif } - QObject::connect(m_pTcpServer, &QTcpServer::acceptError, q_ptr, &QWebSocketServer::acceptError); + QObject::connect(m_pTcpServer, &QTcpServer::acceptError, q, &QWebSocketServer::acceptError); } /*! diff --git a/src/websockets/qwebsocketserver_p.h b/src/websockets/qwebsocketserver_p.h index 0ca7495..be7744f 100644 --- a/src/websockets/qwebsocketserver_p.h +++ b/src/websockets/qwebsocketserver_p.h @@ -55,6 +55,7 @@ #include <QtCore/QString> #include <QtNetwork/QHostAddress> #include <private/qobject_p.h> +#include "qwebsocketserver.h" #include "qwebsocket.h" #ifndef QT_NO_SSL @@ -66,7 +67,6 @@ QT_BEGIN_NAMESPACE class QTcpServer; class QTcpSocket; -class QWebSocketServer; class QWebSocketServerPrivate : public QObjectPrivate { @@ -80,9 +80,8 @@ public: NonSecureMode }; - explicit QWebSocketServerPrivate(const QString &serverName, SslMode secureMode, - QWebSocketServer * const pWebSocketServer); - virtual ~QWebSocketServerPrivate(); + explicit QWebSocketServerPrivate(const QString &serverName, SslMode secureMode); + ~QWebSocketServerPrivate() override; void init(); void close(bool aboutToDestroy = false); @@ -123,8 +122,6 @@ public: void handleConnection(QTcpSocket *pTcpSocket) const; - QWebSocketServer * const q_ptr; - private: QTcpServer *m_pTcpServer; QString m_serverName; diff --git a/src/websockets/websockets.pro b/src/websockets/websockets.pro index e4366ba..87eecc5 100644 --- a/src/websockets/websockets.pro +++ b/src/websockets/websockets.pro @@ -40,6 +40,8 @@ SOURCES += \ $$PWD/qmaskgenerator.cpp \ $$PWD/qdefaultmaskgenerator_p.cpp +wasm: SOURCES += $$PWD/qwebsocket_wasm_p.cpp + qtConfig(ssl) { SOURCES += $$PWD/qsslserver.cpp PRIVATE_HEADERS += $$PWD/qsslserver_p.h diff --git a/tests/auto/websockets/dataprocessor/dataprocessor.pro b/tests/auto/websockets/dataprocessor/dataprocessor.pro index ad99900..907bfeb 100644 --- a/tests/auto/websockets/dataprocessor/dataprocessor.pro +++ b/tests/auto/websockets/dataprocessor/dataprocessor.pro @@ -6,7 +6,7 @@ TEMPLATE = app TARGET = tst_dataprocessor -QT = core testlib websockets websockets-private +QT = testlib websockets-private SOURCES += tst_dataprocessor.cpp diff --git a/tests/auto/websockets/dataprocessor/tst_dataprocessor.cpp b/tests/auto/websockets/dataprocessor/tst_dataprocessor.cpp index 5f6cfba..f9a91d5 100644 --- a/tests/auto/websockets/dataprocessor/tst_dataprocessor.cpp +++ b/tests/auto/websockets/dataprocessor/tst_dataprocessor.cpp @@ -901,7 +901,7 @@ void tst_DataProcessor::frameTooBig_data() QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode"); quint64 swapped64 = 0; - const char *wireRepresentation = 0; + const char *wireRepresentation = nullptr; //only data frames are checked for being too big //control frames have explicit checking on a maximum payload size of 125, diff --git a/tests/auto/websockets/handshakerequest/handshakerequest.pro b/tests/auto/websockets/handshakerequest/handshakerequest.pro index aa7779e..b641445 100644 --- a/tests/auto/websockets/handshakerequest/handshakerequest.pro +++ b/tests/auto/websockets/handshakerequest/handshakerequest.pro @@ -6,7 +6,7 @@ TEMPLATE = app TARGET = tst_handshakerequest -QT = core testlib websockets websockets-private +QT = testlib websockets-private SOURCES += tst_handshakerequest.cpp diff --git a/tests/auto/websockets/handshakeresponse/handshakeresponse.pro b/tests/auto/websockets/handshakeresponse/handshakeresponse.pro index ab6682b..61ff2f7 100644 --- a/tests/auto/websockets/handshakeresponse/handshakeresponse.pro +++ b/tests/auto/websockets/handshakeresponse/handshakeresponse.pro @@ -6,7 +6,7 @@ TEMPLATE = app TARGET = tst_handshakeresponse -QT = core testlib websockets websockets-private +QT = testlib websockets-private SOURCES += tst_handshakeresponse.cpp diff --git a/tests/auto/websockets/qdefaultmaskgenerator/qdefaultmaskgenerator.pro b/tests/auto/websockets/qdefaultmaskgenerator/qdefaultmaskgenerator.pro index c3b1046..07ea14d 100644 --- a/tests/auto/websockets/qdefaultmaskgenerator/qdefaultmaskgenerator.pro +++ b/tests/auto/websockets/qdefaultmaskgenerator/qdefaultmaskgenerator.pro @@ -6,7 +6,7 @@ TEMPLATE = app TARGET = tst_defaultmaskgenerator -QT = core testlib websockets websockets-private +QT = testlib websockets-private SOURCES += tst_defaultmaskgenerator.cpp diff --git a/tests/auto/websockets/qwebsocket/qwebsocket.pro b/tests/auto/websockets/qwebsocket/qwebsocket.pro index 1b08dc7..df143d5 100644 --- a/tests/auto/websockets/qwebsocket/qwebsocket.pro +++ b/tests/auto/websockets/qwebsocket/qwebsocket.pro @@ -2,7 +2,7 @@ CONFIG += console CONFIG += testcase CONFIG -= app_bundle -QT = core testlib websockets +QT = testlib websockets TARGET = tst_qwebsocket diff --git a/tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp b/tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp index 211ea25..2bb5d16 100644 --- a/tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp +++ b/tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp @@ -435,9 +435,13 @@ void tst_QWebSocket::tst_sendTextMessage() QUrl urlConnected = arguments.at(0).toUrl(); QCOMPARE(urlConnected, url); + QCOMPARE(socket.bytesToWrite(), 0); socket.sendTextMessage(QStringLiteral("Hello world!")); + QVERIFY(socket.bytesToWrite() > 12); // 12 + a few extra bytes for header QVERIFY(textMessageReceived.wait(500)); + QCOMPARE(socket.bytesToWrite(), 0); + QCOMPARE(textMessageReceived.count(), 1); QCOMPARE(binaryMessageReceived.count(), 0); QCOMPARE(binaryFrameReceived.count(), 0); @@ -509,9 +513,13 @@ void tst_QWebSocket::tst_sendBinaryMessage() QTRY_COMPARE(socketConnectedSpy.count(), 1); QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); + QCOMPARE(socket.bytesToWrite(), 0); socket.sendBinaryMessage(QByteArrayLiteral("Hello world!")); + QVERIFY(socket.bytesToWrite() > 12); // 12 + a few extra bytes for header QVERIFY(binaryMessageReceived.wait(500)); + QCOMPARE(socket.bytesToWrite(), 0); + QCOMPARE(textMessageReceived.count(), 0); QCOMPARE(textFrameReceived.count(), 0); QCOMPARE(binaryMessageReceived.count(), 1); @@ -650,7 +658,7 @@ struct Warned origHandler(type, context, str); } }; -QtMessageHandler Warned::origHandler = 0; +QtMessageHandler Warned::origHandler = nullptr; bool Warned::warned = false; diff --git a/tests/auto/websockets/qwebsocketcorsauthenticator/qwebsocketcorsauthenticator.pro b/tests/auto/websockets/qwebsocketcorsauthenticator/qwebsocketcorsauthenticator.pro index 9a5af6b..caa97ad 100644 --- a/tests/auto/websockets/qwebsocketcorsauthenticator/qwebsocketcorsauthenticator.pro +++ b/tests/auto/websockets/qwebsocketcorsauthenticator/qwebsocketcorsauthenticator.pro @@ -6,7 +6,7 @@ TEMPLATE = app TARGET = tst_qwebsocketcorsauthenticator -QT = core testlib websockets +QT = testlib websockets SOURCES += tst_qwebsocketcorsauthenticator.cpp diff --git a/tests/auto/websockets/qwebsocketserver/qwebsocketserver.pro b/tests/auto/websockets/qwebsocketserver/qwebsocketserver.pro index 178fd88..c1ca4af 100644 --- a/tests/auto/websockets/qwebsocketserver/qwebsocketserver.pro +++ b/tests/auto/websockets/qwebsocketserver/qwebsocketserver.pro @@ -2,7 +2,7 @@ CONFIG += console CONFIG += testcase CONFIG -= app_bundle -QT = core testlib websockets +QT = testlib websockets TARGET = tst_qwebsocketserver diff --git a/tests/auto/websockets/qwebsocketserver/tst_qwebsocketserver.cpp b/tests/auto/websockets/qwebsocketserver/tst_qwebsocketserver.cpp index 8a3760d..2f17619 100644 --- a/tests/auto/websockets/qwebsocketserver/tst_qwebsocketserver.cpp +++ b/tests/auto/websockets/qwebsocketserver/tst_qwebsocketserver.cpp @@ -191,7 +191,11 @@ void tst_QWebSocketServer::tst_initialisation() QCOMPARE(server.maxPendingConnections(), 30); QCOMPARE(server.serverPort(), quint16(0)); QCOMPARE(server.serverAddress(), QHostAddress()); +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) QCOMPARE(server.socketDescriptor(), -1); +#else // ### Qt 6: Remove leftovers + QCOMPARE(server.nativeDescriptor(), -1); +#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) QVERIFY(!server.hasPendingConnections()); QVERIFY(!server.nextPendingConnection()); QCOMPARE(server.error(), QWebSocketProtocol::CloseCodeNormal); @@ -216,7 +220,11 @@ void tst_QWebSocketServer::tst_initialisation() QCOMPARE(server.maxPendingConnections(), 30); QCOMPARE(server.serverPort(), quint16(0)); QCOMPARE(server.serverAddress(), QHostAddress()); +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) QCOMPARE(server.socketDescriptor(), -1); +#else // ### Qt 6: Remove leftovers + QCOMPARE(server.nativeDescriptor(), -1); +#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) QVERIFY(!server.hasPendingConnections()); QVERIFY(!server.nextPendingConnection()); QCOMPARE(server.error(), QWebSocketProtocol::CloseCodeNormal); @@ -252,8 +260,13 @@ void tst_QWebSocketServer::tst_settersAndGetters() server.setMaxPendingConnections(INT_MAX); QCOMPARE(server.maxPendingConnections(), INT_MAX); +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) QVERIFY(!server.setSocketDescriptor(-2)); QCOMPARE(server.socketDescriptor(), -1); +#else // ### Qt 6: Remove leftovers + QVERIFY(!server.setNativeDescriptor(-2)); + QCOMPARE(server.nativeDescriptor(), -1); +#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) server.setServerName(QStringLiteral("Qt WebSocketServer")); QCOMPARE(server.serverName(), QStringLiteral("Qt WebSocketServer")); @@ -640,6 +653,14 @@ void tst_QWebSocketServer::tst_handleConnection() QTRY_COMPARE(wsMessageReceivedSpy.count(), 1); QList<QVariant> arguments = wsMessageReceivedSpy.takeFirst(); QCOMPARE(arguments.first().toString(), QString("dummy")); + + QSignalSpy clientMessageReceivedSpy(&webSocket, &QWebSocket::textMessageReceived); + webServerSocket->sendTextMessage("hello"); + QVERIFY(webServerSocket->bytesToWrite() > 5); // 5 + a few extra bytes for header + QTRY_COMPARE(webServerSocket->bytesToWrite(), 0); + QTRY_COMPARE(clientMessageReceivedSpy.count(), 1); + arguments = clientMessageReceivedSpy.takeFirst(); + QCOMPARE(arguments.first().toString(), QString("hello")); } QTEST_MAIN(tst_QWebSocketServer) diff --git a/tests/auto/websockets/websocketframe/websocketframe.pro b/tests/auto/websockets/websocketframe/websocketframe.pro index 8f58302..babb296 100644 --- a/tests/auto/websockets/websocketframe/websocketframe.pro +++ b/tests/auto/websockets/websocketframe/websocketframe.pro @@ -6,7 +6,7 @@ TEMPLATE = app TARGET = tst_websocketframe -QT = core testlib websockets websockets-private +QT = testlib websockets-private SOURCES += tst_websocketframe.cpp diff --git a/tests/auto/websockets/websocketprotocol/websocketprotocol.pro b/tests/auto/websockets/websocketprotocol/websocketprotocol.pro index 27748a9..22a8140 100644 --- a/tests/auto/websockets/websocketprotocol/websocketprotocol.pro +++ b/tests/auto/websockets/websocketprotocol/websocketprotocol.pro @@ -6,7 +6,7 @@ TEMPLATE = app TARGET = tst_websocketprotocol -QT = core testlib websockets websockets-private +QT = testlib websockets-private SOURCES += tst_websocketprotocol.cpp diff --git a/tests/manual/compliance/compliance.pro b/tests/manual/compliance/compliance.pro index 30ac320..078c258 100644 --- a/tests/manual/compliance/compliance.pro +++ b/tests/manual/compliance/compliance.pro @@ -1,5 +1,4 @@ CONFIG += console -CONFIG += c++11 CONFIG += testcase CONFIG -= app_bundle @@ -7,7 +6,6 @@ TEMPLATE = app TARGET = tst_compliance -QT = core network websockets testlib +QT = websockets testlib SOURCES += tst_compliance.cpp - diff --git a/tests/manual/compliance/tst_compliance.cpp b/tests/manual/compliance/tst_compliance.cpp index 478ca33..8ef3c14 100644 --- a/tests/manual/compliance/tst_compliance.cpp +++ b/tests/manual/compliance/tst_compliance.cpp @@ -37,116 +37,74 @@ class tst_ComplianceTest : public QObject { Q_OBJECT -public: - tst_ComplianceTest(); - private Q_SLOTS: - void initTestCase(); void cleanupTestCase(); - void init(); - void cleanup(); - /** - * @brief Runs the autobahn tests against our implementation - */ - void autobahnTest(); - -private: - QUrl m_url; - void runTestCases(int startNbr, int stopNbr = -1); - void runTestCase(int nbr, int total); + void autobahnTest_data(); + void autobahnTest(); }; -tst_ComplianceTest::tst_ComplianceTest() : - m_url("ws://localhost:9001") -{ -} - -void tst_ComplianceTest::initTestCase() -{ -} +static const QUrl baseUrl { "ws://localhost:9001" }; +static const auto agent = QStringLiteral("QtWebSockets/" QT_VERSION_STR); void tst_ComplianceTest::cleanupTestCase() { -} - -void tst_ComplianceTest::init() -{ -} - -void tst_ComplianceTest::cleanup() -{ -} - -void tst_ComplianceTest::runTestCase(int nbr, int total) -{ - if (nbr == total) - { - return; - } - - QWebSocket *pWebSocket = new QWebSocket; - QSignalSpy spy(pWebSocket, SIGNAL(disconnected())); - - //next for every case, connect to url - //ws://ipaddress:port/runCase?case=<number>&agent=<agentname> - //where agent name will be QWebSocket - QObject::connect(pWebSocket, &QWebSocket::textMessageReceived, [=](QString message) { - pWebSocket->sendTextMessage(message); - }); - QObject::connect(pWebSocket, &QWebSocket::binaryMessageReceived, [=](QByteArray message) { - pWebSocket->sendBinaryMessage(message); - }); - - qDebug() << "Executing test" << (nbr + 1) << "/" << total; - QUrl url = m_url; - url.setPath(QStringLiteral("/runCase")); + QWebSocket webSocket; + QSignalSpy spy(&webSocket, &QWebSocket::disconnected); + auto url = baseUrl; + url.setPath(QStringLiteral("/updateReports")); QUrlQuery query; - query.addQueryItem(QStringLiteral("case"), QString::number(nbr + 1)); - query.addQueryItem(QStringLiteral("agent"), QStringLiteral("QtWebSockets/1.0")); + query.addQueryItem(QStringLiteral("agent"), agent); url.setQuery(query); - pWebSocket->open(url); - spy.wait(60000); - pWebSocket->close(); - delete pWebSocket; - pWebSocket = nullptr; - runTestCase(nbr + 1, total); -} - -void tst_ComplianceTest::runTestCases(int startNbr, int stopNbr) -{ - runTestCase(startNbr, stopNbr); + webSocket.open(url); + QVERIFY(spy.wait()); } -void tst_ComplianceTest::autobahnTest() +void tst_ComplianceTest::autobahnTest_data() { - //connect to autobahn server at url ws://ipaddress:port/getCaseCount - QWebSocket *pWebSocket = new QWebSocket; - QUrl url = m_url; - int numberOfTestCases = 0; - QSignalSpy spy(pWebSocket, SIGNAL(disconnected())); - QObject::connect(pWebSocket, &QWebSocket::textMessageReceived, [&](QString message) { - numberOfTestCases = message.toInt(); + QTest::addColumn<int>("testCase"); + + // Ask /getCaseCount how many tests we have + QWebSocket webSocket; + QSignalSpy spy(&webSocket, &QWebSocket::disconnected); + + connect(&webSocket, &QWebSocket::textMessageReceived, [](QString message) { + bool ok; + const auto numberOfTestCases = message.toInt(&ok); + if (!ok) + QSKIP("Unable to parse /getCaseCount result"); + for (auto i = 1; i <= numberOfTestCases; ++i) + QTest::addRow("%d", i) << i; }); + auto url = baseUrl; url.setPath(QStringLiteral("/getCaseCount")); - pWebSocket->open(url); - spy.wait(60000); - QVERIFY(numberOfTestCases > 0); - - QObject::disconnect(pWebSocket, &QWebSocket::textMessageReceived, 0, 0); - runTestCases(0, numberOfTestCases); + webSocket.open(url); + if (!spy.wait()) + QSKIP("AutoBahn test server didn't deliver case-count"); +} - url.setPath(QStringLiteral("/updateReports")); +void tst_ComplianceTest::autobahnTest() +{ + QFETCH(int, testCase); + QWebSocket webSocket; + QSignalSpy spy(&webSocket, &QWebSocket::disconnected); + connect(&webSocket, &QWebSocket::textMessageReceived, + &webSocket, &QWebSocket::sendTextMessage); + connect(&webSocket, &QWebSocket::binaryMessageReceived, + &webSocket, &QWebSocket::sendBinaryMessage); + + // Ask /runCase?case=<number>&agent=<agent> to run the test-case. + auto url = baseUrl; + url.setPath(QStringLiteral("/runCase")); QUrlQuery query; - query.addQueryItem(QStringLiteral("agent"), QStringLiteral("QtWebSockets")); + query.addQueryItem(QStringLiteral("case"), QString::number(testCase)); + query.addQueryItem(QStringLiteral("agent"), agent); url.setQuery(query); - pWebSocket->open(url); - spy.wait(60000); - delete pWebSocket; + webSocket.open(url); + QVERIFY(spy.wait()); } QTEST_MAIN(tst_ComplianceTest) #include "tst_compliance.moc" - diff --git a/tests/manual/websockets/websockets.pro b/tests/manual/websockets/websockets.pro index a8b2edb..62000b9 100644 --- a/tests/manual/websockets/websockets.pro +++ b/tests/manual/websockets/websockets.pro @@ -1,5 +1,4 @@ CONFIG += console -CONFIG += c++11 CONFIG += testcase CONFIG -= app_bundle @@ -7,8 +6,6 @@ TEMPLATE = app TARGET = tst_websockets -QT = core network websockets testlib +QT = websockets testlib SOURCES += tst_websockets.cpp - -DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 |