1 /****************************************************************************
3 ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the test suite of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
41 #include <QtTest/QtTest>
42 #include <QtTest/qtestcase.h>
43 #include <QtTest/QSignalSpy>
44 #include <QtCore/QBuffer>
45 #include <QtCore/QByteArray>
46 #include <QtCore/QDebug>
48 #include "private/qwebsocketdataprocessor_p.h"
49 #include "private/qwebsocketprotocol_p.h"
50 #include "QtWebSockets/qwebsocketprotocol.h"
52 const quint8 FIN = 0x80;
53 const quint8 RSV1 = 0x40;
54 const quint8 RSV2 = 0x30;
55 const quint8 RSV3 = 0x10;
56 const quint8 MASK = 0x80;
60 Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode)
61 Q_DECLARE_METATYPE(QWebSocketProtocol::OpCode)
63 class tst_DataProcessor : public QObject
72 void cleanupTestCase();
76 /***************************************************************************
78 ***************************************************************************/
80 \brief Tests all kinds of valid binary frames, including zero length frames
82 void goodBinaryFrame();
83 void goodBinaryFrame_data();
86 \brief Tests all kinds of valid text frames, including zero length frames
89 void goodTextFrame_data();
92 * \brief Test all kinds of valid control frames.
94 void goodControlFrame();
97 * \brief Test all kinds of valid close frames.
99 void goodCloseFrame();
100 void goodCloseFrame_data();
103 * \brief Test all valid opcodes
106 void goodOpcodes_data();
109 Tests the QWebSocketDataProcessor for the correct handling of non-charactercodes
110 Due to a workaround in QTextCodec, non-characters are treated as illegal.
111 This workaround is not necessary anymore, and hence code should be changed in Qt
112 to allow non-characters again.
114 void nonCharacterCodes();
115 void nonCharacterCodes_data();
117 /***************************************************************************
119 ***************************************************************************/
121 \brief Tests the QWebSocketDataProcessor for correct handling of frames that don't contain the starting 2 bytes.
122 This test is a border case, where not enough bytes are received to even start parsing a frame.
123 This test does not test sequences of frames, only single frames are tested
125 void frameTooSmall();
128 \brief Tests the QWebSocketDataProcessor for correct handling of frames that are oversized.
129 This test does not test sequences of frames, only single frames are tested
132 void frameTooBig_data();
135 \brief Tests the QWebSocketDataProcessor for the correct handling of malformed frame headers.
136 This test does not test sequences of frames, only single frames are tested
138 void invalidHeader();
139 void invalidHeader_data();
142 \brief Tests the QWebSocketDataProcessor for the correct handling of invalid control frames.
143 Invalid means: payload bigger than 125, frame is fragmented, ...
144 This test does not test sequences of frames, only single frames are tested
146 void invalidControlFrame();
147 void invalidControlFrame_data();
149 void invalidCloseFrame();
150 void invalidCloseFrame_data();
153 \brief Tests the QWebSocketDataProcessor for the correct handling of incomplete size fields for large and big payloads.
155 void incompleteSizeField();
156 void incompleteSizeField_data();
159 \brief Tests the QWebSocketDataProcessor for the correct handling of incomplete payloads.
161 - incomplete length bytes for large and big payloads (16- and 64-bit values),
162 - minimum size representation (see RFC 6455 paragraph 5.2),
163 - frames that are too large (larger than MAX_INT in bytes)
164 - incomplete payloads (less bytes than indicated in the size field)
165 This test does not test sequences of frames, only single frames are tested
167 void incompletePayload();
168 void incompletePayload_data();
171 \brief Tests the QWebSocketDataProcessor for the correct handling of invalid UTF-8 payloads.
172 This test does not test sequences of frames, only single frames are tested
174 void invalidPayload();
175 void invalidPayload_data(bool isControlFrame = false);
177 void invalidPayloadInCloseFrame();
178 void invalidPayloadInCloseFrame_data();
181 Tests the QWebSocketDataProcessor for the correct handling of the minimum size representation requirement of RFC 6455 (see paragraph 5.2)
183 void minimumSizeRequirement();
184 void minimumSizeRequirement_data();
187 //helper function that constructs a new row of test data for invalid UTF8 sequences
188 void invalidUTF8(const char *dataTag, const char *utf8Sequence, bool isCloseFrame);
189 //helper function that constructs a new row of test data for invalid leading field values
190 void invalidField(const char *dataTag, quint8 invalidFieldValue);
191 //helper functions that construct a new row of test data for size fields that do not adhere to the minimum size requirement
192 void minimumSize16Bit(quint16 sizeInBytes);
193 void minimumSize64Bit(quint64 sizeInBytes);
194 //helper function to construct a new row of test data containing frames with a payload size smaller than indicated in the header
195 void incompleteFrame(quint8 controlCode, quint64 indicatedSize, quint64 actualPayloadSize);
196 void insertIncompleteSizeFieldTest(quint8 payloadCode, quint8 numBytesFollowing);
198 //helper function to construct a new row of test data containing text frames containing sequences
199 void nonCharacterSequence(const char *sequence);
202 void doCloseFrameTest();
204 QString opCodeToString(quint8 opCode);
207 tst_DataProcessor::tst_DataProcessor()
211 void tst_DataProcessor::initTestCase()
215 void tst_DataProcessor::cleanupTestCase()
219 void tst_DataProcessor::init()
221 qRegisterMetaType<QWebSocketProtocol::OpCode>("QWebSocketProtocol::OpCode");
222 qRegisterMetaType<QWebSocketProtocol::CloseCode>("QWebSocketProtocol::CloseCode");
225 void tst_DataProcessor::cleanup()
229 void tst_DataProcessor::goodBinaryFrame_data()
231 QTest::addColumn<QByteArray>("payload");
232 for (int i = 0; i < (65536 + 256); i += 128) //be sure to get small (< 126 bytes), large (> 125 bytes & < 64K) and big (>64K) frames
234 QTest::newRow(QStringLiteral("Binary frame with %1 bytes").arg(i).toLatin1().constData())
235 << QByteArray(i, char(1));
237 for (int i = 0; i < 256; ++i) //test all possible bytes in the payload
239 QTest::newRow(QStringLiteral("Binary frame containing byte: '0x%1'")
240 .arg(QByteArray(1, char(i)).toHex().constData()).toLatin1().constData())
241 << QByteArray(i, char(1));
245 void tst_DataProcessor::goodBinaryFrame()
249 QWebSocketDataProcessor dataProcessor;
250 QFETCH(QByteArray, payload);
252 data.append((char)(FIN | QWebSocketProtocol::OC_BINARY));
254 if (payload.length() < 126)
256 data.append(char(payload.length()));
258 else if (payload.length() < 65536)
260 quint16 swapped = qToBigEndian<quint16>(payload.length());
261 const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
262 data.append(char(126)).append(wireRepresentation, 2);
266 quint64 swapped = qToBigEndian<quint64>(payload.length());
267 const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
268 data.append(char(127)).append(wireRepresentation, 8);
271 data.append(payload);
272 buffer.setData(data);
273 buffer.open(QIODevice::ReadOnly);
275 QSignalSpy errorReceivedSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
276 QSignalSpy closeReceivedSpy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
277 QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
278 QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
279 QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
280 QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
281 QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
282 QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
283 dataProcessor.process(&buffer);
284 QCOMPARE(errorReceivedSpy.count(), 0);
285 QCOMPARE(pingReceivedSpy.count(), 0);
286 QCOMPARE(pongReceivedSpy.count(), 0);
287 QCOMPARE(closeReceivedSpy.count(), 0);
288 QCOMPARE(binaryFrameReceivedSpy.count(), 1);
289 QCOMPARE(binaryMessageReceivedSpy.count(), 1);
290 QCOMPARE(textFrameReceivedSpy.count(), 0);
291 QCOMPARE(textMessageReceivedSpy.count(), 0);
292 QList<QVariant> arguments = binaryFrameReceivedSpy.takeFirst();
293 QCOMPARE(arguments.at(0).toByteArray().length(), payload.length());
294 arguments = binaryMessageReceivedSpy.takeFirst();
295 QCOMPARE(arguments.at(0).toByteArray().length(), payload.length());
299 void tst_DataProcessor::goodTextFrame_data()
301 QTest::addColumn<QByteArray>("payload");
302 QTest::addColumn<int>("size");
304 //test frames with small (< 126), large ( < 65536) and big ( > 65535) payloads
305 for (int i = 0; i < (65536 + 256); i += 128)
307 QTest::newRow(QStringLiteral("Text frame with %1 ASCII characters").arg(i).toLatin1().constData())
308 << QByteArray(i, 'a') << i;
310 //test all valid ASCII characters
311 for (int i = 0; i < 128; ++i)
313 QTest::newRow(QStringLiteral("Text frame with containing ASCII character '0x%1'")
314 .arg(QByteArray(1, char(i)).toHex().constData()).toLatin1().constData())
315 << QByteArray(1, char(i)) << 1;
318 //the text string reads: Text frame containing Hello-µ@ßöäüà á-UTF-8!!
319 //Visual Studio doesn't like UTF-8 in source code, so we use escape codes for the string
320 //The number 22 refers to the length of the string; the length was incorrectly calculated on Visual Studio
321 QTest::newRow(QStringLiteral("Text frame containing Hello-\xC2\xB5\x40\xC3\x9F\xC3\xB6\xC3\xA4\xC3\xBC\xC3\xA0\xC3\xA1-UTF-8!!").toLatin1().constData())
322 << QByteArray::fromHex("48656c6c6f2dc2b540c39fc3b6c3a4c3bcc3a0c3a12d5554462d382121")
326 void tst_DataProcessor::goodTextFrame()
330 QWebSocketDataProcessor dataProcessor;
331 QFETCH(QByteArray, payload);
334 data.append((char)(FIN | QWebSocketProtocol::OC_TEXT));
336 if (payload.length() < 126)
338 data.append(char(payload.length()));
340 else if (payload.length() < 65536)
342 quint16 swapped = qToBigEndian<quint16>(payload.length());
343 const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
344 data.append(char(126)).append(wireRepresentation, 2);
348 quint64 swapped = qToBigEndian<quint64>(payload.length());
349 const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
350 data.append(char(127)).append(wireRepresentation, 8);
353 data.append(payload);
354 buffer.setData(data);
355 buffer.open(QIODevice::ReadOnly);
357 QSignalSpy errorReceivedSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
358 QSignalSpy closeReceivedSpy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
359 QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
360 QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
361 QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
362 QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
363 QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
364 QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
366 dataProcessor.process(&buffer);
368 QCOMPARE(errorReceivedSpy.count(), 0);
369 QCOMPARE(pingReceivedSpy.count(), 0);
370 QCOMPARE(pongReceivedSpy.count(), 0);
371 QCOMPARE(closeReceivedSpy.count(), 0);
372 QCOMPARE(textFrameReceivedSpy.count(), 1);
373 QCOMPARE(textMessageReceivedSpy.count(), 1);
374 QCOMPARE(binaryFrameReceivedSpy.count(), 0);
375 QCOMPARE(binaryMessageReceivedSpy.count(), 0);
376 QList<QVariant> arguments = textFrameReceivedSpy.takeFirst();
377 QCOMPARE(arguments.at(0).toString().length(), size);
378 arguments = textMessageReceivedSpy.takeFirst();
379 QCOMPARE(arguments.at(0).toString().length(), size);
383 void tst_DataProcessor::goodControlFrame()
387 QWebSocketDataProcessor dataProcessor;
389 QSignalSpy closeFrameReceivedSpy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
390 QSignalSpy errorReceivedSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
391 QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
392 QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
393 QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
394 QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
395 QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
396 QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
398 data.append((char)(FIN | QWebSocketProtocol::OC_PING));
399 data.append(QChar::fromLatin1(0));
400 buffer.setData(data);
401 buffer.open(QIODevice::ReadOnly);
402 dataProcessor.process(&buffer);
403 QCOMPARE(errorReceivedSpy.count(), 0);
404 QCOMPARE(textFrameReceivedSpy.count(), 0);
405 QCOMPARE(textMessageReceivedSpy.count(), 0);
406 QCOMPARE(binaryFrameReceivedSpy.count(), 0);
407 QCOMPARE(binaryMessageReceivedSpy.count(), 0);
408 QCOMPARE(closeFrameReceivedSpy.count(), 0);
409 QCOMPARE(pongReceivedSpy.count(), 0);
410 QCOMPARE(pingReceivedSpy.count(), 1);
414 pingReceivedSpy.clear();
415 pongReceivedSpy.clear();
416 data.append((char)(FIN | QWebSocketProtocol::OC_PONG));
417 data.append(QChar::fromLatin1(0));
418 buffer.setData(data);
419 buffer.open(QIODevice::ReadOnly);
420 dataProcessor.process(&buffer);
421 QCOMPARE(errorReceivedSpy.count(), 0);
422 QCOMPARE(textFrameReceivedSpy.count(), 0);
423 QCOMPARE(textMessageReceivedSpy.count(), 0);
424 QCOMPARE(binaryFrameReceivedSpy.count(), 0);
425 QCOMPARE(binaryMessageReceivedSpy.count(), 0);
426 QCOMPARE(closeFrameReceivedSpy.count(), 0);
427 QCOMPARE(pingReceivedSpy.count(), 0);
428 QCOMPARE(pongReceivedSpy.count(), 1);
432 void tst_DataProcessor::goodCloseFrame_data()
434 QTest::addColumn<QString>("payload");
435 QTest::addColumn<QWebSocketProtocol::CloseCode>("closeCode");
436 //control frame data cannot exceed 125 bytes; smaller than 124, because we also need a 2 byte close code
437 for (int i = 0; i < 124; ++i)
439 QTest::newRow(QStringLiteral("Close frame with %1 ASCII characters").arg(i).toLatin1().constData())
440 << QString(i, 'a') << QWebSocketProtocol::CC_NORMAL;
442 for (int i = 0; i < 126; ++i)
444 QTest::newRow(QStringLiteral("Text frame with containing ASCII character '0x%1'")
445 .arg(QByteArray(1, char(i)).toHex().constData()).toLatin1().constData())
446 << QString(1, char(i)) << QWebSocketProtocol::CC_NORMAL;
448 QTest::newRow("Close frame with close code NORMAL") << QString(1, 'a') << QWebSocketProtocol::CC_NORMAL;
449 QTest::newRow("Close frame with close code BAD OPERATION") << QString(1, 'a') << QWebSocketProtocol::CC_BAD_OPERATION;
450 QTest::newRow("Close frame with close code DATATYPE NOT SUPPORTED") << QString(1, 'a') << QWebSocketProtocol::CC_DATATYPE_NOT_SUPPORTED;
451 QTest::newRow("Close frame with close code GOING AWAY") << QString(1, 'a') << QWebSocketProtocol::CC_GOING_AWAY;
452 QTest::newRow("Close frame with close code MISSING EXTENSION") << QString(1, 'a') << QWebSocketProtocol::CC_MISSING_EXTENSION;
453 QTest::newRow("Close frame with close code POLICY VIOLATED") << QString(1, 'a') << QWebSocketProtocol::CC_POLICY_VIOLATED;
454 QTest::newRow("Close frame with close code PROTOCOL ERROR") << QString(1, 'a') << QWebSocketProtocol::CC_PROTOCOL_ERROR;
455 QTest::newRow("Close frame with close code TOO MUCH DATA") << QString(1, 'a') << QWebSocketProtocol::CC_TOO_MUCH_DATA;
456 QTest::newRow("Close frame with close code WRONG DATATYPE") << QString(1, 'a') << QWebSocketProtocol::CC_WRONG_DATATYPE;
457 QTest::newRow("Close frame with close code 3000") << QString(1, 'a') << QWebSocketProtocol::CloseCode(3000);
458 QTest::newRow("Close frame with close code 3999") << QString(1, 'a') << QWebSocketProtocol::CloseCode(3999);
459 QTest::newRow("Close frame with close code 4000") << QString(1, 'a') << QWebSocketProtocol::CloseCode(4000);
460 QTest::newRow("Close frame with close code 4999") << QString(1, 'a') << QWebSocketProtocol::CloseCode(4999);
462 //close frames with no close reason
463 QTest::newRow("Close frame with close code NORMAL and no reason") << QString() << QWebSocketProtocol::CC_NORMAL;
464 QTest::newRow("Close frame with close code BAD OPERATION and no reason") << QString() << QWebSocketProtocol::CC_BAD_OPERATION;
465 QTest::newRow("Close frame with close code DATATYPE NOT SUPPORTED and no reason") << QString() << QWebSocketProtocol::CC_DATATYPE_NOT_SUPPORTED;
466 QTest::newRow("Close frame with close code GOING AWAY and no reason") << QString() << QWebSocketProtocol::CC_GOING_AWAY;
467 QTest::newRow("Close frame with close code MISSING EXTENSION and no reason") << QString() << QWebSocketProtocol::CC_MISSING_EXTENSION;
468 QTest::newRow("Close frame with close code POLICY VIOLATED and no reason") << QString() << QWebSocketProtocol::CC_POLICY_VIOLATED;
469 QTest::newRow("Close frame with close code PROTOCOL ERROR and no reason") << QString() << QWebSocketProtocol::CC_PROTOCOL_ERROR;
470 QTest::newRow("Close frame with close code TOO MUCH DATA and no reason") << QString() << QWebSocketProtocol::CC_TOO_MUCH_DATA;
471 QTest::newRow("Close frame with close code WRONG DATATYPE and no reason") << QString() << QWebSocketProtocol::CC_WRONG_DATATYPE;
472 QTest::newRow("Close frame with close code 3000 and no reason") << QString() << QWebSocketProtocol::CloseCode(3000);
473 QTest::newRow("Close frame with close code 3999 and no reason") << QString() << QWebSocketProtocol::CloseCode(3999);
474 QTest::newRow("Close frame with close code 4000 and no reason") << QString() << QWebSocketProtocol::CloseCode(4000);
475 QTest::newRow("Close frame with close code 4999 and no reason") << QString() << QWebSocketProtocol::CloseCode(4999);
477 QTest::newRow("Close frame with no close code and no reason") << QString() << QWebSocketProtocol::CloseCode(0);
480 void tst_DataProcessor::goodOpcodes_data()
482 QTest::addColumn<QWebSocketProtocol::OpCode>("opCode");
484 QTest::newRow("Frame with PING opcode") << QWebSocketProtocol::OC_PING;
485 QTest::newRow("Frame with PONG opcode") << QWebSocketProtocol::OC_PONG;
486 QTest::newRow("Frame with TEXT opcode") << QWebSocketProtocol::OC_TEXT;
487 QTest::newRow("Frame with BINARY opcode") << QWebSocketProtocol::OC_BINARY;
488 QTest::newRow("Frame with CLOSE opcode") << QWebSocketProtocol::OC_CLOSE;
491 void tst_DataProcessor::goodOpcodes()
495 QWebSocketDataProcessor dataProcessor;
496 QFETCH(QWebSocketProtocol::OpCode, opCode);
498 data.append((char)(FIN | opCode));
499 data.append(char(0)); //zero length
501 buffer.setData(data);
502 buffer.open(QIODevice::ReadOnly);
504 QSignalSpy errorReceivedSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
505 QSignalSpy closeReceivedSpy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
506 QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
507 QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
508 QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
509 QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
510 QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
511 QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
513 dataProcessor.process(&buffer);
515 QCOMPARE(errorReceivedSpy.count(), 0);
516 QCOMPARE(pingReceivedSpy.count(), opCode == QWebSocketProtocol::OC_PING ? 1 : 0);
517 QCOMPARE(pongReceivedSpy.count(), opCode == QWebSocketProtocol::OC_PONG ? 1 : 0);
518 QCOMPARE(closeReceivedSpy.count(), opCode == QWebSocketProtocol::OC_CLOSE ? 1 : 0);
519 QCOMPARE(textFrameReceivedSpy.count(), opCode == QWebSocketProtocol::OC_TEXT ? 1 : 0);
520 QCOMPARE(textMessageReceivedSpy.count(), opCode == QWebSocketProtocol::OC_TEXT ? 1 : 0);
521 QCOMPARE(binaryFrameReceivedSpy.count(), opCode == QWebSocketProtocol::OC_BINARY ? 1 : 0);
522 QCOMPARE(binaryMessageReceivedSpy.count(), opCode == QWebSocketProtocol::OC_BINARY ? 1 : 0);
527 void tst_DataProcessor::goodCloseFrame()
531 QWebSocketDataProcessor dataProcessor;
532 QFETCH(QString, payload);
533 QFETCH(QWebSocketProtocol::CloseCode, closeCode);
534 quint16 swapped = qToBigEndian<quint16>(closeCode);
535 const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
537 data.append((char)(FIN | QWebSocketProtocol::OC_CLOSE));
540 data.append(char(payload.length() + 2)).append(wireRepresentation, 2).append(payload);
544 data.append(QChar::fromLatin1(0)); //payload length 0;
545 //dataprocessor emits a CC_NORMAL close code when none is present
546 closeCode = QWebSocketProtocol::CC_NORMAL;
548 buffer.setData(data);
549 buffer.open(QIODevice::ReadOnly);
551 QSignalSpy errorReceivedSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
552 QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
553 QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
554 QSignalSpy closeFrameReceivedSpy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
555 QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
556 QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
557 QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
558 QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
560 dataProcessor.process(&buffer);
562 QCOMPARE(errorReceivedSpy.count(), 0);
563 QCOMPARE(pingReceivedSpy.count(), 0);
564 QCOMPARE(pongReceivedSpy.count(), 0);
565 QCOMPARE(closeFrameReceivedSpy.count(), 1);
566 QCOMPARE(textFrameReceivedSpy.count(), 0);
567 QCOMPARE(textMessageReceivedSpy.count(), 0);
568 QCOMPARE(binaryFrameReceivedSpy.count(), 0);
569 QCOMPARE(binaryMessageReceivedSpy.count(), 0);
570 QList<QVariant> arguments = closeFrameReceivedSpy.takeFirst();
571 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), closeCode);
572 QCOMPARE(arguments.at(1).toString().length(), payload.length());
576 void tst_DataProcessor::nonCharacterCodes_data()
578 QTest::addColumn<quint8>("firstByte");
579 QTest::addColumn<quint8>("secondByte");
580 QTest::addColumn<QByteArray>("payload");
581 QTest::addColumn<bool>("isContinuationFrame");
583 nonCharacterSequence("efbfbe");
584 nonCharacterSequence("efbfbf");
585 nonCharacterSequence("f09fbfbe");
586 nonCharacterSequence("f09fbfbf");
587 nonCharacterSequence("f0afbfbe");
588 nonCharacterSequence("f0afbfbf");
589 nonCharacterSequence("f0bfbfbe");
590 nonCharacterSequence("f0bfbfbf");
591 nonCharacterSequence("f18fbfbe");
592 nonCharacterSequence("f18fbfbf");
593 nonCharacterSequence("f19fbfbe");
594 nonCharacterSequence("f19fbfbf");
595 nonCharacterSequence("f1afbfbe");
596 nonCharacterSequence("f1afbfbf");
597 nonCharacterSequence("f1bfbfbe");
598 nonCharacterSequence("f1bfbfbf");
599 nonCharacterSequence("f28fbfbe");
600 nonCharacterSequence("f28fbfbf");
601 nonCharacterSequence("f29fbfbe");
602 nonCharacterSequence("f29fbfbf");
603 nonCharacterSequence("f2afbfbe");
604 nonCharacterSequence("f2afbfbf");
605 nonCharacterSequence("f2bfbfbe");
606 nonCharacterSequence("f2bfbfbf");
607 nonCharacterSequence("f38fbfbe");
608 nonCharacterSequence("f38fbfbf");
609 nonCharacterSequence("f39fbfbe");
610 nonCharacterSequence("f39fbfbf");
611 nonCharacterSequence("f3afbfbe");
612 nonCharacterSequence("f3afbfbf");
613 nonCharacterSequence("f3bfbfbe");
614 nonCharacterSequence("f3bfbfbf");
615 nonCharacterSequence("f48fbfbe");
616 nonCharacterSequence("f48fbfbf");
619 void tst_DataProcessor::nonCharacterCodes()
621 QFETCH(quint8, firstByte);
622 QFETCH(quint8, secondByte);
623 QFETCH(QByteArray, payload);
624 QFETCH(bool, isContinuationFrame);
626 if (!isContinuationFrame)
630 QWebSocketDataProcessor dataProcessor;
631 QSignalSpy errorSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
632 QSignalSpy closeSpy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
633 QSignalSpy pingFrameSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
634 QSignalSpy pongFrameSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
635 QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
636 QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
637 QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
638 QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
640 data.append(firstByte).append(secondByte);
641 data.append(payload);
642 buffer.setData(data);
643 buffer.open(QIODevice::ReadOnly);
644 dataProcessor.process(&buffer);
646 QCOMPARE(errorSpy.count(), 0);
647 QCOMPARE(closeSpy.count(), 0);
648 QCOMPARE(pingFrameSpy.count(), 0);
649 QCOMPARE(pongFrameSpy.count(), 0);
650 QCOMPARE(textFrameSpy.count(), 1);
651 QCOMPARE(textMessageSpy.count(), 1);
652 QCOMPARE(binaryFrameSpy.count(), 0);
653 QCOMPARE(binaryMessageSpy.count(), 0);
655 QVariantList arguments = textFrameSpy.takeFirst();
656 QCOMPARE(arguments.at(0).value<QString>().toUtf8(), payload);
657 QCOMPARE(arguments.at(1).value<bool>(), !isContinuationFrame);
658 arguments = textMessageSpy.takeFirst();
659 QCOMPARE(arguments.at(0).value<QString>().toUtf8(), payload);
664 void tst_DataProcessor::frameTooSmall()
668 QWebSocketDataProcessor dataProcessor;
669 QByteArray firstFrame;
671 firstFrame.append(quint8(QWebSocketProtocol::OC_TEXT)).append(char(1)).append(QByteArray(1, 'a'));
673 //with nothing in the buffer, the dataProcessor should time out and the error should be CC_GOING_AWAY
674 //meaning the socket will be closed
675 buffer.setData(data);
676 buffer.open(QIODevice::ReadOnly);
677 QSignalSpy errorSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
678 QSignalSpy closeSpy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
679 QSignalSpy pingMessageSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
680 QSignalSpy pongMessageSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
681 QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
682 QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
683 QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString, bool)));
684 QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
686 dataProcessor.process(&buffer);
688 QCOMPARE(errorSpy.count(), 1);
689 QCOMPARE(closeSpy.count(), 0);
690 QCOMPARE(pingMessageSpy.count(), 0);
691 QCOMPARE(pongMessageSpy.count(), 0);
692 QCOMPARE(textMessageSpy.count(), 0);
693 QCOMPARE(binaryMessageSpy.count(), 0);
694 QCOMPARE(textFrameSpy.count(), 0);
695 QCOMPARE(binaryFrameSpy.count(), 0);
697 QList<QVariant> arguments = errorSpy.takeFirst();
698 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_GOING_AWAY);
701 pingMessageSpy.clear();
702 pongMessageSpy.clear();
703 textMessageSpy.clear();
704 binaryMessageSpy.clear();
705 textFrameSpy.clear();
706 binaryFrameSpy.clear();
710 //only one byte; this is far too little; should get a time out as well and the error should be CC_GOING_AWAY
711 //meaning the socket will be closed
712 data.append(quint8('1')); //put 1 byte in the buffer; this is too little
713 buffer.setData(data);
714 buffer.open(QIODevice::ReadOnly);
716 dataProcessor.process(&buffer);
718 QCOMPARE(errorSpy.count(), 1);
719 QCOMPARE(closeSpy.count(), 0);
720 QCOMPARE(pingMessageSpy.count(), 0);
721 QCOMPARE(pongMessageSpy.count(), 0);
722 QCOMPARE(textMessageSpy.count(), 0);
723 QCOMPARE(binaryMessageSpy.count(), 0);
724 QCOMPARE(textFrameSpy.count(), 0);
725 QCOMPARE(binaryFrameSpy.count(), 0);
727 arguments = errorSpy.takeFirst();
728 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_GOING_AWAY);
732 pingMessageSpy.clear();
733 pongMessageSpy.clear();
734 textMessageSpy.clear();
735 binaryMessageSpy.clear();
736 textFrameSpy.clear();
737 binaryFrameSpy.clear();
742 //text frame with final bit not set
743 data.append((char)(QWebSocketProtocol::OC_TEXT)).append(char(0x0));
744 buffer.setData(data);
745 buffer.open(QIODevice::ReadOnly);
747 dataProcessor.process(&buffer);
752 //with nothing in the buffer, the dataProcessor should time out and the error should be CC_GOING_AWAY
753 //meaning the socket will be closed
754 buffer.setData(data);
755 buffer.open(QIODevice::ReadOnly);
756 QSignalSpy errorSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
757 dataProcessor.process(&buffer);
759 QCOMPARE(errorSpy.count(), 1);
760 QCOMPARE(closeSpy.count(), 0);
761 QCOMPARE(pingMessageSpy.count(), 0);
762 QCOMPARE(pongMessageSpy.count(), 0);
763 QCOMPARE(textMessageSpy.count(), 0);
764 QCOMPARE(binaryMessageSpy.count(), 0);
765 QCOMPARE(textFrameSpy.count(), 1);
766 QCOMPARE(binaryFrameSpy.count(), 0);
768 QList<QVariant> arguments = errorSpy.takeFirst();
769 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_GOING_AWAY);
772 pingMessageSpy.clear();
773 pongMessageSpy.clear();
774 textMessageSpy.clear();
775 binaryMessageSpy.clear();
776 textFrameSpy.clear();
777 binaryFrameSpy.clear();
781 //text frame with final bit not set
782 data.append((char)(QWebSocketProtocol::OC_TEXT)).append(char(0x0));
783 buffer.setData(data);
784 buffer.open(QIODevice::ReadOnly);
785 dataProcessor.process(&buffer);
787 QCOMPARE(errorSpy.count(), 1);
788 QCOMPARE(closeSpy.count(), 0);
789 QCOMPARE(pingMessageSpy.count(), 0);
790 QCOMPARE(pongMessageSpy.count(), 0);
791 QCOMPARE(textMessageSpy.count(), 0);
792 QCOMPARE(binaryMessageSpy.count(), 0);
793 QCOMPARE(textFrameSpy.count(), 1);
794 QCOMPARE(binaryFrameSpy.count(), 0);
801 pingMessageSpy.clear();
802 pongMessageSpy.clear();
803 textMessageSpy.clear();
804 binaryMessageSpy.clear();
805 textFrameSpy.clear();
806 binaryFrameSpy.clear();
808 //only 1 byte follows in continuation frame; should time out with close code CC_GOING_AWAY
810 buffer.setData(data);
811 buffer.open(QIODevice::ReadOnly);
813 dataProcessor.process(&buffer);
814 QCOMPARE(errorSpy.count(), 1);
815 QCOMPARE(closeSpy.count(), 0);
816 QCOMPARE(pingMessageSpy.count(), 0);
817 QCOMPARE(pongMessageSpy.count(), 0);
818 QCOMPARE(textMessageSpy.count(), 0);
819 QCOMPARE(binaryMessageSpy.count(), 0);
820 QCOMPARE(textFrameSpy.count(), 0);
821 QCOMPARE(binaryFrameSpy.count(), 0);
822 arguments = errorSpy.takeFirst();
823 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), QWebSocketProtocol::CC_GOING_AWAY);
828 void tst_DataProcessor::frameTooBig_data()
830 QTest::addColumn<quint8>("firstByte");
831 QTest::addColumn<quint8>("secondByte");
832 QTest::addColumn<QByteArray>("payload");
833 QTest::addColumn<bool>("isContinuationFrame");
834 QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
836 quint64 swapped64 = 0;
837 const char *wireRepresentation = 0;
839 //only data frames are checked for being too big
840 //control frames have explicit checking on a maximum payload size of 125, which is tested elsewhere
842 swapped64 = qToBigEndian<quint64>(QWebSocketDataProcessor::maxFrameSize() + 1);
843 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
844 QTest::newRow("Text frame with payload size > INT_MAX")
845 << quint8(FIN | QWebSocketProtocol::OC_TEXT)
847 << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a'))
849 << QWebSocketProtocol::CC_TOO_MUCH_DATA;
851 swapped64 = qToBigEndian<quint64>(QWebSocketDataProcessor::maxFrameSize() + 1);
852 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
853 QTest::newRow("Binary frame with payload size > INT_MAX")
854 << quint8(FIN | QWebSocketProtocol::OC_BINARY)
856 << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a'))
858 << QWebSocketProtocol::CC_TOO_MUCH_DATA;
860 swapped64 = qToBigEndian<quint64>(QWebSocketDataProcessor::maxFrameSize() + 1);
861 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
862 QTest::newRow("Continuation frame with payload size > INT_MAX")
863 << quint8(FIN | QWebSocketProtocol::OC_CONTINUE)
865 << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a'))
867 << QWebSocketProtocol::CC_TOO_MUCH_DATA;
870 void tst_DataProcessor::frameTooBig()
875 void tst_DataProcessor::invalidHeader_data()
877 //The first byte contain the FIN, RSV1, RSV2, RSV3 and the Opcode
878 //The second byte contains the MaskFlag and the length of the frame
879 QTest::addColumn<quint8>("firstByte");
880 QTest::addColumn<quint8>("secondByte");
881 QTest::addColumn<QByteArray>("payload"); //superfluous, but present to be able to call doTest(), which expects a payload field
882 QTest::addColumn<bool>("isContinuationFrame");
883 QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
886 invalidField("RSV1 set", RSV1);
887 invalidField("RSV2 set", RSV2);
888 invalidField("RSV3 set", RSV3);
889 invalidField("RSV1 and RSV2 set", RSV1 | RSV2);
890 invalidField("RSV1 and RSV3 set", RSV1 | RSV3);
891 invalidField("RSV2 and RSV3 set", RSV2 | RSV3);
892 invalidField("RSV1, RSV2 and RSV3 set", RSV1 | RSV2 | RSV3);
895 invalidField("Invalid OpCode 3", QWebSocketProtocol::OC_RESERVED_3);
896 invalidField("Invalid OpCode 4", QWebSocketProtocol::OC_RESERVED_4);
897 invalidField("Invalid OpCode 5", QWebSocketProtocol::OC_RESERVED_5);
898 invalidField("Invalid OpCode 6", QWebSocketProtocol::OC_RESERVED_6);
899 invalidField("Invalid OpCode 7", QWebSocketProtocol::OC_RESERVED_7);
900 invalidField("Invalid OpCode B", QWebSocketProtocol::OC_RESERVED_B);
901 invalidField("Invalid OpCode C", QWebSocketProtocol::OC_RESERVED_C);
902 invalidField("Invalid OpCode D", QWebSocketProtocol::OC_RESERVED_D);
903 invalidField("Invalid OpCode E", QWebSocketProtocol::OC_RESERVED_E);
904 invalidField("Invalid OpCode F", QWebSocketProtocol::OC_RESERVED_F);
907 void tst_DataProcessor::invalidHeader()
912 void tst_DataProcessor::invalidControlFrame_data()
914 QTest::addColumn<quint8>("firstByte");
915 QTest::addColumn<quint8>("secondByte");
916 QTest::addColumn<QByteArray>("payload");
917 QTest::addColumn<bool>("isContinuationFrame");
918 QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
921 QTest::newRow("Close control frame with payload size 126")
922 << quint8(FIN | QWebSocketProtocol::OC_CLOSE)
926 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
927 QTest::newRow("Ping control frame with payload size 126")
928 << quint8(FIN | QWebSocketProtocol::OC_PING)
932 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
933 QTest::newRow("Close control frame with payload size 126")
934 << quint8(FIN | QWebSocketProtocol::OC_PONG)
938 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
940 QTest::newRow("Non-final close control frame (fragmented)")
941 << quint8(QWebSocketProtocol::OC_CLOSE)
945 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
946 QTest::newRow("Non-final ping control frame (fragmented)")
947 << quint8(QWebSocketProtocol::OC_PING)
948 << quint8(32) << QByteArray()
950 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
951 QTest::newRow("Non-final pong control frame (fragmented)")
952 << quint8(QWebSocketProtocol::OC_PONG)
956 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
959 void tst_DataProcessor::invalidControlFrame()
964 void tst_DataProcessor::invalidCloseFrame_data()
966 QTest::addColumn<quint8>("firstByte");
967 QTest::addColumn<quint8>("secondByte");
968 QTest::addColumn<QByteArray>("payload");
969 QTest::addColumn<bool>("isContinuationFrame");
970 QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
972 QTest::newRow("Close control frame with payload size 1")
973 << quint8(FIN | QWebSocketProtocol::OC_CLOSE)
975 << QByteArray(1, 'a')
977 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
978 quint16 swapped = qToBigEndian<quint16>(QWebSocketProtocol::CC_ABNORMAL_DISCONNECTION);
979 const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
981 //Not allowed per RFC 6455 (see para 7.4.1)
982 QTest::newRow("Close control frame close code ABNORMAL DISCONNECTION")
983 << quint8(FIN | QWebSocketProtocol::OC_CLOSE)
985 << QByteArray(wireRepresentation, 2)
987 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
988 swapped = qToBigEndian<quint16>(QWebSocketProtocol::CC_MISSING_STATUS_CODE);
989 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
990 //Not allowed per RFC 6455 (see para 7.4.1)
991 QTest::newRow("Close control frame close code MISSING STATUS CODE")
992 << quint8(FIN | QWebSocketProtocol::OC_CLOSE)
994 << QByteArray(wireRepresentation, 2)
996 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
997 swapped = qToBigEndian<quint16>(1004);
998 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
999 QTest::newRow("Close control frame close code 1004")
1000 << quint8(FIN | QWebSocketProtocol::OC_CLOSE)
1002 << QByteArray(wireRepresentation, 2)
1004 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
1005 swapped = qToBigEndian<quint16>(QWebSocketProtocol::CC_TLS_HANDSHAKE_FAILED);
1006 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1007 //Not allowed per RFC 6455 (see para 7.4.1)
1008 QTest::newRow("Close control frame close code TLS HANDSHAKE FAILED")
1009 << quint8(FIN | QWebSocketProtocol::OC_CLOSE)
1011 << QByteArray(wireRepresentation, 2)
1013 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
1014 swapped = qToBigEndian<quint16>(0);
1015 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1016 QTest::newRow("Close control frame close code 0")
1017 << quint8(FIN | QWebSocketProtocol::OC_CLOSE)
1019 << QByteArray(wireRepresentation, 2)
1021 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
1022 swapped = qToBigEndian<quint16>(999);
1023 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1024 QTest::newRow("Close control frame close code 999")
1025 << quint8(FIN | QWebSocketProtocol::OC_CLOSE)
1027 << QByteArray(wireRepresentation, 2)
1029 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
1030 swapped = qToBigEndian<quint16>(1012);
1031 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1032 QTest::newRow("Close control frame close code 1012")
1033 << quint8(FIN | QWebSocketProtocol::OC_CLOSE)
1035 << QByteArray(wireRepresentation, 2)
1037 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
1038 swapped = qToBigEndian<quint16>(1013);
1039 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1040 QTest::newRow("Close control frame close code 1013")
1041 << quint8(FIN | QWebSocketProtocol::OC_CLOSE)
1043 << QByteArray(wireRepresentation, 2)
1045 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
1046 swapped = qToBigEndian<quint16>(1014);
1047 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1048 QTest::newRow("Close control frame close code 1014")
1049 << quint8(FIN | QWebSocketProtocol::OC_CLOSE)
1051 << QByteArray(wireRepresentation, 2)
1053 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
1054 swapped = qToBigEndian<quint16>(1100);
1055 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1056 QTest::newRow("Close control frame close code 1100")
1057 << quint8(FIN | QWebSocketProtocol::OC_CLOSE)
1059 << QByteArray(wireRepresentation, 2)
1061 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
1062 swapped = qToBigEndian<quint16>(2000);
1063 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1064 QTest::newRow("Close control frame close code 2000")
1065 << quint8(FIN | QWebSocketProtocol::OC_CLOSE)
1067 << QByteArray(wireRepresentation, 2)
1069 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
1070 swapped = qToBigEndian<quint16>(2999);
1071 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1072 QTest::newRow("Close control frame close code 2999")
1073 << quint8(FIN | QWebSocketProtocol::OC_CLOSE)
1075 << QByteArray(wireRepresentation, 2)
1077 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
1078 swapped = qToBigEndian<quint16>(5000);
1079 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1080 QTest::newRow("Close control frame close code 5000")
1081 << quint8(FIN | QWebSocketProtocol::OC_CLOSE)
1083 << QByteArray(wireRepresentation, 2)
1085 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
1086 swapped = qToBigEndian<quint16>(65535u);
1087 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1088 QTest::newRow("Close control frame close code 65535")
1089 << quint8(FIN | QWebSocketProtocol::OC_CLOSE)
1091 << QByteArray(wireRepresentation, 2)
1093 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
1096 void tst_DataProcessor::invalidCloseFrame()
1101 void tst_DataProcessor::minimumSizeRequirement_data()
1103 QTest::addColumn<quint8>("firstByte");
1104 QTest::addColumn<quint8>("secondByte");
1105 QTest::addColumn<QByteArray>("payload");
1106 QTest::addColumn<bool>("isContinuationFrame");
1107 QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
1109 minimumSize16Bit(0);
1110 minimumSize16Bit(64);
1111 minimumSize16Bit(125);
1113 minimumSize64Bit(0);
1114 minimumSize64Bit(64);
1115 minimumSize64Bit(125);
1116 minimumSize64Bit(126);
1117 minimumSize64Bit(256);
1118 minimumSize64Bit(512);
1119 minimumSize64Bit(1024);
1120 minimumSize64Bit(2048);
1121 minimumSize64Bit(4096);
1122 minimumSize64Bit(8192);
1123 minimumSize64Bit(16384);
1124 minimumSize64Bit(32768);
1125 minimumSize64Bit(0xFFFFu);
1128 void tst_DataProcessor::minimumSizeRequirement()
1133 void tst_DataProcessor::invalidPayload_data(bool isControlFrame)
1135 QTest::addColumn<quint8>("firstByte");
1136 QTest::addColumn<quint8>("secondByte");
1137 QTest::addColumn<QByteArray>("payload");
1138 QTest::addColumn<bool>("isContinuationFrame");
1139 QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
1141 //6.3: invalid UTF-8 sequence
1142 invalidUTF8("case 6.3.1", "cebae1bdb9cf83cebcceb5eda080656469746564", isControlFrame);
1144 //6.4.: fail fast tests; invalid UTF-8 in middle of string
1145 invalidUTF8("case 6.4.1", "cebae1bdb9cf83cebcceb5f4908080656469746564", isControlFrame);
1146 invalidUTF8("case 6.4.4", "cebae1bdb9cf83cebcceb5eda080656469746564", isControlFrame);
1148 //6.6: All prefixes of a valid UTF-8 string that contains multi-byte code points
1149 invalidUTF8("case 6.6.1", "ce", isControlFrame);
1150 invalidUTF8("case 6.6.3", "cebae1", isControlFrame);
1151 invalidUTF8("case 6.6.4", "cebae1bd", isControlFrame);
1152 invalidUTF8("case 6.6.6", "cebae1bdb9cf", isControlFrame);
1153 invalidUTF8("case 6.6.8", "cebae1bdb9cf83ce", isControlFrame);
1154 invalidUTF8("case 6.6.10", "cebae1bdb9cf83cebcce", isControlFrame);
1156 //6.8: First possible sequence length 5/6 (invalid codepoints)
1157 invalidUTF8("case 6.8.1", "f888808080", isControlFrame);
1158 invalidUTF8("case 6.8.2", "fc8480808080", isControlFrame);
1160 //6.10: Last possible sequence length 4/5/6 (invalid codepoints)
1161 invalidUTF8("case 6.10.1", "f7bfbfbf", isControlFrame);
1162 invalidUTF8("case 6.10.2", "fbbfbfbfbf", isControlFrame);
1163 invalidUTF8("case 6.10.3", "fdbfbfbfbfbf", isControlFrame);
1165 //5.11: boundary conditions
1166 invalidUTF8("case 6.11.5", "f4908080", isControlFrame);
1168 //6.12: unexpected continuation bytes
1169 invalidUTF8("case 6.12.1", "80", isControlFrame);
1170 invalidUTF8("case 6.12.2", "bf", isControlFrame);
1171 invalidUTF8("case 6.12.3", "80bf", isControlFrame);
1172 invalidUTF8("case 6.12.4", "80bf80", isControlFrame);
1173 invalidUTF8("case 6.12.5", "80bf80bf", isControlFrame);
1174 invalidUTF8("case 6.12.6", "80bf80bf80", isControlFrame);
1175 invalidUTF8("case 6.12.7", "80bf80bf80bf", isControlFrame);
1176 invalidUTF8("case 6.12.8", "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbe", isControlFrame);
1178 //6.13: lonely start characters
1179 invalidUTF8("case 6.13.1", "c020c120c220c320c420c520c620c720c820c920ca20cb20cc20cd20ce20cf20d020d120d220d320d420d520d620d720d820d920da20db20dc20dd20de20", isControlFrame);
1180 invalidUTF8("case 6.13.2", "e020e120e220e320e420e520e620e720e820e920ea20eb20ec20ed20ee20", isControlFrame);
1181 invalidUTF8("case 6.13.3", "f020f120f220f320f420f520f620", isControlFrame);
1182 invalidUTF8("case 6.13.4", "f820f920fa20", isControlFrame);
1183 invalidUTF8("case 6.13.5", "fc20", isControlFrame);
1185 //6.14: sequences with last continuation byte missing
1186 invalidUTF8("case 6.14.1", "c0", isControlFrame);
1187 invalidUTF8("case 6.14.2", "e080", isControlFrame);
1188 invalidUTF8("case 6.14.3", "f08080", isControlFrame);
1189 invalidUTF8("case 6.14.4", "f8808080", isControlFrame);
1190 invalidUTF8("case 6.14.5", "fc80808080", isControlFrame);
1191 invalidUTF8("case 6.14.6", "df", isControlFrame);
1192 invalidUTF8("case 6.14.7", "efbf", isControlFrame);
1193 invalidUTF8("case 6.14.8", "f7bfbf", isControlFrame);
1194 invalidUTF8("case 6.14.9", "fbbfbfbf", isControlFrame);
1195 invalidUTF8("case 6.14.10", "fdbfbfbfbf", isControlFrame);
1197 //6.15: concatenation of incomplete sequences
1198 invalidUTF8("case 6.15.1", "c0e080f08080f8808080fc80808080dfefbff7bfbffbbfbfbffdbfbfbfbf", isControlFrame);
1200 //6.16: impossible bytes
1201 invalidUTF8("case 6.16.1", "fe", isControlFrame);
1202 invalidUTF8("case 6.16.2", "ff", isControlFrame);
1203 invalidUTF8("case 6.16.3", "fefeffff", isControlFrame);
1205 //6.17: overlong ASCII characters
1206 invalidUTF8("case 6.17.1", "c0af", isControlFrame);
1207 invalidUTF8("case 6.17.2", "e080af", isControlFrame);
1208 invalidUTF8("case 6.17.3", "f08080af", isControlFrame);
1209 invalidUTF8("case 6.17.4", "f8808080af", isControlFrame);
1210 invalidUTF8("case 6.17.5", "fc80808080af", isControlFrame);
1212 //6.18: maximum overlong sequences
1213 invalidUTF8("case 6.18.1", "c1bf", isControlFrame);
1214 invalidUTF8("case 6.18.2", "e09fbf", isControlFrame);
1215 invalidUTF8("case 6.18.3", "f08fbfbf", isControlFrame);
1216 invalidUTF8("case 6.18.4", "f887bfbfbf", isControlFrame);
1217 invalidUTF8("case 6.18.5", "fc83bfbfbfbf", isControlFrame);
1219 //6.19: overlong presentation of the NUL character
1220 invalidUTF8("case 6.19.1", "c080", isControlFrame);
1221 invalidUTF8("case 6.19.2", "e08080", isControlFrame);
1222 invalidUTF8("case 6.19.3", "f0808080", isControlFrame);
1223 invalidUTF8("case 6.19.4", "f880808080", isControlFrame);
1224 invalidUTF8("case 6.19.5", "fc8080808080", isControlFrame);
1226 //6.20: Single UTF-16 surrogates
1227 invalidUTF8("case 6.20.1", "eda080", isControlFrame);
1228 invalidUTF8("case 6.20.2", "edadbf", isControlFrame);
1229 invalidUTF8("case 6.20.3", "edae80", isControlFrame);
1230 invalidUTF8("case 6.20.4", "edafbf", isControlFrame);
1231 invalidUTF8("case 6.20.5", "edb080", isControlFrame);
1232 invalidUTF8("case 6.20.6", "edbe80", isControlFrame);
1233 invalidUTF8("case 6.20.7", "edbfbf", isControlFrame);
1235 //6.21: Paired UTF-16 surrogates
1236 invalidUTF8("case 6.21.1", "eda080edb080", isControlFrame);
1237 invalidUTF8("case 6.21.2", "eda080edbfbf", isControlFrame);
1238 invalidUTF8("case 6.21.3", "edadbfedb080", isControlFrame);
1239 invalidUTF8("case 6.21.4", "edadbfedbfbf", isControlFrame);
1240 invalidUTF8("case 6.21.5", "edae80edb080", isControlFrame);
1241 invalidUTF8("case 6.21.6", "edae80edbfbf", isControlFrame);
1242 invalidUTF8("case 6.21.7", "edafbfedb080", isControlFrame);
1243 invalidUTF8("case 6.21.8", "edafbfedbfbf", isControlFrame);
1246 void tst_DataProcessor::invalidPayload()
1251 void tst_DataProcessor::invalidPayloadInCloseFrame_data()
1253 invalidPayload_data(true);
1256 void tst_DataProcessor::invalidPayloadInCloseFrame()
1258 QFETCH(quint8, firstByte);
1259 QFETCH(quint8, secondByte);
1260 QFETCH(QByteArray, payload);
1261 QFETCH(bool, isContinuationFrame);
1262 QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
1264 Q_UNUSED(isContinuationFrame)
1268 QWebSocketDataProcessor dataProcessor;
1269 QSignalSpy closeSpy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
1270 QSignalSpy errorSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
1271 QSignalSpy pingMessageSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
1272 QSignalSpy pongMessageSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
1273 QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
1274 QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
1275 QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString, bool)));
1276 QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
1278 data.append(firstByte).append(secondByte);
1279 data.append(payload);
1280 buffer.setData(data);
1281 buffer.open(QIODevice::ReadOnly);
1282 dataProcessor.process(&buffer);
1283 QCOMPARE(closeSpy.count(), 1);
1284 QCOMPARE(errorSpy.count(), 0);
1285 QCOMPARE(pingMessageSpy.count(), 0);
1286 QCOMPARE(pongMessageSpy.count(), 0);
1287 QCOMPARE(textMessageSpy.count(), 0);
1288 QCOMPARE(binaryMessageSpy.count(), 0);
1289 QCOMPARE(textFrameSpy.count(), 0);
1290 QCOMPARE(binaryFrameSpy.count(), 0);
1291 QVariantList arguments = closeSpy.takeFirst();
1292 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), expectedCloseCode);
1296 void tst_DataProcessor::incompletePayload_data()
1298 QTest::addColumn<quint8>("firstByte");
1299 QTest::addColumn<quint8>("secondByte");
1300 QTest::addColumn<QByteArray>("payload");
1301 QTest::addColumn<bool>("isContinuationFrame");
1302 QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
1304 incompleteFrame(QWebSocketProtocol::OC_TEXT, 125, 0);
1305 incompleteFrame(QWebSocketProtocol::OC_TEXT, 64, 32);
1306 incompleteFrame(QWebSocketProtocol::OC_TEXT, 256, 32);
1307 incompleteFrame(QWebSocketProtocol::OC_TEXT, 128000, 32);
1308 incompleteFrame(QWebSocketProtocol::OC_BINARY, 125, 0);
1309 incompleteFrame(QWebSocketProtocol::OC_BINARY, 64, 32);
1310 incompleteFrame(QWebSocketProtocol::OC_BINARY, 256, 32);
1311 incompleteFrame(QWebSocketProtocol::OC_BINARY, 128000, 32);
1312 incompleteFrame(QWebSocketProtocol::OC_CONTINUE, 125, 0);
1313 incompleteFrame(QWebSocketProtocol::OC_CONTINUE, 64, 32);
1314 incompleteFrame(QWebSocketProtocol::OC_CONTINUE, 256, 32);
1315 incompleteFrame(QWebSocketProtocol::OC_CONTINUE, 128000, 32);
1317 incompleteFrame(QWebSocketProtocol::OC_CLOSE, 64, 32);
1318 incompleteFrame(QWebSocketProtocol::OC_PING, 64, 32);
1319 incompleteFrame(QWebSocketProtocol::OC_PONG, 64, 32);
1322 void tst_DataProcessor::incompletePayload()
1327 void tst_DataProcessor::incompleteSizeField_data()
1329 QTest::addColumn<quint8>("firstByte");
1330 QTest::addColumn<quint8>("secondByte");
1331 QTest::addColumn<QByteArray>("payload");
1332 QTest::addColumn<bool>("isContinuationFrame");
1333 QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
1335 //for a frame length value of 126, there should be 2 bytes following to form a 16-bit frame length
1336 insertIncompleteSizeFieldTest(126, 0);
1337 insertIncompleteSizeFieldTest(126, 1);
1339 //for a frame length value of 127, there should be 8 bytes following to form a 64-bit frame length
1340 insertIncompleteSizeFieldTest(127, 0);
1341 insertIncompleteSizeFieldTest(127, 1);
1342 insertIncompleteSizeFieldTest(127, 2);
1343 insertIncompleteSizeFieldTest(127, 3);
1344 insertIncompleteSizeFieldTest(127, 4);
1345 insertIncompleteSizeFieldTest(127, 5);
1346 insertIncompleteSizeFieldTest(127, 6);
1347 insertIncompleteSizeFieldTest(127, 7);
1350 void tst_DataProcessor::incompleteSizeField()
1355 //////////////////////////////////////////////////////////////////////////////////////////
1356 /// HELPER FUNCTIONS
1357 //////////////////////////////////////////////////////////////////////////////////////////
1358 void tst_DataProcessor::doTest()
1360 QFETCH(quint8, firstByte);
1361 QFETCH(quint8, secondByte);
1362 QFETCH(QByteArray, payload);
1363 QFETCH(bool, isContinuationFrame);
1364 QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
1368 QWebSocketDataProcessor dataProcessor;
1369 QSignalSpy errorSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
1370 QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
1371 QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
1372 QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString, bool)));
1373 QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
1375 if (isContinuationFrame)
1377 data.append(quint8(QWebSocketProtocol::OC_TEXT)).append(char(1)).append(QByteArray(1, 'a'));
1379 data.append(firstByte).append(secondByte);
1380 data.append(payload);
1381 buffer.setData(data);
1382 buffer.open(QIODevice::ReadOnly);
1383 dataProcessor.process(&buffer);
1384 QCOMPARE(errorSpy.count(), 1);
1385 QCOMPARE(textMessageSpy.count(), 0);
1386 QCOMPARE(binaryMessageSpy.count(), 0);
1387 QCOMPARE(textFrameSpy.count(), isContinuationFrame ? 1 : 0);
1388 QCOMPARE(binaryFrameSpy.count(), 0);
1389 QVariantList arguments = errorSpy.takeFirst();
1390 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), expectedCloseCode);
1396 void tst_DataProcessor::doCloseFrameTest()
1398 QFETCH(quint8, firstByte);
1399 QFETCH(quint8, secondByte);
1400 QFETCH(QByteArray, payload);
1401 QFETCH(bool, isContinuationFrame);
1402 QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
1404 Q_UNUSED(isContinuationFrame)
1408 QWebSocketDataProcessor dataProcessor;
1409 QSignalSpy closeSpy(&dataProcessor, SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
1410 QSignalSpy errorSpy(&dataProcessor, SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
1411 QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
1412 QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
1413 QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString, bool)));
1414 QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
1416 data.append(firstByte).append(secondByte);
1417 data.append(payload);
1418 buffer.setData(data);
1419 buffer.open(QIODevice::ReadOnly);
1420 dataProcessor.process(&buffer);
1421 QCOMPARE(closeSpy.count(), 1);
1422 QCOMPARE(errorSpy.count(), 0);
1423 QCOMPARE(textMessageSpy.count(), 0);
1424 QCOMPARE(binaryMessageSpy.count(), 0);
1425 QCOMPARE(textFrameSpy.count(), 0);
1426 QCOMPARE(binaryFrameSpy.count(), 0);
1427 QVariantList arguments = closeSpy.takeFirst();
1428 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), expectedCloseCode);
1432 QString tst_DataProcessor::opCodeToString(quint8 opCode)
1437 case QWebSocketProtocol::OC_BINARY:
1439 frameType = QStringLiteral("Binary");
1442 case QWebSocketProtocol::OC_TEXT:
1444 frameType = QStringLiteral("Text");
1447 case QWebSocketProtocol::OC_PING:
1449 frameType = QStringLiteral("Ping");
1452 case QWebSocketProtocol::OC_PONG:
1454 frameType = QStringLiteral("Pong");
1457 case QWebSocketProtocol::OC_CLOSE:
1459 frameType = QStringLiteral("Close");
1462 case QWebSocketProtocol::OC_CONTINUE:
1464 frameType = QStringLiteral("Continuation");
1467 case QWebSocketProtocol::OC_RESERVED_3:
1469 frameType = QStringLiteral("Reserved3");
1472 case QWebSocketProtocol::OC_RESERVED_4:
1474 frameType = QStringLiteral("Reserved5");
1477 case QWebSocketProtocol::OC_RESERVED_5:
1479 frameType = QStringLiteral("Reserved5");
1482 case QWebSocketProtocol::OC_RESERVED_6:
1484 frameType = QStringLiteral("Reserved6");
1487 case QWebSocketProtocol::OC_RESERVED_7:
1489 frameType = QStringLiteral("Reserved7");
1492 case QWebSocketProtocol::OC_RESERVED_B:
1494 frameType = QStringLiteral("ReservedB");
1497 case QWebSocketProtocol::OC_RESERVED_C:
1499 frameType = QStringLiteral("ReservedC");
1502 case QWebSocketProtocol::OC_RESERVED_D:
1504 frameType = QStringLiteral("ReservedD");
1507 case QWebSocketProtocol::OC_RESERVED_E:
1509 frameType = QStringLiteral("ReservedE");
1512 case QWebSocketProtocol::OC_RESERVED_F:
1514 frameType = QStringLiteral("ReservedF");
1519 //should never come here
1526 void tst_DataProcessor::minimumSize16Bit(quint16 sizeInBytes)
1528 quint16 swapped16 = qToBigEndian<quint16>(sizeInBytes);
1529 const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped16));
1530 QTest::newRow(QStringLiteral("Text frame with payload size %1, represented in 2 bytes")
1531 .arg(sizeInBytes).toLatin1().constData())
1532 << quint8(FIN | QWebSocketProtocol::OC_TEXT)
1534 << QByteArray(wireRepresentation, 2)
1536 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
1537 QTest::newRow(QStringLiteral("Binary frame with payload size %1, represented in 2 bytes")
1538 .arg(sizeInBytes).toLatin1().constBegin())
1539 << quint8(FIN | QWebSocketProtocol::OC_BINARY)
1541 << QByteArray(wireRepresentation, 2)
1543 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
1544 QTest::newRow(QStringLiteral("Continuation frame with payload size %1, represented in 2 bytes")
1545 .arg(sizeInBytes).toLatin1().constData())
1546 << quint8(FIN | QWebSocketProtocol::OC_CONTINUE)
1548 << QByteArray(wireRepresentation, 2)
1550 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
1553 void tst_DataProcessor::minimumSize64Bit(quint64 sizeInBytes)
1555 quint64 swapped64 = qToBigEndian<quint64>(sizeInBytes);
1556 const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
1558 QTest::newRow(QStringLiteral("Text frame with payload size %1, represented in 8 bytes")
1559 .arg(sizeInBytes).toLatin1().constData())
1560 << quint8(FIN | QWebSocketProtocol::OC_TEXT)
1562 << QByteArray(wireRepresentation, 8)
1564 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
1566 QTest::newRow(QStringLiteral("Binary frame with payload size %1, represented in 8 bytes")
1567 .arg(sizeInBytes).toLatin1().constData())
1568 << quint8(FIN | QWebSocketProtocol::OC_BINARY)
1570 << QByteArray(wireRepresentation, 8)
1572 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
1574 QTest::newRow(QStringLiteral("Continuation frame with payload size %1, represented in 8 bytes")
1575 .arg(sizeInBytes).toLatin1().constData())
1576 << quint8(FIN | QWebSocketProtocol::OC_CONTINUE)
1578 << QByteArray(wireRepresentation, 8)
1580 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
1583 void tst_DataProcessor::invalidUTF8(const char *dataTag, const char *utf8Sequence, bool isCloseFrame)
1585 QByteArray payload = QByteArray::fromHex(utf8Sequence);
1589 quint16 closeCode = qToBigEndian<quint16>(QWebSocketProtocol::CC_NORMAL);
1590 const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&closeCode));
1591 QTest::newRow(QStringLiteral("Close frame with invalid UTF8-sequence: %1")
1592 .arg(dataTag).toLatin1().constData())
1593 << quint8(FIN | QWebSocketProtocol::OC_CLOSE)
1594 << quint8(payload.length() + 2)
1595 << QByteArray(wireRepresentation, 2).append(payload)
1597 << QWebSocketProtocol::CC_WRONG_DATATYPE;
1601 QTest::newRow(QStringLiteral("Text frame with invalid UTF8-sequence: %1")
1602 .arg(dataTag).toLatin1().constData())
1603 << quint8(FIN | QWebSocketProtocol::OC_TEXT)
1604 << quint8(payload.length())
1607 << QWebSocketProtocol::CC_WRONG_DATATYPE;
1609 QTest::newRow(QStringLiteral("Continuation text frame with invalid UTF8-sequence: %1")
1610 .arg(dataTag).toLatin1().constData())
1611 << quint8(FIN | QWebSocketProtocol::OC_CONTINUE)
1612 << quint8(payload.length())
1615 << QWebSocketProtocol::CC_WRONG_DATATYPE;
1619 void tst_DataProcessor::invalidField(const char *dataTag, quint8 invalidFieldValue)
1621 QTest::newRow(dataTag) << quint8(FIN | invalidFieldValue)
1625 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
1626 QTest::newRow(QString::fromLatin1(dataTag).append(" with continuation frame").toLatin1().constData())
1627 << quint8(FIN | invalidFieldValue)
1631 << QWebSocketProtocol::CC_PROTOCOL_ERROR;
1634 void tst_DataProcessor::incompleteFrame(quint8 controlCode, quint64 indicatedSize, quint64 actualPayloadSize)
1636 QVERIFY(!QWebSocketProtocol::isOpCodeReserved(QWebSocketProtocol::OpCode(controlCode)));
1637 QVERIFY(indicatedSize > actualPayloadSize);
1639 QString frameType = opCodeToString(controlCode);
1640 QByteArray firstFrame;
1642 if (indicatedSize < 126)
1644 QTest::newRow(frameType.append(QStringLiteral(" frame with payload size %1, but only %2 bytes of data")
1645 .arg(indicatedSize).arg(actualPayloadSize)).toLatin1().constData())
1646 << quint8(FIN | controlCode)
1647 << quint8(indicatedSize)
1648 << firstFrame.append(QByteArray(actualPayloadSize, 'a'))
1649 << (controlCode == QWebSocketProtocol::OC_CONTINUE)
1650 << QWebSocketProtocol::CC_GOING_AWAY;
1652 else if (indicatedSize <= 0xFFFFu)
1654 quint16 swapped16 = qToBigEndian<quint16>(static_cast<quint16>(indicatedSize));
1655 const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped16));
1656 QTest::newRow(frameType.append(QStringLiteral(" frame with payload size %1, but only %2 bytes of data")
1657 .arg(indicatedSize).arg(actualPayloadSize)).toLatin1().constData())
1658 << quint8(FIN | controlCode)
1660 << firstFrame.append(QByteArray(wireRepresentation, 2).append(QByteArray(actualPayloadSize, 'a')))
1661 << (controlCode == QWebSocketProtocol::OC_CONTINUE)
1662 << QWebSocketProtocol::CC_GOING_AWAY;
1666 quint64 swapped64 = qToBigEndian<quint64>(indicatedSize);
1667 const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
1668 QTest::newRow(frameType.append(QStringLiteral(" frame with payload size %1, but only %2 bytes of data")
1669 .arg(indicatedSize).arg(actualPayloadSize)).toLatin1().constData())
1670 << quint8(FIN | controlCode)
1672 << firstFrame.append(QByteArray(wireRepresentation, 8).append(QByteArray(actualPayloadSize, 'a')))
1673 << (controlCode == QWebSocketProtocol::OC_CONTINUE)
1674 << QWebSocketProtocol::CC_GOING_AWAY;
1678 void tst_DataProcessor::nonCharacterSequence(const char *sequence)
1680 QByteArray utf8Sequence = QByteArray::fromHex(sequence);
1682 QTest::newRow(QStringLiteral("Text frame with payload containing the non-control character sequence 0x%1")
1683 .arg(QString::fromLocal8Bit(sequence)).toLatin1().constData())
1684 << quint8(FIN | QWebSocketProtocol::OC_TEXT)
1685 << quint8(utf8Sequence.size())
1689 QTest::newRow(QStringLiteral("Continuation frame with payload containing the non-control character sequence 0x%1")
1690 .arg(QString::fromLocal8Bit(sequence)).toLatin1().constData())
1691 << quint8(FIN | QWebSocketProtocol::OC_CONTINUE)
1692 << quint8(utf8Sequence.size())
1697 void tst_DataProcessor::insertIncompleteSizeFieldTest(quint8 payloadCode, quint8 numBytesFollowing)
1699 QTest::newRow(QStringLiteral("Text frame with payload size %1, with %2 bytes following.")
1700 .arg(payloadCode).arg(numBytesFollowing).toLatin1().constData())
1701 << quint8(FIN | QWebSocketProtocol::OC_TEXT)
1702 << quint8(payloadCode)
1703 << QByteArray(numBytesFollowing, quint8(1))
1705 << QWebSocketProtocol::CC_GOING_AWAY;
1706 QTest::newRow(QStringLiteral("Binary frame with payload size %1, with %2 bytes following.")
1707 .arg(payloadCode).arg(numBytesFollowing).toLatin1().constData())
1708 << quint8(FIN | QWebSocketProtocol::OC_BINARY)
1709 << quint8(payloadCode)
1710 << QByteArray(numBytesFollowing, quint8(1))
1712 << QWebSocketProtocol::CC_GOING_AWAY;
1713 QTest::newRow(QStringLiteral("Continuation frame with payload size %1, with %2 bytes following.")
1714 .arg(payloadCode).arg(numBytesFollowing).toLatin1().constData())
1715 << quint8(FIN | QWebSocketProtocol::OC_CONTINUE)
1716 << quint8(payloadCode)
1717 << QByteArray(numBytesFollowing, quint8(1))
1719 << QWebSocketProtocol::CC_GOING_AWAY;
1722 QTEST_MAIN(tst_DataProcessor)
1724 #include "tst_dataprocessor.moc"