diff options
Diffstat (limited to 'src')
25 files changed, 404 insertions, 98 deletions
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 |