diff options
-rw-r--r-- | .qmake.conf | 2 | ||||
-rw-r--r-- | src/imports/imports.pro | 3 | ||||
-rw-r--r-- | src/imports/qmlwebsockets/plugins.qmltypes | 4 | ||||
-rw-r--r-- | src/imports/qmlwebsockets/qmldir | 2 | ||||
-rw-r--r-- | src/imports/qmlwebsockets/qmlwebsockets.pro | 2 | ||||
-rw-r--r-- | src/imports/qmlwebsockets/qmlwebsockets_plugin.cpp | 5 | ||||
-rw-r--r-- | src/imports/qmlwebsockets/qqmlwebsocket.cpp | 2 | ||||
-rw-r--r-- | src/imports/qmlwebsockets/qqmlwebsocketserver.cpp | 2 | ||||
-rw-r--r-- | src/imports/qmlwebsockets_compat/qmldir | 4 | ||||
-rw-r--r-- | src/imports/qmlwebsockets_compat/qmlwebsockets_compat.pro | 7 | ||||
-rw-r--r-- | src/websockets/doc/src/qtwebsockets-module.qdoc | 4 | ||||
-rw-r--r-- | src/websockets/qwebsocket_p.cpp | 110 | ||||
-rw-r--r-- | src/websockets/qwebsocket_p.h | 13 | ||||
-rw-r--r-- | tests/auto/qwebsocket/tst_qwebsocket.cpp | 7 |
14 files changed, 113 insertions, 54 deletions
diff --git a/.qmake.conf b/.qmake.conf index d6d6c20..76fcbdf 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -3,4 +3,4 @@ load(qt_build_config) CONFIG += qt_example_installs CONFIG += warning_clean -MODULE_VERSION = 5.4.2 +MODULE_VERSION = 5.5.0 diff --git a/src/imports/imports.pro b/src/imports/imports.pro index 6bf8069..bb0d300 100644 --- a/src/imports/imports.pro +++ b/src/imports/imports.pro @@ -1,3 +1,4 @@ TEMPLATE = subdirs -SUBDIRS += qmlwebsockets +SUBDIRS += qmlwebsockets \ + qmlwebsockets_compat diff --git a/src/imports/qmlwebsockets/plugins.qmltypes b/src/imports/qmlwebsockets/plugins.qmltypes index 4404a51..5b8d1f9 100644 --- a/src/imports/qmlwebsockets/plugins.qmltypes +++ b/src/imports/qmlwebsockets/plugins.qmltypes @@ -4,13 +4,13 @@ import QtQuick.tooling 1.1 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -notrelocatable Qt.WebSockets 1.0' +// 'qmlplugindump -notrelocatable QtWebSockets 1.0' Module { Component { name: "QQmlWebSocket" prototype: "QObject" - exports: ["Qt.WebSockets/WebSocket 1.0"] + exports: ["QtWebSockets/WebSocket 1.0"] exportMetaObjectRevisions: [0] Enum { name: "Status" diff --git a/src/imports/qmlwebsockets/qmldir b/src/imports/qmlwebsockets/qmldir index 3202976..130b79f 100644 --- a/src/imports/qmlwebsockets/qmldir +++ b/src/imports/qmlwebsockets/qmldir @@ -1,4 +1,4 @@ -module Qt.WebSockets +module QtWebSockets plugin declarative_qmlwebsockets classname QtWebSocketsDeclarativeModule typeinfo plugins.qmltypes diff --git a/src/imports/qmlwebsockets/qmlwebsockets.pro b/src/imports/qmlwebsockets/qmlwebsockets.pro index 58c6df0..dea84a8 100644 --- a/src/imports/qmlwebsockets/qmlwebsockets.pro +++ b/src/imports/qmlwebsockets/qmlwebsockets.pro @@ -1,6 +1,6 @@ QT = core websockets qml -TARGETPATH = Qt/WebSockets +TARGETPATH = QtWebSockets HEADERS += qmlwebsockets_plugin.h \ qqmlwebsocket.h \ diff --git a/src/imports/qmlwebsockets/qmlwebsockets_plugin.cpp b/src/imports/qmlwebsockets/qmlwebsockets_plugin.cpp index fea105e..684d711 100644 --- a/src/imports/qmlwebsockets/qmlwebsockets_plugin.cpp +++ b/src/imports/qmlwebsockets/qmlwebsockets_plugin.cpp @@ -42,9 +42,10 @@ QT_BEGIN_NAMESPACE void QtWebSocketsDeclarativeModule::registerTypes(const char *uri) { - Q_ASSERT(uri == QLatin1String("Qt.WebSockets")); + // ### Qt 6: Remove support for the "Qt.WebSockets" QML module. + Q_ASSERT(uri == QLatin1String("QtWebSockets") || uri == QLatin1String("Qt.WebSockets")); - // @uri Qt.WebSockets + // @uri QtWebSockets qmlRegisterType<QQmlWebSocket>(uri, 1 /*major*/, 0 /*minor*/, "WebSocket"); qmlRegisterType<QQmlWebSocketServer>(uri, 1 /*major*/, 0 /*minor*/, "WebSocketServer"); } diff --git a/src/imports/qmlwebsockets/qqmlwebsocket.cpp b/src/imports/qmlwebsockets/qqmlwebsocket.cpp index 08d39f6..568f8ce 100644 --- a/src/imports/qmlwebsockets/qqmlwebsocket.cpp +++ b/src/imports/qmlwebsockets/qqmlwebsocket.cpp @@ -36,7 +36,7 @@ \instantiates QQmlWebSocket \since 5.3 - \inqmlmodule Qt.WebSockets + \inqmlmodule QtWebSockets \ingroup websockets-qml \brief QML interface to QWebSocket. diff --git a/src/imports/qmlwebsockets/qqmlwebsocketserver.cpp b/src/imports/qmlwebsockets/qqmlwebsocketserver.cpp index 6425fe2..9c302ea 100644 --- a/src/imports/qmlwebsockets/qqmlwebsocketserver.cpp +++ b/src/imports/qmlwebsockets/qqmlwebsocketserver.cpp @@ -41,7 +41,7 @@ QT_USE_NAMESPACE \instantiates QQmlWebSocketServer \since 5.3 - \inqmlmodule Qt.WebSockets + \inqmlmodule QtWebSockets \ingroup websockets-qml \brief QML interface to QWebSocketServer. */ diff --git a/src/imports/qmlwebsockets_compat/qmldir b/src/imports/qmlwebsockets_compat/qmldir new file mode 100644 index 0000000..8541103 --- /dev/null +++ b/src/imports/qmlwebsockets_compat/qmldir @@ -0,0 +1,4 @@ +module Qt.WebSockets +plugin ../../QtWebSockets/declarative_qmlwebsockets +classname QtWebSocketsDeclarativeModule +typeinfo ../../QtWebSockets/plugins.qmltypes diff --git a/src/imports/qmlwebsockets_compat/qmlwebsockets_compat.pro b/src/imports/qmlwebsockets_compat/qmlwebsockets_compat.pro new file mode 100644 index 0000000..a6610b6 --- /dev/null +++ b/src/imports/qmlwebsockets_compat/qmlwebsockets_compat.pro @@ -0,0 +1,7 @@ +### Qt 6: Remove support for the old "Qt.WebSockets" QML module. + +QT = core websockets qml + +TARGETPATH = Qt/WebSockets + +load(qml_module) diff --git a/src/websockets/doc/src/qtwebsockets-module.qdoc b/src/websockets/doc/src/qtwebsockets-module.qdoc index dc7009b..2c5892d 100644 --- a/src/websockets/doc/src/qtwebsockets-module.qdoc +++ b/src/websockets/doc/src/qtwebsockets-module.qdoc @@ -48,7 +48,7 @@ */ /*! - \qmlmodule Qt.WebSockets 1.0 + \qmlmodule QtWebSockets 1.0 \title Qt WebSockets QML Types \ingroup qmlmodules \brief Provides QML types for WebSockets communication. @@ -57,6 +57,6 @@ The QML types are accessed by using: \code - import Qt.WebSockets 1.0 + import QtWebSockets 1.0 \endcode */ diff --git a/src/websockets/qwebsocket_p.cpp b/src/websockets/qwebsocket_p.cpp index 45913e5..ab2fec5 100644 --- a/src/websockets/qwebsocket_p.cpp +++ b/src/websockets/qwebsocket_p.cpp @@ -137,7 +137,8 @@ QWebSocketPrivate::QWebSocketPrivate(QTcpSocket *pTcpSocket, QWebSocketProtocol: m_dataProcessor(), m_configuration(), m_pMaskGenerator(&m_defaultMaskGenerator), - m_defaultMaskGenerator() + m_defaultMaskGenerator(), + m_handshakeState(NothingDoneState) { } @@ -362,7 +363,7 @@ void QWebSocketPrivate::open(const QUrl &url, bool mask) if (!resourceName.endsWith(QChar::fromLatin1('?'))) { resourceName.append(QChar::fromLatin1('?')); } - resourceName.append(url.query()); + resourceName.append(url.query(QUrl::FullyEncoded)); } if (resourceName.isEmpty()) resourceName = QStringLiteral("/"); @@ -898,46 +899,66 @@ void QWebSocketPrivate::processHandshake(QTcpSocket *pSocket) Q_Q(QWebSocket); if (Q_UNLIKELY(!pSocket)) return; + // Reset handshake on a new connection. + if (m_handshakeState == AllDoneState) + m_handshakeState = NothingDoneState; - bool ok = false; QString errorDescription; - const QByteArray statusLine = pSocket->readLine(); - int httpMajorVersion, httpMinorVersion; - int httpStatusCode; - QString httpStatusMessage; - if (Q_UNLIKELY(!parseStatusLine(statusLine, &httpMajorVersion, &httpMinorVersion, - &httpStatusCode, &httpStatusMessage))) { - errorDescription = QWebSocket::tr("Invalid statusline in response: %1.").arg(QString::fromLatin1(statusLine)); - } else { - QString headerLine = readLine(pSocket); - QMap<QString, QString> headers; - while (!headerLine.isEmpty()) { + switch (m_handshakeState) { + case NothingDoneState: + m_headers.clear(); + m_handshakeState = ReadingStatusState; + // no break + case ReadingStatusState: + if (!pSocket->canReadLine()) + return; + m_statusLine = pSocket->readLine(); + if (Q_UNLIKELY(!parseStatusLine(m_statusLine, &m_httpMajorVersion, &m_httpMinorVersion, &m_httpStatusCode, &m_httpStatusMessage))) { + errorDescription = QWebSocket::tr("Invalid statusline in response: %1.").arg(QString::fromLatin1(m_statusLine)); + break; + } + m_handshakeState = ReadingHeaderState; + // no break + case ReadingHeaderState: + while (pSocket->canReadLine()) { + QString headerLine = readLine(pSocket); const QStringList headerField = headerLine.split(QStringLiteral(": "), QString::SkipEmptyParts); if (headerField.size() == 2) { - headers.insertMulti(headerField[0].toLower(), headerField[1]); + m_headers.insertMulti(headerField[0].toLower(), headerField[1]); + } + if (headerField.isEmpty()) { + m_handshakeState = ParsingHeaderState; + break; } - headerLine = readLine(pSocket); } - const QString acceptKey = headers.value(QStringLiteral("sec-websocket-accept"), - QString()); - const QString upgrade = headers.value(QStringLiteral("upgrade"), QString()); - const QString connection = headers.value(QStringLiteral("connection"), QString()); + if (m_handshakeState != ParsingHeaderState) { + if (pSocket->atEnd()) { + errorDescription = QWebSocket::tr("QWebSocketPrivate::processHandshake: Connection closed while reading header."); + break; + } + return; + } + // no break + case ParsingHeaderState: { + const QString acceptKey = m_headers.value(QStringLiteral("sec-websocket-accept"), QString()); + const QString upgrade = m_headers.value(QStringLiteral("upgrade"), QString()); + const QString connection = m_headers.value(QStringLiteral("connection"), QString()); // unused for the moment -// const QString extensions = headers.value(QStringLiteral("sec-websocket-extensions"), +// const QString extensions = m_headers.value(QStringLiteral("sec-websocket-extensions"), // QString()); -// const QString protocol = headers.value(QStringLiteral("sec-websocket-protocol"), +// const QString protocol = m_headers.value(QStringLiteral("sec-websocket-protocol"), // QString()); - const QString version = headers.value(QStringLiteral("sec-websocket-version"), - QString()); + const QString version = m_headers.value(QStringLiteral("sec-websocket-version"), QString()); - if (Q_LIKELY(httpStatusCode == 101)) { + bool ok = false; + if (Q_LIKELY(m_httpStatusCode == 101)) { //HTTP/x.y 101 Switching Protocols //TODO: do not check the httpStatusText right now ok = !(acceptKey.isEmpty() || - (httpMajorVersion < 1 || httpMinorVersion < 1) || + (m_httpMajorVersion < 1 || m_httpMinorVersion < 1) || (upgrade.toLower() != QStringLiteral("websocket")) || (connection.toLower() != QStringLiteral("upgrade"))); if (ok) { @@ -950,9 +971,9 @@ void QWebSocketPrivate::processHandshake(QTcpSocket *pSocket) } else { errorDescription = QWebSocket::tr("QWebSocketPrivate::processHandshake: Invalid statusline in response: %1.") - .arg(QString::fromLatin1(statusLine)); + .arg(QString::fromLatin1(m_statusLine)); } - } else if (httpStatusCode == 400) { + } else if (m_httpStatusCode == 400) { //HTTP/1.1 400 Bad Request if (!version.isEmpty()) { const QStringList versions = version.split(QStringLiteral(", "), @@ -963,29 +984,38 @@ void QWebSocketPrivate::processHandshake(QTcpSocket *pSocket) errorDescription = QWebSocket::tr("Handshake: Server requests a version that we don't support: %1.") .arg(versions.join(QStringLiteral(", "))); - ok = false; } else { //we tried v13, but something different went wrong errorDescription = QWebSocket::tr("QWebSocketPrivate::processHandshake: Unknown error condition encountered. Aborting connection."); - ok = false; } + } else { + errorDescription = + QWebSocket::tr("QWebSocketPrivate::processHandshake: Unknown error condition encountered. Aborting connection."); } } else { errorDescription = QWebSocket::tr("QWebSocketPrivate::processHandshake: Unhandled http status code: %1 (%2).") - .arg(httpStatusCode).arg(httpStatusMessage); - ok = false; + .arg(m_httpStatusCode).arg(m_httpStatusMessage); } + if (ok) + m_handshakeState = AllDoneState; + break; + } + case AllDoneState: + Q_UNREACHABLE(); + break; + } - if (!ok) { - setErrorString(errorDescription); - Q_EMIT q->error(QAbstractSocket::ConnectionRefusedError); - } else { - //handshake succeeded - setSocketState(QAbstractSocket::ConnectedState); - Q_EMIT q->connected(); - } + if (m_handshakeState == AllDoneState) { + // handshake succeeded + setSocketState(QAbstractSocket::ConnectedState); + Q_EMIT q->connected(); + } else { + // handshake failed + m_handshakeState = AllDoneState; + setErrorString(errorDescription); + Q_EMIT q->error(QAbstractSocket::ConnectionRefusedError); } } diff --git a/src/websockets/qwebsocket_p.h b/src/websockets/qwebsocket_p.h index f13e08d..9d4ba1c 100644 --- a/src/websockets/qwebsocket_p.h +++ b/src/websockets/qwebsocket_p.h @@ -224,6 +224,19 @@ private: QMaskGenerator *m_pMaskGenerator; QDefaultMaskGenerator m_defaultMaskGenerator; + enum HandshakeState { + NothingDoneState, + ReadingStatusState, + ReadingHeaderState, + ParsingHeaderState, + AllDoneState + } m_handshakeState; + QByteArray m_statusLine; + int m_httpStatusCode; + int m_httpMajorVersion, m_httpMinorVersion; + QString m_httpStatusMessage; + QMap<QString, QString> m_headers; + friend class QWebSocketServerPrivate; }; diff --git a/tests/auto/qwebsocket/tst_qwebsocket.cpp b/tests/auto/qwebsocket/tst_qwebsocket.cpp index 29ba7a3..537aa31 100644 --- a/tests/auto/qwebsocket/tst_qwebsocket.cpp +++ b/tests/auto/qwebsocket/tst_qwebsocket.cpp @@ -413,8 +413,11 @@ void tst_QWebSocket::tst_sendTextMessage() QSignalSpy binaryMessageReceived(&socket, SIGNAL(binaryMessageReceived(QByteArray))); QSignalSpy binaryFrameReceived(&socket, SIGNAL(binaryFrameReceived(QByteArray,bool))); - socket.open(QUrl(QStringLiteral("ws://") + echoServer.hostAddress().toString() + - QStringLiteral(":") + QString::number(echoServer.port()))); + QUrl url = QUrl(QStringLiteral("ws://") + echoServer.hostAddress().toString() + + QStringLiteral(":") + QString::number(echoServer.port())); + url.addQueryItem("queryitem", "with encoded characters"); + + socket.open(url); if (socketConnectedSpy.count() == 0) QVERIFY(socketConnectedSpy.wait(500)); |