summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlexandru Croitor <alexandru.croitor@qt.io>2020-03-23 16:00:29 +0100
committerAlexandru Croitor <alexandru.croitor@qt.io>2020-03-23 16:00:29 +0100
commit6b19edaefe7edcdc12a1faa269d77e42a14fc81d (patch)
tree2c5a803fc8f7b0e8b2c83f49dcd846c2dba72e16 /src
parent5fc2b148cfa763007810d7b6256ea50d82bf7e45 (diff)
parent8fc139318b2f870aa633e93874b3fa6e9d1113ae (diff)
downloadqtwebsockets-6b19edaefe7edcdc12a1faa269d77e42a14fc81d.tar.gz
Merge remote-tracking branch 'origin/dev' into wip/cmake
Conflicts: dependencies.yaml Change-Id: I1608720522e974c7107f00599a9fb70f17865189
Diffstat (limited to 'src')
-rw-r--r--src/imports/qmlwebsockets/plugins.qmltypes2
-rw-r--r--src/websockets/doc/src/external-resources.qdoc5
-rw-r--r--src/websockets/qsslserver.cpp6
-rw-r--r--src/websockets/qsslserver_p.h3
-rw-r--r--src/websockets/qwebsocket.cpp77
-rw-r--r--src/websockets/qwebsocket.h6
-rw-r--r--src/websockets/qwebsocket_p.cpp41
-rw-r--r--src/websockets/qwebsocket_p.h5
-rw-r--r--src/websockets/qwebsocketframe.cpp122
-rw-r--r--src/websockets/qwebsocketframe_p.h40
-rw-r--r--src/websockets/qwebsockethandshakerequest.cpp15
-rw-r--r--src/websockets/qwebsockethandshakerequest_p.h2
-rw-r--r--src/websockets/qwebsocketserver.cpp25
-rw-r--r--src/websockets/qwebsocketserver.h3
-rw-r--r--src/websockets/qwebsocketserver_p.cpp56
15 files changed, 200 insertions, 208 deletions
diff --git a/src/imports/qmlwebsockets/plugins.qmltypes b/src/imports/qmlwebsockets/plugins.qmltypes
index 79e2f97..cabe5a2 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 -dependencies dependencies.json QtWebSockets 1.13'
+// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtWebSockets 1.15'
Module {
dependencies: []
diff --git a/src/websockets/doc/src/external-resources.qdoc b/src/websockets/doc/src/external-resources.qdoc
index 40e4257..ce39b9b 100644
--- a/src/websockets/doc/src/external-resources.qdoc
+++ b/src/websockets/doc/src/external-resources.qdoc
@@ -86,12 +86,12 @@
*/
/*!
- \externalpage http://autobahn.ws/testsuite/
+ \externalpage https://github.com/crossbario/autobahn-testsuite
\title Autobahn|Testsuite
*/
/*!
- \externalpage http://autobahn.ws/testsuite/installation.html
+ \externalpage https://github.com/crossbario/autobahn-testsuite/blob/master/README.md#installation
\title Autobahn|Testsuite installation documentation
*/
@@ -103,6 +103,7 @@
/*!
\externalpage https://bugzilla.mozilla.org/show_bug.cgi?id=594502
\title Firefox bug 594502
+*/
/*
This prevents autolinking of each occurrence of 'WebSocket'
diff --git a/src/websockets/qsslserver.cpp b/src/websockets/qsslserver.cpp
index ec645c9..7f33a9d 100644
--- a/src/websockets/qsslserver.cpp
+++ b/src/websockets/qsslserver.cpp
@@ -121,6 +121,12 @@ void QSslServer::incomingConnection(qintptr socket)
this, &QSslServer::socketEncrypted);
connect(pSslSocket, &QSslSocket::preSharedKeyAuthenticationRequired,
this, &QSslServer::preSharedKeyAuthenticationRequired);
+ connect(pSslSocket, &QSslSocket::alertSent,
+ this, &QSslServer::alertSent);
+ connect(pSslSocket, &QSslSocket::alertReceived,
+ this, &QSslServer::alertReceived);
+ connect(pSslSocket, &QSslSocket::handshakeInterruptedOnError,
+ this, &QSslServer::handshakeInterruptedOnError);
Q_EMIT startedEncryptionHandshake(pSslSocket);
diff --git a/src/websockets/qsslserver_p.h b/src/websockets/qsslserver_p.h
index 6283058..e0c77fa 100644
--- a/src/websockets/qsslserver_p.h
+++ b/src/websockets/qsslserver_p.h
@@ -78,6 +78,9 @@ Q_SIGNALS:
void peerVerifyError(const QSslError &error);
void newEncryptedConnection();
void preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator);
+ void alertSent(QAlertLevel level, QAlertType type, const QString &description);
+ void alertReceived(QAlertLevel level, QAlertType type, const QString &description);
+ void handshakeInterruptedOnError(const QSslError &error);
void startedEncryptionHandshake(QSslSocket *socket);
protected:
diff --git a/src/websockets/qwebsocket.cpp b/src/websockets/qwebsocket.cpp
index ade1eb4..e9bba37 100644
--- a/src/websockets/qwebsocket.cpp
+++ b/src/websockets/qwebsocket.cpp
@@ -261,6 +261,67 @@ not been filled in with new information when the signal returns.
\sa QSslSocket::preSharedKeyAuthenticationRequired()
*/
/*!
+ \fn void QWebSocket::peerVerifyError(const QSslError &error)
+ \since 6.0
+
+ QWebSocket can emit this signal several times during the SSL handshake,
+ before encryption has been established, to indicate that an error has
+ occurred while establishing the identity of the peer. The \a error is
+ usually an indication that QWebSocket is unable to securely identify the
+ peer.
+
+ This signal provides you with an early indication when something's wrong.
+ By connecting to this signal, you can manually choose to tear down the
+ connection from inside the connected slot before the handshake has
+ completed. If no action is taken, QWebSocket will proceed to emitting
+ QWebSocket::sslErrors().
+
+ \sa sslErrors()
+*/
+/*!
+ \fn void QWebSocket::alertSent(QAlertLevel level, QAlertType type, const QString &description)
+ \since 6.0
+
+ QWebSocket emits this signal if an alert message was sent to a peer. \a level
+ describes if it was a warning or a fatal error. \a type gives the code
+ of the alert message. When a textual description of the alert message is
+ available, it is supplied in \a description.
+
+ \note This signal is mostly informational and can be used for debugging
+ purposes, normally it does not require any actions from the application.
+ \note Not all backends support this functionality.
+
+ \sa alertReceived(), QSslSocket::QAlertLevel, QSslSocket::QAlertType
+*/
+/*!
+ \fn void QWebSocket::alertReceived(QAlertLevel level, QAlertType type, const QString &description)
+ \since 6.0
+
+ QWebSocket emits this signal if an alert message was received from a peer.
+ \a level tells if the alert was fatal or it was a warning. \a type is the
+ code explaining why the alert was sent. When a textual description of
+ the alert message is available, it is supplied in \a description.
+
+ \note The signal is mostly for informational and debugging purposes and does not
+ require any handling in the application. If the alert was fatal, underlying
+ backend will handle it and close the connection.
+ \note Not all backends support this functionality.
+
+ \sa alertSent(), QSslSocket::QAlertLevel, QSslSocket::QAlertType
+*/
+/*!
+ \fn void QWebSocket::handshakeInterruptedOnError(const QSslError &error)
+ \since 6.0
+
+ QWebSocket emits this signal if a certificate verification error was
+ found and if early error reporting was enabled in QSslConfiguration.
+ An application is expected to inspect the \a error and decide if
+ it wants to continue the handshake, or abort it and send an alert message
+ to the peer. The signal-slot connection must be direct.
+
+ \sa continueInterruptedHandshake(), sslErrors(), QSslConfiguration::setHandshakeMustInterruptOnError()
+*/
+/*!
\fn void QWebSocket::pong(quint64 elapsedTime, const QByteArray &payload)
Emitted when a pong message is received in reply to a previous ping.
@@ -483,6 +544,22 @@ void QWebSocket::ignoreSslErrors()
}
/*!
+ \since 6.0
+
+ If an application wants to conclude a handshake even after receiving
+ handshakeInterruptedOnError() signal, it must call this function.
+ This call must be done from a slot function attached to the signal.
+ The signal-slot connection must be direct.
+
+ \sa handshakeInterruptedOnError(), QSslConfiguration::setHandshakeMustInterruptOnError()
+*/
+void QWebSocket::continueInterruptedHandshake()
+{
+ Q_D(QWebSocket);
+ d->continueInterruptedHandshake();
+}
+
+/*!
\overload
This method tells QWebSocket to ignore the errors given in \a errors.
diff --git a/src/websockets/qwebsocket.h b/src/websockets/qwebsocket.h
index 4944689..530127f 100644
--- a/src/websockets/qwebsocket.h
+++ b/src/websockets/qwebsocket.h
@@ -109,6 +109,8 @@ public:
#ifndef QT_NO_SSL
void ignoreSslErrors(const QList<QSslError> &errors);
+ void continueInterruptedHandshake();
+
void setSslConfiguration(const QSslConfiguration &sslConfiguration);
QSslConfiguration sslConfiguration() const;
#endif
@@ -143,8 +145,12 @@ Q_SIGNALS:
void bytesWritten(qint64 bytes);
#ifndef QT_NO_SSL
+ void peerVerifyError(const QSslError &error);
void sslErrors(const QList<QSslError> &errors);
void preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator);
+ void alertSent(QAlertLevel level, QAlertType type, const QString &description);
+ void alertReceived(QAlertLevel level, QAlertType type, const QString &description);
+ void handshakeInterruptedOnError(const QSslError &error);
#endif
private:
diff --git a/src/websockets/qwebsocket_p.cpp b/src/websockets/qwebsocket_p.cpp
index 36aefd9..6ca8d1a 100644
--- a/src/websockets/qwebsocket_p.cpp
+++ b/src/websockets/qwebsocket_p.cpp
@@ -285,6 +285,18 @@ void QWebSocketPrivate::ignoreSslErrors()
}
/*!
+ * \internal
+ */
+void QWebSocketPrivate::continueInterruptedHandshake()
+{
+ if (Q_LIKELY(m_pSocket)) {
+ QSslSocket *pSslSocket = qobject_cast<QSslSocket *>(m_pSocket);
+ if (Q_LIKELY(pSslSocket))
+ pSslSocket->continueInterruptedHandshake();
+ }
+}
+
+/*!
* \internal
*/
void QWebSocketPrivate::_q_updateSslConfiguration()
@@ -569,7 +581,7 @@ void QWebSocketPrivate::enableMasking(bool enable)
/*!
* \internal
*/
-void QWebSocketPrivate::makeConnections(const QTcpSocket *pTcpSocket)
+void QWebSocketPrivate::makeConnections(QTcpSocket *pTcpSocket)
{
Q_ASSERT(pTcpSocket);
Q_Q(QWebSocket);
@@ -612,6 +624,14 @@ void QWebSocketPrivate::makeConnections(const QTcpSocket *pTcpSocket)
q, &QWebSocket::sslErrors);
QObjectPrivate::connect(sslSocket, &QSslSocket::encrypted,
this, &QWebSocketPrivate::_q_updateSslConfiguration);
+ QObject::connect(sslSocket, &QSslSocket::peerVerifyError,
+ q, &QWebSocket::peerVerifyError);
+ QObject::connect(sslSocket, &QSslSocket::alertSent,
+ q, &QWebSocket::alertSent);
+ QObject::connect(sslSocket, &QSslSocket::alertReceived,
+ q, &QWebSocket::alertReceived);
+ QObject::connect(sslSocket, &QSslSocket::handshakeInterruptedOnError,
+ q, &QWebSocket::handshakeInterruptedOnError);
} else
#endif // QT_NO_SSL
{
@@ -636,6 +656,10 @@ void QWebSocketPrivate::makeConnections(const QTcpSocket *pTcpSocket)
&QWebSocketPrivate::processPong);
QObjectPrivate::connect(&m_dataProcessor, &QWebSocketDataProcessor::closeReceived, this,
&QWebSocketPrivate::processClose);
+
+ //fire readyread, in case we already have data inside the tcpSocket
+ if (pTcpSocket->bytesAvailable())
+ Q_EMIT pTcpSocket->readyRead();
}
/*!
@@ -1000,8 +1024,8 @@ void QWebSocketPrivate::processHandshake(QTcpSocket *pSocket)
errorDescription = QWebSocket::tr("Malformed header in response: %1.").arg(headerLine);
break;
}
- lastHeader = m_headers.insertMulti(headerLine.left(colonPos).trimmed().toLower(),
- headerLine.mid(colonPos + 1).trimmed());
+ lastHeader = m_headers.insert(headerLine.left(colonPos).trimmed().toLower(),
+ headerLine.mid(colonPos + 1).trimmed());
}
}
@@ -1048,8 +1072,7 @@ void QWebSocketPrivate::processHandshake(QTcpSocket *pSocket)
} else if (m_httpStatusCode == 400) {
//HTTP/1.1 400 Bad Request
if (!version.isEmpty()) {
- const QStringList versions = version.split(QStringLiteral(", "),
- QString::SkipEmptyParts);
+ const QStringList versions = version.split(QStringLiteral(", "), Qt::SkipEmptyParts);
if (!versions.contains(QString::number(QWebSocketProtocol::currentVersion()))) {
//if needed to switch protocol version, then we are finished here
//because we cannot handle other protocols than the RFC one (v13)
@@ -1099,9 +1122,6 @@ void QWebSocketPrivate::processStateChanged(QAbstractSocket::SocketState socketS
Q_ASSERT(m_pSocket);
Q_Q(QWebSocket);
QAbstractSocket::SocketState webSocketState = this->state();
- int port = 80;
- if (m_request.url().scheme() == QStringLiteral("wss"))
- port = 443;
switch (socketState) {
case QAbstractSocket::ConnectedState:
@@ -1120,11 +1140,10 @@ void QWebSocketPrivate::processStateChanged(QAbstractSocket::SocketState socketS
const auto format = QUrl::RemoveScheme | QUrl::RemoveUserInfo
| QUrl::RemovePath | QUrl::RemoveQuery
- | QUrl::RemoveFragment | QUrl::RemovePort;
+ | QUrl::RemoveFragment;
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)),
+ host,
origin(),
QString(),
QString(),
diff --git a/src/websockets/qwebsocket_p.h b/src/websockets/qwebsocket_p.h
index e72daa5..d0fa38c 100644
--- a/src/websockets/qwebsocket_p.h
+++ b/src/websockets/qwebsocket_p.h
@@ -149,6 +149,7 @@ public:
#ifndef QT_NO_SSL
void ignoreSslErrors(const QList<QSslError> &errors);
void ignoreSslErrors();
+ void continueInterruptedHandshake();
void setSslConfiguration(const QSslConfiguration &sslConfiguration);
QSslConfiguration sslConfiguration() const;
void _q_updateSslConfiguration();
@@ -182,7 +183,7 @@ private:
Q_REQUIRED_RESULT qint64 doWriteFrames(const QByteArray &data, bool isBinary);
- void makeConnections(const QTcpSocket *pTcpSocket);
+ void makeConnections(QTcpSocket *pTcpSocket);
void releaseConnections(const QTcpSocket *pTcpSocket);
QByteArray getFrameHeader(QWebSocketProtocol::OpCode opCode, quint64 payloadLength,
@@ -248,7 +249,7 @@ private:
int m_httpStatusCode;
int m_httpMajorVersion, m_httpMinorVersion;
QString m_httpStatusMessage;
- QMap<QString, QString> m_headers;
+ QMultiMap<QString, QString> m_headers;
friend class QWebSocketServerPrivate;
#ifdef Q_OS_WASM
diff --git a/src/websockets/qwebsocketframe.cpp b/src/websockets/qwebsocketframe.cpp
index 11373a7..cfa63ed 100644
--- a/src/websockets/qwebsocketframe.cpp
+++ b/src/websockets/qwebsocketframe.cpp
@@ -64,128 +64,6 @@ QT_BEGIN_NAMESPACE
/*!
\internal
*/
-QWebSocketFrame::QWebSocketFrame() :
- m_closeCode(QWebSocketProtocol::CloseCodeNormal),
- m_closeReason(),
- m_mask(0),
- m_opCode(QWebSocketProtocol::OpCodeReservedC),
- m_length(0),
- m_payload(),
- m_isFinalFrame(true),
- m_rsv1(false),
- m_rsv2(false),
- m_rsv3(false),
- m_isValid(false)
-{
-}
-
-/*!
- \internal
- */
-QWebSocketFrame::QWebSocketFrame(const QWebSocketFrame &other) :
- m_closeCode(other.m_closeCode),
- m_closeReason(other.m_closeReason),
- m_mask(other.m_mask),
- m_opCode(other.m_opCode),
- m_length(other.m_length),
- m_payload(other.m_payload),
- m_isFinalFrame(other.m_isFinalFrame),
- m_rsv1(other.m_rsv1),
- m_rsv2(other.m_rsv2),
- m_rsv3(other.m_rsv3),
- m_isValid(other.m_isValid),
- m_processingState(other.m_processingState)
-{
-}
-
-/*!
- \internal
- */
-QWebSocketFrame &QWebSocketFrame::operator =(const QWebSocketFrame &other)
-{
- m_closeCode = other.m_closeCode;
- m_closeReason = other.m_closeReason;
- m_isFinalFrame = other.m_isFinalFrame;
- m_mask = other.m_mask;
- m_rsv1 = other.m_rsv1;
- m_rsv2 = other.m_rsv2;
- m_rsv3 = other.m_rsv3;
- m_opCode = other.m_opCode;
- m_length = other.m_length;
- m_payload = other.m_payload;
- m_isValid = other.m_isValid;
- m_processingState = other.m_processingState;
-
- return *this;
-}
-
-#ifdef Q_COMPILER_RVALUE_REFS
-/*!
- \internal
- */
-QWebSocketFrame::QWebSocketFrame(QWebSocketFrame &&other) :
- m_closeCode(qMove(other.m_closeCode)),
- m_closeReason(qMove(other.m_closeReason)),
- m_mask(qMove(other.m_mask)),
- m_opCode(qMove(other.m_opCode)),
- m_length(qMove(other.m_length)),
- m_payload(qMove(other.m_payload)),
- m_isFinalFrame(qMove(other.m_isFinalFrame)),
- m_rsv1(qMove(other.m_rsv1)),
- m_rsv2(qMove(other.m_rsv2)),
- m_rsv3(qMove(other.m_rsv3)),
- m_isValid(qMove(other.m_isValid)),
- m_processingState(qMove(other.m_processingState))
-{}
-
-
-/*!
- \internal
- */
-QWebSocketFrame &QWebSocketFrame::operator =(QWebSocketFrame &&other)
-{
- qSwap(m_closeCode, other.m_closeCode);
- qSwap(m_closeReason, other.m_closeReason);
- qSwap(m_isFinalFrame, other.m_isFinalFrame);
- qSwap(m_mask, other.m_mask);
- qSwap(m_rsv1, other.m_rsv1);
- qSwap(m_rsv2, other.m_rsv2);
- qSwap(m_rsv3, other.m_rsv3);
- qSwap(m_opCode, other.m_opCode);
- qSwap(m_length, other.m_length);
- qSwap(m_payload, other.m_payload);
- qSwap(m_isValid, other.m_isValid);
- qSwap(m_processingState, other.m_processingState);
-
- return *this;
-}
-
-#endif
-
-/*!
- \internal
- */
-void QWebSocketFrame::swap(QWebSocketFrame &other)
-{
- if (&other != this) {
- qSwap(m_closeCode, other.m_closeCode);
- qSwap(m_closeReason, other.m_closeReason);
- qSwap(m_isFinalFrame, other.m_isFinalFrame);
- qSwap(m_mask, other.m_mask);
- qSwap(m_rsv1, other.m_rsv1);
- qSwap(m_rsv2, other.m_rsv2);
- qSwap(m_rsv3, other.m_rsv3);
- qSwap(m_opCode, other.m_opCode);
- qSwap(m_length, other.m_length);
- qSwap(m_payload, other.m_payload);
- qSwap(m_isValid, other.m_isValid);
- qSwap(m_processingState, other.m_processingState);
- }
-}
-
-/*!
- \internal
- */
QWebSocketProtocol::CloseCode QWebSocketFrame::closeCode() const
{
return isDone() ? m_closeCode : QWebSocketProtocol::CloseCodeGoingAway;
diff --git a/src/websockets/qwebsocketframe_p.h b/src/websockets/qwebsocketframe_p.h
index e2b4e9f..a8b9684 100644
--- a/src/websockets/qwebsocketframe_p.h
+++ b/src/websockets/qwebsocketframe_p.h
@@ -54,7 +54,7 @@
#include <QtCore/QString>
#include <QtCore/QByteArray>
#include <QtCore/QCoreApplication>
-#include <limits.h>
+#include <limits>
#include "qwebsockets_global.h"
#include "qwebsocketprotocol.h"
@@ -64,25 +64,15 @@ QT_BEGIN_NAMESPACE
class QIODevice;
-const quint64 MAX_FRAME_SIZE_IN_BYTES = INT_MAX - 1;
-const quint64 MAX_MESSAGE_SIZE_IN_BYTES = INT_MAX - 1;
+const quint64 MAX_FRAME_SIZE_IN_BYTES = std::numeric_limits<int>::max() - 1;
+const quint64 MAX_MESSAGE_SIZE_IN_BYTES = std::numeric_limits<int>::max() - 1;
class Q_AUTOTEST_EXPORT QWebSocketFrame
{
Q_DECLARE_TR_FUNCTIONS(QWebSocketFrame)
public:
- QWebSocketFrame();
- QWebSocketFrame(const QWebSocketFrame &other);
-
- QWebSocketFrame &operator =(const QWebSocketFrame &other);
-
-#ifdef Q_COMPILER_RVALUE_REFS
- QWebSocketFrame(QWebSocketFrame &&other);
- QWebSocketFrame &operator =(QWebSocketFrame &&other);
-#endif
-
- void swap(QWebSocketFrame &other);
+ QWebSocketFrame() = default;
QWebSocketProtocol::CloseCode closeCode() const;
QString closeReason() const;
@@ -106,18 +96,12 @@ public:
void readFrame(QIODevice *pIoDevice);
private:
- QWebSocketProtocol::CloseCode m_closeCode;
QString m_closeReason;
- quint32 m_mask;
- QWebSocketProtocol::OpCode m_opCode;
- quint64 m_length;
QByteArray m_payload;
-
- bool m_isFinalFrame;
- bool m_rsv1;
- bool m_rsv2;
- bool m_rsv3;
- bool m_isValid;
+ quint64 m_length = 0;
+ quint32 m_mask = 0;
+ QWebSocketProtocol::CloseCode m_closeCode = QWebSocketProtocol::CloseCodeNormal;
+ QWebSocketProtocol::OpCode m_opCode = QWebSocketProtocol::OpCodeReservedC;
enum ProcessingState
{
@@ -127,7 +111,13 @@ private:
PS_READ_PAYLOAD,
PS_DISPATCH_RESULT,
PS_WAIT_FOR_MORE_DATA
- } m_processingState{PS_READ_HEADER};
+ } m_processingState = PS_READ_HEADER;
+
+ bool m_isFinalFrame = true;
+ bool m_rsv1 = false;
+ bool m_rsv2 = false;
+ bool m_rsv3 = false;
+ bool m_isValid = false;
ProcessingState readFrameHeader(QIODevice *pIoDevice);
ProcessingState readFramePayloadLength(QIODevice *pIoDevice);
diff --git a/src/websockets/qwebsockethandshakerequest.cpp b/src/websockets/qwebsockethandshakerequest.cpp
index bfc8a3d..17275eb 100644
--- a/src/websockets/qwebsockethandshakerequest.cpp
+++ b/src/websockets/qwebsockethandshakerequest.cpp
@@ -230,7 +230,7 @@ void QWebSocketHandshakeRequest::readHandshake(QTextStream &textStream, int maxH
clear();
return;
}
- const QStringList tokens = requestLine.split(' ', QString::SkipEmptyParts);
+ const QStringList tokens = requestLine.split(' ', Qt::SkipEmptyParts);
if (Q_UNLIKELY(tokens.length() < 3)) {
clear();
return;
@@ -268,8 +268,8 @@ void QWebSocketHandshakeRequest::readHandshake(QTextStream &textStream, int maxH
clear();
return;
}
- lastHeader = m_headers.insertMulti(headerLine.left(colonPos).trimmed().toLower(),
- headerLine.mid(colonPos + 1).trimmed());
+ lastHeader = m_headers.insert(headerLine.left(colonPos).trimmed().toLower(),
+ headerLine.mid(colonPos + 1).trimmed());
}
if (m_headers.size() > maxHeaders) {
clear();
@@ -301,7 +301,7 @@ void QWebSocketHandshakeRequest::readHandshake(QTextStream &textStream, int maxH
const QStringList versionLines = m_headers.values(QStringLiteral("sec-websocket-version"));
for (QStringList::const_iterator v = versionLines.begin(); v != versionLines.end(); ++v) {
- const QStringList versions = (*v).split(QStringLiteral(","), QString::SkipEmptyParts);
+ const QStringList versions = (*v).split(QStringLiteral(","), Qt::SkipEmptyParts);
for (QStringList::const_iterator i = versions.begin(); i != versions.end(); ++i) {
bool ok = false;
(void)(*i).toUInt(&ok);
@@ -321,8 +321,7 @@ void QWebSocketHandshakeRequest::readHandshake(QTextStream &textStream, int maxH
const QString upgrade = m_headers.value(QStringLiteral("upgrade"), QString());
//must be equal to "websocket", case-insensitive
const QString connection = m_headers.value(QStringLiteral("connection"), QString());
- const QStringList connectionLine = connection.split(QStringLiteral(","),
- QString::SkipEmptyParts);
+ const QStringList connectionLine = connection.split(QStringLiteral(","), Qt::SkipEmptyParts);
QStringList connectionValues;
for (QStringList::const_iterator c = connectionLine.begin(); c != connectionLine.end(); ++c)
connectionValues << (*c).trimmed();
@@ -331,14 +330,14 @@ void QWebSocketHandshakeRequest::readHandshake(QTextStream &textStream, int maxH
m_origin = m_headers.value(QStringLiteral("origin"), QString());
const QStringList protocolLines = m_headers.values(QStringLiteral("sec-websocket-protocol"));
for (const QString& pl : protocolLines) {
- const QStringList protocols = pl.split(QStringLiteral(","), QString::SkipEmptyParts);
+ const QStringList protocols = pl.split(QStringLiteral(","), Qt::SkipEmptyParts);
for (const QString& p : protocols)
m_protocols << p.trimmed();
}
const QStringList extensionLines = m_headers.values(QStringLiteral("sec-websocket-extensions"));
for (const QString& el : extensionLines) {
- const QStringList extensions = el.split(QStringLiteral(","), QString::SkipEmptyParts);
+ const QStringList extensions = el.split(QStringLiteral(","), Qt::SkipEmptyParts);
for (const QString& e : extensions)
m_extensions << e.trimmed();
}
diff --git a/src/websockets/qwebsockethandshakerequest_p.h b/src/websockets/qwebsockethandshakerequest_p.h
index e5762df..e14c05d 100644
--- a/src/websockets/qwebsockethandshakerequest_p.h
+++ b/src/websockets/qwebsockethandshakerequest_p.h
@@ -91,7 +91,7 @@ private:
int m_port;
bool m_isSecure;
bool m_isValid;
- QMap<QString, QString> m_headers;
+ QMultiMap<QString, QString> m_headers;
QList<QWebSocketProtocol::Version> m_versions;
QString m_key;
QString m_origin;
diff --git a/src/websockets/qwebsocketserver.cpp b/src/websockets/qwebsocketserver.cpp
index eafe3fd..b833503 100644
--- a/src/websockets/qwebsocketserver.cpp
+++ b/src/websockets/qwebsocketserver.cpp
@@ -656,31 +656,6 @@ qintptr QWebSocketServer::socketDescriptor() const
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
diff --git a/src/websockets/qwebsocketserver.h b/src/websockets/qwebsocketserver.h
index ceb9106..478b35e 100644
--- a/src/websockets/qwebsocketserver.h
+++ b/src/websockets/qwebsocketserver.h
@@ -158,6 +158,9 @@ Q_SIGNALS:
void peerVerifyError(const QSslError &error);
void sslErrors(const QList<QSslError> &errors);
void preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator);
+ void alertSent(QAlertLevel level, QAlertType type, const QString &description);
+ void alertReceived(QAlertLevel level, QAlertType type, const QString &description);
+ void handshakeInterruptedOnError(const QSslError &error);
#endif
void closed();
};
diff --git a/src/websockets/qwebsocketserver_p.cpp b/src/websockets/qwebsocketserver_p.cpp
index 8225b59..f922098 100644
--- a/src/websockets/qwebsocketserver_p.cpp
+++ b/src/websockets/qwebsocketserver_p.cpp
@@ -107,6 +107,12 @@ void QWebSocketServerPrivate::init()
q, &QWebSocketServer::sslErrors);
QObject::connect(pSslServer, &QSslServer::preSharedKeyAuthenticationRequired,
q, &QWebSocketServer::preSharedKeyAuthenticationRequired);
+ QObject::connect(pSslServer, &QSslServer::alertSent,
+ q, &QWebSocketServer::alertSent);
+ QObject::connect(pSslServer, &QSslServer::alertReceived,
+ q, &QWebSocketServer::alertReceived);
+ QObject::connect(pSslServer, &QSslServer::handshakeInterruptedOnError,
+ q, &QWebSocketServer::handshakeInterruptedOnError);
}
#else
qFatal("SSL not supported on this platform.");
@@ -430,24 +436,50 @@ void QWebSocketServerPrivate::handshakeReceived()
//This is a bug in FireFox (see https://bugzilla.mozilla.org/show_bug.cgi?id=594502)
// According to RFC822 the body is separated from the headers by a null line (CRLF)
- if (!pTcpSocket->peek(pTcpSocket->bytesAvailable()).endsWith(QByteArrayLiteral("\r\n\r\n"))) {
+ const QByteArray& endOfHeaderMarker = QByteArrayLiteral("\r\n\r\n");
+
+ const qint64 byteAvailable = pTcpSocket->bytesAvailable();
+ QByteArray header = pTcpSocket->peek(byteAvailable);
+ const int endOfHeaderIndex = header.indexOf(endOfHeaderMarker);
+ if (endOfHeaderIndex < 0) {
+ //then we don't have our header complete yet
+ //check that no one is trying to exhaust our virtual memory
+ const qint64 maxHeaderLength = MAX_HEADERLINE_LENGTH * MAX_HEADERLINES + endOfHeaderMarker.size();
+ if (Q_UNLIKELY(byteAvailable > maxHeaderLength)) {
+ pTcpSocket->close();
+ setError(QWebSocketProtocol::CloseCodeTooMuchData,
+ QWebSocketServer::tr("Header is too large."));
+ }
return;
}
+ const int headerSize = endOfHeaderIndex + endOfHeaderMarker.size();
+
disconnect(pTcpSocket, &QTcpSocket::readyRead,
this, &QWebSocketServerPrivate::handshakeReceived);
bool success = false;
bool isSecure = (m_secureMode == SecureMode);
- if (m_pendingConnections.length() >= maxPendingConnections()) {
+ if (Q_UNLIKELY(m_pendingConnections.length() >= maxPendingConnections())) {
pTcpSocket->close();
- pTcpSocket->deleteLater();
setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection,
QWebSocketServer::tr("Too many pending connections."));
return;
}
+ //don't read past the header
+ header.resize(headerSize);
+ //remove our header from the tcpSocket
+ qint64 skippedSize = pTcpSocket->skip(headerSize);
+
+ if (Q_UNLIKELY(skippedSize != headerSize)) {
+ pTcpSocket->close();
+ setError(QWebSocketProtocol::CloseCodeProtocolError,
+ QWebSocketServer::tr("Read handshake request header failed."));
+ return;
+ }
+
QWebSocketHandshakeRequest request(pTcpSocket->peerPort(), isSecure);
- QTextStream textStream(pTcpSocket);
+ QTextStream textStream(header, QIODevice::ReadOnly);
request.readHandshake(textStream, MAX_HEADERLINE_LENGTH, MAX_HEADERLINES);
if (request.isValid()) {
@@ -461,16 +493,16 @@ void QWebSocketServerPrivate::handshakeReceived()
supportedProtocols(),
supportedExtensions());
- if (response.isValid()) {
+ if (Q_LIKELY(response.isValid())) {
QTextStream httpStream(pTcpSocket);
httpStream << response;
httpStream.flush();
- if (response.canUpgrade()) {
+ if (Q_LIKELY(response.canUpgrade())) {
QWebSocket *pWebSocket = QWebSocketPrivate::upgradeFrom(pTcpSocket,
request,
response);
- if (pWebSocket) {
+ if (Q_LIKELY(pWebSocket)) {
finishHandshakeTimeout(pTcpSocket);
addPendingConnection(pWebSocket);
Q_EMIT q->newConnection();
@@ -501,11 +533,13 @@ void QWebSocketServerPrivate::handleConnection(QTcpSocket *pTcpSocket) const
QObjectPrivate::connect(pTcpSocket, &QTcpSocket::readyRead,
this, &QWebSocketServerPrivate::handshakeReceived,
Qt::QueuedConnection);
- if (pTcpSocket->canReadLine()) {
- // We received some data! We must emit now to be sure that handshakeReceived is called
- // since the data could have been received before the signal and slot was connected.
- emit pTcpSocket->readyRead();
+
+ // We received some data! We must emit now to be sure that handshakeReceived is called
+ // since the data could have been received before the signal and slot was connected.
+ if (pTcpSocket->bytesAvailable()) {
+ Q_EMIT pTcpSocket->readyRead();
}
+
QObjectPrivate::connect(pTcpSocket, &QTcpSocket::disconnected,
this, &QWebSocketServerPrivate::onSocketDisconnected);
}