diff options
34 files changed, 282 insertions, 51 deletions
diff --git a/.qmake.conf b/.qmake.conf index f068d13..d1e1c4c 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -1,5 +1,6 @@ load(qt_build_config) CONFIG += warning_clean +DEFINES += QT_NO_FOREACH -MODULE_VERSION = 5.7.1 +MODULE_VERSION = 5.8.0 diff --git a/examples/websockets/echoserver/echoserver.cpp b/examples/websockets/echoserver/echoserver.cpp index 013ddc2..d4e3b65 100644 --- a/examples/websockets/echoserver/echoserver.cpp +++ b/examples/websockets/echoserver/echoserver.cpp @@ -59,7 +59,6 @@ EchoServer::EchoServer(quint16 port, bool debug, QObject *parent) : QObject(parent), m_pWebSocketServer(new QWebSocketServer(QStringLiteral("Echo Server"), QWebSocketServer::NonSecureMode, this)), - m_clients(), m_debug(debug) { if (m_pWebSocketServer->listen(QHostAddress::Any, port)) { diff --git a/examples/websockets/simplechat/chatserver.cpp b/examples/websockets/simplechat/chatserver.cpp index 33e5d8d..ae207f5 100644 --- a/examples/websockets/simplechat/chatserver.cpp +++ b/examples/websockets/simplechat/chatserver.cpp @@ -57,8 +57,7 @@ QT_USE_NAMESPACE //! [constructor] ChatServer::ChatServer(quint16 port, QObject *parent) : QObject(parent), - m_pWebSocketServer(Q_NULLPTR), - m_clients() + m_pWebSocketServer(Q_NULLPTR) { m_pWebSocketServer = new QWebSocketServer(QStringLiteral("Chat Server"), QWebSocketServer::NonSecureMode, @@ -94,8 +93,7 @@ void ChatServer::onNewConnection() void ChatServer::processMessage(QString message) { QWebSocket *pSender = qobject_cast<QWebSocket *>(sender()); - Q_FOREACH (QWebSocket *pClient, m_clients) - { + for (QWebSocket *pClient : qAsConst(m_clients)) { if (pClient != pSender) //don't echo message back to sender { pClient->sendTextMessage(message); diff --git a/examples/websockets/sslechoclient/sslechoclient.cpp b/examples/websockets/sslechoclient/sslechoclient.cpp index cb15e35..3de2fec 100644 --- a/examples/websockets/sslechoclient/sslechoclient.cpp +++ b/examples/websockets/sslechoclient/sslechoclient.cpp @@ -56,8 +56,7 @@ QT_USE_NAMESPACE //! [constructor] SslEchoClient::SslEchoClient(const QUrl &url, QObject *parent) : - QObject(parent), - m_webSocket() + QObject(parent) { connect(&m_webSocket, &QWebSocket::connected, this, &SslEchoClient::onConnected); typedef void (QWebSocket:: *sslErrorsSignal)(const QList<QSslError> &); diff --git a/examples/websockets/sslechoserver/sslechoserver.cpp b/examples/websockets/sslechoserver/sslechoserver.cpp index 777d8dd..ae5d9ad 100644 --- a/examples/websockets/sslechoserver/sslechoserver.cpp +++ b/examples/websockets/sslechoserver/sslechoserver.cpp @@ -60,8 +60,7 @@ QT_USE_NAMESPACE //! [constructor] SslEchoServer::SslEchoServer(quint16 port, QObject *parent) : QObject(parent), - m_pWebSocketServer(Q_NULLPTR), - m_clients() + m_pWebSocketServer(Q_NULLPTR) { m_pWebSocketServer = new QWebSocketServer(QStringLiteral("SSL Echo Server"), QWebSocketServer::SecureMode, @@ -109,7 +108,6 @@ void SslEchoServer::onNewConnection() connect(pSocket, &QWebSocket::binaryMessageReceived, this, &SslEchoServer::processBinaryMessage); connect(pSocket, &QWebSocket::disconnected, this, &SslEchoServer::socketDisconnected); - //connect(pSocket, &QWebSocket::pong, this, &SslEchoServer::processPong); m_clients << pSocket; } diff --git a/examples/websockets/websockets.pro b/examples/websockets/websockets.pro index e5eddf6..fa6c0c0 100644 --- a/examples/websockets/websockets.pro +++ b/examples/websockets/websockets.pro @@ -1,4 +1,5 @@ TEMPLATE = subdirs +QT_FOR_CONFIG += network SUBDIRS = echoclient \ echoserver \ @@ -9,7 +10,7 @@ SUBDIRS += qmlwebsocketclient \ qmlwebsocketserver } -contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) { +qtConfig(ssl) { SUBDIRS += \ sslechoserver \ sslechoclient diff --git a/src/imports/qmlwebsockets/plugins.qmltypes b/src/imports/qmlwebsockets/plugins.qmltypes index b79da44..cbbb628 100644 --- a/src/imports/qmlwebsockets/plugins.qmltypes +++ b/src/imports/qmlwebsockets/plugins.qmltypes @@ -4,15 +4,15 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -nonrelocatable QtWebSockets 1.0' +// 'qmlplugindump -nonrelocatable QtWebSockets 1.1' Module { dependencies: [] Component { name: "QQmlWebSocket" prototype: "QObject" - exports: ["QtWebSockets/WebSocket 1.0"] - exportMetaObjectRevisions: [0] + exports: ["QtWebSockets/WebSocket 1.0", "QtWebSockets/WebSocket 1.1"] + exportMetaObjectRevisions: [0, 1] Enum { name: "Status" values: { @@ -32,6 +32,11 @@ Module { Parameter { name: "message"; type: "string" } } Signal { + name: "binaryMessageReceived" + revision: 1 + Parameter { name: "message"; type: "QByteArray" } + } + Signal { name: "statusChanged" Parameter { name: "status"; type: "Status" } } @@ -48,6 +53,12 @@ Module { type: "qlonglong" Parameter { name: "message"; type: "string" } } + Method { + name: "sendBinaryMessage" + revision: 1 + type: "qlonglong" + Parameter { name: "message"; type: "QByteArray" } + } } Component { name: "QQmlWebSocketServer" diff --git a/src/imports/qmlwebsockets/qmlwebsockets.pro b/src/imports/qmlwebsockets/qmlwebsockets.pro index dea84a8..fef47f4 100644 --- a/src/imports/qmlwebsockets/qmlwebsockets.pro +++ b/src/imports/qmlwebsockets/qmlwebsockets.pro @@ -1,4 +1,4 @@ -QT = core websockets qml +QT = core websockets qml qml-private core-private TARGETPATH = QtWebSockets diff --git a/src/imports/qmlwebsockets/qmlwebsockets_plugin.cpp b/src/imports/qmlwebsockets/qmlwebsockets_plugin.cpp index 11c9dec..24fe34a 100644 --- a/src/imports/qmlwebsockets/qmlwebsockets_plugin.cpp +++ b/src/imports/qmlwebsockets/qmlwebsockets_plugin.cpp @@ -53,6 +53,7 @@ void QtWebSocketsDeclarativeModule::registerTypes(const char *uri) // @uri QtWebSockets qmlRegisterType<QQmlWebSocket>(uri, 1 /*major*/, 0 /*minor*/, "WebSocket"); + qmlRegisterType<QQmlWebSocket, 1>(uri, 1 /*major*/, 1 /*minor*/, "WebSocket"); qmlRegisterType<QQmlWebSocketServer>(uri, 1 /*major*/, 0 /*minor*/, "WebSocketServer"); } diff --git a/src/imports/qmlwebsockets/qmlwebsockets_plugin.h b/src/imports/qmlwebsockets/qmlwebsockets_plugin.h index 318e0c7..749d830 100644 --- a/src/imports/qmlwebsockets/qmlwebsockets_plugin.h +++ b/src/imports/qmlwebsockets/qmlwebsockets_plugin.h @@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE class QtWebSocketsDeclarativeModule : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: QtWebSocketsDeclarativeModule(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); } diff --git a/src/imports/qmlwebsockets/qqmlwebsocket.cpp b/src/imports/qmlwebsockets/qqmlwebsocket.cpp index aea2c82..9ff88d5 100644 --- a/src/imports/qmlwebsockets/qqmlwebsocket.cpp +++ b/src/imports/qmlwebsockets/qqmlwebsocket.cpp @@ -90,6 +90,12 @@ */ /*! + \qmlsignal WebSocket::binaryMessageReceived(QString message) + \since 5.8 + This signal is emitted when a binary message is received. + */ + +/*! \qmlsignal WebSocket::statusChanged(Status status) This signal is emitted when the status of the WebSocket changes. the \l [QML]{WebSocket::status}{status} argument provides the current status. @@ -102,6 +108,12 @@ Sends \c message to the server. */ +/*! + \qmlmethod void WebSocket::sendBinaryMessage(ArrayBuffer message) + \since 5.8 + Sends \c message to the server. + */ + #include "qqmlwebsocket.h" #include <QtWebSockets/QWebSocket> @@ -144,6 +156,16 @@ qint64 QQmlWebSocket::sendTextMessage(const QString &message) return m_webSocket->sendTextMessage(message); } +qint64 QQmlWebSocket::sendBinaryMessage(const QByteArray &message) +{ + if (m_status != Open) { + setErrorString(tr("Messages can only be sent when the socket is open.")); + setStatus(Error); + return 0; + } + return m_webSocket->sendBinaryMessage(message); +} + QUrl QQmlWebSocket::url() const { return m_url; @@ -198,6 +220,8 @@ void QQmlWebSocket::setSocket(QWebSocket *socket) m_webSocket->setParent(Q_NULLPTR); connect(m_webSocket.data(), &QWebSocket::textMessageReceived, this, &QQmlWebSocket::textMessageReceived); + connect(m_webSocket.data(), &QWebSocket::binaryMessageReceived, + this, &QQmlWebSocket::binaryMessageReceived); typedef void (QWebSocket::* ErrorSignal)(QAbstractSocket::SocketError); connect(m_webSocket.data(), static_cast<ErrorSignal>(&QWebSocket::error), this, &QQmlWebSocket::onError); diff --git a/src/imports/qmlwebsockets/qqmlwebsocket.h b/src/imports/qmlwebsockets/qqmlwebsocket.h index c5682ed..c3a808f 100644 --- a/src/imports/qmlwebsockets/qqmlwebsocket.h +++ b/src/imports/qmlwebsockets/qqmlwebsocket.h @@ -83,10 +83,11 @@ public: bool isActive() const; Q_INVOKABLE qint64 sendTextMessage(const QString &message); - + Q_REVISION(1) Q_INVOKABLE qint64 sendBinaryMessage(const QByteArray &message); Q_SIGNALS: void textMessageReceived(QString message); + Q_REVISION(1) void binaryMessageReceived(QByteArray message); void statusChanged(Status status); void activeChanged(bool isActive); void errorStringChanged(QString errorString); diff --git a/src/websockets/doc/src/qtwebsockets-module.qdoc b/src/websockets/doc/src/qtwebsockets-module.qdoc index 6c717f4..971e22c 100644 --- a/src/websockets/doc/src/qtwebsockets-module.qdoc +++ b/src/websockets/doc/src/qtwebsockets-module.qdoc @@ -48,7 +48,7 @@ */ /*! - \qmlmodule QtWebSockets 1.0 + \qmlmodule QtWebSockets 1.1 \title Qt WebSockets QML Types \ingroup qmlmodules \brief Provides QML types for WebSocket-based communication. @@ -56,7 +56,7 @@ The QML types are accessed by using: \code - import QtWebSockets 1.0 + import QtWebSockets 1.1 \endcode \note Prior to Qt 5.5, the import statement was \c{import Qt.WebSockets 1.0} diff --git a/src/websockets/qsslserver.cpp b/src/websockets/qsslserver.cpp index 41db66a..5df59f7 100644 --- a/src/websockets/qsslserver.cpp +++ b/src/websockets/qsslserver.cpp @@ -119,6 +119,7 @@ void QSslServer::incomingConnection(qintptr socket) connect(pSslSocket, static_cast<sslErrorsSignal>(&QSslSocket::sslErrors), this, &QSslServer::sslErrors); connect(pSslSocket, &QSslSocket::encrypted, this, &QSslServer::newEncryptedConnection); + connect(pSslSocket, &QSslSocket::preSharedKeyAuthenticationRequired, this, &QSslServer::preSharedKeyAuthenticationRequired); addPendingConnection(pSslSocket); diff --git a/src/websockets/qsslserver_p.h b/src/websockets/qsslserver_p.h index 538e3b5..d5e581a 100644 --- a/src/websockets/qsslserver_p.h +++ b/src/websockets/qsslserver_p.h @@ -54,6 +54,7 @@ #include <QtNetwork/QTcpServer> #include <QtNetwork/QSslError> #include <QtNetwork/QSslConfiguration> +#include <QtNetwork/QSslPreSharedKeyAuthenticator> #include <QtCore/QList> QT_BEGIN_NAMESPACE @@ -74,6 +75,7 @@ Q_SIGNALS: void sslErrors(const QList<QSslError> &errors); void peerVerifyError(const QSslError &error); void newEncryptedConnection(); + void preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator); protected: virtual void incomingConnection(qintptr socket); diff --git a/src/websockets/qwebsocket.cpp b/src/websockets/qwebsocket.cpp index 90973d6..ba343e4 100644 --- a/src/websockets/qwebsocket.cpp +++ b/src/websockets/qwebsocket.cpp @@ -239,6 +239,28 @@ not been filled in with new information when the signal returns. QWebSocket::ignoreSslErrors() will have no effect. */ /*! + \fn void QWebSocket::preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator) + \since 5.8 + + This signal is emitted if the SSL/TLS handshake negotiates a PSK + ciphersuite, and therefore a PSK authentication is then required. + + When using PSK, the client must send to the server a valid identity and a + valid pre shared key, in order for the SSL handshake to continue. + Applications can provide this information in a slot connected to this + signal, by filling in the passed \a authenticator object according to their + needs. + + \note Ignoring this signal, or failing to provide the required credentials, + will cause the handshake to fail, and therefore the connection to be aborted. + + \note The \a authenticator object is owned by the websocket and must not be + deleted by the application. + + \sa QSslPreSharedKeyAuthenticator + \sa QSslSocket::preSharedKeyAuthenticationRequired() +*/ +/*! \fn void QWebSocket::pong(quint64 elapsedTime, const QByteArray &payload) Emitted when a pong message is received in reply to a previous ping. diff --git a/src/websockets/qwebsocket.h b/src/websockets/qwebsocket.h index e6c2473..cbe53ca 100644 --- a/src/websockets/qwebsocket.h +++ b/src/websockets/qwebsocket.h @@ -142,6 +142,7 @@ Q_SIGNALS: #ifndef QT_NO_SSL void sslErrors(const QList<QSslError> &errors); + void preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator); #endif private: diff --git a/src/websockets/qwebsocket_p.cpp b/src/websockets/qwebsocket_p.cpp index be8cb88..8f55e24 100644 --- a/src/websockets/qwebsocket_p.cpp +++ b/src/websockets/qwebsocket_p.cpp @@ -60,6 +60,7 @@ #ifndef QT_NO_SSL #include <QtNetwork/QSslConfiguration> #include <QtNetwork/QSslError> +#include <QtNetwork/QSslPreSharedKeyAuthenticator> #endif #include <QtCore/QDebug> @@ -304,11 +305,9 @@ QWebSocket *QWebSocketPrivate::upgradeFrom(QTcpSocket *pTcpSocket, QWebSocket *pWebSocket = new QWebSocket(pTcpSocket, response.acceptedVersion(), parent); if (Q_LIKELY(pWebSocket)) { QNetworkRequest netRequest(request.requestUrl()); - QMapIterator<QString, QString> headerIter(request.headers()); - while (headerIter.hasNext()) { - headerIter.next(); - netRequest.setRawHeader(headerIter.key().toLatin1(), headerIter.value().toLatin1()); - } + const auto headers = request.headers(); + for (auto it = headers.begin(), end = headers.end(); it != end; ++it) + netRequest.setRawHeader(it.key().toLatin1(), it.value().toLatin1()); #ifndef QT_NO_SSL if (QSslSocket *sslSock = qobject_cast<QSslSocket *>(pTcpSocket)) pWebSocket->setSslConfiguration(sslSock->sslConfiguration()); @@ -592,6 +591,8 @@ void QWebSocketPrivate::makeConnections(const QTcpSocket *pTcpSocket) #ifndef QT_NO_SSL const QSslSocket * const sslSocket = qobject_cast<const QSslSocket *>(pTcpSocket); if (sslSocket) { + QObject::connect(sslSocket, &QSslSocket::preSharedKeyAuthenticationRequired, q, + &QWebSocket::preSharedKeyAuthenticationRequired); QObject::connect(sslSocket, &QSslSocket::encryptedBytesWritten, q, &QWebSocket::bytesWritten); typedef void (QSslSocket:: *sslErrorSignalType)(const QList<QSslError> &); @@ -708,12 +709,11 @@ QByteArray QWebSocketPrivate::getFrameHeader(QWebSocketProtocol::OpCode opCode, bool lastFrame) { QByteArray header; - quint8 byte = 0x00; bool ok = payloadLength <= 0x7FFFFFFFFFFFFFFFULL; if (Q_LIKELY(ok)) { //FIN, RSV1-3, opcode (RSV-1, RSV-2 and RSV-3 are zero) - byte = static_cast<quint8>((opCode & 0x0F) | (lastFrame ? 0x80 : 0x00)); + quint8 byte = static_cast<quint8>((opCode & 0x0F) | (lastFrame ? 0x80 : 0x00)); header.append(static_cast<char>(byte)); byte = 0x00; @@ -773,7 +773,6 @@ qint64 QWebSocketPrivate::doWriteFrames(const QByteArray &data, bool isBinary) if (Q_UNLIKELY(numFrames == 0)) numFrames = 1; quint64 currentPosition = 0; - qint64 bytesWritten = 0; quint64 bytesLeft = data.size(); for (int i = 0; i < numFrames; ++i) { @@ -789,7 +788,7 @@ qint64 QWebSocketPrivate::doWriteFrames(const QByteArray &data, bool isBinary) : QWebSocketProtocol::OpCodeContinue; //write header - bytesWritten += m_pSocket->write(getFrameHeader(opcode, size, maskingKey, isLastFrame)); + m_pSocket->write(getFrameHeader(opcode, size, maskingKey, isLastFrame)); //write payload if (Q_LIKELY(size > 0)) { @@ -798,7 +797,6 @@ qint64 QWebSocketPrivate::doWriteFrames(const QByteArray &data, bool isBinary) QWebSocketProtocol::mask(currentData, size, maskingKey); qint64 written = m_pSocket->write(currentData, static_cast<qint64>(size)); if (Q_LIKELY(written > 0)) { - bytesWritten += written; payloadWritten += written; } else { m_pSocket->flush(); @@ -881,7 +879,7 @@ qint64 QWebSocketPrivate::writeFrame(const QByteArray &frame) /*! \internal */ -QString readLine(QTcpSocket *pSocket) +static QString readLine(QTcpSocket *pSocket) { Q_ASSERT(pSocket); QString line; @@ -1087,7 +1085,8 @@ void QWebSocketPrivate::processStateChanged(QAbstractSocket::SocketState socketS m_key = generateKey(); QList<QPair<QString, QString> > headers; - foreach (const QByteArray &key, m_request.rawHeaderList()) + const auto keys = m_request.rawHeaderList(); + for (const QByteArray &key : keys) headers << qMakePair(QString::fromLatin1(key), QString::fromLatin1(m_request.rawHeader(key))); @@ -1203,7 +1202,7 @@ QString QWebSocketPrivate::createHandShakeRequest(QString resourceName, QString extensions, QString protocols, QByteArray key, - QList<QPair<QString, QString> > headers) + const QList<QPair<QString, QString> > &headers) { QStringList handshakeRequest; if (resourceName.contains(QStringLiteral("\r\n"))) { @@ -1246,11 +1245,9 @@ QString QWebSocketPrivate::createHandShakeRequest(QString resourceName, if (protocols.length() > 0) handshakeRequest << QStringLiteral("Sec-WebSocket-Protocol: ") % protocols; - QListIterator<QPair<QString, QString> > headerIter(headers); - while (headerIter.hasNext()) { - const QPair<QString,QString> &header = headerIter.next(); + for (const auto &header : headers) handshakeRequest << header.first % QStringLiteral(": ") % header.second; - } + handshakeRequest << QStringLiteral("\r\n"); return handshakeRequest.join(QStringLiteral("\r\n")); diff --git a/src/websockets/qwebsocket_p.h b/src/websockets/qwebsocket_p.h index 139c7ff..4863de7 100644 --- a/src/websockets/qwebsocket_p.h +++ b/src/websockets/qwebsocket_p.h @@ -193,7 +193,7 @@ private: QString extensions, QString protocols, QByteArray key, - QList<QPair<QString, QString> > headers); + const QList<QPair<QString, QString> > &headers); static QWebSocket *upgradeFrom(QTcpSocket *tcpSocket, const QWebSocketHandshakeRequest &request, diff --git a/src/websockets/qwebsockethandshakeresponse.cpp b/src/websockets/qwebsockethandshakeresponse.cpp index b5e1052..ee57d5c 100644 --- a/src/websockets/qwebsockethandshakeresponse.cpp +++ b/src/websockets/qwebsockethandshakeresponse.cpp @@ -207,7 +207,7 @@ QString QWebSocketHandshakeResponse::getHandshakeResponse( if (Q_UNLIKELY(!m_canUpgrade)) { response << QStringLiteral("HTTP/1.1 400 Bad Request"); QStringList versions; - Q_FOREACH (QWebSocketProtocol::Version version, supportedVersions) + for (QWebSocketProtocol::Version version : supportedVersions) versions << QString::number(static_cast<int>(version)); response << QStringLiteral("Sec-WebSocket-Version: ") % versions.join(QStringLiteral(", ")); diff --git a/src/websockets/qwebsocketserver.cpp b/src/websockets/qwebsocketserver.cpp index ab5da31..f8ecdf2 100644 --- a/src/websockets/qwebsocketserver.cpp +++ b/src/websockets/qwebsocketserver.cpp @@ -193,6 +193,29 @@ */ /*! + \fn void QWebSocketServer::preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator) + \since 5.8 + + QWebSocketServer emits this signal when it negotiates a PSK ciphersuite, and + therefore a PSK authentication is then required. + + When using PSK, the client must send to the server a valid identity and a + valid pre shared key, in order for the SSL handshake to continue. + Applications can provide this information in a slot connected to this + signal, by filling in the passed \a authenticator object according to their + needs. + + \note Ignoring this signal, or failing to provide the required credentials, + will cause the handshake to fail, and therefore the connection to be aborted. + + \note The \a authenticator object is owned by the socket and must not be + deleted by the application. + + \sa QSslPreSharedKeyAuthenticator + \sa QSslSocket::preSharedKeyAuthenticationRequired() +*/ + +/*! \enum QWebSocketServer::SslMode Indicates whether the server operates over wss (SecureMode) or ws (NonSecureMode) diff --git a/src/websockets/qwebsocketserver.h b/src/websockets/qwebsocketserver.h index 58a3d54..47113e4 100644 --- a/src/websockets/qwebsocketserver.h +++ b/src/websockets/qwebsocketserver.h @@ -128,6 +128,7 @@ Q_SIGNALS: #ifndef QT_NO_SSL void peerVerifyError(const QSslError &error); void sslErrors(const QList<QSslError> &errors); + void preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator); #endif void closed(); }; diff --git a/src/websockets/qwebsocketserver_p.cpp b/src/websockets/qwebsocketserver_p.cpp index 288c05b..91bfafc 100644 --- a/src/websockets/qwebsocketserver_p.cpp +++ b/src/websockets/qwebsocketserver_p.cpp @@ -104,6 +104,8 @@ void QWebSocketServerPrivate::init() q_ptr, &QWebSocketServer::peerVerifyError); QObject::connect(pSslServer, &QSslServer::sslErrors, q_ptr, &QWebSocketServer::sslErrors); + QObject::connect(pSslServer, &QSslServer::preSharedKeyAuthenticationRequired, + q_ptr, &QWebSocketServer::preSharedKeyAuthenticationRequired); } #else qFatal("SSL not supported on this platform."); diff --git a/src/websockets/websockets.pro b/src/websockets/websockets.pro index b9a513b..e4366ba 100644 --- a/src/websockets/websockets.pro +++ b/src/websockets/websockets.pro @@ -40,7 +40,7 @@ SOURCES += \ $$PWD/qmaskgenerator.cpp \ $$PWD/qdefaultmaskgenerator_p.cpp -contains(QT_CONFIG, ssl) | contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) { +qtConfig(ssl) { SOURCES += $$PWD/qsslserver.cpp PRIVATE_HEADERS += $$PWD/qsslserver_p.h } diff --git a/tests/auto/qml/qmlwebsockets/tst_qmlwebsockets.qml b/tests/auto/qml/qmlwebsockets/tst_qmlwebsockets.qml index a8d3225..d0f19f6 100644 --- a/tests/auto/qml/qmlwebsockets/tst_qmlwebsockets.qml +++ b/tests/auto/qml/qmlwebsockets/tst_qmlwebsockets.qml @@ -27,7 +27,7 @@ ****************************************************************************/ import QtQuick 2.5 -import QtWebSockets 1.0 +import QtWebSockets 1.1 import QtTest 1.1 Rectangle { @@ -84,5 +84,28 @@ Rectangle { socket.sendTextMessage('hello'); tryCompare(socket, 'status', WebSocket.Error); } + + function test_send_receive_binary() { + ensureConnected(); + + var o = {}; + var sending = new Uint8Array([42, 43]); + server.currentSocket.binaryMessageReceived.connect(function(received) { + var view = new DataView(received); + compare(received.byteLength, sending.length); + compare(view.getUInt8(0), sending[0]); + compare(view.getUInt8(1), sending[1]); + o.called = true; + }); + + socket.sendBinaryMessage(sending.buffer); + tryCompare(o, 'called', true); + } + + function test_send_binary_error_closed() { + ensureDisconnected(); + socket.sendBinaryMessage('hello'); + tryCompare(socket, 'status', WebSocket.Error); + } } } diff --git a/tests/auto/websockets/dataprocessor/dataprocessor.pro b/tests/auto/websockets/dataprocessor/dataprocessor.pro index 41fc91f..ad99900 100644 --- a/tests/auto/websockets/dataprocessor/dataprocessor.pro +++ b/tests/auto/websockets/dataprocessor/dataprocessor.pro @@ -10,4 +10,4 @@ QT = core testlib websockets websockets-private SOURCES += tst_dataprocessor.cpp -requires(contains(QT_CONFIG, private_tests)) +requires(qtConfig(private_tests)) diff --git a/tests/auto/websockets/handshakerequest/handshakerequest.pro b/tests/auto/websockets/handshakerequest/handshakerequest.pro index 6a373b8..aa7779e 100644 --- a/tests/auto/websockets/handshakerequest/handshakerequest.pro +++ b/tests/auto/websockets/handshakerequest/handshakerequest.pro @@ -10,4 +10,4 @@ QT = core testlib websockets websockets-private SOURCES += tst_handshakerequest.cpp -requires(contains(QT_CONFIG, private_tests)) +requires(qtConfig(private_tests)) diff --git a/tests/auto/websockets/handshakeresponse/handshakeresponse.pro b/tests/auto/websockets/handshakeresponse/handshakeresponse.pro index 9e23c46..ab6682b 100644 --- a/tests/auto/websockets/handshakeresponse/handshakeresponse.pro +++ b/tests/auto/websockets/handshakeresponse/handshakeresponse.pro @@ -10,4 +10,4 @@ QT = core testlib websockets websockets-private SOURCES += tst_handshakeresponse.cpp -requires(contains(QT_CONFIG, private_tests)) +requires(qtConfig(private_tests)) diff --git a/tests/auto/websockets/qdefaultmaskgenerator/qdefaultmaskgenerator.pro b/tests/auto/websockets/qdefaultmaskgenerator/qdefaultmaskgenerator.pro index e284bc5..c3b1046 100644 --- a/tests/auto/websockets/qdefaultmaskgenerator/qdefaultmaskgenerator.pro +++ b/tests/auto/websockets/qdefaultmaskgenerator/qdefaultmaskgenerator.pro @@ -10,4 +10,4 @@ QT = core testlib websockets websockets-private SOURCES += tst_defaultmaskgenerator.cpp -requires(contains(QT_CONFIG, private_tests)) +requires(qtConfig(private_tests)) diff --git a/tests/auto/websockets/qwebsocketserver/tst_qwebsocketserver.cpp b/tests/auto/websockets/qwebsocketserver/tst_qwebsocketserver.cpp index fb3d5b8..699939f 100644 --- a/tests/auto/websockets/qwebsocketserver/tst_qwebsocketserver.cpp +++ b/tests/auto/websockets/qwebsocketserver/tst_qwebsocketserver.cpp @@ -28,6 +28,10 @@ #include <QString> #include <QtTest> #include <QNetworkProxy> +#ifndef QT_NO_OPENSSL +#include <QtNetwork/qsslpresharedkeyauthenticator.h> +#include <QtNetwork/qsslcipher.h> +#endif #include <QtWebSockets/QWebSocketServer> #include <QtWebSockets/QWebSocket> #include <QtWebSockets/QWebSocketCorsAuthenticator> @@ -43,6 +47,47 @@ Q_DECLARE_METATYPE(QWebSocketCorsAuthenticator *) Q_DECLARE_METATYPE(QSslError) #endif +#ifndef QT_NO_OPENSSL +// Use this cipher to force PSK key sharing. +static const QString PSK_CIPHER_WITHOUT_AUTH = QStringLiteral("PSK-AES256-CBC-SHA"); +static const QByteArray PSK_CLIENT_PRESHAREDKEY = QByteArrayLiteral("\x1a\x2b\x3c\x4d\x5e\x6f"); +static const QByteArray PSK_SERVER_IDENTITY_HINT = QByteArrayLiteral("QtTestServerHint"); +static const QByteArray PSK_CLIENT_IDENTITY = QByteArrayLiteral("Client_identity"); + +class PskProvider : public QObject +{ + Q_OBJECT + +public: + bool m_server = false; + QByteArray m_identity; + QByteArray m_psk; + +public slots: + void providePsk(QSslPreSharedKeyAuthenticator *authenticator) + { + QVERIFY(authenticator); + QCOMPARE(authenticator->identityHint(), PSK_SERVER_IDENTITY_HINT); + if (m_server) + QCOMPARE(authenticator->maximumIdentityLength(), 0); + else + QVERIFY(authenticator->maximumIdentityLength() > 0); + + QVERIFY(authenticator->maximumPreSharedKeyLength() > 0); + + if (!m_identity.isEmpty()) { + authenticator->setIdentity(m_identity); + QCOMPARE(authenticator->identity(), m_identity); + } + + if (!m_psk.isEmpty()) { + authenticator->setPreSharedKey(m_psk); + QCOMPARE(authenticator->preSharedKey(), m_psk); + } + } +}; +#endif + class tst_QWebSocketServer : public QObject { Q_OBJECT @@ -58,6 +103,7 @@ private Q_SLOTS: void tst_settersAndGetters(); void tst_listening(); void tst_connectivity(); + void tst_preSharedKey(); void tst_maxPendingConnections(); void tst_serverDestroyedWhileSocketConnected(); }; @@ -74,6 +120,9 @@ void tst_QWebSocketServer::init() qRegisterMetaType<QWebSocketCorsAuthenticator *>("QWebSocketCorsAuthenticator *"); #ifndef QT_NO_SSL qRegisterMetaType<QSslError>("QSslError"); +#ifndef QT_NO_OPENSSL + qRegisterMetaType<QSslPreSharedKeyAuthenticator *>(); +#endif #endif } @@ -268,6 +317,84 @@ void tst_QWebSocketServer::tst_connectivity() QCOMPARE(serverErrorSpy.count(), 0); } +void tst_QWebSocketServer::tst_preSharedKey() +{ +#ifndef QT_NO_OPENSSL + QWebSocketServer server(QString(), QWebSocketServer::SecureMode); + + bool cipherFound = false; + const QList<QSslCipher> supportedCiphers = QSslSocket::supportedCiphers(); + for (const QSslCipher &cipher : supportedCiphers) { + if (cipher.name() == PSK_CIPHER_WITHOUT_AUTH) { + cipherFound = true; + break; + } + } + + if (!cipherFound) + QSKIP("SSL implementation does not support the necessary cipher"); + + QSslCipher cipher(PSK_CIPHER_WITHOUT_AUTH); + QList<QSslCipher> list; + list << cipher; + + QSslConfiguration config = QSslConfiguration::defaultConfiguration(); + config.setCiphers(list); + config.setPeerVerifyMode(QSslSocket::VerifyNone); + config.setPreSharedKeyIdentityHint(PSK_SERVER_IDENTITY_HINT); + server.setSslConfiguration(config); + + PskProvider providerServer; + providerServer.m_server = true; + providerServer.m_identity = PSK_CLIENT_IDENTITY; + providerServer.m_psk = PSK_CLIENT_PRESHAREDKEY; + connect(&server, &QWebSocketServer::preSharedKeyAuthenticationRequired, &providerServer, &PskProvider::providePsk); + + QSignalSpy serverPskRequiredSpy(&server, &QWebSocketServer::preSharedKeyAuthenticationRequired); + QSignalSpy serverConnectionSpy(&server, &QWebSocketServer::newConnection); + QSignalSpy serverErrorSpy(&server, + SIGNAL(serverError(QWebSocketProtocol::CloseCode))); + QSignalSpy serverClosedSpy(&server, &QWebSocketServer::closed); + QSignalSpy sslErrorsSpy(&server, SIGNAL(sslErrors(QList<QSslError>))); + + QWebSocket socket; + QSslConfiguration socketConfig = QSslConfiguration::defaultConfiguration(); + socketConfig.setPeerVerifyMode(QSslSocket::VerifyNone); + socketConfig.setCiphers(list); + socket.setSslConfiguration(socketConfig); + + PskProvider providerClient; + providerClient.m_identity = PSK_CLIENT_IDENTITY; + providerClient.m_psk = PSK_CLIENT_PRESHAREDKEY; + connect(&socket, &QWebSocket::preSharedKeyAuthenticationRequired, &providerClient, &PskProvider::providePsk); + QSignalSpy socketPskRequiredSpy(&socket, &QWebSocket::preSharedKeyAuthenticationRequired); + QSignalSpy socketConnectedSpy(&socket, &QWebSocket::connected); + + QVERIFY(server.listen()); + QCOMPARE(server.serverAddress(), QHostAddress(QHostAddress::Any)); + QCOMPARE(server.serverUrl(), QUrl(QString::asprintf("wss://%ls:%d", + qUtf16Printable(QHostAddress(QHostAddress::LocalHost).toString()), server.serverPort()))); + + socket.open(server.serverUrl().toString()); + + if (socketConnectedSpy.count() == 0) + QVERIFY(socketConnectedSpy.wait()); + QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); + QCOMPARE(serverConnectionSpy.count(), 1); + QCOMPARE(serverPskRequiredSpy.count(), 1); + QCOMPARE(socketPskRequiredSpy.count(), 1); + + QCOMPARE(serverClosedSpy.count(), 0); + + server.close(); + + QVERIFY(serverClosedSpy.wait()); + QCOMPARE(serverClosedSpy.count(), 1); + QCOMPARE(sslErrorsSpy.count(), 0); + QCOMPARE(serverErrorSpy.count(), 0); +#endif +} + void tst_QWebSocketServer::tst_maxPendingConnections() { //tests if maximum connections are respected diff --git a/tests/auto/websockets/websocketframe/websocketframe.pro b/tests/auto/websockets/websocketframe/websocketframe.pro index df9c910..8f58302 100644 --- a/tests/auto/websockets/websocketframe/websocketframe.pro +++ b/tests/auto/websockets/websocketframe/websocketframe.pro @@ -10,4 +10,4 @@ QT = core testlib websockets websockets-private SOURCES += tst_websocketframe.cpp -requires(contains(QT_CONFIG, private_tests)) +requires(qtConfig(private_tests)) diff --git a/tests/auto/websockets/websocketprotocol/websocketprotocol.pro b/tests/auto/websockets/websocketprotocol/websocketprotocol.pro index 8ee7ff9..27748a9 100644 --- a/tests/auto/websockets/websocketprotocol/websocketprotocol.pro +++ b/tests/auto/websockets/websocketprotocol/websocketprotocol.pro @@ -10,4 +10,4 @@ QT = core testlib websockets websockets-private SOURCES += tst_websocketprotocol.cpp -requires(contains(QT_CONFIG, private_tests)) +requires(qtConfig(private_tests)) diff --git a/tests/auto/websockets/websockets.pro b/tests/auto/websockets/websockets.pro index 4698cd0..b000229 100644 --- a/tests/auto/websockets/websockets.pro +++ b/tests/auto/websockets/websockets.pro @@ -3,7 +3,7 @@ TEMPLATE = subdirs SUBDIRS = \ qwebsocketcorsauthenticator -contains(QT_CONFIG, private_tests): SUBDIRS += \ +qtConfig(private_tests): SUBDIRS += \ websocketprotocol \ dataprocessor \ websocketframe \ diff --git a/tests/manual/websockets/tst_websockets.cpp b/tests/manual/websockets/tst_websockets.cpp index 8568532..6b327aa 100644 --- a/tests/manual/websockets/tst_websockets.cpp +++ b/tests/manual/websockets/tst_websockets.cpp @@ -152,12 +152,11 @@ void tst_WebSocketsTest::testLocalAddress() void tst_WebSocketsTest::testPeerAddress() { QHostInfo hostInfo = QHostInfo::fromName(m_url.host()); - QList<QHostAddress> addresses = hostInfo.addresses(); + const QList<QHostAddress> addresses = hostInfo.addresses(); QVERIFY(addresses.length() > 0); QHostAddress peer = m_pWebSocket->peerAddress(); bool found = false; - Q_FOREACH (const QHostAddress &a, addresses) - { + for (const QHostAddress &a : addresses) { if (a == peer) { found = true; |