//TODO: test valid UTF8 sequences (see UC 6.2)
//TODO: test on masking correctness
//TODO: test for valid fields
-//TODO: test for valid control frames
-//DONE: test for valid close codes
-//DONE: test close frame with no close code and reason
//TODO: test if opcode is correct after processing of a continuation frame (text and binary frames)
//TODO: test valid frame sequences
//rainy-day flow
-//DONE: test invalid UTF8 sequences
-//DONE: test invalid UTF8 sequences in control/close frames
//TODO: test invalid masks
//TODO: test for AutoBahn testcase 5
//TODO: test for AutoBahn testcase 6.1
//TODO: test for AutoBahn testcase 6.3 (fragmentation test)
//TODO: test for AutoBahn testcase 6.4 (fragmentation test)
-//DONE: test for invalid fields
-//DONE: test for invalid opcodes
-//DONE: test continuation frames for too big payload
-//DONE: test continuation frames for too small frame
-//DONE: test continuation frames for bad rsv fields, etc.
-//DONE: test continuation frames for incomplete payload
-//DONE: test close frame with payload length 1 (is either 0, if no close code, or at least 2, close code + optional reason)
-//DONE: besides spying on errors, we should also check if the frame and message signals are not emitted (or partially emitted)
//TODO: test invalid frame sequences
\brief Tests all kinds of valid binary frames, including zero length frames
*/
void goodBinaryFrame();
+ void goodBinaryFrame_data();
/*!
\brief Tests all kinds of valid text frames, including zero length frames
*/
void goodTextFrame();
+ void goodTextFrame_data();
/*!
* \brief Test all kinds of valid control frames.
*/
- //void goodControlFrame();
+ void goodControlFrame();
+
/*!
* \brief Test all kinds of valid close frames.
*/
void goodCloseFrame();
+ void goodCloseFrame_data();
//void goodHeaders(); //test all valid opcodes
to allow non-characters again.
*/
void nonCharacterCodes();
+ void nonCharacterCodes_data();
/***************************************************************************
- * Unhappy Flows
+ * Rainy Day Flows
***************************************************************************/
/*!
\brief Tests the QWebSocketDataProcessor for correct handling of frames that don't contain the starting 2 bytes.
This test does not test sequences of frames, only single frames are tested
*/
void frameTooBig();
+ void frameTooBig_data();
/*!
\brief Tests the QWebSocketDataProcessor for the correct handling of malformed frame headers.
This test does not test sequences of frames, only single frames are tested
*/
void invalidHeader();
+ void invalidHeader_data();
/*!
\brief Tests the QWebSocketDataProcessor for the correct handling of invalid control frames.
This test does not test sequences of frames, only single frames are tested
*/
void invalidControlFrame();
+ void invalidControlFrame_data();
+
void invalidCloseFrame();
+ void invalidCloseFrame_data();
/*!
\brief Tests the QWebSocketDataProcessor for the correct handling of incomplete size fields for large and big payloads.
*/
void incompleteSizeField();
+ void incompleteSizeField_data();
/*!
\brief Tests the QWebSocketDataProcessor for the correct handling of incomplete payloads.
This test does not test sequences of frames, only single frames are tested
*/
void incompletePayload();
+ void incompletePayload_data();
/*!
\brief Tests the QWebSocketDataProcessor for the correct handling of invalid UTF-8 payloads.
This test does not test sequences of frames, only single frames are tested
*/
void invalidPayload();
+ void invalidPayload_data(bool isControlFrame = false);
void invalidPayloadInCloseFrame();
+ void invalidPayloadInCloseFrame_data();
/*!
Tests the QWebSocketDataProcessor for the correct handling of the minimum size representation requirement of RFC 6455 (see paragraph 5.2)
*/
void minimumSizeRequirement();
-
- void invalidHeader_data();
- void incompleteSizeField_data();
- void incompletePayload_data();
- void invalidPayload_data(bool isControlFrame = false);
- void invalidPayloadInCloseFrame_data();
void minimumSizeRequirement_data();
- void invalidControlFrame_data();
- void invalidCloseFrame_data();
- void frameTooBig_data();
-
- void nonCharacterCodes_data();
- void goodTextFrame_data();
- void goodBinaryFrame_data();
- void goodCloseFrame_data();
private:
//helper function that constructs a new row of test data for invalid UTF8 sequences
{
}
-void tst_DataProcessor::goodTextFrame_data()
-{
- QTest::addColumn<QByteArray>("payload");
-
- //test frames with small (< 126), large ( < 65536) and big ( > 65535) payloads
- for (int i = 0; i < (65536 + 256); i += 128)
- {
- QTest::newRow(QString("Text frame with %1 ASCII characters").arg(i).toStdString().data()) << QByteArray(i, 'a');
- }
- //test all valid ASCII characters
- for (int i = 0; i < 128; ++i)
- {
- QTest::newRow(QString("Text frame with containing ASCII character '0x%1'").arg(QByteArray(1, char(i)).toHex().constData()).toStdString().data()) << QByteArray(1, char(i));
- }
-}
-
void tst_DataProcessor::goodBinaryFrame_data()
{
QTest::addColumn<QByteArray>("payload");
- for (int i = 0; i < (65536 + 256); i += 128)
+ for (int i = 0; i < (65536 + 256); i += 128) //be sure to get small (< 126 bytes), large (> 125 bytes & < 64K) and big (>64K) frames
{
QTest::newRow(QString("Binary frame with %1 bytes").arg(i).toStdString().data()) << QByteArray(i, char(1));
}
- for (int i = 0; i < 256; ++i)
+ for (int i = 0; i < 256; ++i) //test all possible bytes in the payload
{
QTest::newRow(QString("Binary frame containing byte: '0x%1'").arg(QByteArray(1, char(i)).toHex().constData()).toStdString().data()) << QByteArray(i, char(1));
}
}
-void tst_DataProcessor::goodCloseFrame_data()
-{
- QTest::addColumn<QString>("payload");
- QTest::addColumn<QWebSocketProtocol::CloseCode>("closeCode");
- //control frame data cannot exceed 125 bytes; smaller than 124, because we also need a 2 byte close code
- for (int i = 0; i < 124; ++i)
- {
- QTest::newRow(QString("Close frame with %1 ASCII characters").arg(i).toStdString().data()) << QString(i, 'a') << QWebSocketProtocol::CC_NORMAL;
- }
- for (int i = 0; i < 126; ++i)
- {
- QTest::newRow(QString("Text frame with containing ASCII character '0x%1'").arg(QByteArray(1, char(i)).toHex().constData()).toStdString().data()) << QString(1, char(i)) << QWebSocketProtocol::CC_NORMAL;
- }
- QTest::newRow("Close frame with close code NORMAL") << QString(1, 'a') << QWebSocketProtocol::CC_NORMAL;
- QTest::newRow("Close frame with close code BAD OPERATION") << QString(1, 'a') << QWebSocketProtocol::CC_BAD_OPERATION;
- QTest::newRow("Close frame with close code DATATYPE NOT SUPPORTED") << QString(1, 'a') << QWebSocketProtocol::CC_DATATYPE_NOT_SUPPORTED;
- QTest::newRow("Close frame with close code GOING AWAY") << QString(1, 'a') << QWebSocketProtocol::CC_GOING_AWAY;
- QTest::newRow("Close frame with close code MISSING EXTENSION") << QString(1, 'a') << QWebSocketProtocol::CC_MISSING_EXTENSION;
- QTest::newRow("Close frame with close code POLICY VIOLATED") << QString(1, 'a') << QWebSocketProtocol::CC_POLICY_VIOLATED;
- QTest::newRow("Close frame with close code PROTOCOL ERROR") << QString(1, 'a') << QWebSocketProtocol::CC_PROTOCOL_ERROR;
- QTest::newRow("Close frame with close code TOO MUCH DATA") << QString(1, 'a') << QWebSocketProtocol::CC_TOO_MUCH_DATA;
- QTest::newRow("Close frame with close code WRONG DATATYPE") << QString(1, 'a') << QWebSocketProtocol::CC_WRONG_DATATYPE;
- QTest::newRow("Close frame with close code 3000") << QString(1, 'a') << QWebSocketProtocol::CloseCode(3000);
- QTest::newRow("Close frame with close code 3999") << QString(1, 'a') << QWebSocketProtocol::CloseCode(3999);
- QTest::newRow("Close frame with close code 4000") << QString(1, 'a') << QWebSocketProtocol::CloseCode(4000);
- QTest::newRow("Close frame with close code 4999") << QString(1, 'a') << QWebSocketProtocol::CloseCode(4999);
-
- //close frames with no close reason
- QTest::newRow("Close frame with close code NORMAL and no reason") << QString() << QWebSocketProtocol::CC_NORMAL;
- QTest::newRow("Close frame with close code BAD OPERATION and no reason") << QString() << QWebSocketProtocol::CC_BAD_OPERATION;
- QTest::newRow("Close frame with close code DATATYPE NOT SUPPORTED and no reason") << QString() << QWebSocketProtocol::CC_DATATYPE_NOT_SUPPORTED;
- QTest::newRow("Close frame with close code GOING AWAY and no reason") << QString() << QWebSocketProtocol::CC_GOING_AWAY;
- QTest::newRow("Close frame with close code MISSING EXTENSION and no reason") << QString() << QWebSocketProtocol::CC_MISSING_EXTENSION;
- QTest::newRow("Close frame with close code POLICY VIOLATED and no reason") << QString() << QWebSocketProtocol::CC_POLICY_VIOLATED;
- QTest::newRow("Close frame with close code PROTOCOL ERROR and no reason") << QString() << QWebSocketProtocol::CC_PROTOCOL_ERROR;
- QTest::newRow("Close frame with close code TOO MUCH DATA and no reason") << QString() << QWebSocketProtocol::CC_TOO_MUCH_DATA;
- QTest::newRow("Close frame with close code WRONG DATATYPE and no reason") << QString() << QWebSocketProtocol::CC_WRONG_DATATYPE;
- QTest::newRow("Close frame with close code 3000 and no reason") << QString() << QWebSocketProtocol::CloseCode(3000);
- QTest::newRow("Close frame with close code 3999 and no reason") << QString() << QWebSocketProtocol::CloseCode(3999);
- QTest::newRow("Close frame with close code 4000 and no reason") << QString() << QWebSocketProtocol::CloseCode(4000);
- QTest::newRow("Close frame with close code 4999 and no reason") << QString() << QWebSocketProtocol::CloseCode(4999);
-
- QTest::newRow("Close frame with no close code and no reason") << QString() << QWebSocketProtocol::CloseCode(0);
-}
-
void tst_DataProcessor::goodBinaryFrame()
{
QByteArray data;
buffer.setData(data);
buffer.open(QIODevice::ReadOnly);
- QSignalSpy spyFrameReceived(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
- QSignalSpy spyMessageReceived(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
- QSignalSpy spyTextFrameReceived(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
- QSignalSpy spyTextMessageReceived(&dataProcessor, SIGNAL(textMessageReceived(QString)));
+ QSignalSpy errorReceivedSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
+ QSignalSpy closeReceivedSpy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
+ QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
+ QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
+ QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
+ QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
+ QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
+ QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
dataProcessor.process(&buffer);
- QCOMPARE(spyFrameReceived.count(), 1);
- QCOMPARE(spyMessageReceived.count(), 1);
- QCOMPARE(spyTextFrameReceived.count(), 0);
- QCOMPARE(spyTextMessageReceived.count(), 0);
- QList<QVariant> arguments = spyFrameReceived.takeFirst();
+ QCOMPARE(errorReceivedSpy.count(), 0);
+ QCOMPARE(pingReceivedSpy.count(), 0);
+ QCOMPARE(pongReceivedSpy.count(), 0);
+ QCOMPARE(closeReceivedSpy.count(), 0);
+ QCOMPARE(binaryFrameReceivedSpy.count(), 1);
+ QCOMPARE(binaryMessageReceivedSpy.count(), 1);
+ QCOMPARE(textFrameReceivedSpy.count(), 0);
+ QCOMPARE(textMessageReceivedSpy.count(), 0);
+ QList<QVariant> arguments = binaryFrameReceivedSpy.takeFirst();
QCOMPARE(arguments.at(0).toByteArray().length(), payload.length());
- arguments = spyMessageReceived.takeFirst();
+ arguments = binaryMessageReceivedSpy.takeFirst();
QCOMPARE(arguments.at(0).toByteArray().length(), payload.length());
buffer.close();
- spyFrameReceived.clear();
- spyMessageReceived.clear();
- data.clear();
+}
+
+void tst_DataProcessor::goodTextFrame_data()
+{
+ QTest::addColumn<QByteArray>("payload");
+
+ //test frames with small (< 126), large ( < 65536) and big ( > 65535) payloads
+ for (int i = 0; i < (65536 + 256); i += 128)
+ {
+ QTest::newRow(QString("Text frame with %1 ASCII characters").arg(i).toStdString().data()) << QByteArray(i, 'a');
+ }
+ //test all valid ASCII characters
+ for (int i = 0; i < 128; ++i)
+ {
+ QTest::newRow(QString("Text frame with containing ASCII character '0x%1'").arg(QByteArray(1, char(i)).toHex().constData()).toStdString().data()) << QByteArray(1, char(i));
+ }
}
void tst_DataProcessor::goodTextFrame()
buffer.setData(data);
buffer.open(QIODevice::ReadOnly);
- QSignalSpy spyFrameReceived(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
- QSignalSpy spyMessageReceived(&dataProcessor, SIGNAL(textMessageReceived(QString)));
- QSignalSpy spyBinaryFrameReceived(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
- QSignalSpy spyBinaryMessageReceived(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
+ QSignalSpy errorReceivedSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
+ QSignalSpy closeReceivedSpy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
+ QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
+ QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
+ QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
+ QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
+ QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
+ QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
+
dataProcessor.process(&buffer);
- QCOMPARE(spyFrameReceived.count(), 1);
- QCOMPARE(spyMessageReceived.count(), 1);
- QCOMPARE(spyBinaryFrameReceived.count(), 0);
- QCOMPARE(spyBinaryMessageReceived.count(), 0);
- QList<QVariant> arguments = spyFrameReceived.takeFirst();
+
+ QCOMPARE(errorReceivedSpy.count(), 0);
+ QCOMPARE(pingReceivedSpy.count(), 0);
+ QCOMPARE(pongReceivedSpy.count(), 0);
+ QCOMPARE(closeReceivedSpy.count(), 0);
+ QCOMPARE(textFrameReceivedSpy.count(), 1);
+ QCOMPARE(textMessageReceivedSpy.count(), 1);
+ QCOMPARE(binaryFrameReceivedSpy.count(), 0);
+ QCOMPARE(binaryMessageReceivedSpy.count(), 0);
+ QList<QVariant> arguments = textFrameReceivedSpy.takeFirst();
QCOMPARE(arguments.at(0).toString().length(), payload.length());
- arguments = spyMessageReceived.takeFirst();
+ arguments = textMessageReceivedSpy.takeFirst();
QCOMPARE(arguments.at(0).toString().length(), payload.length());
buffer.close();
- spyFrameReceived.clear();
- spyMessageReceived.clear();
+}
+
+void tst_DataProcessor::goodControlFrame()
+{
+ QByteArray data;
+ QBuffer buffer;
+ QWebSocketDataProcessor dataProcessor;
+
+ QSignalSpy closeFrameReceivedSpy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
+ QSignalSpy errorReceivedSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
+ QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
+ QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
+ QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
+ QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
+ QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
+ QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
+
+ data.append((char)(FIN | QWebSocketProtocol::OC_PING));
+ data.append(QChar::fromLatin1(0));
+ buffer.setData(data);
+ buffer.open(QIODevice::ReadOnly);
+ dataProcessor.process(&buffer);
+ QCOMPARE(errorReceivedSpy.count(), 0);
+ QCOMPARE(textFrameReceivedSpy.count(), 0);
+ QCOMPARE(textMessageReceivedSpy.count(), 0);
+ QCOMPARE(binaryFrameReceivedSpy.count(), 0);
+ QCOMPARE(binaryMessageReceivedSpy.count(), 0);
+ QCOMPARE(closeFrameReceivedSpy.count(), 0);
+ QCOMPARE(pongReceivedSpy.count(), 0);
+ QCOMPARE(pingReceivedSpy.count(), 1);
+ buffer.close();
+
data.clear();
+ pingReceivedSpy.clear();
+ pongReceivedSpy.clear();
+ data.append((char)(FIN | QWebSocketProtocol::OC_PONG));
+ data.append(QChar::fromLatin1(0));
+ buffer.setData(data);
+ buffer.open(QIODevice::ReadOnly);
+ dataProcessor.process(&buffer);
+ QCOMPARE(errorReceivedSpy.count(), 0);
+ QCOMPARE(textFrameReceivedSpy.count(), 0);
+ QCOMPARE(textMessageReceivedSpy.count(), 0);
+ QCOMPARE(binaryFrameReceivedSpy.count(), 0);
+ QCOMPARE(binaryMessageReceivedSpy.count(), 0);
+ QCOMPARE(closeFrameReceivedSpy.count(), 0);
+ QCOMPARE(pingReceivedSpy.count(), 0);
+ QCOMPARE(pongReceivedSpy.count(), 1);
+ buffer.close();
+}
+
+void tst_DataProcessor::goodCloseFrame_data()
+{
+ QTest::addColumn<QString>("payload");
+ QTest::addColumn<QWebSocketProtocol::CloseCode>("closeCode");
+ //control frame data cannot exceed 125 bytes; smaller than 124, because we also need a 2 byte close code
+ for (int i = 0; i < 124; ++i)
+ {
+ QTest::newRow(QString("Close frame with %1 ASCII characters").arg(i).toStdString().data()) << QString(i, 'a') << QWebSocketProtocol::CC_NORMAL;
+ }
+ for (int i = 0; i < 126; ++i)
+ {
+ QTest::newRow(QString("Text frame with containing ASCII character '0x%1'").arg(QByteArray(1, char(i)).toHex().constData()).toStdString().data()) << QString(1, char(i)) << QWebSocketProtocol::CC_NORMAL;
+ }
+ QTest::newRow("Close frame with close code NORMAL") << QString(1, 'a') << QWebSocketProtocol::CC_NORMAL;
+ QTest::newRow("Close frame with close code BAD OPERATION") << QString(1, 'a') << QWebSocketProtocol::CC_BAD_OPERATION;
+ QTest::newRow("Close frame with close code DATATYPE NOT SUPPORTED") << QString(1, 'a') << QWebSocketProtocol::CC_DATATYPE_NOT_SUPPORTED;
+ QTest::newRow("Close frame with close code GOING AWAY") << QString(1, 'a') << QWebSocketProtocol::CC_GOING_AWAY;
+ QTest::newRow("Close frame with close code MISSING EXTENSION") << QString(1, 'a') << QWebSocketProtocol::CC_MISSING_EXTENSION;
+ QTest::newRow("Close frame with close code POLICY VIOLATED") << QString(1, 'a') << QWebSocketProtocol::CC_POLICY_VIOLATED;
+ QTest::newRow("Close frame with close code PROTOCOL ERROR") << QString(1, 'a') << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow("Close frame with close code TOO MUCH DATA") << QString(1, 'a') << QWebSocketProtocol::CC_TOO_MUCH_DATA;
+ QTest::newRow("Close frame with close code WRONG DATATYPE") << QString(1, 'a') << QWebSocketProtocol::CC_WRONG_DATATYPE;
+ QTest::newRow("Close frame with close code 3000") << QString(1, 'a') << QWebSocketProtocol::CloseCode(3000);
+ QTest::newRow("Close frame with close code 3999") << QString(1, 'a') << QWebSocketProtocol::CloseCode(3999);
+ QTest::newRow("Close frame with close code 4000") << QString(1, 'a') << QWebSocketProtocol::CloseCode(4000);
+ QTest::newRow("Close frame with close code 4999") << QString(1, 'a') << QWebSocketProtocol::CloseCode(4999);
+
+ //close frames with no close reason
+ QTest::newRow("Close frame with close code NORMAL and no reason") << QString() << QWebSocketProtocol::CC_NORMAL;
+ QTest::newRow("Close frame with close code BAD OPERATION and no reason") << QString() << QWebSocketProtocol::CC_BAD_OPERATION;
+ QTest::newRow("Close frame with close code DATATYPE NOT SUPPORTED and no reason") << QString() << QWebSocketProtocol::CC_DATATYPE_NOT_SUPPORTED;
+ QTest::newRow("Close frame with close code GOING AWAY and no reason") << QString() << QWebSocketProtocol::CC_GOING_AWAY;
+ QTest::newRow("Close frame with close code MISSING EXTENSION and no reason") << QString() << QWebSocketProtocol::CC_MISSING_EXTENSION;
+ QTest::newRow("Close frame with close code POLICY VIOLATED and no reason") << QString() << QWebSocketProtocol::CC_POLICY_VIOLATED;
+ QTest::newRow("Close frame with close code PROTOCOL ERROR and no reason") << QString() << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow("Close frame with close code TOO MUCH DATA and no reason") << QString() << QWebSocketProtocol::CC_TOO_MUCH_DATA;
+ QTest::newRow("Close frame with close code WRONG DATATYPE and no reason") << QString() << QWebSocketProtocol::CC_WRONG_DATATYPE;
+ QTest::newRow("Close frame with close code 3000 and no reason") << QString() << QWebSocketProtocol::CloseCode(3000);
+ QTest::newRow("Close frame with close code 3999 and no reason") << QString() << QWebSocketProtocol::CloseCode(3999);
+ QTest::newRow("Close frame with close code 4000 and no reason") << QString() << QWebSocketProtocol::CloseCode(4000);
+ QTest::newRow("Close frame with close code 4999 and no reason") << QString() << QWebSocketProtocol::CloseCode(4999);
+
+ QTest::newRow("Close frame with no close code and no reason") << QString() << QWebSocketProtocol::CloseCode(0);
}
void tst_DataProcessor::goodCloseFrame()
buffer.setData(data);
buffer.open(QIODevice::ReadOnly);
- QSignalSpy spyCloseFrameReceived(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
- QSignalSpy spyTextFrameReceived(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
- QSignalSpy spyTextMessageReceived(&dataProcessor, SIGNAL(textMessageReceived(QString)));
- QSignalSpy spyBinaryFrameReceived(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
- QSignalSpy spyBinaryMessageReceived(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
+ QSignalSpy errorReceivedSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
+ QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
+ QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
+ QSignalSpy closeFrameReceivedSpy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
+ QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
+ QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
+ QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
+ QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
dataProcessor.process(&buffer);
- QCOMPARE(spyCloseFrameReceived.count(), 1);
- QCOMPARE(spyTextFrameReceived.count(), 0);
- QCOMPARE(spyTextMessageReceived.count(), 0);
- QCOMPARE(spyBinaryFrameReceived.count(), 0);
- QCOMPARE(spyBinaryMessageReceived.count(), 0);
- QList<QVariant> arguments = spyCloseFrameReceived.takeFirst();
+
+ QCOMPARE(errorReceivedSpy.count(), 0);
+ QCOMPARE(pingReceivedSpy.count(), 0);
+ QCOMPARE(pongReceivedSpy.count(), 0);
+ QCOMPARE(closeFrameReceivedSpy.count(), 1);
+ QCOMPARE(textFrameReceivedSpy.count(), 0);
+ QCOMPARE(textMessageReceivedSpy.count(), 0);
+ QCOMPARE(binaryFrameReceivedSpy.count(), 0);
+ QCOMPARE(binaryMessageReceivedSpy.count(), 0);
+ QList<QVariant> arguments = closeFrameReceivedSpy.takeFirst();
QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), closeCode);
QCOMPARE(arguments.at(1).toString().length(), payload.length());
buffer.close();
- spyCloseFrameReceived.clear();
- data.clear();
+}
+
+void tst_DataProcessor::nonCharacterCodes_data()
+{
+ QTest::addColumn<quint8>("firstByte");
+ QTest::addColumn<quint8>("secondByte");
+ QTest::addColumn<QByteArray>("payload");
+ QTest::addColumn<bool>("isContinuationFrame");
+
+ nonCharacterSequence("efbfbe");
+ nonCharacterSequence("efbfbf");
+ nonCharacterSequence("f09fbfbe");
+ nonCharacterSequence("f09fbfbf");
+ nonCharacterSequence("f0afbfbe");
+ nonCharacterSequence("f0afbfbf");
+ nonCharacterSequence("f0bfbfbe");
+ nonCharacterSequence("f0bfbfbf");
+ nonCharacterSequence("f18fbfbe");
+ nonCharacterSequence("f18fbfbf");
+ nonCharacterSequence("f19fbfbe");
+ nonCharacterSequence("f19fbfbf");
+ nonCharacterSequence("f1afbfbe");
+ nonCharacterSequence("f1afbfbf");
+ nonCharacterSequence("f1bfbfbe");
+ nonCharacterSequence("f1bfbfbf");
+ nonCharacterSequence("f28fbfbe");
+ nonCharacterSequence("f28fbfbf");
+ nonCharacterSequence("f29fbfbe");
+ nonCharacterSequence("f29fbfbf");
+ nonCharacterSequence("f2afbfbe");
+ nonCharacterSequence("f2afbfbf");
+ nonCharacterSequence("f2bfbfbe");
+ nonCharacterSequence("f2bfbfbf");
+ nonCharacterSequence("f38fbfbe");
+ nonCharacterSequence("f38fbfbf");
+ nonCharacterSequence("f39fbfbe");
+ nonCharacterSequence("f39fbfbf");
+ nonCharacterSequence("f3afbfbe");
+ nonCharacterSequence("f3afbfbf");
+ nonCharacterSequence("f3bfbfbe");
+ nonCharacterSequence("f3bfbfbf");
+ nonCharacterSequence("f48fbfbe");
+ nonCharacterSequence("f48fbfbf");
}
void tst_DataProcessor::nonCharacterCodes()
QByteArray data;
QBuffer buffer;
QWebSocketDataProcessor dataProcessor;
- QSignalSpy frameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
- QSignalSpy messageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
+ QSignalSpy errorSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
+ QSignalSpy closeSpy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
+ QSignalSpy pingFrameSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
+ QSignalSpy pongFrameSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
+ QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
+ QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
buffer.setData(data);
buffer.open(QIODevice::ReadOnly);
dataProcessor.process(&buffer);
- //QEXPECT_FAIL(QTest::currentDataTag(), "Due to QTextCode interpeting non-characters unicode points as invalid (QTBUG-33229).", Abort);
- QCOMPARE(frameSpy.count(), 1);
- QCOMPARE(messageSpy.count(), 1);
+ QCOMPARE(errorSpy.count(), 0);
+ QCOMPARE(closeSpy.count(), 0);
+ QCOMPARE(pingFrameSpy.count(), 0);
+ QCOMPARE(pongFrameSpy.count(), 0);
+ QCOMPARE(textFrameSpy.count(), 1);
+ QCOMPARE(textMessageSpy.count(), 1);
QCOMPARE(binaryFrameSpy.count(), 0);
QCOMPARE(binaryMessageSpy.count(), 0);
- QVariantList arguments = frameSpy.takeFirst();
+ QVariantList arguments = textFrameSpy.takeFirst();
QCOMPARE(arguments.at(0).value<QString>().toUtf8(), payload);
- arguments = messageSpy.takeFirst();
+ QCOMPARE(arguments.at(1).value<bool>(), !isContinuationFrame);
+ arguments = textMessageSpy.takeFirst();
QCOMPARE(arguments.at(0).value<QString>().toUtf8(), payload);
buffer.close();
- frameSpy.clear();
- messageSpy.clear();
- data.clear();
}
}
//meaning the socket will be closed
buffer.setData(data);
buffer.open(QIODevice::ReadOnly);
- QSignalSpy spy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
+ QSignalSpy errorSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
+ QSignalSpy closeSpy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
+ QSignalSpy pingMessageSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
+ QSignalSpy pongMessageSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString, bool)));
QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
+
dataProcessor.process(&buffer);
- QCOMPARE(spy.count(), 1);
+
+ 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(), 0);
QCOMPARE(binaryFrameSpy.count(), 0);
- QList<QVariant> arguments = spy.takeFirst();
+
+ QList<QVariant> arguments = errorSpy.takeFirst();
QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_GOING_AWAY);
- spy.clear();
+ errorSpy.clear();
+ closeSpy.clear();
+ pingMessageSpy.clear();
+ pongMessageSpy.clear();
textMessageSpy.clear();
binaryMessageSpy.clear();
textFrameSpy.clear();
data.append(quint8('1')); //put 1 byte in the buffer; this is too little
buffer.setData(data);
buffer.open(QIODevice::ReadOnly);
+
dataProcessor.process(&buffer);
- QCOMPARE(spy.count(), 1);
+
+ 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(), 0);
QCOMPARE(binaryFrameSpy.count(), 0);
- arguments = spy.takeFirst();
+
+ arguments = errorSpy.takeFirst();
QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_GOING_AWAY);
buffer.close();
- spy.clear();
+ errorSpy.clear();
+ closeSpy.clear();
+ pingMessageSpy.clear();
+ pongMessageSpy.clear();
textMessageSpy.clear();
binaryMessageSpy.clear();
textFrameSpy.clear();
data.append((char)(QWebSocketProtocol::OC_TEXT)).append(char(0x0));
buffer.setData(data);
buffer.open(QIODevice::ReadOnly);
+
dataProcessor.process(&buffer);
buffer.close();
//meaning the socket will be closed
buffer.setData(data);
buffer.open(QIODevice::ReadOnly);
- QSignalSpy spy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
+ QSignalSpy errorSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
dataProcessor.process(&buffer);
- QCOMPARE(spy.count(), 1);
+
+ 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);
- QList<QVariant> arguments = spy.takeFirst();
+
+ QList<QVariant> arguments = errorSpy.takeFirst();
QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_GOING_AWAY);
- spy.clear();
+ errorSpy.clear();
+ closeSpy.clear();
+ pingMessageSpy.clear();
+ pongMessageSpy.clear();
textMessageSpy.clear();
binaryMessageSpy.clear();
textFrameSpy.clear();
buffer.open(QIODevice::ReadOnly);
dataProcessor.process(&buffer);
+ 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);
buffer.close();
data.clear();
- spy.clear();
+
+ errorSpy.clear();
+ closeSpy.clear();
+ pingMessageSpy.clear();
+ pongMessageSpy.clear();
textMessageSpy.clear();
binaryMessageSpy.clear();
textFrameSpy.clear();
buffer.open(QIODevice::ReadOnly);
dataProcessor.process(&buffer);
- QCOMPARE(spy.count(), 1);
+ 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(), 0);
QCOMPARE(binaryFrameSpy.count(), 0);
- arguments = spy.takeFirst();
+ arguments = errorSpy.takeFirst();
QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_GOING_AWAY);
- spy.clear();
buffer.close();
}
}
-void tst_DataProcessor::frameTooBig()
-{
- doTest();
-}
-
-void tst_DataProcessor::invalidHeader()
+void tst_DataProcessor::frameTooBig_data()
{
- doTest();
-}
+ QTest::addColumn<quint8>("firstByte");
+ QTest::addColumn<quint8>("secondByte");
+ QTest::addColumn<QByteArray>("payload");
+ QTest::addColumn<bool>("isContinuationFrame");
+ QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
-void tst_DataProcessor::invalidControlFrame()
-{
- doTest();
-}
+ quint64 swapped64 = 0;
+ const char *wireRepresentation = 0;
-void tst_DataProcessor::invalidCloseFrame()
-{
- doCloseFrameTest();
-}
+ //only data frames are checked for being too big
+ //control frames have explicit checking on a maximum payload size of 125, which is tested elsewhere
-void tst_DataProcessor::minimumSizeRequirement()
-{
- doTest();
+ swapped64 = qToBigEndian<quint64>(QWebSocketDataProcessor::maxFrameSize() + 1);
+ wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
+ QTest::newRow("Text frame with payload size > INT_MAX")
+ << quint8(FIN | QWebSocketProtocol::OC_TEXT)
+ << quint8(127)
+ << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a'))
+ << false
+ << QWebSocketProtocol::CC_TOO_MUCH_DATA;
+
+ swapped64 = qToBigEndian<quint64>(QWebSocketDataProcessor::maxFrameSize() + 1);
+ wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
+ QTest::newRow("Binary frame with payload size > INT_MAX")
+ << quint8(FIN | QWebSocketProtocol::OC_BINARY)
+ << quint8(127)
+ << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a'))
+ << false
+ << QWebSocketProtocol::CC_TOO_MUCH_DATA;
+
+ swapped64 = qToBigEndian<quint64>(QWebSocketDataProcessor::maxFrameSize() + 1);
+ wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
+ QTest::newRow("Continuation frame with payload size > INT_MAX")
+ << quint8(FIN | QWebSocketProtocol::OC_CONTINUE)
+ << quint8(127)
+ << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a'))
+ << true
+ << QWebSocketProtocol::CC_TOO_MUCH_DATA;
}
-void tst_DataProcessor::invalidPayload()
+void tst_DataProcessor::frameTooBig()
{
doTest();
}
-void tst_DataProcessor::invalidPayloadInCloseFrame()
+void tst_DataProcessor::invalidHeader_data()
{
- QFETCH(quint8, firstByte);
- QFETCH(quint8, secondByte);
- QFETCH(QByteArray, payload);
- QFETCH(bool, isContinuationFrame);
- QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
-
- Q_UNUSED(isContinuationFrame)
+ //The first byte contain the FIN, RSV1, RSV2, RSV3 and the Opcode
+ //The second byte contains the MaskFlag and the length of the frame
+ QTest::addColumn<quint8>("firstByte");
+ QTest::addColumn<quint8>("secondByte");
+ QTest::addColumn<QByteArray>("payload"); //superfluous, but present to be able to call doTest(), which expects a payload field
+ QTest::addColumn<bool>("isContinuationFrame");
+ QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
- QByteArray data;
- QBuffer buffer;
- QWebSocketDataProcessor dataProcessor;
- QSignalSpy spy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
- QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
- QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
- QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString, bool)));
- QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
+ //invalid bit fields
+ invalidField("RSV1 set", RSV1);
+ invalidField("RSV2 set", RSV2);
+ invalidField("RSV3 set", RSV3);
+ invalidField("RSV1 and RSV2 set", RSV1 | RSV2);
+ invalidField("RSV1 and RSV3 set", RSV1 | RSV3);
+ invalidField("RSV2 and RSV3 set", RSV2 | RSV3);
+ invalidField("RSV1, RSV2 and RSV3 set", RSV1 | RSV2 | RSV3);
- data.append(firstByte).append(secondByte);
- data.append(payload);
- buffer.setData(data);
- buffer.open(QIODevice::ReadOnly);
- dataProcessor.process(&buffer);
- QCOMPARE(spy.count(), 1);
- QCOMPARE(textMessageSpy.count(), 0);
- QCOMPARE(binaryMessageSpy.count(), 0);
- QCOMPARE(textFrameSpy.count(), 0);
- QCOMPARE(binaryFrameSpy.count(), 0);
- QVariantList arguments = spy.takeFirst();
- QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), expectedCloseCode);
- buffer.close();
- spy.clear();
- data.clear();
+ //invalid opcodes
+ invalidField("Invalid OpCode 3", QWebSocketProtocol::OC_RESERVED_3);
+ invalidField("Invalid OpCode 4", QWebSocketProtocol::OC_RESERVED_4);
+ invalidField("Invalid OpCode 5", QWebSocketProtocol::OC_RESERVED_5);
+ invalidField("Invalid OpCode 6", QWebSocketProtocol::OC_RESERVED_6);
+ invalidField("Invalid OpCode 7", QWebSocketProtocol::OC_RESERVED_7);
+ invalidField("Invalid OpCode B", QWebSocketProtocol::OC_RESERVED_B);
+ invalidField("Invalid OpCode C", QWebSocketProtocol::OC_RESERVED_C);
+ invalidField("Invalid OpCode D", QWebSocketProtocol::OC_RESERVED_D);
+ invalidField("Invalid OpCode E", QWebSocketProtocol::OC_RESERVED_E);
+ invalidField("Invalid OpCode F", QWebSocketProtocol::OC_RESERVED_F);
}
-void tst_DataProcessor::incompletePayload()
+void tst_DataProcessor::invalidHeader()
{
doTest();
}
-void tst_DataProcessor::incompleteSizeField()
+void tst_DataProcessor::invalidControlFrame_data()
{
- doTest();
-}
+ QTest::addColumn<quint8>("firstByte");
+ QTest::addColumn<quint8>("secondByte");
+ QTest::addColumn<QByteArray>("payload");
+ QTest::addColumn<bool>("isContinuationFrame");
+ QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
-//////////////////////////////////////////////////////////////////////////////////////////
-/// HELPER FUNCTIONS
-//////////////////////////////////////////////////////////////////////////////////////////
-void tst_DataProcessor::doTest()
-{
- QFETCH(quint8, firstByte);
- QFETCH(quint8, secondByte);
- QFETCH(QByteArray, payload);
- QFETCH(bool, isContinuationFrame);
- QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
- QByteArray data;
- QBuffer buffer;
- QWebSocketDataProcessor dataProcessor;
- QSignalSpy spy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
- QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
- QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
- QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString, bool)));
- QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
+ QTest::newRow("Close control frame with payload size 126")
+ << quint8(FIN | QWebSocketProtocol::OC_CLOSE) << quint8(126) << QByteArray() << false << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow("Ping control frame with payload size 126")
+ << quint8(FIN | QWebSocketProtocol::OC_PING) << quint8(126) << QByteArray() << false << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow("Close control frame with payload size 126")
+ << quint8(FIN | QWebSocketProtocol::OC_PONG) << quint8(126) << QByteArray() << false << QWebSocketProtocol::CC_PROTOCOL_ERROR;
- if (isContinuationFrame)
- {
- data.append(quint8(QWebSocketProtocol::OC_TEXT)).append(char(1)).append(QByteArray(1, 'a'));
- }
- data.append(firstByte).append(secondByte);
- data.append(payload);
- buffer.setData(data);
- buffer.open(QIODevice::ReadOnly);
- dataProcessor.process(&buffer);
- QCOMPARE(spy.count(), 1);
- QCOMPARE(textMessageSpy.count(), 0);
- QCOMPARE(binaryMessageSpy.count(), 0);
- QCOMPARE(textFrameSpy.count(), isContinuationFrame ? 1 : 0);
- QCOMPARE(binaryFrameSpy.count(), 0);
- QVariantList arguments = spy.takeFirst();
- QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), expectedCloseCode);
- buffer.close();
- spy.clear();
- data.clear();
+ QTest::newRow("Non-final close control frame (fragmented)")
+ << quint8(QWebSocketProtocol::OC_CLOSE) << quint8(32) << QByteArray() << false << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow("Non-final ping control frame (fragmented)")
+ << quint8(QWebSocketProtocol::OC_PING) << quint8(32) << QByteArray() << false << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow("Non-final pong control frame (fragmented)")
+ << quint8(QWebSocketProtocol::OC_PONG) << quint8(32) << QByteArray() << false << QWebSocketProtocol::CC_PROTOCOL_ERROR;
}
-void tst_DataProcessor::doCloseFrameTest()
+void tst_DataProcessor::invalidControlFrame()
{
- QFETCH(quint8, firstByte);
- QFETCH(quint8, secondByte);
- QFETCH(QByteArray, payload);
- QFETCH(bool, isContinuationFrame);
- QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
-
- Q_UNUSED(isContinuationFrame)
-
- QByteArray data;
- QBuffer buffer;
- QWebSocketDataProcessor dataProcessor;
- QSignalSpy spy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
- QSignalSpy errorSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
- QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
- QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
- QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString, bool)));
- QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
-
- data.append(firstByte).append(secondByte);
- data.append(payload);
- buffer.setData(data);
- buffer.open(QIODevice::ReadOnly);
- dataProcessor.process(&buffer);
- QCOMPARE(spy.count(), 1);
- QCOMPARE(errorSpy.count(), 0);
- QCOMPARE(textMessageSpy.count(), 0);
- QCOMPARE(binaryMessageSpy.count(), 0);
- QCOMPARE(textFrameSpy.count(), 0);
- QCOMPARE(binaryFrameSpy.count(), 0);
- QVariantList arguments = spy.takeFirst();
- QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), expectedCloseCode);
- buffer.close();
- spy.clear();
- data.clear();
+ doTest();
}
-QString tst_DataProcessor::opCodeToString(quint8 opCode)
+void tst_DataProcessor::invalidCloseFrame_data()
{
- QString frameType;
- switch (opCode)
- {
- case QWebSocketProtocol::OC_BINARY:
- {
- frameType = "Binary";
- break;
- }
- case QWebSocketProtocol::OC_TEXT:
- {
- frameType = "Text";
- break;
- }
- case QWebSocketProtocol::OC_PING:
- {
- frameType = "Ping";
- break;
- }
- case QWebSocketProtocol::OC_PONG:
- {
- frameType = "Pong";
- break;
- }
- case QWebSocketProtocol::OC_CLOSE:
- {
- frameType = "Close";
- break;
- }
- case QWebSocketProtocol::OC_CONTINUE:
- {
- frameType = "Continuation";
- break;
- }
- case QWebSocketProtocol::OC_RESERVED_3:
- {
- frameType = "Reserved3";
- break;
- }
- case QWebSocketProtocol::OC_RESERVED_4:
- {
- frameType = "Reserved5";
- break;
- }
- case QWebSocketProtocol::OC_RESERVED_5:
- {
- frameType = "Reserved5";
- break;
- }
- case QWebSocketProtocol::OC_RESERVED_6:
- {
- frameType = "Reserved6";
- break;
- }
- case QWebSocketProtocol::OC_RESERVED_7:
- {
- frameType = "Reserved7";
- break;
- }
- case QWebSocketProtocol::OC_RESERVED_B:
- {
- frameType = "ReservedB";
- break;
- }
- case QWebSocketProtocol::OC_RESERVED_C:
- {
- frameType = "ReservedC";
- break;
- }
- case QWebSocketProtocol::OC_RESERVED_D:
- {
- frameType = "ReservedD";
- break;
- }
- case QWebSocketProtocol::OC_RESERVED_E:
- {
- frameType = "ReservedE";
- break;
- }
- case QWebSocketProtocol::OC_RESERVED_F:
- {
- frameType = "ReservedF";
- break;
- }
- default:
- {
- //should never come here
- Q_ASSERT(false);
- }
- }
- return frameType;
-}
+ QTest::addColumn<quint8>("firstByte");
+ QTest::addColumn<quint8>("secondByte");
+ QTest::addColumn<QByteArray>("payload");
+ QTest::addColumn<bool>("isContinuationFrame");
+ QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
-void tst_DataProcessor::minimumSize16Bit(quint16 sizeInBytes)
-{
- quint16 swapped16 = qToBigEndian<quint16>(sizeInBytes);
- const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped16));
- QTest::newRow(QString("Text frame with payload size %1, represented in 2 bytes").arg(sizeInBytes).toStdString().data())
- << quint8(FIN | QWebSocketProtocol::OC_TEXT)
- << quint8(126)
- << QByteArray(wireRepresentation, 2)
- << false
- << QWebSocketProtocol::CC_PROTOCOL_ERROR;
- QTest::newRow(QString("Binary frame with payload size %1, represented in 2 bytes").arg(sizeInBytes).toStdString().data())
- << quint8(FIN | QWebSocketProtocol::OC_BINARY)
- << quint8(126)
- << QByteArray(wireRepresentation, 2)
- << false
- << QWebSocketProtocol::CC_PROTOCOL_ERROR;
- QTest::newRow(QString("Continuation frame with payload size %1, represented in 2 bytes").arg(sizeInBytes).toStdString().data())
- << quint8(FIN | QWebSocketProtocol::OC_CONTINUE)
- << quint8(126)
- << QByteArray(wireRepresentation, 2)
- << true
- << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow("Close control frame with payload size 1")
+ << quint8(FIN | QWebSocketProtocol::OC_CLOSE) << quint8(1) << QByteArray(1, 'a') << false << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ quint16 swapped = qToBigEndian<quint16>(QWebSocketProtocol::CC_ABNORMAL_DISCONNECTION);
+ const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+
+ //Not allowed per RFC 6455 (see para 7.4.1)
+ QTest::newRow("Close control frame close code ABNORMAL DISCONNECTION")
+ << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
+ quint8(2) <<
+ QByteArray(wireRepresentation, 2) <<
+ false <<
+ QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ swapped = qToBigEndian<quint16>(QWebSocketProtocol::CC_MISSING_STATUS_CODE);
+ wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+ //Not allowed per RFC 6455 (see para 7.4.1)
+ QTest::newRow("Close control frame close code MISSING STATUS CODE")
+ << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
+ quint8(2) <<
+ QByteArray(wireRepresentation, 2) <<
+ false <<
+ QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ swapped = qToBigEndian<quint16>(1004);
+ wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+ QTest::newRow("Close control frame close code 1004")
+ << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
+ quint8(2) <<
+ QByteArray(wireRepresentation, 2) <<
+ false <<
+ QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ swapped = qToBigEndian<quint16>(QWebSocketProtocol::CC_TLS_HANDSHAKE_FAILED);
+ wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+ //Not allowed per RFC 6455 (see para 7.4.1)
+ QTest::newRow("Close control frame close code TLS HANDSHAKE FAILED")
+ << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
+ quint8(2) <<
+ QByteArray(wireRepresentation, 2) <<
+ false <<
+ QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ swapped = qToBigEndian<quint16>(0);
+ wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+ QTest::newRow("Close control frame close code 0")
+ << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
+ quint8(2) <<
+ QByteArray(wireRepresentation, 2) <<
+ false <<
+ QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ swapped = qToBigEndian<quint16>(999);
+ wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+ QTest::newRow("Close control frame close code 999")
+ << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
+ quint8(2) <<
+ QByteArray(wireRepresentation, 2) <<
+ false <<
+ QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ swapped = qToBigEndian<quint16>(1012);
+ wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+ QTest::newRow("Close control frame close code 1012")
+ << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
+ quint8(2) <<
+ QByteArray(wireRepresentation, 2) <<
+ false <<
+ QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ swapped = qToBigEndian<quint16>(1013);
+ wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+ QTest::newRow("Close control frame close code 1013")
+ << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
+ quint8(2) <<
+ QByteArray(wireRepresentation, 2) <<
+ false <<
+ QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ swapped = qToBigEndian<quint16>(1014);
+ wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+ QTest::newRow("Close control frame close code 1014")
+ << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
+ quint8(2) <<
+ QByteArray(wireRepresentation, 2) <<
+ false <<
+ QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ swapped = qToBigEndian<quint16>(1100);
+ wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+ QTest::newRow("Close control frame close code 1100")
+ << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
+ quint8(2) <<
+ QByteArray(wireRepresentation, 2) <<
+ false <<
+ QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ swapped = qToBigEndian<quint16>(2000);
+ wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+ QTest::newRow("Close control frame close code 2000")
+ << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
+ quint8(2) <<
+ QByteArray(wireRepresentation, 2) <<
+ false <<
+ QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ swapped = qToBigEndian<quint16>(2999);
+ wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+ QTest::newRow("Close control frame close code 2999")
+ << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
+ quint8(2) <<
+ QByteArray(wireRepresentation, 2) <<
+ false <<
+ QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ swapped = qToBigEndian<quint16>(5000);
+ wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+ QTest::newRow("Close control frame close code 5000")
+ << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
+ quint8(2) <<
+ QByteArray(wireRepresentation, 2) <<
+ false <<
+ QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ swapped = qToBigEndian<quint16>(65535u);
+ wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+ QTest::newRow("Close control frame close code 65535")
+ << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
+ quint8(2) <<
+ QByteArray(wireRepresentation, 2) <<
+ false <<
+ QWebSocketProtocol::CC_PROTOCOL_ERROR;
}
-void tst_DataProcessor::minimumSize64Bit(quint64 sizeInBytes)
+void tst_DataProcessor::invalidCloseFrame()
{
- quint64 swapped64 = qToBigEndian<quint64>(sizeInBytes);
- const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
-
- QTest::newRow(QString("Text frame with payload size %1, represented in 8 bytes").arg(sizeInBytes).toStdString().data())
- << quint8(FIN | QWebSocketProtocol::OC_TEXT)
- << quint8(127)
- << QByteArray(wireRepresentation, 8)
- << false
- << QWebSocketProtocol::CC_PROTOCOL_ERROR;
-
- QTest::newRow(QString("Binary frame with payload size %1, represented in 8 bytes").arg(sizeInBytes).toStdString().data())
- << quint8(FIN | QWebSocketProtocol::OC_BINARY)
- << quint8(127)
- << QByteArray(wireRepresentation, 8)
- << false
- << QWebSocketProtocol::CC_PROTOCOL_ERROR;
-
- QTest::newRow(QString("Continuation frame with payload size %1, represented in 8 bytes").arg(sizeInBytes).toStdString().data())
- << quint8(FIN | QWebSocketProtocol::OC_CONTINUE)
- << quint8(127)
- << QByteArray(wireRepresentation, 8)
- << true
- << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ doCloseFrameTest();
}
-void tst_DataProcessor::invalidUTF8(const char *dataTag, const char *utf8Sequence, bool isCloseFrame)
+void tst_DataProcessor::minimumSizeRequirement_data()
{
- QByteArray payload = QByteArray::fromHex(utf8Sequence);
+ QTest::addColumn<quint8>("firstByte");
+ QTest::addColumn<quint8>("secondByte");
+ QTest::addColumn<QByteArray>("payload");
+ QTest::addColumn<bool>("isContinuationFrame");
+ QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
- if (isCloseFrame)
- {
- quint16 closeCode = qToBigEndian<quint16>(QWebSocketProtocol::CC_NORMAL);
- const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&closeCode));
- QTest::newRow(QString("Close frame with invalid UTF8-sequence: %1").arg(dataTag).toStdString().data())
- << quint8(FIN | QWebSocketProtocol::OC_CLOSE)
- << quint8(payload.length() + 2)
- << QByteArray(wireRepresentation, 2).append(payload)
- << false
- << QWebSocketProtocol::CC_WRONG_DATATYPE;
- }
- else
- {
- QTest::newRow(QString("Text frame with invalid UTF8-sequence: %1").arg(dataTag).toStdString().data())
- << quint8(FIN | QWebSocketProtocol::OC_TEXT)
- << quint8(payload.length())
- << payload
- << false
- << QWebSocketProtocol::CC_WRONG_DATATYPE;
+ minimumSize16Bit(0);
+ minimumSize16Bit(64);
+ minimumSize16Bit(125);
- QTest::newRow(QString("Continuation text frame with invalid UTF8-sequence: %1").arg(dataTag).toStdString().data())
- << quint8(FIN | QWebSocketProtocol::OC_CONTINUE)
- << quint8(payload.length())
- << payload
- << true
- << QWebSocketProtocol::CC_WRONG_DATATYPE;
- }
+ minimumSize64Bit(0);
+ minimumSize64Bit(64);
+ minimumSize64Bit(125);
+ minimumSize64Bit(126);
+ minimumSize64Bit(256);
+ minimumSize64Bit(512);
+ minimumSize64Bit(1024);
+ minimumSize64Bit(2048);
+ minimumSize64Bit(4096);
+ minimumSize64Bit(8192);
+ minimumSize64Bit(16384);
+ minimumSize64Bit(32768);
+ minimumSize64Bit(0xFFFFu);
}
-void tst_DataProcessor::invalidField(const char *dataTag, quint8 invalidFieldValue)
+void tst_DataProcessor::minimumSizeRequirement()
{
- QTest::newRow(dataTag) << quint8(FIN | invalidFieldValue)
- << quint8(0x00)
- << QByteArray()
- << false
- << QWebSocketProtocol::CC_PROTOCOL_ERROR;
- QTest::newRow(QString(dataTag).append(" with continuation frame").toStdString().data())
- << quint8(FIN | invalidFieldValue)
- << quint8(0x00)
- << QByteArray()
- << true
- << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ doTest();
}
-void tst_DataProcessor::incompleteFrame(quint8 controlCode, quint64 indicatedSize, quint64 actualPayloadSize)
+void tst_DataProcessor::invalidPayload_data(bool isControlFrame)
{
- QVERIFY(!QWebSocketProtocol::isOpCodeReserved(QWebSocketProtocol::OpCode(controlCode)));
- QVERIFY(indicatedSize > actualPayloadSize);
-
- QString frameType = opCodeToString(controlCode);
- QByteArray firstFrame;
-
- if (indicatedSize < 126)
- {
- QTest::newRow(frameType.append(QString(" frame with payload size %1, but only %2 bytes of data").arg(indicatedSize).arg(actualPayloadSize)).toStdString().data())
- << quint8(FIN | controlCode)
- << quint8(indicatedSize)
- << firstFrame.append(QByteArray(actualPayloadSize, 'a'))
- << (controlCode == QWebSocketProtocol::OC_CONTINUE)
- << QWebSocketProtocol::CC_GOING_AWAY;
- }
- else if (indicatedSize <= 0xFFFFu)
- {
- quint16 swapped16 = qToBigEndian<quint16>(static_cast<quint16>(indicatedSize));
- const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped16));
- QTest::newRow(frameType.append(QString(" frame with payload size %1, but only %2 bytes of data").arg(indicatedSize).arg(actualPayloadSize)).toStdString().data())
- << quint8(FIN | controlCode)
- << quint8(126)
- << firstFrame.append(QByteArray(wireRepresentation, 2).append(QByteArray(actualPayloadSize, 'a')))
- << (controlCode == QWebSocketProtocol::OC_CONTINUE)
- << QWebSocketProtocol::CC_GOING_AWAY;
- }
- else
- {
- quint64 swapped64 = qToBigEndian<quint64>(indicatedSize);
- const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
- QTest::newRow(frameType.append(QString(" frame with payload size %1, but only %2 bytes of data").arg(indicatedSize).arg(actualPayloadSize)).toStdString().data())
- << quint8(FIN | controlCode)
- << quint8(127)
- << firstFrame.append(QByteArray(wireRepresentation, 8).append(QByteArray(actualPayloadSize, 'a')))
- << (controlCode == QWebSocketProtocol::OC_CONTINUE)
- << QWebSocketProtocol::CC_GOING_AWAY;
- }
-}
-
-void tst_DataProcessor::nonCharacterSequence(const char *sequence)
-{
- QByteArray utf8Sequence = QByteArray::fromHex(sequence);
- //TODO: qstrdup - memory leak! qstrdup is necessary because once QString goes out of scope we have garbage
- const char *tagName = qstrdup(qPrintable(QString("Text frame with payload containing the non-control character sequence 0x%1").arg(QString(sequence))));
- const char *tagName2 = qstrdup(qPrintable(QString("Continuation frame with payload containing the non-control character sequence 0x%1").arg(QString(sequence))));
-
- QTest::newRow(tagName)
- << quint8(FIN | QWebSocketProtocol::OC_TEXT)
- << quint8(utf8Sequence.size())
- << utf8Sequence
- << false;
-
- QTest::newRow(tagName2)
- << quint8(FIN | QWebSocketProtocol::OC_CONTINUE)
- << quint8(utf8Sequence.size())
- << utf8Sequence
- << true;
-}
-
-void tst_DataProcessor::insertIncompleteSizeFieldTest(quint8 payloadCode, quint8 numBytesFollowing)
-{
- QTest::newRow(QString("Text frame with payload size %1, with %2 bytes following.").arg(payloadCode).arg(numBytesFollowing).toStdString().data())
- << quint8(FIN | QWebSocketProtocol::OC_TEXT)
- << quint8(payloadCode)
- << QByteArray(numBytesFollowing, quint8(1))
- << false
- << QWebSocketProtocol::CC_GOING_AWAY;
- QTest::newRow(QString("Binary frame with payload size %1, with %2 bytes following.").arg(payloadCode).arg(numBytesFollowing).toStdString().data())
- << quint8(FIN | QWebSocketProtocol::OC_BINARY)
- << quint8(payloadCode)
- << QByteArray(numBytesFollowing, quint8(1))
- << false
- << QWebSocketProtocol::CC_GOING_AWAY;
- QTest::newRow(QString("Continuation frame with payload size %1, with %2 bytes following.").arg(payloadCode).arg(numBytesFollowing).toStdString().data())
- << quint8(FIN | QWebSocketProtocol::OC_CONTINUE)
- << quint8(payloadCode)
- << QByteArray(numBytesFollowing, quint8(1))
- << true
- << QWebSocketProtocol::CC_GOING_AWAY;
-}
-
-//////////////////////////////////////////////////////////////////////////////////
-//// TEST DATA
-//////////////////////////////////////////////////////////////////////////////////
-void tst_DataProcessor::invalidHeader_data()
-{
- //The first byte contain the FIN, RSV1, RSV2, RSV3 and the Opcode
- //The second byte contains the MaskFlag and the length of the frame
- QTest::addColumn<quint8>("firstByte");
- QTest::addColumn<quint8>("secondByte");
- QTest::addColumn<QByteArray>("payload"); //superfluous, but present to be able to call doTest(), which expects a payload field
- QTest::addColumn<bool>("isContinuationFrame");
- QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
-
- //invalid bit fields
- invalidField("RSV1 set", RSV1);
- invalidField("RSV2 set", RSV2);
- invalidField("RSV3 set", RSV3);
- invalidField("RSV1 and RSV2 set", RSV1 | RSV2);
- invalidField("RSV1 and RSV3 set", RSV1 | RSV3);
- invalidField("RSV2 and RSV3 set", RSV2 | RSV3);
- invalidField("RSV1, RSV2 and RSV3 set", RSV1 | RSV2 | RSV3);
-
- //invalid opcodes
- invalidField("Invalid OpCode 3", QWebSocketProtocol::OC_RESERVED_3);
- invalidField("Invalid OpCode 4", QWebSocketProtocol::OC_RESERVED_4);
- invalidField("Invalid OpCode 5", QWebSocketProtocol::OC_RESERVED_5);
- invalidField("Invalid OpCode 6", QWebSocketProtocol::OC_RESERVED_6);
- invalidField("Invalid OpCode 7", QWebSocketProtocol::OC_RESERVED_7);
- invalidField("Invalid OpCode B", QWebSocketProtocol::OC_RESERVED_B);
- invalidField("Invalid OpCode C", QWebSocketProtocol::OC_RESERVED_C);
- invalidField("Invalid OpCode D", QWebSocketProtocol::OC_RESERVED_D);
- invalidField("Invalid OpCode E", QWebSocketProtocol::OC_RESERVED_E);
- invalidField("Invalid OpCode F", QWebSocketProtocol::OC_RESERVED_F);
-}
-
-void tst_DataProcessor::invalidPayloadInCloseFrame_data()
-{
- invalidPayload_data(true);
-}
-
-void tst_DataProcessor::invalidPayload_data(bool isControlFrame)
-{
- QTest::addColumn<quint8>("firstByte");
- QTest::addColumn<quint8>("secondByte");
- QTest::addColumn<QByteArray>("payload");
- QTest::addColumn<bool>("isContinuationFrame");
- QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
+ QTest::addColumn<quint8>("firstByte");
+ QTest::addColumn<quint8>("secondByte");
+ QTest::addColumn<QByteArray>("payload");
+ QTest::addColumn<bool>("isContinuationFrame");
+ QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
//6.3: invalid UTF-8 sequence
invalidUTF8("case 6.3.1", "cebae1bdb9cf83cebcceb5eda080656469746564", isControlFrame);
invalidUTF8("case 6.21.8", "edafbfedbfbf", isControlFrame);
}
-void tst_DataProcessor::minimumSizeRequirement_data()
+void tst_DataProcessor::invalidPayload()
{
- QTest::addColumn<quint8>("firstByte");
- QTest::addColumn<quint8>("secondByte");
- QTest::addColumn<QByteArray>("payload");
- QTest::addColumn<bool>("isContinuationFrame");
- QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
+ doTest();
+}
- minimumSize16Bit(0);
- minimumSize16Bit(64);
- minimumSize16Bit(125);
+void tst_DataProcessor::invalidPayloadInCloseFrame_data()
+{
+ invalidPayload_data(true);
+}
- minimumSize64Bit(0);
- minimumSize64Bit(64);
- minimumSize64Bit(125);
- minimumSize64Bit(126);
- minimumSize64Bit(256);
- minimumSize64Bit(512);
- minimumSize64Bit(1024);
- minimumSize64Bit(2048);
- minimumSize64Bit(4096);
- minimumSize64Bit(8192);
- minimumSize64Bit(16384);
- minimumSize64Bit(32768);
- minimumSize64Bit(0xFFFFu);
+void tst_DataProcessor::invalidPayloadInCloseFrame()
+{
+ QFETCH(quint8, firstByte);
+ QFETCH(quint8, secondByte);
+ QFETCH(QByteArray, payload);
+ QFETCH(bool, isContinuationFrame);
+ QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
+
+ Q_UNUSED(isContinuationFrame)
+
+ QByteArray data;
+ QBuffer buffer;
+ QWebSocketDataProcessor dataProcessor;
+ QSignalSpy closeSpy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
+ QSignalSpy errorSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
+ QSignalSpy pingMessageSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
+ QSignalSpy pongMessageSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
+ QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
+ QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
+ QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString, bool)));
+ QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
+
+ data.append(firstByte).append(secondByte);
+ data.append(payload);
+ buffer.setData(data);
+ buffer.open(QIODevice::ReadOnly);
+ dataProcessor.process(&buffer);
+ QCOMPARE(closeSpy.count(), 1);
+ QCOMPARE(errorSpy.count(), 0);
+ QCOMPARE(pingMessageSpy.count(), 0);
+ QCOMPARE(pongMessageSpy.count(), 0);
+ QCOMPARE(textMessageSpy.count(), 0);
+ QCOMPARE(binaryMessageSpy.count(), 0);
+ QCOMPARE(textFrameSpy.count(), 0);
+ QCOMPARE(binaryFrameSpy.count(), 0);
+ QVariantList arguments = closeSpy.takeFirst();
+ QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), expectedCloseCode);
+ buffer.close();
}
-void tst_DataProcessor::invalidControlFrame_data()
+void tst_DataProcessor::incompletePayload_data()
{
QTest::addColumn<quint8>("firstByte");
QTest::addColumn<quint8>("secondByte");
QTest::addColumn<bool>("isContinuationFrame");
QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
+ incompleteFrame(QWebSocketProtocol::OC_TEXT, 125, 0);
+ incompleteFrame(QWebSocketProtocol::OC_TEXT, 64, 32);
+ incompleteFrame(QWebSocketProtocol::OC_TEXT, 256, 32);
+ incompleteFrame(QWebSocketProtocol::OC_TEXT, 128000, 32);
+ incompleteFrame(QWebSocketProtocol::OC_BINARY, 125, 0);
+ incompleteFrame(QWebSocketProtocol::OC_BINARY, 64, 32);
+ incompleteFrame(QWebSocketProtocol::OC_BINARY, 256, 32);
+ incompleteFrame(QWebSocketProtocol::OC_BINARY, 128000, 32);
+ incompleteFrame(QWebSocketProtocol::OC_CONTINUE, 125, 0);
+ incompleteFrame(QWebSocketProtocol::OC_CONTINUE, 64, 32);
+ incompleteFrame(QWebSocketProtocol::OC_CONTINUE, 256, 32);
+ incompleteFrame(QWebSocketProtocol::OC_CONTINUE, 128000, 32);
- QTest::newRow("Close control frame with payload size 126")
- << quint8(FIN | QWebSocketProtocol::OC_CLOSE) << quint8(126) << QByteArray() << false << QWebSocketProtocol::CC_PROTOCOL_ERROR;
- QTest::newRow("Ping control frame with payload size 126")
- << quint8(FIN | QWebSocketProtocol::OC_PING) << quint8(126) << QByteArray() << false << QWebSocketProtocol::CC_PROTOCOL_ERROR;
- QTest::newRow("Close control frame with payload size 126")
- << quint8(FIN | QWebSocketProtocol::OC_PONG) << quint8(126) << QByteArray() << false << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ incompleteFrame(QWebSocketProtocol::OC_CLOSE, 64, 32);
+ incompleteFrame(QWebSocketProtocol::OC_PING, 64, 32);
+ incompleteFrame(QWebSocketProtocol::OC_PONG, 64, 32);
+}
- QTest::newRow("Non-final close control frame (fragmented)")
- << quint8(QWebSocketProtocol::OC_CLOSE) << quint8(32) << QByteArray() << false << QWebSocketProtocol::CC_PROTOCOL_ERROR;
- QTest::newRow("Non-final ping control frame (fragmented)")
- << quint8(QWebSocketProtocol::OC_PING) << quint8(32) << QByteArray() << false << QWebSocketProtocol::CC_PROTOCOL_ERROR;
- QTest::newRow("Non-final pong control frame (fragmented)")
- << quint8(QWebSocketProtocol::OC_PONG) << quint8(32) << QByteArray() << false << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+void tst_DataProcessor::incompletePayload()
+{
+ doTest();
}
-void tst_DataProcessor::invalidCloseFrame_data()
+void tst_DataProcessor::incompleteSizeField_data()
{
QTest::addColumn<quint8>("firstByte");
QTest::addColumn<quint8>("secondByte");
QTest::addColumn<bool>("isContinuationFrame");
QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
- QTest::newRow("Close control frame with payload size 1")
- << quint8(FIN | QWebSocketProtocol::OC_CLOSE) << quint8(1) << QByteArray(1, 'a') << false << QWebSocketProtocol::CC_PROTOCOL_ERROR;
- quint16 swapped = qToBigEndian<quint16>(QWebSocketProtocol::CC_ABNORMAL_DISCONNECTION);
- const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
+ //////////////////////////////////////////////////////////////////////////////////////////////////
+ //for a frame length value of 126, there should be 2 bytes following to form a 16-bit frame length
+ //////////////////////////////////////////////////////////////////////////////////////////////////
+ insertIncompleteSizeFieldTest(126, 0);
+ insertIncompleteSizeFieldTest(126, 1);
- //Not allowed per RFC 6455 (see para 7.4.1)
- QTest::newRow("Close control frame close code ABNORMAL DISCONNECTION")
- << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
- quint8(2) <<
- QByteArray(wireRepresentation, 2) <<
- false <<
- QWebSocketProtocol::CC_PROTOCOL_ERROR;
- swapped = qToBigEndian<quint16>(QWebSocketProtocol::CC_MISSING_STATUS_CODE);
- wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
- //Not allowed per RFC 6455 (see para 7.4.1)
- QTest::newRow("Close control frame close code MISSING STATUS CODE")
- << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
- quint8(2) <<
- QByteArray(wireRepresentation, 2) <<
- false <<
- QWebSocketProtocol::CC_PROTOCOL_ERROR;
- swapped = qToBigEndian<quint16>(1004);
- wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
- QTest::newRow("Close control frame close code 1004")
- << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
- quint8(2) <<
- QByteArray(wireRepresentation, 2) <<
- false <<
- QWebSocketProtocol::CC_PROTOCOL_ERROR;
- swapped = qToBigEndian<quint16>(QWebSocketProtocol::CC_TLS_HANDSHAKE_FAILED);
- wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
- //Not allowed per RFC 6455 (see para 7.4.1)
- QTest::newRow("Close control frame close code TLS HANDSHAKE FAILED")
- << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
- quint8(2) <<
- QByteArray(wireRepresentation, 2) <<
- false <<
- QWebSocketProtocol::CC_PROTOCOL_ERROR;
- swapped = qToBigEndian<quint16>(0);
- wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
- QTest::newRow("Close control frame close code 0")
- << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
- quint8(2) <<
- QByteArray(wireRepresentation, 2) <<
- false <<
- QWebSocketProtocol::CC_PROTOCOL_ERROR;
- swapped = qToBigEndian<quint16>(999);
- wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
- QTest::newRow("Close control frame close code 999")
- << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
- quint8(2) <<
- QByteArray(wireRepresentation, 2) <<
- false <<
- QWebSocketProtocol::CC_PROTOCOL_ERROR;
- swapped = qToBigEndian<quint16>(1012);
- wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
- QTest::newRow("Close control frame close code 1012")
- << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
- quint8(2) <<
- QByteArray(wireRepresentation, 2) <<
- false <<
- QWebSocketProtocol::CC_PROTOCOL_ERROR;
- swapped = qToBigEndian<quint16>(1013);
- wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
- QTest::newRow("Close control frame close code 1013")
- << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
- quint8(2) <<
- QByteArray(wireRepresentation, 2) <<
- false <<
- QWebSocketProtocol::CC_PROTOCOL_ERROR;
- swapped = qToBigEndian<quint16>(1014);
- wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
- QTest::newRow("Close control frame close code 1014")
- << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
- quint8(2) <<
- QByteArray(wireRepresentation, 2) <<
- false <<
- QWebSocketProtocol::CC_PROTOCOL_ERROR;
- swapped = qToBigEndian<quint16>(1100);
- wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
- QTest::newRow("Close control frame close code 1100")
- << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
- quint8(2) <<
- QByteArray(wireRepresentation, 2) <<
- false <<
- QWebSocketProtocol::CC_PROTOCOL_ERROR;
- swapped = qToBigEndian<quint16>(2000);
- wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
- QTest::newRow("Close control frame close code 2000")
- << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
- quint8(2) <<
- QByteArray(wireRepresentation, 2) <<
- false <<
- QWebSocketProtocol::CC_PROTOCOL_ERROR;
- swapped = qToBigEndian<quint16>(2999);
- wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
- QTest::newRow("Close control frame close code 2999")
- << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
- quint8(2) <<
- QByteArray(wireRepresentation, 2) <<
- false <<
- QWebSocketProtocol::CC_PROTOCOL_ERROR;
- swapped = qToBigEndian<quint16>(5000);
- wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
- QTest::newRow("Close control frame close code 5000")
- << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
- quint8(2) <<
- QByteArray(wireRepresentation, 2) <<
- false <<
- QWebSocketProtocol::CC_PROTOCOL_ERROR;
- swapped = qToBigEndian<quint16>(65535u);
- wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
- QTest::newRow("Close control frame close code 65535")
- << quint8(FIN | QWebSocketProtocol::OC_CLOSE) <<
- quint8(2) <<
- QByteArray(wireRepresentation, 2) <<
- false <<
- QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ //////////////////////////////////////////////////////////////////////////////////////////////////
+ //for a frame length value of 127, there should be 8 bytes following to form a 64-bit frame length
+ //////////////////////////////////////////////////////////////////////////////////////////////////
+ insertIncompleteSizeFieldTest(127, 0);
+ insertIncompleteSizeFieldTest(127, 1);
+ insertIncompleteSizeFieldTest(127, 2);
+ insertIncompleteSizeFieldTest(127, 3);
+ insertIncompleteSizeFieldTest(127, 4);
+ insertIncompleteSizeFieldTest(127, 5);
+ insertIncompleteSizeFieldTest(127, 6);
+ insertIncompleteSizeFieldTest(127, 7);
+}
+
+void tst_DataProcessor::incompleteSizeField()
+{
+ doTest();
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+/// HELPER FUNCTIONS
+//////////////////////////////////////////////////////////////////////////////////////////
+void tst_DataProcessor::doTest()
+{
+ QFETCH(quint8, firstByte);
+ QFETCH(quint8, secondByte);
+ QFETCH(QByteArray, payload);
+ QFETCH(bool, isContinuationFrame);
+ QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
+
+ QByteArray data;
+ QBuffer buffer;
+ QWebSocketDataProcessor dataProcessor;
+ QSignalSpy errorSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
+ QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
+ QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
+ QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString, bool)));
+ QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
+
+ if (isContinuationFrame)
+ {
+ data.append(quint8(QWebSocketProtocol::OC_TEXT)).append(char(1)).append(QByteArray(1, 'a'));
+ }
+ data.append(firstByte).append(secondByte);
+ data.append(payload);
+ buffer.setData(data);
+ buffer.open(QIODevice::ReadOnly);
+ dataProcessor.process(&buffer);
+ QCOMPARE(errorSpy.count(), 1);
+ QCOMPARE(textMessageSpy.count(), 0);
+ QCOMPARE(binaryMessageSpy.count(), 0);
+ QCOMPARE(textFrameSpy.count(), isContinuationFrame ? 1 : 0);
+ QCOMPARE(binaryFrameSpy.count(), 0);
+ QVariantList arguments = errorSpy.takeFirst();
+ QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), expectedCloseCode);
+ buffer.close();
+ errorSpy.clear();
+ data.clear();
+}
+
+void tst_DataProcessor::doCloseFrameTest()
+{
+ QFETCH(quint8, firstByte);
+ QFETCH(quint8, secondByte);
+ QFETCH(QByteArray, payload);
+ QFETCH(bool, isContinuationFrame);
+ QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
+
+ Q_UNUSED(isContinuationFrame)
+
+ QByteArray data;
+ QBuffer buffer;
+ QWebSocketDataProcessor dataProcessor;
+ QSignalSpy closeSpy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
+ QSignalSpy errorSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
+ QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
+ QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
+ QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString, bool)));
+ QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
+
+ data.append(firstByte).append(secondByte);
+ data.append(payload);
+ buffer.setData(data);
+ buffer.open(QIODevice::ReadOnly);
+ dataProcessor.process(&buffer);
+ QCOMPARE(closeSpy.count(), 1);
+ QCOMPARE(errorSpy.count(), 0);
+ QCOMPARE(textMessageSpy.count(), 0);
+ QCOMPARE(binaryMessageSpy.count(), 0);
+ QCOMPARE(textFrameSpy.count(), 0);
+ QCOMPARE(binaryFrameSpy.count(), 0);
+ QVariantList arguments = closeSpy.takeFirst();
+ QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), expectedCloseCode);
+ buffer.close();
+}
+
+QString tst_DataProcessor::opCodeToString(quint8 opCode)
+{
+ QString frameType;
+ switch (opCode)
+ {
+ case QWebSocketProtocol::OC_BINARY:
+ {
+ frameType = "Binary";
+ break;
+ }
+ case QWebSocketProtocol::OC_TEXT:
+ {
+ frameType = "Text";
+ break;
+ }
+ case QWebSocketProtocol::OC_PING:
+ {
+ frameType = "Ping";
+ break;
+ }
+ case QWebSocketProtocol::OC_PONG:
+ {
+ frameType = "Pong";
+ break;
+ }
+ case QWebSocketProtocol::OC_CLOSE:
+ {
+ frameType = "Close";
+ break;
+ }
+ case QWebSocketProtocol::OC_CONTINUE:
+ {
+ frameType = "Continuation";
+ break;
+ }
+ case QWebSocketProtocol::OC_RESERVED_3:
+ {
+ frameType = "Reserved3";
+ break;
+ }
+ case QWebSocketProtocol::OC_RESERVED_4:
+ {
+ frameType = "Reserved5";
+ break;
+ }
+ case QWebSocketProtocol::OC_RESERVED_5:
+ {
+ frameType = "Reserved5";
+ break;
+ }
+ case QWebSocketProtocol::OC_RESERVED_6:
+ {
+ frameType = "Reserved6";
+ break;
+ }
+ case QWebSocketProtocol::OC_RESERVED_7:
+ {
+ frameType = "Reserved7";
+ break;
+ }
+ case QWebSocketProtocol::OC_RESERVED_B:
+ {
+ frameType = "ReservedB";
+ break;
+ }
+ case QWebSocketProtocol::OC_RESERVED_C:
+ {
+ frameType = "ReservedC";
+ break;
+ }
+ case QWebSocketProtocol::OC_RESERVED_D:
+ {
+ frameType = "ReservedD";
+ break;
+ }
+ case QWebSocketProtocol::OC_RESERVED_E:
+ {
+ frameType = "ReservedE";
+ break;
+ }
+ case QWebSocketProtocol::OC_RESERVED_F:
+ {
+ frameType = "ReservedF";
+ break;
+ }
+ default:
+ {
+ //should never come here
+ Q_ASSERT(false);
+ }
+ }
+ return frameType;
+}
+
+void tst_DataProcessor::minimumSize16Bit(quint16 sizeInBytes)
+{
+ quint16 swapped16 = qToBigEndian<quint16>(sizeInBytes);
+ const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped16));
+ QTest::newRow(QString("Text frame with payload size %1, represented in 2 bytes").arg(sizeInBytes).toStdString().data())
+ << quint8(FIN | QWebSocketProtocol::OC_TEXT)
+ << quint8(126)
+ << QByteArray(wireRepresentation, 2)
+ << false
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow(QString("Binary frame with payload size %1, represented in 2 bytes").arg(sizeInBytes).toStdString().data())
+ << quint8(FIN | QWebSocketProtocol::OC_BINARY)
+ << quint8(126)
+ << QByteArray(wireRepresentation, 2)
+ << false
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow(QString("Continuation frame with payload size %1, represented in 2 bytes").arg(sizeInBytes).toStdString().data())
+ << quint8(FIN | QWebSocketProtocol::OC_CONTINUE)
+ << quint8(126)
+ << QByteArray(wireRepresentation, 2)
+ << true
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
}
-void tst_DataProcessor::incompleteSizeField_data()
+void tst_DataProcessor::minimumSize64Bit(quint64 sizeInBytes)
{
- QTest::addColumn<quint8>("firstByte");
- QTest::addColumn<quint8>("secondByte");
- QTest::addColumn<QByteArray>("payload");
- QTest::addColumn<bool>("isContinuationFrame");
- QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
+ quint64 swapped64 = qToBigEndian<quint64>(sizeInBytes);
+ const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
- //////////////////////////////////////////////////////////////////////////////////////////////////
- //for a frame length value of 126, there should be 2 bytes following to form a 16-bit frame length
- //////////////////////////////////////////////////////////////////////////////////////////////////
- insertIncompleteSizeFieldTest(126, 0);
- insertIncompleteSizeFieldTest(126, 1);
+ QTest::newRow(QString("Text frame with payload size %1, represented in 8 bytes").arg(sizeInBytes).toStdString().data())
+ << quint8(FIN | QWebSocketProtocol::OC_TEXT)
+ << quint8(127)
+ << QByteArray(wireRepresentation, 8)
+ << false
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
- //////////////////////////////////////////////////////////////////////////////////////////////////
- //for a frame length value of 127, there should be 8 bytes following to form a 64-bit frame length
- //////////////////////////////////////////////////////////////////////////////////////////////////
- insertIncompleteSizeFieldTest(127, 0);
- insertIncompleteSizeFieldTest(127, 1);
- insertIncompleteSizeFieldTest(127, 2);
- insertIncompleteSizeFieldTest(127, 3);
- insertIncompleteSizeFieldTest(127, 4);
- insertIncompleteSizeFieldTest(127, 5);
- insertIncompleteSizeFieldTest(127, 6);
- insertIncompleteSizeFieldTest(127, 7);
+ QTest::newRow(QString("Binary frame with payload size %1, represented in 8 bytes").arg(sizeInBytes).toStdString().data())
+ << quint8(FIN | QWebSocketProtocol::OC_BINARY)
+ << quint8(127)
+ << QByteArray(wireRepresentation, 8)
+ << false
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+
+ QTest::newRow(QString("Continuation frame with payload size %1, represented in 8 bytes").arg(sizeInBytes).toStdString().data())
+ << quint8(FIN | QWebSocketProtocol::OC_CONTINUE)
+ << quint8(127)
+ << QByteArray(wireRepresentation, 8)
+ << true
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
}
-void tst_DataProcessor::nonCharacterCodes_data()
+void tst_DataProcessor::invalidUTF8(const char *dataTag, const char *utf8Sequence, bool isCloseFrame)
{
- QTest::addColumn<quint8>("firstByte");
- QTest::addColumn<quint8>("secondByte");
- QTest::addColumn<QByteArray>("payload");
- QTest::addColumn<bool>("isContinuationFrame");
+ QByteArray payload = QByteArray::fromHex(utf8Sequence);
- nonCharacterSequence("efbfbe");
- nonCharacterSequence("efbfbf");
- nonCharacterSequence("f09fbfbe");
- nonCharacterSequence("f09fbfbf");
- nonCharacterSequence("f0afbfbe");
- nonCharacterSequence("f0afbfbf");
- nonCharacterSequence("f0bfbfbe");
- nonCharacterSequence("f0bfbfbf");
- nonCharacterSequence("f18fbfbe");
- nonCharacterSequence("f18fbfbf");
- nonCharacterSequence("f19fbfbe");
- nonCharacterSequence("f19fbfbf");
- nonCharacterSequence("f1afbfbe");
- nonCharacterSequence("f1afbfbf");
- nonCharacterSequence("f1bfbfbe");
- nonCharacterSequence("f1bfbfbf");
- nonCharacterSequence("f28fbfbe");
- nonCharacterSequence("f28fbfbf");
- nonCharacterSequence("f29fbfbe");
- nonCharacterSequence("f29fbfbf");
- nonCharacterSequence("f2afbfbe");
- nonCharacterSequence("f2afbfbf");
- nonCharacterSequence("f2bfbfbe");
- nonCharacterSequence("f2bfbfbf");
- nonCharacterSequence("f38fbfbe");
- nonCharacterSequence("f38fbfbf");
- nonCharacterSequence("f39fbfbe");
- nonCharacterSequence("f39fbfbf");
- nonCharacterSequence("f3afbfbe");
- nonCharacterSequence("f3afbfbf");
- nonCharacterSequence("f3bfbfbe");
- nonCharacterSequence("f3bfbfbf");
- nonCharacterSequence("f48fbfbe");
- nonCharacterSequence("f48fbfbf");
+ if (isCloseFrame)
+ {
+ quint16 closeCode = qToBigEndian<quint16>(QWebSocketProtocol::CC_NORMAL);
+ const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&closeCode));
+ QTest::newRow(QString("Close frame with invalid UTF8-sequence: %1").arg(dataTag).toStdString().data())
+ << quint8(FIN | QWebSocketProtocol::OC_CLOSE)
+ << quint8(payload.length() + 2)
+ << QByteArray(wireRepresentation, 2).append(payload)
+ << false
+ << QWebSocketProtocol::CC_WRONG_DATATYPE;
+ }
+ else
+ {
+ QTest::newRow(QString("Text frame with invalid UTF8-sequence: %1").arg(dataTag).toStdString().data())
+ << quint8(FIN | QWebSocketProtocol::OC_TEXT)
+ << quint8(payload.length())
+ << payload
+ << false
+ << QWebSocketProtocol::CC_WRONG_DATATYPE;
+
+ QTest::newRow(QString("Continuation text frame with invalid UTF8-sequence: %1").arg(dataTag).toStdString().data())
+ << quint8(FIN | QWebSocketProtocol::OC_CONTINUE)
+ << quint8(payload.length())
+ << payload
+ << true
+ << QWebSocketProtocol::CC_WRONG_DATATYPE;
+ }
}
-void tst_DataProcessor::incompletePayload_data()
+void tst_DataProcessor::invalidField(const char *dataTag, quint8 invalidFieldValue)
{
- QTest::addColumn<quint8>("firstByte");
- QTest::addColumn<quint8>("secondByte");
- QTest::addColumn<QByteArray>("payload");
- QTest::addColumn<bool>("isContinuationFrame");
- QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
+ QTest::newRow(dataTag) << quint8(FIN | invalidFieldValue)
+ << quint8(0x00)
+ << QByteArray()
+ << false
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+ QTest::newRow(QString(dataTag).append(" with continuation frame").toStdString().data())
+ << quint8(FIN | invalidFieldValue)
+ << quint8(0x00)
+ << QByteArray()
+ << true
+ << QWebSocketProtocol::CC_PROTOCOL_ERROR;
+}
- incompleteFrame(QWebSocketProtocol::OC_TEXT, 125, 0);
- incompleteFrame(QWebSocketProtocol::OC_TEXT, 64, 32);
- incompleteFrame(QWebSocketProtocol::OC_TEXT, 256, 32);
- incompleteFrame(QWebSocketProtocol::OC_TEXT, 128000, 32);
- incompleteFrame(QWebSocketProtocol::OC_BINARY, 125, 0);
- incompleteFrame(QWebSocketProtocol::OC_BINARY, 64, 32);
- incompleteFrame(QWebSocketProtocol::OC_BINARY, 256, 32);
- incompleteFrame(QWebSocketProtocol::OC_BINARY, 128000, 32);
- incompleteFrame(QWebSocketProtocol::OC_CONTINUE, 125, 0);
- incompleteFrame(QWebSocketProtocol::OC_CONTINUE, 64, 32);
- incompleteFrame(QWebSocketProtocol::OC_CONTINUE, 256, 32);
- incompleteFrame(QWebSocketProtocol::OC_CONTINUE, 128000, 32);
+void tst_DataProcessor::incompleteFrame(quint8 controlCode, quint64 indicatedSize, quint64 actualPayloadSize)
+{
+ QVERIFY(!QWebSocketProtocol::isOpCodeReserved(QWebSocketProtocol::OpCode(controlCode)));
+ QVERIFY(indicatedSize > actualPayloadSize);
- incompleteFrame(QWebSocketProtocol::OC_CLOSE, 64, 32);
- incompleteFrame(QWebSocketProtocol::OC_PING, 64, 32);
- incompleteFrame(QWebSocketProtocol::OC_PONG, 64, 32);
+ QString frameType = opCodeToString(controlCode);
+ QByteArray firstFrame;
+
+ if (indicatedSize < 126)
+ {
+ QTest::newRow(frameType.append(QString(" frame with payload size %1, but only %2 bytes of data").arg(indicatedSize).arg(actualPayloadSize)).toStdString().data())
+ << quint8(FIN | controlCode)
+ << quint8(indicatedSize)
+ << firstFrame.append(QByteArray(actualPayloadSize, 'a'))
+ << (controlCode == QWebSocketProtocol::OC_CONTINUE)
+ << QWebSocketProtocol::CC_GOING_AWAY;
+ }
+ else if (indicatedSize <= 0xFFFFu)
+ {
+ quint16 swapped16 = qToBigEndian<quint16>(static_cast<quint16>(indicatedSize));
+ const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped16));
+ QTest::newRow(frameType.append(QString(" frame with payload size %1, but only %2 bytes of data").arg(indicatedSize).arg(actualPayloadSize)).toStdString().data())
+ << quint8(FIN | controlCode)
+ << quint8(126)
+ << firstFrame.append(QByteArray(wireRepresentation, 2).append(QByteArray(actualPayloadSize, 'a')))
+ << (controlCode == QWebSocketProtocol::OC_CONTINUE)
+ << QWebSocketProtocol::CC_GOING_AWAY;
+ }
+ else
+ {
+ quint64 swapped64 = qToBigEndian<quint64>(indicatedSize);
+ const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
+ QTest::newRow(frameType.append(QString(" frame with payload size %1, but only %2 bytes of data").arg(indicatedSize).arg(actualPayloadSize)).toStdString().data())
+ << quint8(FIN | controlCode)
+ << quint8(127)
+ << firstFrame.append(QByteArray(wireRepresentation, 8).append(QByteArray(actualPayloadSize, 'a')))
+ << (controlCode == QWebSocketProtocol::OC_CONTINUE)
+ << QWebSocketProtocol::CC_GOING_AWAY;
+ }
}
-void tst_DataProcessor::frameTooBig_data()
+void tst_DataProcessor::nonCharacterSequence(const char *sequence)
{
- QTest::addColumn<quint8>("firstByte");
- QTest::addColumn<quint8>("secondByte");
- QTest::addColumn<QByteArray>("payload");
- QTest::addColumn<bool>("isContinuationFrame");
- QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
+ QByteArray utf8Sequence = QByteArray::fromHex(sequence);
+ //TODO: qstrdup - memory leak! qstrdup is necessary because once QString goes out of scope we have garbage
+ const char *tagName = qstrdup(qPrintable(QString("Text frame with payload containing the non-control character sequence 0x%1").arg(QString(sequence))));
+ const char *tagName2 = qstrdup(qPrintable(QString("Continuation frame with payload containing the non-control character sequence 0x%1").arg(QString(sequence))));
- quint64 swapped64 = 0;
- const char *wireRepresentation = 0;
+ QTest::newRow(tagName)
+ << quint8(FIN | QWebSocketProtocol::OC_TEXT)
+ << quint8(utf8Sequence.size())
+ << utf8Sequence
+ << false;
- //only data frames are checked for being too big
- //control frames have explicit checking on a maximum payload size of 125, which is tested elsewhere
+ QTest::newRow(tagName2)
+ << quint8(FIN | QWebSocketProtocol::OC_CONTINUE)
+ << quint8(utf8Sequence.size())
+ << utf8Sequence
+ << true;
+}
- swapped64 = qToBigEndian<quint64>(QWebSocketDataProcessor::maxFrameSize() + 1);
- wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
- QTest::newRow("Text frame with payload size > INT_MAX")
+void tst_DataProcessor::insertIncompleteSizeFieldTest(quint8 payloadCode, quint8 numBytesFollowing)
+{
+ QTest::newRow(QString("Text frame with payload size %1, with %2 bytes following.").arg(payloadCode).arg(numBytesFollowing).toStdString().data())
<< quint8(FIN | QWebSocketProtocol::OC_TEXT)
- << quint8(127)
- << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a'))
+ << quint8(payloadCode)
+ << QByteArray(numBytesFollowing, quint8(1))
<< false
- << QWebSocketProtocol::CC_TOO_MUCH_DATA;
-
- swapped64 = qToBigEndian<quint64>(QWebSocketDataProcessor::maxFrameSize() + 1);
- wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
- QTest::newRow("Binary frame with payload size > INT_MAX")
+ << QWebSocketProtocol::CC_GOING_AWAY;
+ QTest::newRow(QString("Binary frame with payload size %1, with %2 bytes following.").arg(payloadCode).arg(numBytesFollowing).toStdString().data())
<< quint8(FIN | QWebSocketProtocol::OC_BINARY)
- << quint8(127)
- << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a'))
+ << quint8(payloadCode)
+ << QByteArray(numBytesFollowing, quint8(1))
<< false
- << QWebSocketProtocol::CC_TOO_MUCH_DATA;
-
- swapped64 = qToBigEndian<quint64>(QWebSocketDataProcessor::maxFrameSize() + 1);
- wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
- QTest::newRow("Continuation frame with payload size > INT_MAX")
+ << QWebSocketProtocol::CC_GOING_AWAY;
+ QTest::newRow(QString("Continuation frame with payload size %1, with %2 bytes following.").arg(payloadCode).arg(numBytesFollowing).toStdString().data())
<< quint8(FIN | QWebSocketProtocol::OC_CONTINUE)
- << quint8(127)
- << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a'))
+ << quint8(payloadCode)
+ << QByteArray(numBytesFollowing, quint8(1))
<< true
- << QWebSocketProtocol::CC_TOO_MUCH_DATA;
+ << QWebSocketProtocol::CC_GOING_AWAY;
}
QTEST_MAIN(tst_DataProcessor)