1 /****************************************************************************
3 ** Copyright (C) 2014 Kurt Pattyn <pattyn.kurt@gmail.com>.
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 Tests all kinds of valid binary frames, including zero length frames
82 void goodBinaryFrame();
83 void goodBinaryFrame_data();
86 Tests all kinds of valid text frames, including zero length frames
89 void goodTextFrame_data();
92 * Test all kinds of valid control frames.
94 void goodControlFrame();
97 * Test all kinds of valid close frames.
99 void goodCloseFrame();
100 void goodCloseFrame_data();
103 * 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 Tests the QWebSocketDataProcessor for correct handling of frames that don't
122 contain the starting 2 bytes.
123 This test is a border case, where not enough bytes are received to even start parsing a
125 This test does not test sequences of frames, only single frames are tested
127 void frameTooSmall();
130 Tests the QWebSocketDataProcessor for correct handling of frames that are oversized.
131 This test does not test sequences of frames, only single frames are tested
134 void frameTooBig_data();
137 Tests the QWebSocketDataProcessor for the correct handling of malformed frame headers.
138 This test does not test sequences of frames, only single frames are tested
140 void invalidHeader();
141 void invalidHeader_data();
144 Tests the QWebSocketDataProcessor for the correct handling of invalid control frames.
145 Invalid means: payload bigger than 125, frame is fragmented, ...
146 This test does not test sequences of frames, only single frames are tested
148 void invalidControlFrame();
149 void invalidControlFrame_data();
151 void invalidCloseFrame();
152 void invalidCloseFrame_data();
155 Tests the QWebSocketDataProcessor for the correct handling of incomplete size fields
156 for large and big payloads.
158 void incompleteSizeField();
159 void incompleteSizeField_data();
162 Tests the QWebSocketDataProcessor for the correct handling of incomplete payloads.
164 - incomplete length bytes for large and big payloads (16- and 64-bit values),
165 - minimum size representation (see RFC 6455 paragraph 5.2),
166 - frames that are too large (larger than MAX_INT in bytes)
167 - incomplete payloads (less bytes than indicated in the size field)
168 This test does not test sequences of frames, only single frames are tested
170 void incompletePayload();
171 void incompletePayload_data();
174 Tests the QWebSocketDataProcessor for the correct handling of invalid UTF-8 payloads.
175 This test does not test sequences of frames, only single frames are tested
177 void invalidPayload();
178 void invalidPayload_data(bool isControlFrame = false);
180 void invalidPayloadInCloseFrame();
181 void invalidPayloadInCloseFrame_data();
184 Tests the QWebSocketDataProcessor for the correct handling of the minimum size representation
185 requirement of RFC 6455 (see paragraph 5.2)
187 void minimumSizeRequirement();
188 void minimumSizeRequirement_data();
191 //helper function that constructs a new row of test data for invalid UTF8 sequences
192 void invalidUTF8(const char *dataTag, const char *utf8Sequence, bool isCloseFrame);
193 //helper function that constructs a new row of test data for invalid leading field values
194 void invalidField(const char *dataTag, quint8 invalidFieldValue);
195 //helper functions that construct a new row of test data for size fields that do not adhere
196 //to the minimum size requirement
197 void minimumSize16Bit(quint16 sizeInBytes);
198 void minimumSize64Bit(quint64 sizeInBytes);
199 //helper function to construct a new row of test data containing frames with a payload size
200 //smaller than indicated in the header
201 void incompleteFrame(quint8 controlCode, quint64 indicatedSize, quint64 actualPayloadSize);
202 void insertIncompleteSizeFieldTest(quint8 payloadCode, quint8 numBytesFollowing);
204 //helper function to construct a new row of test data containing text frames containing
206 void nonCharacterSequence(const char *sequence);
209 void doCloseFrameTest();
211 QString opCodeToString(quint8 opCode);
214 tst_DataProcessor::tst_DataProcessor()
218 void tst_DataProcessor::initTestCase()
222 void tst_DataProcessor::cleanupTestCase()
226 void tst_DataProcessor::init()
228 qRegisterMetaType<QWebSocketProtocol::OpCode>("QWebSocketProtocol::OpCode");
229 qRegisterMetaType<QWebSocketProtocol::CloseCode>("QWebSocketProtocol::CloseCode");
232 void tst_DataProcessor::cleanup()
236 void tst_DataProcessor::goodBinaryFrame_data()
238 QTest::addColumn<QByteArray>("payload");
239 //be sure to get small (< 126 bytes), large (> 125 bytes & < 64K) and big (>64K) frames
240 for (int i = 0; i < (65536 + 256); i += 128)
242 QTest::newRow(QStringLiteral("Binary frame with %1 bytes").arg(i).toLatin1().constData())
243 << QByteArray(i, char(1));
245 for (int i = 0; i < 256; ++i) //test all possible bytes in the payload
247 QTest::newRow(QStringLiteral("Binary frame containing byte: '0x%1'")
248 .arg(QByteArray(1, char(i)).toHex().constData()).toLatin1().constData())
249 << QByteArray(i, char(1));
253 void tst_DataProcessor::goodBinaryFrame()
257 QWebSocketDataProcessor dataProcessor;
258 QFETCH(QByteArray, payload);
260 data.append((char)(FIN | QWebSocketProtocol::OpCodeBinary));
262 if (payload.length() < 126)
264 data.append(char(payload.length()));
266 else if (payload.length() < 65536)
268 quint16 swapped = qToBigEndian<quint16>(payload.length());
269 const char *wireRepresentation
270 = static_cast<const char *>(static_cast<const void *>(&swapped));
271 data.append(char(126)).append(wireRepresentation, 2);
275 quint64 swapped = qToBigEndian<quint64>(payload.length());
276 const char *wireRepresentation
277 = static_cast<const char *>(static_cast<const void *>(&swapped));
278 data.append(char(127)).append(wireRepresentation, 8);
281 data.append(payload);
282 buffer.setData(data);
283 buffer.open(QIODevice::ReadOnly);
285 QSignalSpy errorReceivedSpy(&dataProcessor,
286 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
287 QSignalSpy closeReceivedSpy(&dataProcessor,
288 SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
289 QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
290 QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
291 QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
292 QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
293 QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
294 QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
295 dataProcessor.process(&buffer);
296 QCOMPARE(errorReceivedSpy.count(), 0);
297 QCOMPARE(pingReceivedSpy.count(), 0);
298 QCOMPARE(pongReceivedSpy.count(), 0);
299 QCOMPARE(closeReceivedSpy.count(), 0);
300 QCOMPARE(binaryFrameReceivedSpy.count(), 1);
301 QCOMPARE(binaryMessageReceivedSpy.count(), 1);
302 QCOMPARE(textFrameReceivedSpy.count(), 0);
303 QCOMPARE(textMessageReceivedSpy.count(), 0);
304 QList<QVariant> arguments = binaryFrameReceivedSpy.takeFirst();
305 QCOMPARE(arguments.at(0).toByteArray().length(), payload.length());
306 arguments = binaryMessageReceivedSpy.takeFirst();
307 QCOMPARE(arguments.at(0).toByteArray().length(), payload.length());
311 void tst_DataProcessor::goodTextFrame_data()
313 QTest::addColumn<QByteArray>("payload");
314 QTest::addColumn<int>("size");
316 //test frames with small (< 126), large ( < 65536) and big ( > 65535) payloads
317 for (int i = 0; i < (65536 + 256); i += 128)
319 QTest::newRow(QStringLiteral("Text frame with %1 ASCII characters")
320 .arg(i).toLatin1().constData()) << QByteArray(i, 'a') << i;
322 //test all valid ASCII characters
323 for (int i = 0; i < 128; ++i)
325 QTest::newRow(QStringLiteral("Text frame with containing ASCII character '0x%1'")
326 .arg(QByteArray(1, char(i)).toHex().constData()).toLatin1().constData())
327 << QByteArray(1, char(i)) << 1;
330 //the text string reads: Text frame containing Hello-µ@ßöäüà á-UTF-8!!
331 //Visual Studio doesn't like UTF-8 in source code, so we use escape codes for the string
332 //The number 22 refers to the length of the string;
333 //the length was incorrectly calculated on Visual Studio
335 //doing extensive QStringLiteral concatenations here, because
336 //MSVC 2010 complains when using concatenation literal strings about
337 //concatenation of wide and narrow strings:
338 //error C2308: concatenating mismatched strings
339 QTest::newRow((QStringLiteral("Text frame containing Hello-") +
340 QStringLiteral("\xC2\xB5\x40\xC3\x9F\xC3\xB6\xC3\xA4\xC3\xBC\xC3\xA0") +
341 QStringLiteral("\xC3\xA1-UTF-8!!")).toLatin1().constData())
342 << QByteArray::fromHex("48656c6c6f2dc2b540c39fc3b6c3a4c3bcc3a0c3a12d5554462d382121")
346 void tst_DataProcessor::goodTextFrame()
350 QWebSocketDataProcessor dataProcessor;
351 QFETCH(QByteArray, payload);
354 data.append((char)(FIN | QWebSocketProtocol::OpCodeText));
356 if (payload.length() < 126)
358 data.append(char(payload.length()));
360 else if (payload.length() < 65536)
362 quint16 swapped = qToBigEndian<quint16>(payload.length());
363 const char *wireRepresentation
364 = static_cast<const char *>(static_cast<const void *>(&swapped));
365 data.append(char(126)).append(wireRepresentation, 2);
369 quint64 swapped = qToBigEndian<quint64>(payload.length());
370 const char *wireRepresentation
371 = static_cast<const char *>(static_cast<const void *>(&swapped));
372 data.append(char(127)).append(wireRepresentation, 8);
375 data.append(payload);
376 buffer.setData(data);
377 buffer.open(QIODevice::ReadOnly);
379 QSignalSpy errorReceivedSpy(&dataProcessor,
380 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
381 QSignalSpy closeReceivedSpy(&dataProcessor,
382 SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
383 QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
384 QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
385 QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
386 QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
387 QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
388 QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
390 dataProcessor.process(&buffer);
392 QCOMPARE(errorReceivedSpy.count(), 0);
393 QCOMPARE(pingReceivedSpy.count(), 0);
394 QCOMPARE(pongReceivedSpy.count(), 0);
395 QCOMPARE(closeReceivedSpy.count(), 0);
396 QCOMPARE(textFrameReceivedSpy.count(), 1);
397 QCOMPARE(textMessageReceivedSpy.count(), 1);
398 QCOMPARE(binaryFrameReceivedSpy.count(), 0);
399 QCOMPARE(binaryMessageReceivedSpy.count(), 0);
400 QList<QVariant> arguments = textFrameReceivedSpy.takeFirst();
401 QCOMPARE(arguments.at(0).toString().length(), size);
402 arguments = textMessageReceivedSpy.takeFirst();
403 QCOMPARE(arguments.at(0).toString().length(), size);
407 void tst_DataProcessor::goodControlFrame()
411 QWebSocketDataProcessor dataProcessor;
413 QSignalSpy closeFrameReceivedSpy(&dataProcessor,
414 SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
415 QSignalSpy errorReceivedSpy(&dataProcessor,
416 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
417 QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
418 QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
419 QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
420 QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
421 QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
422 QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
424 data.append((char)(FIN | QWebSocketProtocol::OpCodePing));
425 data.append(QChar::fromLatin1(0));
426 buffer.setData(data);
427 buffer.open(QIODevice::ReadOnly);
428 dataProcessor.process(&buffer);
429 QCOMPARE(errorReceivedSpy.count(), 0);
430 QCOMPARE(textFrameReceivedSpy.count(), 0);
431 QCOMPARE(textMessageReceivedSpy.count(), 0);
432 QCOMPARE(binaryFrameReceivedSpy.count(), 0);
433 QCOMPARE(binaryMessageReceivedSpy.count(), 0);
434 QCOMPARE(closeFrameReceivedSpy.count(), 0);
435 QCOMPARE(pongReceivedSpy.count(), 0);
436 QCOMPARE(pingReceivedSpy.count(), 1);
440 pingReceivedSpy.clear();
441 pongReceivedSpy.clear();
442 data.append((char)(FIN | QWebSocketProtocol::OpCodePong));
443 data.append(QChar::fromLatin1(0));
444 buffer.setData(data);
445 buffer.open(QIODevice::ReadOnly);
446 dataProcessor.process(&buffer);
447 QCOMPARE(errorReceivedSpy.count(), 0);
448 QCOMPARE(textFrameReceivedSpy.count(), 0);
449 QCOMPARE(textMessageReceivedSpy.count(), 0);
450 QCOMPARE(binaryFrameReceivedSpy.count(), 0);
451 QCOMPARE(binaryMessageReceivedSpy.count(), 0);
452 QCOMPARE(closeFrameReceivedSpy.count(), 0);
453 QCOMPARE(pingReceivedSpy.count(), 0);
454 QCOMPARE(pongReceivedSpy.count(), 1);
458 void tst_DataProcessor::goodCloseFrame_data()
460 QTest::addColumn<QString>("payload");
461 QTest::addColumn<QWebSocketProtocol::CloseCode>("closeCode");
462 //control frame data cannot exceed 125 bytes; smaller than 124,
463 //because we also need a 2 byte close code
464 for (int i = 0; i < 124; ++i)
466 QTest::newRow(QStringLiteral("Close frame with %1 ASCII characters")
467 .arg(i).toLatin1().constData())
469 << QWebSocketProtocol::CloseCodeNormal;
471 for (int i = 0; i < 126; ++i)
473 QTest::newRow(QStringLiteral("Text frame with containing ASCII character '0x%1'")
474 .arg(QByteArray(1, char(i)).toHex().constData()).toLatin1().constData())
475 << QString(1, char(i)) << QWebSocketProtocol::CloseCodeNormal;
477 QTest::newRow("Close frame with close code NORMAL")
478 << QString(1, 'a') << QWebSocketProtocol::CloseCodeNormal;
479 QTest::newRow("Close frame with close code BAD OPERATION")
480 << QString(1, 'a') << QWebSocketProtocol::CloseCodeBadOperation;
481 QTest::newRow("Close frame with close code DATATYPE NOT SUPPORTED")
482 << QString(1, 'a') << QWebSocketProtocol::CloseCodeDatatypeNotSupported;
483 QTest::newRow("Close frame with close code GOING AWAY")
484 << QString(1, 'a') << QWebSocketProtocol::CloseCodeGoingAway;
485 QTest::newRow("Close frame with close code MISSING EXTENSION")
486 << QString(1, 'a') << QWebSocketProtocol::CloseCodeMissingExtension;
487 QTest::newRow("Close frame with close code POLICY VIOLATED")
488 << QString(1, 'a') << QWebSocketProtocol::CloseCodePolicyViolated;
489 QTest::newRow("Close frame with close code PROTOCOL ERROR")
490 << QString(1, 'a') << QWebSocketProtocol::CloseCodeProtocolError;
491 QTest::newRow("Close frame with close code TOO MUCH DATA")
492 << QString(1, 'a') << QWebSocketProtocol::CloseCodeTooMuchData;
493 QTest::newRow("Close frame with close code WRONG DATATYPE")
494 << QString(1, 'a') << QWebSocketProtocol::CloseCodeWrongDatatype;
495 QTest::newRow("Close frame with close code 3000")
496 << QString(1, 'a') << QWebSocketProtocol::CloseCode(3000);
497 QTest::newRow("Close frame with close code 3999")
498 << QString(1, 'a') << QWebSocketProtocol::CloseCode(3999);
499 QTest::newRow("Close frame with close code 4000")
500 << QString(1, 'a') << QWebSocketProtocol::CloseCode(4000);
501 QTest::newRow("Close frame with close code 4999")
502 << QString(1, 'a') << QWebSocketProtocol::CloseCode(4999);
504 //close frames with no close reason
505 QTest::newRow("Close frame with close code NORMAL and no reason")
506 << QString() << QWebSocketProtocol::CloseCodeNormal;
507 QTest::newRow("Close frame with close code BAD OPERATION and no reason")
508 << QString() << QWebSocketProtocol::CloseCodeBadOperation;
509 QTest::newRow("Close frame with close code DATATYPE NOT SUPPORTED and no reason")
510 << QString() << QWebSocketProtocol::CloseCodeDatatypeNotSupported;
511 QTest::newRow("Close frame with close code GOING AWAY and no reason")
512 << QString() << QWebSocketProtocol::CloseCodeGoingAway;
513 QTest::newRow("Close frame with close code MISSING EXTENSION and no reason")
514 << QString() << QWebSocketProtocol::CloseCodeMissingExtension;
515 QTest::newRow("Close frame with close code POLICY VIOLATED and no reason")
516 << QString() << QWebSocketProtocol::CloseCodePolicyViolated;
517 QTest::newRow("Close frame with close code PROTOCOL ERROR and no reason")
518 << QString() << QWebSocketProtocol::CloseCodeProtocolError;
519 QTest::newRow("Close frame with close code TOO MUCH DATA and no reason")
520 << QString() << QWebSocketProtocol::CloseCodeTooMuchData;
521 QTest::newRow("Close frame with close code WRONG DATATYPE and no reason")
522 << QString() << QWebSocketProtocol::CloseCodeWrongDatatype;
523 QTest::newRow("Close frame with close code 3000 and no reason")
524 << QString() << QWebSocketProtocol::CloseCode(3000);
525 QTest::newRow("Close frame with close code 3999 and no reason")
526 << QString() << QWebSocketProtocol::CloseCode(3999);
527 QTest::newRow("Close frame with close code 4000 and no reason")
528 << QString() << QWebSocketProtocol::CloseCode(4000);
529 QTest::newRow("Close frame with close code 4999 and no reason")
530 << QString() << QWebSocketProtocol::CloseCode(4999);
532 QTest::newRow("Close frame with no close code and no reason")
533 << QString() << QWebSocketProtocol::CloseCode(0);
536 void tst_DataProcessor::goodOpcodes_data()
538 QTest::addColumn<QWebSocketProtocol::OpCode>("opCode");
540 QTest::newRow("Frame with PING opcode") << QWebSocketProtocol::OpCodePing;
541 QTest::newRow("Frame with PONG opcode") << QWebSocketProtocol::OpCodePong;
542 QTest::newRow("Frame with TEXT opcode") << QWebSocketProtocol::OpCodeText;
543 QTest::newRow("Frame with BINARY opcode") << QWebSocketProtocol::OpCodeBinary;
544 QTest::newRow("Frame with CLOSE opcode") << QWebSocketProtocol::OpCodeClose;
547 void tst_DataProcessor::goodOpcodes()
551 QWebSocketDataProcessor dataProcessor;
552 QFETCH(QWebSocketProtocol::OpCode, opCode);
554 data.append((char)(FIN | opCode));
555 data.append(char(0)); //zero length
557 buffer.setData(data);
558 buffer.open(QIODevice::ReadOnly);
560 QSignalSpy errorReceivedSpy(&dataProcessor,
561 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
562 QSignalSpy closeReceivedSpy(&dataProcessor,
563 SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
564 QSignalSpy pingReceivedSpy(&dataProcessor,
565 SIGNAL(pingReceived(QByteArray)));
566 QSignalSpy pongReceivedSpy(&dataProcessor,
567 SIGNAL(pongReceived(QByteArray)));
568 QSignalSpy textFrameReceivedSpy(&dataProcessor,
569 SIGNAL(textFrameReceived(QString,bool)));
570 QSignalSpy textMessageReceivedSpy(&dataProcessor,
571 SIGNAL(textMessageReceived(QString)));
572 QSignalSpy binaryFrameReceivedSpy(&dataProcessor,
573 SIGNAL(binaryFrameReceived(QByteArray,bool)));
574 QSignalSpy binaryMessageReceivedSpy(&dataProcessor,
575 SIGNAL(binaryMessageReceived(QByteArray)));
577 dataProcessor.process(&buffer);
579 QCOMPARE(errorReceivedSpy.count(), 0);
580 QCOMPARE(pingReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodePing ? 1 : 0);
581 QCOMPARE(pongReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodePong ? 1 : 0);
582 QCOMPARE(closeReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodeClose ? 1 : 0);
583 QCOMPARE(textFrameReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodeText ? 1 : 0);
584 QCOMPARE(textMessageReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodeText ? 1 : 0);
585 QCOMPARE(binaryFrameReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodeBinary ? 1 : 0);
586 QCOMPARE(binaryMessageReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodeBinary ? 1 : 0);
591 void tst_DataProcessor::goodCloseFrame()
595 QWebSocketDataProcessor dataProcessor;
596 QFETCH(QString, payload);
597 QFETCH(QWebSocketProtocol::CloseCode, closeCode);
598 quint16 swapped = qToBigEndian<quint16>(closeCode);
599 const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
601 data.append((char)(FIN | QWebSocketProtocol::OpCodeClose));
604 data.append(char(payload.length() + 2)).append(wireRepresentation, 2).append(payload);
608 data.append(QChar::fromLatin1(0)); //payload length 0;
609 //dataprocessor emits a CloseCodeNormal close code when none is present
610 closeCode = QWebSocketProtocol::CloseCodeNormal;
612 buffer.setData(data);
613 buffer.open(QIODevice::ReadOnly);
615 QSignalSpy errorReceivedSpy(&dataProcessor,
616 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
617 QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
618 QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
619 QSignalSpy closeFrameReceivedSpy(&dataProcessor,
620 SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
621 QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
622 QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
623 QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
624 QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
626 dataProcessor.process(&buffer);
628 QCOMPARE(errorReceivedSpy.count(), 0);
629 QCOMPARE(pingReceivedSpy.count(), 0);
630 QCOMPARE(pongReceivedSpy.count(), 0);
631 QCOMPARE(closeFrameReceivedSpy.count(), 1);
632 QCOMPARE(textFrameReceivedSpy.count(), 0);
633 QCOMPARE(textMessageReceivedSpy.count(), 0);
634 QCOMPARE(binaryFrameReceivedSpy.count(), 0);
635 QCOMPARE(binaryMessageReceivedSpy.count(), 0);
636 QList<QVariant> arguments = closeFrameReceivedSpy.takeFirst();
637 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), closeCode);
638 QCOMPARE(arguments.at(1).toString().length(), payload.length());
642 void tst_DataProcessor::nonCharacterCodes_data()
644 QTest::addColumn<quint8>("firstByte");
645 QTest::addColumn<quint8>("secondByte");
646 QTest::addColumn<QByteArray>("payload");
647 QTest::addColumn<bool>("isContinuationFrame");
649 nonCharacterSequence("efbfbe");
650 nonCharacterSequence("efbfbf");
651 nonCharacterSequence("f09fbfbe");
652 nonCharacterSequence("f09fbfbf");
653 nonCharacterSequence("f0afbfbe");
654 nonCharacterSequence("f0afbfbf");
655 nonCharacterSequence("f0bfbfbe");
656 nonCharacterSequence("f0bfbfbf");
657 nonCharacterSequence("f18fbfbe");
658 nonCharacterSequence("f18fbfbf");
659 nonCharacterSequence("f19fbfbe");
660 nonCharacterSequence("f19fbfbf");
661 nonCharacterSequence("f1afbfbe");
662 nonCharacterSequence("f1afbfbf");
663 nonCharacterSequence("f1bfbfbe");
664 nonCharacterSequence("f1bfbfbf");
665 nonCharacterSequence("f28fbfbe");
666 nonCharacterSequence("f28fbfbf");
667 nonCharacterSequence("f29fbfbe");
668 nonCharacterSequence("f29fbfbf");
669 nonCharacterSequence("f2afbfbe");
670 nonCharacterSequence("f2afbfbf");
671 nonCharacterSequence("f2bfbfbe");
672 nonCharacterSequence("f2bfbfbf");
673 nonCharacterSequence("f38fbfbe");
674 nonCharacterSequence("f38fbfbf");
675 nonCharacterSequence("f39fbfbe");
676 nonCharacterSequence("f39fbfbf");
677 nonCharacterSequence("f3afbfbe");
678 nonCharacterSequence("f3afbfbf");
679 nonCharacterSequence("f3bfbfbe");
680 nonCharacterSequence("f3bfbfbf");
681 nonCharacterSequence("f48fbfbe");
682 nonCharacterSequence("f48fbfbf");
685 void tst_DataProcessor::nonCharacterCodes()
687 QFETCH(quint8, firstByte);
688 QFETCH(quint8, secondByte);
689 QFETCH(QByteArray, payload);
690 QFETCH(bool, isContinuationFrame);
692 if (!isContinuationFrame)
696 QWebSocketDataProcessor dataProcessor;
697 QSignalSpy errorSpy(&dataProcessor,
698 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
699 QSignalSpy closeSpy(&dataProcessor,
700 SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
701 QSignalSpy pingFrameSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
702 QSignalSpy pongFrameSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
703 QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
704 QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
705 QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
706 QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
708 data.append(firstByte).append(secondByte);
709 data.append(payload);
710 buffer.setData(data);
711 buffer.open(QIODevice::ReadOnly);
712 dataProcessor.process(&buffer);
714 QCOMPARE(errorSpy.count(), 0);
715 QCOMPARE(closeSpy.count(), 0);
716 QCOMPARE(pingFrameSpy.count(), 0);
717 QCOMPARE(pongFrameSpy.count(), 0);
718 QCOMPARE(textFrameSpy.count(), 1);
719 QCOMPARE(textMessageSpy.count(), 1);
720 QCOMPARE(binaryFrameSpy.count(), 0);
721 QCOMPARE(binaryMessageSpy.count(), 0);
723 QVariantList arguments = textFrameSpy.takeFirst();
724 QCOMPARE(arguments.at(0).value<QString>().toUtf8(), payload);
725 QCOMPARE(arguments.at(1).value<bool>(), !isContinuationFrame);
726 arguments = textMessageSpy.takeFirst();
727 QCOMPARE(arguments.at(0).value<QString>().toUtf8(), payload);
732 void tst_DataProcessor::frameTooSmall()
736 QWebSocketDataProcessor dataProcessor;
737 QByteArray firstFrame;
739 firstFrame.append(quint8(QWebSocketProtocol::OpCodeText)).append(char(1))
740 .append(QByteArray(1, 'a'));
742 //with nothing in the buffer, the dataProcessor should time out
743 //and the error should be CloseCodeGoingAway meaning the socket will be closed
744 buffer.setData(data);
745 buffer.open(QIODevice::ReadOnly);
746 QSignalSpy errorSpy(&dataProcessor,
747 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
748 QSignalSpy closeSpy(&dataProcessor,
749 SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
750 QSignalSpy pingMessageSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
751 QSignalSpy pongMessageSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
752 QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
753 QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
754 QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
755 QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
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(), 0);
766 QCOMPARE(binaryFrameSpy.count(), 0);
768 QList<QVariant> arguments = errorSpy.takeFirst();
769 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(),
770 QWebSocketProtocol::CloseCodeGoingAway);
773 pingMessageSpy.clear();
774 pongMessageSpy.clear();
775 textMessageSpy.clear();
776 binaryMessageSpy.clear();
777 textFrameSpy.clear();
778 binaryFrameSpy.clear();
782 //only one byte; this is far too little;
783 //should get a time out as well and the error should be CloseCodeGoingAway
784 //meaning the socket will be closed
785 data.append(quint8('1')); //put 1 byte in the buffer; this is too little
786 buffer.setData(data);
787 buffer.open(QIODevice::ReadOnly);
789 dataProcessor.process(&buffer);
791 QCOMPARE(errorSpy.count(), 1);
792 QCOMPARE(closeSpy.count(), 0);
793 QCOMPARE(pingMessageSpy.count(), 0);
794 QCOMPARE(pongMessageSpy.count(), 0);
795 QCOMPARE(textMessageSpy.count(), 0);
796 QCOMPARE(binaryMessageSpy.count(), 0);
797 QCOMPARE(textFrameSpy.count(), 0);
798 QCOMPARE(binaryFrameSpy.count(), 0);
800 arguments = errorSpy.takeFirst();
801 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(),
802 QWebSocketProtocol::CloseCodeGoingAway);
806 pingMessageSpy.clear();
807 pongMessageSpy.clear();
808 textMessageSpy.clear();
809 binaryMessageSpy.clear();
810 textFrameSpy.clear();
811 binaryFrameSpy.clear();
816 //text frame with final bit not set
817 data.append((char)(QWebSocketProtocol::OpCodeText)).append(char(0x0));
818 buffer.setData(data);
819 buffer.open(QIODevice::ReadOnly);
821 dataProcessor.process(&buffer);
826 //with nothing in the buffer,
827 //the dataProcessor should time out and the error should be CloseCodeGoingAway
828 //meaning the socket will be closed
829 buffer.setData(data);
830 buffer.open(QIODevice::ReadOnly);
831 QSignalSpy errorSpy(&dataProcessor,
832 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
833 dataProcessor.process(&buffer);
835 QCOMPARE(errorSpy.count(), 1);
836 QCOMPARE(closeSpy.count(), 0);
837 QCOMPARE(pingMessageSpy.count(), 0);
838 QCOMPARE(pongMessageSpy.count(), 0);
839 QCOMPARE(textMessageSpy.count(), 0);
840 QCOMPARE(binaryMessageSpy.count(), 0);
841 QCOMPARE(textFrameSpy.count(), 1);
842 QCOMPARE(binaryFrameSpy.count(), 0);
844 QList<QVariant> arguments = errorSpy.takeFirst();
845 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(),
846 QWebSocketProtocol::CloseCodeGoingAway);
849 pingMessageSpy.clear();
850 pongMessageSpy.clear();
851 textMessageSpy.clear();
852 binaryMessageSpy.clear();
853 textFrameSpy.clear();
854 binaryFrameSpy.clear();
858 //text frame with final bit not set
859 data.append((char)(QWebSocketProtocol::OpCodeText)).append(char(0x0));
860 buffer.setData(data);
861 buffer.open(QIODevice::ReadOnly);
862 dataProcessor.process(&buffer);
864 QCOMPARE(errorSpy.count(), 1);
865 QCOMPARE(closeSpy.count(), 0);
866 QCOMPARE(pingMessageSpy.count(), 0);
867 QCOMPARE(pongMessageSpy.count(), 0);
868 QCOMPARE(textMessageSpy.count(), 0);
869 QCOMPARE(binaryMessageSpy.count(), 0);
870 QCOMPARE(textFrameSpy.count(), 1);
871 QCOMPARE(binaryFrameSpy.count(), 0);
878 pingMessageSpy.clear();
879 pongMessageSpy.clear();
880 textMessageSpy.clear();
881 binaryMessageSpy.clear();
882 textFrameSpy.clear();
883 binaryFrameSpy.clear();
885 //only 1 byte follows in continuation frame;
886 //should time out with close code CloseCodeGoingAway
888 buffer.setData(data);
889 buffer.open(QIODevice::ReadOnly);
891 dataProcessor.process(&buffer);
892 QCOMPARE(errorSpy.count(), 1);
893 QCOMPARE(closeSpy.count(), 0);
894 QCOMPARE(pingMessageSpy.count(), 0);
895 QCOMPARE(pongMessageSpy.count(), 0);
896 QCOMPARE(textMessageSpy.count(), 0);
897 QCOMPARE(binaryMessageSpy.count(), 0);
898 QCOMPARE(textFrameSpy.count(), 0);
899 QCOMPARE(binaryFrameSpy.count(), 0);
900 arguments = errorSpy.takeFirst();
901 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(),
902 QWebSocketProtocol::CloseCodeGoingAway);
907 void tst_DataProcessor::frameTooBig_data()
909 QTest::addColumn<quint8>("firstByte");
910 QTest::addColumn<quint8>("secondByte");
911 QTest::addColumn<QByteArray>("payload");
912 QTest::addColumn<bool>("isContinuationFrame");
913 QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
915 quint64 swapped64 = 0;
916 const char *wireRepresentation = 0;
918 //only data frames are checked for being too big
919 //control frames have explicit checking on a maximum payload size of 125,
920 //which is tested elsewhere
922 swapped64 = qToBigEndian<quint64>(QWebSocketDataProcessor::maxFrameSize() + 1);
923 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
924 QTest::newRow("Text frame with payload size > INT_MAX")
925 << quint8(FIN | QWebSocketProtocol::OpCodeText)
927 << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a'))
929 << QWebSocketProtocol::CloseCodeTooMuchData;
931 swapped64 = qToBigEndian<quint64>(QWebSocketDataProcessor::maxFrameSize() + 1);
932 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
933 QTest::newRow("Binary frame with payload size > INT_MAX")
934 << quint8(FIN | QWebSocketProtocol::OpCodeBinary)
936 << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a'))
938 << QWebSocketProtocol::CloseCodeTooMuchData;
940 swapped64 = qToBigEndian<quint64>(QWebSocketDataProcessor::maxFrameSize() + 1);
941 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
942 QTest::newRow("Continuation frame with payload size > INT_MAX")
943 << quint8(FIN | QWebSocketProtocol::OpCodeContinue)
945 << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a'))
947 << QWebSocketProtocol::CloseCodeTooMuchData;
950 void tst_DataProcessor::frameTooBig()
955 void tst_DataProcessor::invalidHeader_data()
957 //The first byte contain the FIN, RSV1, RSV2, RSV3 and the Opcode
958 //The second byte contains the MaskFlag and the length of the frame
959 QTest::addColumn<quint8>("firstByte");
960 QTest::addColumn<quint8>("secondByte");
961 //superfluous, but present to be able to call doTest(), which expects a payload field
962 QTest::addColumn<QByteArray>("payload");
963 QTest::addColumn<bool>("isContinuationFrame");
964 QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
967 invalidField("RSV1 set", RSV1);
968 invalidField("RSV2 set", RSV2);
969 invalidField("RSV3 set", RSV3);
970 invalidField("RSV1 and RSV2 set", RSV1 | RSV2);
971 invalidField("RSV1 and RSV3 set", RSV1 | RSV3);
972 invalidField("RSV2 and RSV3 set", RSV2 | RSV3);
973 invalidField("RSV1, RSV2 and RSV3 set", RSV1 | RSV2 | RSV3);
976 invalidField("Invalid OpCode 3", QWebSocketProtocol::OpCodeReserved3);
977 invalidField("Invalid OpCode 4", QWebSocketProtocol::OpCodeReserved4);
978 invalidField("Invalid OpCode 5", QWebSocketProtocol::OpCodeReserved5);
979 invalidField("Invalid OpCode 6", QWebSocketProtocol::OpCodeReserved6);
980 invalidField("Invalid OpCode 7", QWebSocketProtocol::OpCodeReserved7);
981 invalidField("Invalid OpCode B", QWebSocketProtocol::OpCodeReservedB);
982 invalidField("Invalid OpCode C", QWebSocketProtocol::OpCodeReservedC);
983 invalidField("Invalid OpCode D", QWebSocketProtocol::OpCodeReservedD);
984 invalidField("Invalid OpCode E", QWebSocketProtocol::OpCodeReservedE);
985 invalidField("Invalid OpCode F", QWebSocketProtocol::OpCodeReservedF);
988 void tst_DataProcessor::invalidHeader()
993 void tst_DataProcessor::invalidControlFrame_data()
995 QTest::addColumn<quint8>("firstByte");
996 QTest::addColumn<quint8>("secondByte");
997 QTest::addColumn<QByteArray>("payload");
998 QTest::addColumn<bool>("isContinuationFrame");
999 QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
1002 QTest::newRow("Close control frame with payload size 126")
1003 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1007 << QWebSocketProtocol::CloseCodeProtocolError;
1008 QTest::newRow("Ping control frame with payload size 126")
1009 << quint8(FIN | QWebSocketProtocol::OpCodePing)
1013 << QWebSocketProtocol::CloseCodeProtocolError;
1014 QTest::newRow("Close control frame with payload size 126")
1015 << quint8(FIN | QWebSocketProtocol::OpCodePong)
1019 << QWebSocketProtocol::CloseCodeProtocolError;
1021 QTest::newRow("Non-final close control frame (fragmented)")
1022 << quint8(QWebSocketProtocol::OpCodeClose)
1026 << QWebSocketProtocol::CloseCodeProtocolError;
1027 QTest::newRow("Non-final ping control frame (fragmented)")
1028 << quint8(QWebSocketProtocol::OpCodePing)
1029 << quint8(32) << QByteArray()
1031 << QWebSocketProtocol::CloseCodeProtocolError;
1032 QTest::newRow("Non-final pong control frame (fragmented)")
1033 << quint8(QWebSocketProtocol::OpCodePong)
1037 << QWebSocketProtocol::CloseCodeProtocolError;
1040 void tst_DataProcessor::invalidControlFrame()
1045 void tst_DataProcessor::invalidCloseFrame_data()
1047 QTest::addColumn<quint8>("firstByte");
1048 QTest::addColumn<quint8>("secondByte");
1049 QTest::addColumn<QByteArray>("payload");
1050 QTest::addColumn<bool>("isContinuationFrame");
1051 QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
1053 QTest::newRow("Close control frame with payload size 1")
1054 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1056 << QByteArray(1, 'a')
1058 << QWebSocketProtocol::CloseCodeProtocolError;
1059 quint16 swapped = qToBigEndian<quint16>(QWebSocketProtocol::CloseCodeAbnormalDisconnection);
1060 const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1062 //Not allowed per RFC 6455 (see para 7.4.1)
1063 QTest::newRow("Close control frame close code ABNORMAL DISCONNECTION")
1064 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1066 << QByteArray(wireRepresentation, 2)
1068 << QWebSocketProtocol::CloseCodeProtocolError;
1069 swapped = qToBigEndian<quint16>(QWebSocketProtocol::CloseCodeMissingStatusCode);
1070 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1071 //Not allowed per RFC 6455 (see para 7.4.1)
1072 QTest::newRow("Close control frame close code MISSING STATUS CODE")
1073 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1075 << QByteArray(wireRepresentation, 2)
1077 << QWebSocketProtocol::CloseCodeProtocolError;
1078 swapped = qToBigEndian<quint16>(1004);
1079 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1080 QTest::newRow("Close control frame close code 1004")
1081 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1083 << QByteArray(wireRepresentation, 2)
1085 << QWebSocketProtocol::CloseCodeProtocolError;
1086 swapped = qToBigEndian<quint16>(QWebSocketProtocol::CloseCodeTlsHandshakeFailed);
1087 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1088 //Not allowed per RFC 6455 (see para 7.4.1)
1089 QTest::newRow("Close control frame close code TLS HANDSHAKE FAILED")
1090 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1092 << QByteArray(wireRepresentation, 2)
1094 << QWebSocketProtocol::CloseCodeProtocolError;
1095 swapped = qToBigEndian<quint16>(0);
1096 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1097 QTest::newRow("Close control frame close code 0")
1098 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1100 << QByteArray(wireRepresentation, 2)
1102 << QWebSocketProtocol::CloseCodeProtocolError;
1103 swapped = qToBigEndian<quint16>(999);
1104 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1105 QTest::newRow("Close control frame close code 999")
1106 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1108 << QByteArray(wireRepresentation, 2)
1110 << QWebSocketProtocol::CloseCodeProtocolError;
1111 swapped = qToBigEndian<quint16>(1012);
1112 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1113 QTest::newRow("Close control frame close code 1012")
1114 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1116 << QByteArray(wireRepresentation, 2)
1118 << QWebSocketProtocol::CloseCodeProtocolError;
1119 swapped = qToBigEndian<quint16>(1013);
1120 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1121 QTest::newRow("Close control frame close code 1013")
1122 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1124 << QByteArray(wireRepresentation, 2)
1126 << QWebSocketProtocol::CloseCodeProtocolError;
1127 swapped = qToBigEndian<quint16>(1014);
1128 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1129 QTest::newRow("Close control frame close code 1014")
1130 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1132 << QByteArray(wireRepresentation, 2)
1134 << QWebSocketProtocol::CloseCodeProtocolError;
1135 swapped = qToBigEndian<quint16>(1100);
1136 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1137 QTest::newRow("Close control frame close code 1100")
1138 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1140 << QByteArray(wireRepresentation, 2)
1142 << QWebSocketProtocol::CloseCodeProtocolError;
1143 swapped = qToBigEndian<quint16>(2000);
1144 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1145 QTest::newRow("Close control frame close code 2000")
1146 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1148 << QByteArray(wireRepresentation, 2)
1150 << QWebSocketProtocol::CloseCodeProtocolError;
1151 swapped = qToBigEndian<quint16>(2999);
1152 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1153 QTest::newRow("Close control frame close code 2999")
1154 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1156 << QByteArray(wireRepresentation, 2)
1158 << QWebSocketProtocol::CloseCodeProtocolError;
1159 swapped = qToBigEndian<quint16>(5000);
1160 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1161 QTest::newRow("Close control frame close code 5000")
1162 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1164 << QByteArray(wireRepresentation, 2)
1166 << QWebSocketProtocol::CloseCodeProtocolError;
1167 swapped = qToBigEndian<quint16>(65535u);
1168 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1169 QTest::newRow("Close control frame close code 65535")
1170 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1172 << QByteArray(wireRepresentation, 2)
1174 << QWebSocketProtocol::CloseCodeProtocolError;
1177 void tst_DataProcessor::invalidCloseFrame()
1182 void tst_DataProcessor::minimumSizeRequirement_data()
1184 QTest::addColumn<quint8>("firstByte");
1185 QTest::addColumn<quint8>("secondByte");
1186 QTest::addColumn<QByteArray>("payload");
1187 QTest::addColumn<bool>("isContinuationFrame");
1188 QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
1190 minimumSize16Bit(0);
1191 minimumSize16Bit(64);
1192 minimumSize16Bit(125);
1194 minimumSize64Bit(0);
1195 minimumSize64Bit(64);
1196 minimumSize64Bit(125);
1197 minimumSize64Bit(126);
1198 minimumSize64Bit(256);
1199 minimumSize64Bit(512);
1200 minimumSize64Bit(1024);
1201 minimumSize64Bit(2048);
1202 minimumSize64Bit(4096);
1203 minimumSize64Bit(8192);
1204 minimumSize64Bit(16384);
1205 minimumSize64Bit(32768);
1206 minimumSize64Bit(0xFFFFu);
1209 void tst_DataProcessor::minimumSizeRequirement()
1214 void tst_DataProcessor::invalidPayload_data(bool isControlFrame)
1216 QTest::addColumn<quint8>("firstByte");
1217 QTest::addColumn<quint8>("secondByte");
1218 QTest::addColumn<QByteArray>("payload");
1219 QTest::addColumn<bool>("isContinuationFrame");
1220 QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
1222 //6.3: invalid UTF-8 sequence
1223 invalidUTF8("case 6.3.1", "cebae1bdb9cf83cebcceb5eda080656469746564", isControlFrame);
1225 //6.4.: fail fast tests; invalid UTF-8 in middle of string
1226 invalidUTF8("case 6.4.1", "cebae1bdb9cf83cebcceb5f4908080656469746564", isControlFrame);
1227 invalidUTF8("case 6.4.4", "cebae1bdb9cf83cebcceb5eda080656469746564", isControlFrame);
1229 //6.6: All prefixes of a valid UTF-8 string that contains multi-byte code points
1230 invalidUTF8("case 6.6.1", "ce", isControlFrame);
1231 invalidUTF8("case 6.6.3", "cebae1", isControlFrame);
1232 invalidUTF8("case 6.6.4", "cebae1bd", isControlFrame);
1233 invalidUTF8("case 6.6.6", "cebae1bdb9cf", isControlFrame);
1234 invalidUTF8("case 6.6.8", "cebae1bdb9cf83ce", isControlFrame);
1235 invalidUTF8("case 6.6.10", "cebae1bdb9cf83cebcce", isControlFrame);
1237 //6.8: First possible sequence length 5/6 (invalid codepoints)
1238 invalidUTF8("case 6.8.1", "f888808080", isControlFrame);
1239 invalidUTF8("case 6.8.2", "fc8480808080", isControlFrame);
1241 //6.10: Last possible sequence length 4/5/6 (invalid codepoints)
1242 invalidUTF8("case 6.10.1", "f7bfbfbf", isControlFrame);
1243 invalidUTF8("case 6.10.2", "fbbfbfbfbf", isControlFrame);
1244 invalidUTF8("case 6.10.3", "fdbfbfbfbfbf", isControlFrame);
1246 //5.11: boundary conditions
1247 invalidUTF8("case 6.11.5", "f4908080", isControlFrame);
1249 //6.12: unexpected continuation bytes
1250 invalidUTF8("case 6.12.1", "80", isControlFrame);
1251 invalidUTF8("case 6.12.2", "bf", isControlFrame);
1252 invalidUTF8("case 6.12.3", "80bf", isControlFrame);
1253 invalidUTF8("case 6.12.4", "80bf80", isControlFrame);
1254 invalidUTF8("case 6.12.5", "80bf80bf", isControlFrame);
1255 invalidUTF8("case 6.12.6", "80bf80bf80", isControlFrame);
1256 invalidUTF8("case 6.12.7", "80bf80bf80bf", isControlFrame);
1257 invalidUTF8("case 6.12.8",
1258 "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a"
1259 "7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbe",
1262 //6.13: lonely start characters
1263 invalidUTF8("case 6.13.1",
1264 "c020c120c220c320c420c520c620c720c820c920ca20cb20cc20cd20ce20cf20d020d120d220"
1265 "d320d420d520d620d720d820d920da20db20dc20dd20de20",
1267 invalidUTF8("case 6.13.2", "e020e120e220e320e420e520e620e720e820e920ea20eb20ec20ed20ee20",
1269 invalidUTF8("case 6.13.3", "f020f120f220f320f420f520f620", isControlFrame);
1270 invalidUTF8("case 6.13.4", "f820f920fa20", isControlFrame);
1271 invalidUTF8("case 6.13.5", "fc20", isControlFrame);
1273 //6.14: sequences with last continuation byte missing
1274 invalidUTF8("case 6.14.1", "c0", isControlFrame);
1275 invalidUTF8("case 6.14.2", "e080", isControlFrame);
1276 invalidUTF8("case 6.14.3", "f08080", isControlFrame);
1277 invalidUTF8("case 6.14.4", "f8808080", isControlFrame);
1278 invalidUTF8("case 6.14.5", "fc80808080", isControlFrame);
1279 invalidUTF8("case 6.14.6", "df", isControlFrame);
1280 invalidUTF8("case 6.14.7", "efbf", isControlFrame);
1281 invalidUTF8("case 6.14.8", "f7bfbf", isControlFrame);
1282 invalidUTF8("case 6.14.9", "fbbfbfbf", isControlFrame);
1283 invalidUTF8("case 6.14.10", "fdbfbfbfbf", isControlFrame);
1285 //6.15: concatenation of incomplete sequences
1286 invalidUTF8("case 6.15.1",
1287 "c0e080f08080f8808080fc80808080dfefbff7bfbffbbfbfbffdbfbfbfbf", isControlFrame);
1289 //6.16: impossible bytes
1290 invalidUTF8("case 6.16.1", "fe", isControlFrame);
1291 invalidUTF8("case 6.16.2", "ff", isControlFrame);
1292 invalidUTF8("case 6.16.3", "fefeffff", isControlFrame);
1294 //6.17: overlong ASCII characters
1295 invalidUTF8("case 6.17.1", "c0af", isControlFrame);
1296 invalidUTF8("case 6.17.2", "e080af", isControlFrame);
1297 invalidUTF8("case 6.17.3", "f08080af", isControlFrame);
1298 invalidUTF8("case 6.17.4", "f8808080af", isControlFrame);
1299 invalidUTF8("case 6.17.5", "fc80808080af", isControlFrame);
1301 //6.18: maximum overlong sequences
1302 invalidUTF8("case 6.18.1", "c1bf", isControlFrame);
1303 invalidUTF8("case 6.18.2", "e09fbf", isControlFrame);
1304 invalidUTF8("case 6.18.3", "f08fbfbf", isControlFrame);
1305 invalidUTF8("case 6.18.4", "f887bfbfbf", isControlFrame);
1306 invalidUTF8("case 6.18.5", "fc83bfbfbfbf", isControlFrame);
1308 //6.19: overlong presentation of the NUL character
1309 invalidUTF8("case 6.19.1", "c080", isControlFrame);
1310 invalidUTF8("case 6.19.2", "e08080", isControlFrame);
1311 invalidUTF8("case 6.19.3", "f0808080", isControlFrame);
1312 invalidUTF8("case 6.19.4", "f880808080", isControlFrame);
1313 invalidUTF8("case 6.19.5", "fc8080808080", isControlFrame);
1315 //6.20: Single UTF-16 surrogates
1316 invalidUTF8("case 6.20.1", "eda080", isControlFrame);
1317 invalidUTF8("case 6.20.2", "edadbf", isControlFrame);
1318 invalidUTF8("case 6.20.3", "edae80", isControlFrame);
1319 invalidUTF8("case 6.20.4", "edafbf", isControlFrame);
1320 invalidUTF8("case 6.20.5", "edb080", isControlFrame);
1321 invalidUTF8("case 6.20.6", "edbe80", isControlFrame);
1322 invalidUTF8("case 6.20.7", "edbfbf", isControlFrame);
1324 //6.21: Paired UTF-16 surrogates
1325 invalidUTF8("case 6.21.1", "eda080edb080", isControlFrame);
1326 invalidUTF8("case 6.21.2", "eda080edbfbf", isControlFrame);
1327 invalidUTF8("case 6.21.3", "edadbfedb080", isControlFrame);
1328 invalidUTF8("case 6.21.4", "edadbfedbfbf", isControlFrame);
1329 invalidUTF8("case 6.21.5", "edae80edb080", isControlFrame);
1330 invalidUTF8("case 6.21.6", "edae80edbfbf", isControlFrame);
1331 invalidUTF8("case 6.21.7", "edafbfedb080", isControlFrame);
1332 invalidUTF8("case 6.21.8", "edafbfedbfbf", isControlFrame);
1335 void tst_DataProcessor::invalidPayload()
1340 void tst_DataProcessor::invalidPayloadInCloseFrame_data()
1342 invalidPayload_data(true);
1345 void tst_DataProcessor::invalidPayloadInCloseFrame()
1347 QFETCH(quint8, firstByte);
1348 QFETCH(quint8, secondByte);
1349 QFETCH(QByteArray, payload);
1350 QFETCH(bool, isContinuationFrame);
1351 QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
1353 Q_UNUSED(isContinuationFrame)
1357 QWebSocketDataProcessor dataProcessor;
1358 QSignalSpy closeSpy(&dataProcessor,
1359 SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
1360 QSignalSpy errorSpy(&dataProcessor,
1361 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
1362 QSignalSpy pingMessageSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
1363 QSignalSpy pongMessageSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
1364 QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
1365 QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
1366 QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
1367 QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
1369 data.append(firstByte).append(secondByte);
1370 data.append(payload);
1371 buffer.setData(data);
1372 buffer.open(QIODevice::ReadOnly);
1373 dataProcessor.process(&buffer);
1374 QCOMPARE(closeSpy.count(), 1);
1375 QCOMPARE(errorSpy.count(), 0);
1376 QCOMPARE(pingMessageSpy.count(), 0);
1377 QCOMPARE(pongMessageSpy.count(), 0);
1378 QCOMPARE(textMessageSpy.count(), 0);
1379 QCOMPARE(binaryMessageSpy.count(), 0);
1380 QCOMPARE(textFrameSpy.count(), 0);
1381 QCOMPARE(binaryFrameSpy.count(), 0);
1382 QVariantList arguments = closeSpy.takeFirst();
1383 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), expectedCloseCode);
1387 void tst_DataProcessor::incompletePayload_data()
1389 QTest::addColumn<quint8>("firstByte");
1390 QTest::addColumn<quint8>("secondByte");
1391 QTest::addColumn<QByteArray>("payload");
1392 QTest::addColumn<bool>("isContinuationFrame");
1393 QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
1395 incompleteFrame(QWebSocketProtocol::OpCodeText, 125, 0);
1396 incompleteFrame(QWebSocketProtocol::OpCodeText, 64, 32);
1397 incompleteFrame(QWebSocketProtocol::OpCodeText, 256, 32);
1398 incompleteFrame(QWebSocketProtocol::OpCodeText, 128000, 32);
1399 incompleteFrame(QWebSocketProtocol::OpCodeBinary, 125, 0);
1400 incompleteFrame(QWebSocketProtocol::OpCodeBinary, 64, 32);
1401 incompleteFrame(QWebSocketProtocol::OpCodeBinary, 256, 32);
1402 incompleteFrame(QWebSocketProtocol::OpCodeBinary, 128000, 32);
1403 incompleteFrame(QWebSocketProtocol::OpCodeContinue, 125, 0);
1404 incompleteFrame(QWebSocketProtocol::OpCodeContinue, 64, 32);
1405 incompleteFrame(QWebSocketProtocol::OpCodeContinue, 256, 32);
1406 incompleteFrame(QWebSocketProtocol::OpCodeContinue, 128000, 32);
1408 incompleteFrame(QWebSocketProtocol::OpCodeClose, 64, 32);
1409 incompleteFrame(QWebSocketProtocol::OpCodePing, 64, 32);
1410 incompleteFrame(QWebSocketProtocol::OpCodePong, 64, 32);
1413 void tst_DataProcessor::incompletePayload()
1418 void tst_DataProcessor::incompleteSizeField_data()
1420 QTest::addColumn<quint8>("firstByte");
1421 QTest::addColumn<quint8>("secondByte");
1422 QTest::addColumn<QByteArray>("payload");
1423 QTest::addColumn<bool>("isContinuationFrame");
1424 QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
1426 //for a frame length value of 126
1427 //there should be 2 bytes following to form a 16-bit frame length
1428 insertIncompleteSizeFieldTest(126, 0);
1429 insertIncompleteSizeFieldTest(126, 1);
1431 //for a frame length value of 127
1432 //there should be 8 bytes following to form a 64-bit frame length
1433 insertIncompleteSizeFieldTest(127, 0);
1434 insertIncompleteSizeFieldTest(127, 1);
1435 insertIncompleteSizeFieldTest(127, 2);
1436 insertIncompleteSizeFieldTest(127, 3);
1437 insertIncompleteSizeFieldTest(127, 4);
1438 insertIncompleteSizeFieldTest(127, 5);
1439 insertIncompleteSizeFieldTest(127, 6);
1440 insertIncompleteSizeFieldTest(127, 7);
1443 void tst_DataProcessor::incompleteSizeField()
1448 //////////////////////////////////////////////////////////////////////////////////////////
1449 /// HELPER FUNCTIONS
1450 //////////////////////////////////////////////////////////////////////////////////////////
1451 void tst_DataProcessor::doTest()
1453 QFETCH(quint8, firstByte);
1454 QFETCH(quint8, secondByte);
1455 QFETCH(QByteArray, payload);
1456 QFETCH(bool, isContinuationFrame);
1457 QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
1461 QWebSocketDataProcessor dataProcessor;
1462 QSignalSpy errorSpy(&dataProcessor,
1463 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
1464 QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
1465 QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
1466 QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
1467 QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
1469 if (isContinuationFrame)
1471 data.append(quint8(QWebSocketProtocol::OpCodeText))
1473 .append(QByteArray(1, 'a'));
1475 data.append(firstByte).append(secondByte);
1476 data.append(payload);
1477 buffer.setData(data);
1478 buffer.open(QIODevice::ReadOnly);
1479 dataProcessor.process(&buffer);
1480 QCOMPARE(errorSpy.count(), 1);
1481 QCOMPARE(textMessageSpy.count(), 0);
1482 QCOMPARE(binaryMessageSpy.count(), 0);
1483 QCOMPARE(textFrameSpy.count(), isContinuationFrame ? 1 : 0);
1484 QCOMPARE(binaryFrameSpy.count(), 0);
1485 QVariantList arguments = errorSpy.takeFirst();
1486 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), expectedCloseCode);
1492 void tst_DataProcessor::doCloseFrameTest()
1494 QFETCH(quint8, firstByte);
1495 QFETCH(quint8, secondByte);
1496 QFETCH(QByteArray, payload);
1497 QFETCH(bool, isContinuationFrame);
1498 QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
1500 Q_UNUSED(isContinuationFrame)
1504 QWebSocketDataProcessor dataProcessor;
1505 QSignalSpy closeSpy(&dataProcessor,
1506 SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
1507 QSignalSpy errorSpy(&dataProcessor,
1508 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
1509 QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
1510 QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
1511 QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
1512 QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
1514 data.append(firstByte).append(secondByte);
1515 data.append(payload);
1516 buffer.setData(data);
1517 buffer.open(QIODevice::ReadOnly);
1518 dataProcessor.process(&buffer);
1519 QCOMPARE(closeSpy.count(), 1);
1520 QCOMPARE(errorSpy.count(), 0);
1521 QCOMPARE(textMessageSpy.count(), 0);
1522 QCOMPARE(binaryMessageSpy.count(), 0);
1523 QCOMPARE(textFrameSpy.count(), 0);
1524 QCOMPARE(binaryFrameSpy.count(), 0);
1525 QVariantList arguments = closeSpy.takeFirst();
1526 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), expectedCloseCode);
1530 QString tst_DataProcessor::opCodeToString(quint8 opCode)
1535 case QWebSocketProtocol::OpCodeBinary:
1537 frameType = QStringLiteral("Binary");
1540 case QWebSocketProtocol::OpCodeText:
1542 frameType = QStringLiteral("Text");
1545 case QWebSocketProtocol::OpCodePing:
1547 frameType = QStringLiteral("Ping");
1550 case QWebSocketProtocol::OpCodePong:
1552 frameType = QStringLiteral("Pong");
1555 case QWebSocketProtocol::OpCodeClose:
1557 frameType = QStringLiteral("Close");
1560 case QWebSocketProtocol::OpCodeContinue:
1562 frameType = QStringLiteral("Continuation");
1565 case QWebSocketProtocol::OpCodeReserved3:
1567 frameType = QStringLiteral("Reserved3");
1570 case QWebSocketProtocol::OpCodeReserved4:
1572 frameType = QStringLiteral("Reserved5");
1575 case QWebSocketProtocol::OpCodeReserved5:
1577 frameType = QStringLiteral("Reserved5");
1580 case QWebSocketProtocol::OpCodeReserved6:
1582 frameType = QStringLiteral("Reserved6");
1585 case QWebSocketProtocol::OpCodeReserved7:
1587 frameType = QStringLiteral("Reserved7");
1590 case QWebSocketProtocol::OpCodeReservedB:
1592 frameType = QStringLiteral("ReservedB");
1595 case QWebSocketProtocol::OpCodeReservedC:
1597 frameType = QStringLiteral("ReservedC");
1600 case QWebSocketProtocol::OpCodeReservedD:
1602 frameType = QStringLiteral("ReservedD");
1605 case QWebSocketProtocol::OpCodeReservedE:
1607 frameType = QStringLiteral("ReservedE");
1610 case QWebSocketProtocol::OpCodeReservedF:
1612 frameType = QStringLiteral("ReservedF");
1617 //should never come here
1624 void tst_DataProcessor::minimumSize16Bit(quint16 sizeInBytes)
1626 quint16 swapped16 = qToBigEndian<quint16>(sizeInBytes);
1627 const char *wireRepresentation
1628 = static_cast<const char *>(static_cast<const void *>(&swapped16));
1629 QTest::newRow(QStringLiteral("Text frame with payload size %1, represented in 2 bytes")
1630 .arg(sizeInBytes).toLatin1().constData())
1631 << quint8(FIN | QWebSocketProtocol::OpCodeText)
1633 << QByteArray(wireRepresentation, 2)
1635 << QWebSocketProtocol::CloseCodeProtocolError;
1636 QTest::newRow(QStringLiteral("Binary frame with payload size %1, represented in 2 bytes")
1637 .arg(sizeInBytes).toLatin1().constBegin())
1638 << quint8(FIN | QWebSocketProtocol::OpCodeBinary)
1640 << QByteArray(wireRepresentation, 2)
1642 << QWebSocketProtocol::CloseCodeProtocolError;
1643 QTest::newRow(QStringLiteral("Continuation frame with payload size %1, represented in 2 bytes")
1644 .arg(sizeInBytes).toLatin1().constData())
1645 << quint8(FIN | QWebSocketProtocol::OpCodeContinue)
1647 << QByteArray(wireRepresentation, 2)
1649 << QWebSocketProtocol::CloseCodeProtocolError;
1652 void tst_DataProcessor::minimumSize64Bit(quint64 sizeInBytes)
1654 quint64 swapped64 = qToBigEndian<quint64>(sizeInBytes);
1655 const char *wireRepresentation
1656 = static_cast<const char *>(static_cast<const void *>(&swapped64));
1658 QTest::newRow(QStringLiteral("Text frame with payload size %1, represented in 8 bytes")
1659 .arg(sizeInBytes).toLatin1().constData())
1660 << quint8(FIN | QWebSocketProtocol::OpCodeText)
1662 << QByteArray(wireRepresentation, 8)
1664 << QWebSocketProtocol::CloseCodeProtocolError;
1666 QTest::newRow(QStringLiteral("Binary frame with payload size %1, represented in 8 bytes")
1667 .arg(sizeInBytes).toLatin1().constData())
1668 << quint8(FIN | QWebSocketProtocol::OpCodeBinary)
1670 << QByteArray(wireRepresentation, 8)
1672 << QWebSocketProtocol::CloseCodeProtocolError;
1674 QTest::newRow(QStringLiteral("Continuation frame with payload size %1, represented in 8 bytes")
1675 .arg(sizeInBytes).toLatin1().constData())
1676 << quint8(FIN | QWebSocketProtocol::OpCodeContinue)
1678 << QByteArray(wireRepresentation, 8)
1680 << QWebSocketProtocol::CloseCodeProtocolError;
1683 void tst_DataProcessor::invalidUTF8(const char *dataTag, const char *utf8Sequence,
1686 QByteArray payload = QByteArray::fromHex(utf8Sequence);
1690 quint16 closeCode = qToBigEndian<quint16>(QWebSocketProtocol::CloseCodeNormal);
1691 const char *wireRepresentation
1692 = static_cast<const char *>(static_cast<const void *>(&closeCode));
1693 QTest::newRow(QStringLiteral("Close frame with invalid UTF8-sequence: %1")
1694 .arg(dataTag).toLatin1().constData())
1695 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1696 << quint8(payload.length() + 2)
1697 << QByteArray(wireRepresentation, 2).append(payload)
1699 << QWebSocketProtocol::CloseCodeWrongDatatype;
1703 QTest::newRow(QStringLiteral("Text frame with invalid UTF8-sequence: %1")
1704 .arg(dataTag).toLatin1().constData())
1705 << quint8(FIN | QWebSocketProtocol::OpCodeText)
1706 << quint8(payload.length())
1709 << QWebSocketProtocol::CloseCodeWrongDatatype;
1711 QTest::newRow(QStringLiteral("Continuation text frame with invalid UTF8-sequence: %1")
1712 .arg(dataTag).toLatin1().constData())
1713 << quint8(FIN | QWebSocketProtocol::OpCodeContinue)
1714 << quint8(payload.length())
1717 << QWebSocketProtocol::CloseCodeWrongDatatype;
1721 void tst_DataProcessor::invalidField(const char *dataTag, quint8 invalidFieldValue)
1723 QTest::newRow(dataTag) << quint8(FIN | invalidFieldValue)
1727 << QWebSocketProtocol::CloseCodeProtocolError;
1728 QTest::newRow(QString::fromLatin1(dataTag).append(QStringLiteral(" with continuation frame"))
1729 .toLatin1().constData())
1730 << quint8(FIN | invalidFieldValue)
1734 << QWebSocketProtocol::CloseCodeProtocolError;
1737 void tst_DataProcessor::incompleteFrame(quint8 controlCode, quint64 indicatedSize,
1738 quint64 actualPayloadSize)
1740 QVERIFY(!QWebSocketProtocol::isOpCodeReserved(QWebSocketProtocol::OpCode(controlCode)));
1741 QVERIFY(indicatedSize > actualPayloadSize);
1743 QString frameType = opCodeToString(controlCode);
1744 QByteArray firstFrame;
1746 if (indicatedSize < 126)
1748 //doing extensive QStringLiteral concatenations here, because
1749 //MSVC 2010 complains when using concatenation literal strings about
1750 //concatenation of wide and narrow strings (error C2308)
1751 QTest::newRow(frameType
1752 .append(QStringLiteral(" frame with payload size %1, but only %2 bytes") +
1753 QStringLiteral(" of data")
1754 .arg(indicatedSize).arg(actualPayloadSize)).toLatin1().constData())
1755 << quint8(FIN | controlCode)
1756 << quint8(indicatedSize)
1757 << firstFrame.append(QByteArray(actualPayloadSize, 'a'))
1758 << (controlCode == QWebSocketProtocol::OpCodeContinue)
1759 << QWebSocketProtocol::CloseCodeGoingAway;
1761 else if (indicatedSize <= 0xFFFFu)
1763 quint16 swapped16 = qToBigEndian<quint16>(static_cast<quint16>(indicatedSize));
1764 const char *wireRepresentation
1765 = static_cast<const char *>(static_cast<const void *>(&swapped16));
1767 frameType.append(QStringLiteral(" frame with payload size %1, but only ") +
1768 QStringLiteral("%2 bytes of data")
1770 .arg(actualPayloadSize)).toLatin1().constData())
1771 << quint8(FIN | controlCode)
1773 << firstFrame.append(QByteArray(wireRepresentation, 2)
1774 .append(QByteArray(actualPayloadSize, 'a')))
1775 << (controlCode == QWebSocketProtocol::OpCodeContinue)
1776 << QWebSocketProtocol::CloseCodeGoingAway;
1780 quint64 swapped64 = qToBigEndian<quint64>(indicatedSize);
1781 const char *wireRepresentation
1782 = static_cast<const char *>(static_cast<const void *>(&swapped64));
1783 QTest::newRow(frameType
1784 .append(QStringLiteral(" frame with payload size %1, but only %2 bytes ") +
1785 QStringLiteral("of data")
1786 .arg(indicatedSize).arg(actualPayloadSize)).toLatin1().constData())
1787 << quint8(FIN | controlCode)
1789 << firstFrame.append(QByteArray(wireRepresentation, 8)
1790 .append(QByteArray(actualPayloadSize, 'a')))
1791 << (controlCode == QWebSocketProtocol::OpCodeContinue)
1792 << QWebSocketProtocol::CloseCodeGoingAway;
1796 void tst_DataProcessor::nonCharacterSequence(const char *sequence)
1798 QByteArray utf8Sequence = QByteArray::fromHex(sequence);
1800 //doing extensive QStringLiteral concatenations here, because
1801 //MSVC 2010 complains when using concatenation literal strings about
1802 //concatenation of wide and narrow strings (error C2308)
1803 QTest::newRow((QStringLiteral("Text frame with payload containing the non-control character ") +
1804 QStringLiteral("sequence 0x%1"))
1805 .arg(QString::fromLocal8Bit(sequence)).toLatin1().constData())
1806 << quint8(FIN | QWebSocketProtocol::OpCodeText)
1807 << quint8(utf8Sequence.size())
1811 QTest::newRow((QStringLiteral("Continuation frame with payload containing the non-control ") +
1812 QStringLiteral("character sequence 0x%1"))
1813 .arg(QString::fromLocal8Bit(sequence)).toLatin1().constData())
1814 << quint8(FIN | QWebSocketProtocol::OpCodeContinue)
1815 << quint8(utf8Sequence.size())
1820 void tst_DataProcessor::insertIncompleteSizeFieldTest(quint8 payloadCode, quint8 numBytesFollowing)
1822 //doing extensive QStringLiteral concatenations here, because
1823 //MSVC 2010 complains when using concatenation literal strings about
1824 //concatenation of wide and narrow strings (error C2308)
1825 QTest::newRow(QStringLiteral("Text frame with payload size %1, with %2 bytes following.")
1826 .arg(payloadCode).arg(numBytesFollowing).toLatin1().constData())
1827 << quint8(FIN | QWebSocketProtocol::OpCodeText)
1828 << quint8(payloadCode)
1829 << QByteArray(numBytesFollowing, quint8(1))
1831 << QWebSocketProtocol::CloseCodeGoingAway;
1832 QTest::newRow(QStringLiteral("Binary frame with payload size %1, with %2 bytes following.")
1833 .arg(payloadCode).arg(numBytesFollowing).toLatin1().constData())
1834 << quint8(FIN | QWebSocketProtocol::OpCodeBinary)
1835 << quint8(payloadCode)
1836 << QByteArray(numBytesFollowing, quint8(1))
1838 << QWebSocketProtocol::CloseCodeGoingAway;
1839 QTest::newRow((QStringLiteral("Continuation frame with payload size %1, with %2 bytes ") +
1840 QStringLiteral("following."))
1841 .arg(payloadCode).arg(numBytesFollowing).toLatin1().constData())
1842 << quint8(FIN | QWebSocketProtocol::OpCodeContinue)
1843 << quint8(payloadCode)
1844 << QByteArray(numBytesFollowing, quint8(1))
1846 << QWebSocketProtocol::CloseCodeGoingAway;
1849 QTEST_MAIN(tst_DataProcessor)
1851 #include "tst_dataprocessor.moc"