diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/websockets/qwebsocket_p.cpp | 12 | ||||
-rw-r--r-- | src/websockets/qwebsocket_p.h | 4 | ||||
-rw-r--r-- | src/websockets/qwebsocketframe.cpp | 122 | ||||
-rw-r--r-- | src/websockets/qwebsocketframe_p.h | 40 | ||||
-rw-r--r-- | src/websockets/qwebsockethandshakerequest.cpp | 4 | ||||
-rw-r--r-- | src/websockets/qwebsockethandshakerequest_p.h | 2 | ||||
-rw-r--r-- | src/websockets/qwebsocketserver_p.cpp | 41 |
7 files changed, 63 insertions, 162 deletions
diff --git a/src/websockets/qwebsocket_p.cpp b/src/websockets/qwebsocket_p.cpp index bca4ccd..1493e15 100644 --- a/src/websockets/qwebsocket_p.cpp +++ b/src/websockets/qwebsocket_p.cpp @@ -198,7 +198,7 @@ QAbstractSocket::SocketError QWebSocketPrivate::error() const { QAbstractSocket::SocketError err = QAbstractSocket::UnknownSocketError; if (Q_LIKELY(m_pSocket)) - err = m_pSocket->error(); + err = m_pSocket->socketError(); return err; } @@ -569,7 +569,7 @@ void QWebSocketPrivate::enableMasking(bool enable) /*! * \internal */ -void QWebSocketPrivate::makeConnections(const QTcpSocket *pTcpSocket) +void QWebSocketPrivate::makeConnections(QTcpSocket *pTcpSocket) { Q_ASSERT(pTcpSocket); Q_Q(QWebSocket); @@ -636,6 +636,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 +1004,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()); } } diff --git a/src/websockets/qwebsocket_p.h b/src/websockets/qwebsocket_p.h index e72daa5..2d56f8a 100644 --- a/src/websockets/qwebsocket_p.h +++ b/src/websockets/qwebsocket_p.h @@ -182,7 +182,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 +248,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..19df09b 100644 --- a/src/websockets/qwebsockethandshakerequest.cpp +++ b/src/websockets/qwebsockethandshakerequest.cpp @@ -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(); 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_p.cpp b/src/websockets/qwebsocketserver_p.cpp index 966126d..8c75721 100644 --- a/src/websockets/qwebsocketserver_p.cpp +++ b/src/websockets/qwebsocketserver_p.cpp @@ -430,9 +430,24 @@ 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 (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; @@ -445,8 +460,20 @@ void QWebSocketServerPrivate::handshakeReceived() return; } + //don't read past the header + header.resize(headerSize); + //remove our header from the tcpSocket + qint64 skippedSize = pTcpSocket->skip(headerSize); + + if (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()) { @@ -500,11 +527,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); } |