summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKari Oikarinen <kari.oikarinen@qt.io>2019-08-27 07:51:43 +0300
committerKari Oikarinen <kari.oikarinen@qt.io>2019-08-27 07:51:43 +0300
commitceeb9952b29345b662669a6a0a5c4dadf49db114 (patch)
treeb9572f228c24304380b9f7b2f815a7b330e7f051
parent6e1fa958c289de639753a60a9384bd94db0e91a8 (diff)
parenta302c6108d79b02a339b4ca93d2fce0b58386d51 (diff)
downloadqtwebsockets-ceeb9952b29345b662669a6a0a5c4dadf49db114.tar.gz
Merge dev into 5.14
Change-Id: I2eaffbe6e9519a78d0f8663c0870f24cb006d222
-rw-r--r--src/websockets/qwebsocket_p.cpp4
-rw-r--r--src/websockets/qwebsocketdataprocessor.cpp25
-rw-r--r--src/websockets/qwebsocketdataprocessor_p.h5
-rw-r--r--src/websockets/qwebsocketframe.cpp370
-rw-r--r--src/websockets/qwebsocketframe_p.h13
-rw-r--r--tests/auto/websockets/dataprocessor/tst_dataprocessor.cpp36
-rw-r--r--tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp36
-rw-r--r--tests/auto/websockets/websocketframe/tst_websocketframe.cpp12
8 files changed, 297 insertions, 204 deletions
diff --git a/src/websockets/qwebsocket_p.cpp b/src/websockets/qwebsocket_p.cpp
index 192019d..0334b8a 100644
--- a/src/websockets/qwebsocket_p.cpp
+++ b/src/websockets/qwebsocket_p.cpp
@@ -1175,10 +1175,10 @@ void QWebSocketPrivate::processData()
{
if (!m_pSocket) // disconnected with data still in-bound
return;
- while (m_pSocket->bytesAvailable()) {
+ if (m_pSocket->bytesAvailable()) {
if (state() == QAbstractSocket::ConnectingState) {
if (!m_pSocket->canReadLine())
- break;
+ return;
processHandshake(m_pSocket);
} else {
m_dataProcessor.process(m_pSocket);
diff --git a/src/websockets/qwebsocketdataprocessor.cpp b/src/websockets/qwebsocketdataprocessor.cpp
index 4f81222..39287d4 100644
--- a/src/websockets/qwebsocketdataprocessor.cpp
+++ b/src/websockets/qwebsocketdataprocessor.cpp
@@ -87,6 +87,10 @@ QWebSocketDataProcessor::QWebSocketDataProcessor(QObject *parent) :
m_pTextCodec(QTextCodec::codecForName("UTF-8"))
{
clear();
+ // initialize the internal timeout timer
+ waitTimer.setInterval(5000);
+ waitTimer.setSingleShot(true);
+ waitTimer.callOnTimeout(this, &QWebSocketDataProcessor::timeout);
}
/*!
@@ -125,8 +129,14 @@ void QWebSocketDataProcessor::process(QIODevice *pIoDevice)
bool isDone = false;
while (!isDone) {
- QWebSocketFrame frame = QWebSocketFrame::readFrame(pIoDevice);
- if (Q_LIKELY(frame.isValid())) {
+ frame.readFrame(pIoDevice);
+ if (!frame.isDone()) {
+ // waiting for more data available
+ QObject::connect(pIoDevice, &QIODevice::readyRead,
+ &waitTimer, &QTimer::stop, Qt::UniqueConnection);
+ waitTimer.start();
+ return;
+ } else if (Q_LIKELY(frame.isValid())) {
if (frame.isControlFrame()) {
isDone = processControlFrame(frame);
} else {
@@ -199,6 +209,7 @@ void QWebSocketDataProcessor::process(QIODevice *pIoDevice)
clear();
isDone = true;
}
+ frame.clear();
}
}
@@ -301,4 +312,14 @@ bool QWebSocketDataProcessor::processControlFrame(const QWebSocketFrame &frame)
return mustStopProcessing;
}
+/*!
+ \internal
+ */
+void QWebSocketDataProcessor::timeout()
+{
+ clear();
+ Q_EMIT errorEncountered(QWebSocketProtocol::CloseCodeGoingAway,
+ tr("Timeout when reading data from socket."));
+}
+
QT_END_NAMESPACE
diff --git a/src/websockets/qwebsocketdataprocessor_p.h b/src/websockets/qwebsocketdataprocessor_p.h
index e80a843..41226d6 100644
--- a/src/websockets/qwebsocketdataprocessor_p.h
+++ b/src/websockets/qwebsocketdataprocessor_p.h
@@ -55,6 +55,8 @@
#include <QtCore/QByteArray>
#include <QtCore/QString>
#include <QtCore/QTextCodec>
+#include <QTimer>
+#include "qwebsocketframe_p.h"
#include "qwebsocketprotocol.h"
#include "qwebsocketprotocol_p.h"
@@ -111,8 +113,11 @@ private:
quint64 m_payloadLength;
QTextCodec::ConverterState *m_pConverterState;
QTextCodec *m_pTextCodec;
+ QWebSocketFrame frame;
+ QTimer waitTimer;
bool processControlFrame(const QWebSocketFrame &frame);
+ void timeout();
};
QT_END_NAMESPACE
diff --git a/src/websockets/qwebsocketframe.cpp b/src/websockets/qwebsocketframe.cpp
index 041302e..11373a7 100644
--- a/src/websockets/qwebsocketframe.cpp
+++ b/src/websockets/qwebsocketframe.cpp
@@ -93,7 +93,8 @@ QWebSocketFrame::QWebSocketFrame(const QWebSocketFrame &other) :
m_rsv1(other.m_rsv1),
m_rsv2(other.m_rsv2),
m_rsv3(other.m_rsv3),
- m_isValid(other.m_isValid)
+ m_isValid(other.m_isValid),
+ m_processingState(other.m_processingState)
{
}
@@ -113,6 +114,7 @@ QWebSocketFrame &QWebSocketFrame::operator =(const QWebSocketFrame &other)
m_length = other.m_length;
m_payload = other.m_payload;
m_isValid = other.m_isValid;
+ m_processingState = other.m_processingState;
return *this;
}
@@ -132,7 +134,8 @@ QWebSocketFrame::QWebSocketFrame(QWebSocketFrame &&other) :
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_isValid(qMove(other.m_isValid)),
+ m_processingState(qMove(other.m_processingState))
{}
@@ -152,6 +155,7 @@ QWebSocketFrame &QWebSocketFrame::operator =(QWebSocketFrame &&other)
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;
}
@@ -175,6 +179,7 @@ void QWebSocketFrame::swap(QWebSocketFrame &other)
qSwap(m_length, other.m_length);
qSwap(m_payload, other.m_payload);
qSwap(m_isValid, other.m_isValid);
+ qSwap(m_processingState, other.m_processingState);
}
}
@@ -183,7 +188,7 @@ void QWebSocketFrame::swap(QWebSocketFrame &other)
*/
QWebSocketProtocol::CloseCode QWebSocketFrame::closeCode() const
{
- return m_closeCode;
+ return isDone() ? m_closeCode : QWebSocketProtocol::CloseCodeGoingAway;
}
/*!
@@ -191,7 +196,7 @@ QWebSocketProtocol::CloseCode QWebSocketFrame::closeCode() const
*/
QString QWebSocketFrame::closeReason() const
{
- return m_closeReason;
+ return isDone() ? m_closeReason : tr("Waiting for more data from socket.");
}
/*!
@@ -276,6 +281,7 @@ void QWebSocketFrame::clear()
m_length = 0;
m_payload.clear();
m_isValid = false;
+ m_processingState = PS_READ_HEADER;
}
/*!
@@ -283,215 +289,211 @@ void QWebSocketFrame::clear()
*/
bool QWebSocketFrame::isValid() const
{
- return m_isValid;
+ return isDone() && m_isValid;
}
-#define WAIT_FOR_MORE_DATA(dataSizeInBytes) \
- { returnState = processingState; \
- processingState = PS_WAIT_FOR_MORE_DATA; dataWaitSize = dataSizeInBytes; }
+/*!
+ \internal
+ */
+bool QWebSocketFrame::isDone() const
+{
+ return m_processingState == PS_DISPATCH_RESULT;
+}
/*!
\internal
*/
-QWebSocketFrame QWebSocketFrame::readFrame(QIODevice *pIoDevice)
+void QWebSocketFrame::readFrame(QIODevice *pIoDevice)
{
- bool isDone = false;
- qint64 bytesRead = 0;
- QWebSocketFrame frame;
- quint64 dataWaitSize = 0;
- Q_UNUSED(dataWaitSize); // value is used in MACRO, Q_UNUSED to avoid compiler warnings
- ProcessingState processingState = PS_READ_HEADER;
- ProcessingState returnState = PS_READ_HEADER;
- bool hasMask = false;
- quint64 payloadLength = 0;
-
- while (!isDone)
+ while (true)
{
- switch (processingState) {
- case PS_WAIT_FOR_MORE_DATA:
- //TODO: waitForReadyRead should really be changed
- //now, when a WebSocket is used in a GUI thread
- //the GUI will hang for at most 5 seconds
- //maybe, a QStateMachine should be used
- if (!pIoDevice->waitForReadyRead(5000)) {
- frame.setError(QWebSocketProtocol::CloseCodeGoingAway,
- tr("Timeout when reading data from socket."));
- processingState = PS_DISPATCH_RESULT;
- } else {
- processingState = returnState;
- }
- break;
-
+ switch (m_processingState) {
case PS_READ_HEADER:
- if (Q_LIKELY(pIoDevice->bytesAvailable() >= 2)) {
- //FIN, RSV1-3, Opcode
- char header[2] = {0};
- bytesRead = pIoDevice->read(header, 2);
- frame.m_isFinalFrame = (header[0] & 0x80) != 0;
- frame.m_rsv1 = (header[0] & 0x40);
- frame.m_rsv2 = (header[0] & 0x20);
- frame.m_rsv3 = (header[0] & 0x10);
- frame.m_opCode = static_cast<QWebSocketProtocol::OpCode>(header[0] & 0x0F);
-
- //Mask, PayloadLength
- hasMask = (header[1] & 0x80) != 0;
- frame.m_length = (header[1] & 0x7F);
-
- switch (frame.m_length)
- {
- case 126:
- {
- processingState = PS_READ_PAYLOAD_LENGTH;
- break;
- }
- case 127:
- {
- processingState = PS_READ_BIG_PAYLOAD_LENGTH;
- break;
- }
- default:
- {
- payloadLength = frame.m_length;
- processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
- break;
- }
- }
- if (!frame.checkValidity())
- processingState = PS_DISPATCH_RESULT;
- } else {
- WAIT_FOR_MORE_DATA(2);
+ m_processingState = readFrameHeader(pIoDevice);
+ if (m_processingState == PS_WAIT_FOR_MORE_DATA) {
+ m_processingState = PS_READ_HEADER;
+ return;
}
break;
case PS_READ_PAYLOAD_LENGTH:
- if (Q_LIKELY(pIoDevice->bytesAvailable() >= 2)) {
- uchar length[2] = {0};
- bytesRead = pIoDevice->read(reinterpret_cast<char *>(length), 2);
- if (Q_UNLIKELY(bytesRead == -1)) {
- frame.setError(QWebSocketProtocol::CloseCodeGoingAway,
- tr("Error occurred while reading from the network: %1")
- .arg(pIoDevice->errorString()));
- processingState = PS_DISPATCH_RESULT;
- } else {
- payloadLength = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(length));
- if (Q_UNLIKELY(payloadLength < 126)) {
- //see http://tools.ietf.org/html/rfc6455#page-28 paragraph 5.2
- //"in all cases, the minimal number of bytes MUST be used to encode
- //the length, for example, the length of a 124-byte-long string
- //can't be encoded as the sequence 126, 0, 124"
- frame.setError(QWebSocketProtocol::CloseCodeProtocolError,
- tr("Lengths smaller than 126 " \
- "must be expressed as one byte."));
- processingState = PS_DISPATCH_RESULT;
- } else {
- processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
- }
- }
- } else {
- WAIT_FOR_MORE_DATA(2);
+ m_processingState = readFramePayloadLength(pIoDevice);
+ if (m_processingState == PS_WAIT_FOR_MORE_DATA) {
+ m_processingState = PS_READ_PAYLOAD_LENGTH;
+ return;
}
break;
- case PS_READ_BIG_PAYLOAD_LENGTH:
- if (Q_LIKELY(pIoDevice->bytesAvailable() >= 8)) {
- uchar length[8] = {0};
- bytesRead = pIoDevice->read(reinterpret_cast<char *>(length), 8);
- if (Q_UNLIKELY(bytesRead < 8)) {
- frame.setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection,
- tr("Something went wrong during "\
- "reading from the network."));
- processingState = PS_DISPATCH_RESULT;
- } else {
- //Most significant bit must be set to 0 as
- //per http://tools.ietf.org/html/rfc6455#section-5.2
- payloadLength = qFromBigEndian<quint64>(length);
- if (Q_UNLIKELY(payloadLength & (quint64(1) << 63))) {
- frame.setError(QWebSocketProtocol::CloseCodeProtocolError,
- tr("Highest bit of payload length is not 0."));
- processingState = PS_DISPATCH_RESULT;
- } else if (Q_UNLIKELY(payloadLength <= 0xFFFFu)) {
- //see http://tools.ietf.org/html/rfc6455#page-28 paragraph 5.2
- //"in all cases, the minimal number of bytes MUST be used to encode
- //the length, for example, the length of a 124-byte-long string
- //can't be encoded as the sequence 126, 0, 124"
- frame.setError(QWebSocketProtocol::CloseCodeProtocolError,
- tr("Lengths smaller than 65536 (2^16) " \
- "must be expressed as 2 bytes."));
- processingState = PS_DISPATCH_RESULT;
- } else {
- processingState = hasMask ? PS_READ_MASK : PS_READ_PAYLOAD;
- }
- }
- } else {
- WAIT_FOR_MORE_DATA(8);
- }
-
- break;
-
case PS_READ_MASK:
- if (Q_LIKELY(pIoDevice->bytesAvailable() >= 4)) {
- bytesRead = pIoDevice->read(reinterpret_cast<char *>(&frame.m_mask),
- sizeof(frame.m_mask));
- if (bytesRead == -1) {
- frame.setError(QWebSocketProtocol::CloseCodeGoingAway,
- tr("Error while reading from the network: %1.")
- .arg(pIoDevice->errorString()));
- processingState = PS_DISPATCH_RESULT;
- } else {
- frame.m_mask = qFromBigEndian(frame.m_mask);
- processingState = PS_READ_PAYLOAD;
- }
- } else {
- WAIT_FOR_MORE_DATA(4);
+ m_processingState = readFrameMask(pIoDevice);
+ if (m_processingState == PS_WAIT_FOR_MORE_DATA) {
+ m_processingState = PS_READ_MASK;
+ return;
}
break;
case PS_READ_PAYLOAD:
- if (!payloadLength) {
- processingState = PS_DISPATCH_RESULT;
- } else if (Q_UNLIKELY(payloadLength > MAX_FRAME_SIZE_IN_BYTES)) {
- frame.setError(QWebSocketProtocol::CloseCodeTooMuchData,
- tr("Maximum framesize exceeded."));
- processingState = PS_DISPATCH_RESULT;
- } else {
- quint64 bytesAvailable = quint64(pIoDevice->bytesAvailable());
- if (bytesAvailable >= 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))) {
- //some error occurred; refer to the Qt documentation of QIODevice::read()
- frame.setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection,
- tr("Some serious error occurred " \
- "while reading from the network."));
- processingState = PS_DISPATCH_RESULT;
- } else {
- if (hasMask)
- QWebSocketProtocol::mask(&frame.m_payload, frame.m_mask);
- processingState = PS_DISPATCH_RESULT;
- }
- } else {
- //if payload is too big, then this will timeout
- WAIT_FOR_MORE_DATA(payloadLength);
- }
+ m_processingState = readFramePayload(pIoDevice);
+ if (m_processingState == PS_WAIT_FOR_MORE_DATA) {
+ m_processingState = PS_READ_PAYLOAD;
+ return;
}
break;
case PS_DISPATCH_RESULT:
- processingState = PS_READ_HEADER;
- isDone = true;
- break;
+ return;
default:
- //should not come here
- qWarning() << "DataProcessor::process: Found invalid state. This should not happen!";
- frame.clear();
- isDone = true;
- break;
- } //end switch
+ Q_UNREACHABLE();
+ return;
+ }
+ }
+}
+
+/*!
+ \internal
+ */
+QWebSocketFrame::ProcessingState QWebSocketFrame::readFrameHeader(QIODevice *pIoDevice)
+{
+ if (Q_LIKELY(pIoDevice->bytesAvailable() >= 2)) {
+ // FIN, RSV1-3, Opcode
+ char header[2] = {0};
+ if (Q_UNLIKELY(pIoDevice->read(header, 2) < 2)) {
+ setError(QWebSocketProtocol::CloseCodeGoingAway,
+ tr("Error occurred while reading header from the network: %1")
+ .arg(pIoDevice->errorString()));
+ return PS_DISPATCH_RESULT;
+ }
+ m_isFinalFrame = (header[0] & 0x80) != 0;
+ m_rsv1 = (header[0] & 0x40);
+ m_rsv2 = (header[0] & 0x20);
+ m_rsv3 = (header[0] & 0x10);
+ m_opCode = static_cast<QWebSocketProtocol::OpCode>(header[0] & 0x0F);
+
+ // Mask
+ // Use zero as mask value to mean there's no mask to read.
+ // When the mask value is read, it over-writes this non-zero value.
+ m_mask = header[1] & 0x80;
+ // PayloadLength
+ m_length = (header[1] & 0x7F);
+
+ if (!checkValidity())
+ return PS_DISPATCH_RESULT;
+
+ switch (m_length) {
+ case 126:
+ case 127:
+ return PS_READ_PAYLOAD_LENGTH;
+ default:
+ return hasMask() ? PS_READ_MASK : PS_READ_PAYLOAD;
+ }
+ }
+ return PS_WAIT_FOR_MORE_DATA;
+}
+
+/*!
+ \internal
+ */
+QWebSocketFrame::ProcessingState QWebSocketFrame::readFramePayloadLength(QIODevice *pIoDevice)
+{
+ // see http://tools.ietf.org/html/rfc6455#page-28 paragraph 5.2
+ // in all cases, the minimal number of bytes MUST be used to encode the length,
+ // for example, the length of a 124-byte-long string can't be encoded as the
+ // sequence 126, 0, 124"
+ switch (m_length) {
+ case 126:
+ if (Q_LIKELY(pIoDevice->bytesAvailable() >= 2)) {
+ uchar length[2] = {0};
+ if (Q_UNLIKELY(pIoDevice->read(reinterpret_cast<char *>(length), 2) < 2)) {
+ setError(QWebSocketProtocol::CloseCodeGoingAway,
+ tr("Error occurred while reading from the network: %1")
+ .arg(pIoDevice->errorString()));
+ return PS_DISPATCH_RESULT;
+ }
+ m_length = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(length));
+ if (Q_UNLIKELY(m_length < 126)) {
+
+ setError(QWebSocketProtocol::CloseCodeProtocolError,
+ tr("Lengths smaller than 126 must be expressed as one byte."));
+ return PS_DISPATCH_RESULT;
+ }
+ return hasMask() ? PS_READ_MASK : PS_READ_PAYLOAD;
+ }
+ break;
+ case 127:
+ if (Q_LIKELY(pIoDevice->bytesAvailable() >= 8)) {
+ uchar length[8] = {0};
+ if (Q_UNLIKELY(pIoDevice->read(reinterpret_cast<char *>(length), 8) < 8)) {
+ setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection,
+ tr("Something went wrong during reading from the network."));
+ return PS_DISPATCH_RESULT;
+ }
+ // Most significant bit must be set to 0 as
+ // per http://tools.ietf.org/html/rfc6455#section-5.2
+ m_length = qFromBigEndian<quint64>(length);
+ if (Q_UNLIKELY(m_length & (quint64(1) << 63))) {
+ setError(QWebSocketProtocol::CloseCodeProtocolError,
+ tr("Highest bit of payload length is not 0."));
+ return PS_DISPATCH_RESULT;
+ }
+ if (Q_UNLIKELY(m_length <= 0xFFFFu)) {
+ setError(QWebSocketProtocol::CloseCodeProtocolError,
+ tr("Lengths smaller than 65536 (2^16) must be expressed as 2 bytes."));
+ return PS_DISPATCH_RESULT;
+ }
+ return hasMask() ? PS_READ_MASK : PS_READ_PAYLOAD;
+ }
+ break;
+ default:
+ Q_UNREACHABLE();
+ break;
}
+ return PS_WAIT_FOR_MORE_DATA;
+}
- return frame;
+/*!
+ \internal
+ */
+QWebSocketFrame::ProcessingState QWebSocketFrame::readFrameMask(QIODevice *pIoDevice)
+{
+ if (Q_LIKELY(pIoDevice->bytesAvailable() >= 4)) {
+ if (Q_UNLIKELY(pIoDevice->read(reinterpret_cast<char *>(&m_mask), sizeof(m_mask)) < 4)) {
+ setError(QWebSocketProtocol::CloseCodeGoingAway,
+ tr("Error while reading from the network: %1.").arg(pIoDevice->errorString()));
+ return PS_DISPATCH_RESULT;
+ }
+ m_mask = qFromBigEndian(m_mask);
+ return PS_READ_PAYLOAD;
+ }
+ return PS_WAIT_FOR_MORE_DATA;
+}
+
+/*!
+ \internal
+ */
+QWebSocketFrame::ProcessingState QWebSocketFrame::readFramePayload(QIODevice *pIoDevice)
+{
+ if (!m_length)
+ return PS_DISPATCH_RESULT;
+
+ if (Q_UNLIKELY(m_length > MAX_FRAME_SIZE_IN_BYTES)) {
+ setError(QWebSocketProtocol::CloseCodeTooMuchData, tr("Maximum framesize exceeded."));
+ return PS_DISPATCH_RESULT;
+ }
+ if (quint64(pIoDevice->bytesAvailable()) >= m_length) {
+ m_payload = pIoDevice->read(int(m_length));
+ // m_length can be safely cast to an integer,
+ // because MAX_FRAME_SIZE_IN_BYTES = MAX_INT
+ if (Q_UNLIKELY(m_payload.length() != int(m_length))) {
+ // some error occurred; refer to the Qt documentation of QIODevice::read()
+ setError(QWebSocketProtocol::CloseCodeAbnormalDisconnection,
+ tr("Some serious error occurred while reading from the network."));
+ } else if (hasMask()) {
+ QWebSocketProtocol::mask(&m_payload, mask());
+ }
+ return PS_DISPATCH_RESULT;
+ }
+ return PS_WAIT_FOR_MORE_DATA;
}
/*!
diff --git a/src/websockets/qwebsocketframe_p.h b/src/websockets/qwebsocketframe_p.h
index 5c3a7df..e2b4e9f 100644
--- a/src/websockets/qwebsocketframe_p.h
+++ b/src/websockets/qwebsocketframe_p.h
@@ -101,15 +101,16 @@ public:
void clear();
bool isValid() const;
+ bool isDone() const;
- static QWebSocketFrame readFrame(QIODevice *pIoDevice);
+ void readFrame(QIODevice *pIoDevice);
private:
QWebSocketProtocol::CloseCode m_closeCode;
QString m_closeReason;
quint32 m_mask;
QWebSocketProtocol::OpCode m_opCode;
- quint8 m_length;
+ quint64 m_length;
QByteArray m_payload;
bool m_isFinalFrame;
@@ -122,12 +123,16 @@ private:
{
PS_READ_HEADER,
PS_READ_PAYLOAD_LENGTH,
- PS_READ_BIG_PAYLOAD_LENGTH,
PS_READ_MASK,
PS_READ_PAYLOAD,
PS_DISPATCH_RESULT,
PS_WAIT_FOR_MORE_DATA
- };
+ } m_processingState{PS_READ_HEADER};
+
+ ProcessingState readFrameHeader(QIODevice *pIoDevice);
+ ProcessingState readFramePayloadLength(QIODevice *pIoDevice);
+ ProcessingState readFrameMask(QIODevice *pIoDevice);
+ ProcessingState readFramePayload(QIODevice *pIoDevice);
void setError(QWebSocketProtocol::CloseCode code, const QString &closeReason);
bool checkValidity();
diff --git a/tests/auto/websockets/dataprocessor/tst_dataprocessor.cpp b/tests/auto/websockets/dataprocessor/tst_dataprocessor.cpp
index f9a91d5..5390ff0 100644
--- a/tests/auto/websockets/dataprocessor/tst_dataprocessor.cpp
+++ b/tests/auto/websockets/dataprocessor/tst_dataprocessor.cpp
@@ -193,7 +193,7 @@ private:
//sequences
void nonCharacterSequence(const char *sequence);
- void doTest();
+ void doTest(int timeout = 0);
void doCloseFrameTest();
QString opCodeToString(quint8 opCode);
@@ -744,6 +744,7 @@ void tst_DataProcessor::frameTooSmall()
dataProcessor.process(&buffer);
+ QTRY_VERIFY_WITH_TIMEOUT(errorSpy.count(), 7000);
QCOMPARE(errorSpy.count(), 1);
QCOMPARE(closeSpy.count(), 0);
QCOMPARE(pingMessageSpy.count(), 0);
@@ -776,6 +777,7 @@ void tst_DataProcessor::frameTooSmall()
dataProcessor.process(&buffer);
+ QTRY_VERIFY_WITH_TIMEOUT(errorSpy.count(), 7000);
QCOMPARE(errorSpy.count(), 1);
QCOMPARE(closeSpy.count(), 0);
QCOMPARE(pingMessageSpy.count(), 0);
@@ -808,6 +810,24 @@ void tst_DataProcessor::frameTooSmall()
dataProcessor.process(&buffer);
+ QTRY_VERIFY_WITH_TIMEOUT(errorSpy.count(), 7000);
+ QCOMPARE(errorSpy.count(), 1);
+ QCOMPARE(closeSpy.count(), 0);
+ QCOMPARE(pingMessageSpy.count(), 0);
+ QCOMPARE(pongMessageSpy.count(), 0);
+ QCOMPARE(textMessageSpy.count(), 0);
+ QCOMPARE(binaryMessageSpy.count(), 0);
+ QCOMPARE(textFrameSpy.count(), 1);
+ QCOMPARE(binaryFrameSpy.count(), 0);
+
+ errorSpy.clear();
+ closeSpy.clear();
+ pingMessageSpy.clear();
+ pongMessageSpy.clear();
+ textMessageSpy.clear();
+ binaryMessageSpy.clear();
+ textFrameSpy.clear();
+ binaryFrameSpy.clear();
buffer.close();
data.clear();
@@ -816,17 +836,16 @@ void tst_DataProcessor::frameTooSmall()
//meaning the socket will be closed
buffer.setData(data);
buffer.open(QIODevice::ReadOnly);
- QSignalSpy errorSpy(&dataProcessor,
- SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
dataProcessor.process(&buffer);
+ QTRY_VERIFY_WITH_TIMEOUT(errorSpy.count(), 7000);
QCOMPARE(errorSpy.count(), 1);
QCOMPARE(closeSpy.count(), 0);
QCOMPARE(pingMessageSpy.count(), 0);
QCOMPARE(pongMessageSpy.count(), 0);
QCOMPARE(textMessageSpy.count(), 0);
QCOMPARE(binaryMessageSpy.count(), 0);
- QCOMPARE(textFrameSpy.count(), 1);
+ QCOMPARE(textFrameSpy.count(), 0);
QCOMPARE(binaryFrameSpy.count(), 0);
QList<QVariant> arguments = errorSpy.takeFirst();
@@ -849,6 +868,7 @@ void tst_DataProcessor::frameTooSmall()
buffer.open(QIODevice::ReadOnly);
dataProcessor.process(&buffer);
+ QTRY_VERIFY_WITH_TIMEOUT(errorSpy.count(), 7000);
QCOMPARE(errorSpy.count(), 1);
QCOMPARE(closeSpy.count(), 0);
QCOMPARE(pingMessageSpy.count(), 0);
@@ -877,6 +897,7 @@ void tst_DataProcessor::frameTooSmall()
buffer.open(QIODevice::ReadOnly);
dataProcessor.process(&buffer);
+ QTRY_VERIFY_WITH_TIMEOUT(errorSpy.count(), 7000);
QCOMPARE(errorSpy.count(), 1);
QCOMPARE(closeSpy.count(), 0);
QCOMPARE(pingMessageSpy.count(), 0);
@@ -1400,7 +1421,7 @@ void tst_DataProcessor::incompletePayload_data()
void tst_DataProcessor::incompletePayload()
{
- doTest();
+ doTest(7000);
}
void tst_DataProcessor::incompleteSizeField_data()
@@ -1430,13 +1451,13 @@ void tst_DataProcessor::incompleteSizeField_data()
void tst_DataProcessor::incompleteSizeField()
{
- doTest();
+ doTest(7000);
}
//////////////////////////////////////////////////////////////////////////////////////////
/// HELPER FUNCTIONS
//////////////////////////////////////////////////////////////////////////////////////////
-void tst_DataProcessor::doTest()
+void tst_DataProcessor::doTest(int timeout)
{
QFETCH(quint8, firstByte);
QFETCH(quint8, secondByte);
@@ -1465,6 +1486,7 @@ void tst_DataProcessor::doTest()
buffer.setData(data);
buffer.open(QIODevice::ReadOnly);
dataProcessor.process(&buffer);
+ QTRY_VERIFY_WITH_TIMEOUT(errorSpy.count(), timeout);
QCOMPARE(errorSpy.count(), 1);
QCOMPARE(textMessageSpy.count(), 0);
QCOMPARE(binaryMessageSpy.count(), 0);
diff --git a/tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp b/tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp
index 2bb5d16..19af815 100644
--- a/tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp
+++ b/tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp
@@ -457,12 +457,46 @@ void tst_QWebSocket::tst_sendTextMessage()
QVERIFY(isLastFrame);
socket.close();
+ socketConnectedSpy.clear();
+ textMessageReceived.clear();
+ textFrameReceived.clear();
- //QTBUG-36762: QWebSocket emits multiplied signals when socket was reopened
+ // QTBUG-74464 QWebsocket doesn't receive text (binary) message with size > 32 kb
+ socket.open(url);
+
+ QTRY_COMPARE(socketConnectedSpy.count(), 1);
+ QCOMPARE(socketError.count(), 0);
+ QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
+ arguments = serverConnectedSpy.takeFirst();
+ urlConnected = arguments.at(0).toUrl();
+ QCOMPARE(urlConnected, url);
+ QCOMPARE(socket.bytesToWrite(), 0);
+
+ // transmit a long text message with 64 kb
+ QString longString(65536, 'a');
+ socket.sendTextMessage(longString);
+ QVERIFY(socket.bytesToWrite() > longString.length());
+ QVERIFY(textMessageReceived.wait());
+ QCOMPARE(socket.bytesToWrite(), 0);
+
+ QCOMPARE(textMessageReceived.count(), 1);
+ QCOMPARE(binaryMessageReceived.count(), 0);
+ QCOMPARE(binaryFrameReceived.count(), 0);
+ arguments = textMessageReceived.takeFirst();
+ messageReceived = arguments.at(0).toString();
+ QCOMPARE(messageReceived.length(), longString.length());
+ QCOMPARE(messageReceived, longString);
+
+ arguments = textFrameReceived.takeLast();
+ isLastFrame = arguments.at(1).toBool();
+ QVERIFY(isLastFrame);
+
+ socket.close();
socketConnectedSpy.clear();
textMessageReceived.clear();
textFrameReceived.clear();
+ //QTBUG-36762: QWebSocket emits multiplied signals when socket was reopened
socket.open(QUrl(QStringLiteral("ws://") + echoServer.hostAddress().toString() +
QStringLiteral(":") + QString::number(echoServer.port())));
diff --git a/tests/auto/websockets/websocketframe/tst_websocketframe.cpp b/tests/auto/websockets/websocketframe/tst_websocketframe.cpp
index 5614df8..6b9aaaf 100644
--- a/tests/auto/websockets/websocketframe/tst_websocketframe.cpp
+++ b/tests/auto/websockets/websocketframe/tst_websocketframe.cpp
@@ -197,7 +197,8 @@ void tst_WebSocketFrame::tst_copyConstructorAndAssignment()
QBuffer buffer(&payload);
buffer.open(QIODevice::ReadOnly);
- QWebSocketFrame frame = QWebSocketFrame::readFrame(&buffer);
+ QWebSocketFrame frame;
+ frame.readFrame(&buffer);
buffer.close();
{
@@ -330,7 +331,8 @@ void tst_WebSocketFrame::tst_goodFrames()
QBuffer buffer;
buffer.setData(wireRepresentation);
buffer.open(QIODevice::ReadOnly);
- QWebSocketFrame frame = QWebSocketFrame::readFrame(&buffer);
+ QWebSocketFrame frame;
+ frame.readFrame(&buffer);
buffer.close();
QVERIFY(frame.isValid());
QCOMPARE(frame.rsv1(), rsv1);
@@ -495,7 +497,8 @@ void tst_WebSocketFrame::tst_invalidFrames()
QBuffer buffer;
buffer.setData(wireRepresentation);
buffer.open(QIODevice::ReadOnly);
- QWebSocketFrame frame = QWebSocketFrame::readFrame(&buffer);
+ QWebSocketFrame frame;
+ frame.readFrame(&buffer);
buffer.close();
QVERIFY(!frame.isValid());
@@ -606,7 +609,8 @@ void tst_WebSocketFrame::tst_malformedFrames()
QBuffer buffer;
buffer.setData(payload);
buffer.open(QIODevice::ReadOnly);
- QWebSocketFrame frame = QWebSocketFrame::readFrame(&buffer);
+ QWebSocketFrame frame;
+ frame.readFrame(&buffer);
buffer.close();
QVERIFY(!frame.isValid());