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;
59 Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode)
60 Q_DECLARE_METATYPE(QWebSocketProtocol::OpCode)
62 class tst_DataProcessor : public QObject
71 void cleanupTestCase();
75 /***************************************************************************
77 ***************************************************************************/
79 Tests all kinds of valid binary frames, including zero length frames
81 void goodBinaryFrame();
82 void goodBinaryFrame_data();
85 Tests all kinds of valid text frames, including zero length frames
88 void goodTextFrame_data();
91 * Test all kinds of valid control frames.
93 void goodControlFrame();
96 * Test all kinds of valid close frames.
98 void goodCloseFrame();
99 void goodCloseFrame_data();
102 * Test all valid opcodes
105 void goodOpcodes_data();
108 Tests the QWebSocketDataProcessor for the correct handling of non-charactercodes
109 Due to a workaround in QTextCodec, non-characters are treated as illegal.
110 This workaround is not necessary anymore, and hence code should be changed in Qt
111 to allow non-characters again.
113 void nonCharacterCodes();
114 void nonCharacterCodes_data();
116 /***************************************************************************
118 ***************************************************************************/
120 Tests the QWebSocketDataProcessor for correct handling of frames that don't
121 contain the starting 2 bytes.
122 This test is a border case, where not enough bytes are received to even start parsing a
124 This test does not test sequences of frames, only single frames are tested
126 void frameTooSmall();
129 Tests the QWebSocketDataProcessor for correct handling of frames that are oversized.
130 This test does not test sequences of frames, only single frames are tested
133 void frameTooBig_data();
136 Tests the QWebSocketDataProcessor for the correct handling of malformed frame headers.
137 This test does not test sequences of frames, only single frames are tested
139 void invalidHeader();
140 void invalidHeader_data();
143 Tests the QWebSocketDataProcessor for the correct handling of invalid control frames.
144 Invalid means: payload bigger than 125, frame is fragmented, ...
145 This test does not test sequences of frames, only single frames are tested
147 void invalidControlFrame();
148 void invalidControlFrame_data();
150 void invalidCloseFrame();
151 void invalidCloseFrame_data();
154 Tests the QWebSocketDataProcessor for the correct handling of incomplete size fields
155 for large and big payloads.
157 void incompleteSizeField();
158 void incompleteSizeField_data();
161 Tests the QWebSocketDataProcessor for the correct handling of incomplete payloads.
163 - incomplete length bytes for large and big payloads (16- and 64-bit values),
164 - minimum size representation (see RFC 6455 paragraph 5.2),
165 - frames that are too large (larger than MAX_INT in bytes)
166 - incomplete payloads (less bytes than indicated in the size field)
167 This test does not test sequences of frames, only single frames are tested
169 void incompletePayload();
170 void incompletePayload_data();
173 Tests the QWebSocketDataProcessor for the correct handling of invalid UTF-8 payloads.
174 This test does not test sequences of frames, only single frames are tested
176 void invalidPayload();
177 void invalidPayload_data(bool isControlFrame = false);
179 void invalidPayloadInCloseFrame();
180 void invalidPayloadInCloseFrame_data();
183 Tests the QWebSocketDataProcessor for the correct handling of the minimum size representation
184 requirement of RFC 6455 (see paragraph 5.2)
186 void minimumSizeRequirement();
187 void minimumSizeRequirement_data();
190 //helper function that constructs a new row of test data for invalid UTF8 sequences
191 void invalidUTF8(const char *dataTag, const char *utf8Sequence, bool isCloseFrame);
192 //helper function that constructs a new row of test data for invalid leading field values
193 void invalidField(const char *dataTag, quint8 invalidFieldValue);
194 //helper functions that construct a new row of test data for size fields that do not adhere
195 //to the minimum size requirement
196 void minimumSize16Bit(quint16 sizeInBytes);
197 void minimumSize64Bit(quint64 sizeInBytes);
198 //helper function to construct a new row of test data containing frames with a payload size
199 //smaller than indicated in the header
200 void incompleteFrame(quint8 controlCode, quint64 indicatedSize, quint64 actualPayloadSize);
201 void insertIncompleteSizeFieldTest(quint8 payloadCode, quint8 numBytesFollowing);
203 //helper function to construct a new row of test data containing text frames containing
205 void nonCharacterSequence(const char *sequence);
208 void doCloseFrameTest();
210 QString opCodeToString(quint8 opCode);
213 tst_DataProcessor::tst_DataProcessor()
217 void tst_DataProcessor::initTestCase()
221 void tst_DataProcessor::cleanupTestCase()
225 void tst_DataProcessor::init()
227 qRegisterMetaType<QWebSocketProtocol::OpCode>("QWebSocketProtocol::OpCode");
228 qRegisterMetaType<QWebSocketProtocol::CloseCode>("QWebSocketProtocol::CloseCode");
231 void tst_DataProcessor::cleanup()
235 void tst_DataProcessor::goodBinaryFrame_data()
237 QTest::addColumn<QByteArray>("payload");
238 //be sure to get small (< 126 bytes), large (> 125 bytes & < 64K) and big (>64K) frames
239 for (int i = 0; i < (65536 + 256); i += 128)
241 QTest::newRow(QStringLiteral("Binary frame with %1 bytes").arg(i).toLatin1().constData())
242 << QByteArray(i, char(1));
244 for (int i = 0; i < 256; ++i) //test all possible bytes in the payload
246 QTest::newRow(QStringLiteral("Binary frame containing byte: '0x%1'")
247 .arg(QByteArray(1, char(i)).toHex().constData()).toLatin1().constData())
248 << QByteArray(i, char(1));
252 void tst_DataProcessor::goodBinaryFrame()
256 QWebSocketDataProcessor dataProcessor;
257 QFETCH(QByteArray, payload);
259 data.append((char)(FIN | QWebSocketProtocol::OpCodeBinary));
261 if (payload.length() < 126)
263 data.append(char(payload.length()));
265 else if (payload.length() < 65536)
267 quint16 swapped = qToBigEndian<quint16>(payload.length());
268 const char *wireRepresentation
269 = static_cast<const char *>(static_cast<const void *>(&swapped));
270 data.append(char(126)).append(wireRepresentation, 2);
274 quint64 swapped = qToBigEndian<quint64>(payload.length());
275 const char *wireRepresentation
276 = static_cast<const char *>(static_cast<const void *>(&swapped));
277 data.append(char(127)).append(wireRepresentation, 8);
280 data.append(payload);
281 buffer.setData(data);
282 buffer.open(QIODevice::ReadOnly);
284 QSignalSpy errorReceivedSpy(&dataProcessor,
285 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
286 QSignalSpy closeReceivedSpy(&dataProcessor,
287 SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
288 QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
289 QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
290 QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
291 QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
292 QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
293 QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
294 dataProcessor.process(&buffer);
295 QCOMPARE(errorReceivedSpy.count(), 0);
296 QCOMPARE(pingReceivedSpy.count(), 0);
297 QCOMPARE(pongReceivedSpy.count(), 0);
298 QCOMPARE(closeReceivedSpy.count(), 0);
299 QCOMPARE(binaryFrameReceivedSpy.count(), 1);
300 QCOMPARE(binaryMessageReceivedSpy.count(), 1);
301 QCOMPARE(textFrameReceivedSpy.count(), 0);
302 QCOMPARE(textMessageReceivedSpy.count(), 0);
303 QList<QVariant> arguments = binaryFrameReceivedSpy.takeFirst();
304 QCOMPARE(arguments.at(0).toByteArray().length(), payload.length());
305 arguments = binaryMessageReceivedSpy.takeFirst();
306 QCOMPARE(arguments.at(0).toByteArray().length(), payload.length());
310 void tst_DataProcessor::goodTextFrame_data()
312 QTest::addColumn<QByteArray>("payload");
313 QTest::addColumn<int>("size");
315 //test frames with small (< 126), large ( < 65536) and big ( > 65535) payloads
316 for (int i = 0; i < (65536 + 256); i += 128)
318 QTest::newRow(QStringLiteral("Text frame with %1 ASCII characters")
319 .arg(i).toLatin1().constData()) << QByteArray(i, 'a') << i;
321 //test all valid ASCII characters
322 for (int i = 0; i < 128; ++i)
324 QTest::newRow(QStringLiteral("Text frame with containing ASCII character '0x%1'")
325 .arg(QByteArray(1, char(i)).toHex().constData()).toLatin1().constData())
326 << QByteArray(1, char(i)) << 1;
329 //the text string reads: Text frame containing Hello-µ@ßöäüà á-UTF-8!!
330 //Visual Studio doesn't like UTF-8 in source code, so we use escape codes for the string
331 //The number 22 refers to the length of the string;
332 //the length was incorrectly calculated on Visual Studio
334 //doing extensive QStringLiteral concatenations here, because
335 //MSVC 2010 complains when using concatenation literal strings about
336 //concatenation of wide and narrow strings:
337 //error C2308: concatenating mismatched strings
338 QTest::newRow((QStringLiteral("Text frame containing Hello-") +
339 QStringLiteral("\xC2\xB5\x40\xC3\x9F\xC3\xB6\xC3\xA4\xC3\xBC\xC3\xA0") +
340 QStringLiteral("\xC3\xA1-UTF-8!!")).toLatin1().constData())
341 << QByteArray::fromHex("48656c6c6f2dc2b540c39fc3b6c3a4c3bcc3a0c3a12d5554462d382121")
345 void tst_DataProcessor::goodTextFrame()
349 QWebSocketDataProcessor dataProcessor;
350 QFETCH(QByteArray, payload);
353 data.append((char)(FIN | QWebSocketProtocol::OpCodeText));
355 if (payload.length() < 126)
357 data.append(char(payload.length()));
359 else if (payload.length() < 65536)
361 quint16 swapped = qToBigEndian<quint16>(payload.length());
362 const char *wireRepresentation
363 = static_cast<const char *>(static_cast<const void *>(&swapped));
364 data.append(char(126)).append(wireRepresentation, 2);
368 quint64 swapped = qToBigEndian<quint64>(payload.length());
369 const char *wireRepresentation
370 = static_cast<const char *>(static_cast<const void *>(&swapped));
371 data.append(char(127)).append(wireRepresentation, 8);
374 data.append(payload);
375 buffer.setData(data);
376 buffer.open(QIODevice::ReadOnly);
378 QSignalSpy errorReceivedSpy(&dataProcessor,
379 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
380 QSignalSpy closeReceivedSpy(&dataProcessor,
381 SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
382 QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
383 QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
384 QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
385 QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
386 QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
387 QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
389 dataProcessor.process(&buffer);
391 QCOMPARE(errorReceivedSpy.count(), 0);
392 QCOMPARE(pingReceivedSpy.count(), 0);
393 QCOMPARE(pongReceivedSpy.count(), 0);
394 QCOMPARE(closeReceivedSpy.count(), 0);
395 QCOMPARE(textFrameReceivedSpy.count(), 1);
396 QCOMPARE(textMessageReceivedSpy.count(), 1);
397 QCOMPARE(binaryFrameReceivedSpy.count(), 0);
398 QCOMPARE(binaryMessageReceivedSpy.count(), 0);
399 QList<QVariant> arguments = textFrameReceivedSpy.takeFirst();
400 QCOMPARE(arguments.at(0).toString().length(), size);
401 arguments = textMessageReceivedSpy.takeFirst();
402 QCOMPARE(arguments.at(0).toString().length(), size);
406 void tst_DataProcessor::goodControlFrame()
410 QWebSocketDataProcessor dataProcessor;
412 QSignalSpy closeFrameReceivedSpy(&dataProcessor,
413 SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
414 QSignalSpy errorReceivedSpy(&dataProcessor,
415 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
416 QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
417 QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
418 QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
419 QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
420 QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
421 QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
423 data.append((char)(FIN | QWebSocketProtocol::OpCodePing));
424 data.append(QChar::fromLatin1(0));
425 buffer.setData(data);
426 buffer.open(QIODevice::ReadOnly);
427 dataProcessor.process(&buffer);
428 QCOMPARE(errorReceivedSpy.count(), 0);
429 QCOMPARE(textFrameReceivedSpy.count(), 0);
430 QCOMPARE(textMessageReceivedSpy.count(), 0);
431 QCOMPARE(binaryFrameReceivedSpy.count(), 0);
432 QCOMPARE(binaryMessageReceivedSpy.count(), 0);
433 QCOMPARE(closeFrameReceivedSpy.count(), 0);
434 QCOMPARE(pongReceivedSpy.count(), 0);
435 QCOMPARE(pingReceivedSpy.count(), 1);
439 pingReceivedSpy.clear();
440 pongReceivedSpy.clear();
441 data.append((char)(FIN | QWebSocketProtocol::OpCodePong));
442 data.append(QChar::fromLatin1(0));
443 buffer.setData(data);
444 buffer.open(QIODevice::ReadOnly);
445 dataProcessor.process(&buffer);
446 QCOMPARE(errorReceivedSpy.count(), 0);
447 QCOMPARE(textFrameReceivedSpy.count(), 0);
448 QCOMPARE(textMessageReceivedSpy.count(), 0);
449 QCOMPARE(binaryFrameReceivedSpy.count(), 0);
450 QCOMPARE(binaryMessageReceivedSpy.count(), 0);
451 QCOMPARE(closeFrameReceivedSpy.count(), 0);
452 QCOMPARE(pingReceivedSpy.count(), 0);
453 QCOMPARE(pongReceivedSpy.count(), 1);
457 void tst_DataProcessor::goodCloseFrame_data()
459 QTest::addColumn<QString>("payload");
460 QTest::addColumn<QWebSocketProtocol::CloseCode>("closeCode");
461 //control frame data cannot exceed 125 bytes; smaller than 124,
462 //because we also need a 2 byte close code
463 for (int i = 0; i < 124; ++i)
465 QTest::newRow(QStringLiteral("Close frame with %1 ASCII characters")
466 .arg(i).toLatin1().constData())
468 << QWebSocketProtocol::CloseCodeNormal;
470 for (int i = 0; i < 126; ++i)
472 QTest::newRow(QStringLiteral("Text frame with containing ASCII character '0x%1'")
473 .arg(QByteArray(1, char(i)).toHex().constData()).toLatin1().constData())
474 << QString(1, char(i)) << QWebSocketProtocol::CloseCodeNormal;
476 QTest::newRow("Close frame with close code NORMAL")
477 << QString(1, 'a') << QWebSocketProtocol::CloseCodeNormal;
478 QTest::newRow("Close frame with close code BAD OPERATION")
479 << QString(1, 'a') << QWebSocketProtocol::CloseCodeBadOperation;
480 QTest::newRow("Close frame with close code DATATYPE NOT SUPPORTED")
481 << QString(1, 'a') << QWebSocketProtocol::CloseCodeDatatypeNotSupported;
482 QTest::newRow("Close frame with close code GOING AWAY")
483 << QString(1, 'a') << QWebSocketProtocol::CloseCodeGoingAway;
484 QTest::newRow("Close frame with close code MISSING EXTENSION")
485 << QString(1, 'a') << QWebSocketProtocol::CloseCodeMissingExtension;
486 QTest::newRow("Close frame with close code POLICY VIOLATED")
487 << QString(1, 'a') << QWebSocketProtocol::CloseCodePolicyViolated;
488 QTest::newRow("Close frame with close code PROTOCOL ERROR")
489 << QString(1, 'a') << QWebSocketProtocol::CloseCodeProtocolError;
490 QTest::newRow("Close frame with close code TOO MUCH DATA")
491 << QString(1, 'a') << QWebSocketProtocol::CloseCodeTooMuchData;
492 QTest::newRow("Close frame with close code WRONG DATATYPE")
493 << QString(1, 'a') << QWebSocketProtocol::CloseCodeWrongDatatype;
494 QTest::newRow("Close frame with close code 3000")
495 << QString(1, 'a') << QWebSocketProtocol::CloseCode(3000);
496 QTest::newRow("Close frame with close code 3999")
497 << QString(1, 'a') << QWebSocketProtocol::CloseCode(3999);
498 QTest::newRow("Close frame with close code 4000")
499 << QString(1, 'a') << QWebSocketProtocol::CloseCode(4000);
500 QTest::newRow("Close frame with close code 4999")
501 << QString(1, 'a') << QWebSocketProtocol::CloseCode(4999);
503 //close frames with no close reason
504 QTest::newRow("Close frame with close code NORMAL and no reason")
505 << QString() << QWebSocketProtocol::CloseCodeNormal;
506 QTest::newRow("Close frame with close code BAD OPERATION and no reason")
507 << QString() << QWebSocketProtocol::CloseCodeBadOperation;
508 QTest::newRow("Close frame with close code DATATYPE NOT SUPPORTED and no reason")
509 << QString() << QWebSocketProtocol::CloseCodeDatatypeNotSupported;
510 QTest::newRow("Close frame with close code GOING AWAY and no reason")
511 << QString() << QWebSocketProtocol::CloseCodeGoingAway;
512 QTest::newRow("Close frame with close code MISSING EXTENSION and no reason")
513 << QString() << QWebSocketProtocol::CloseCodeMissingExtension;
514 QTest::newRow("Close frame with close code POLICY VIOLATED and no reason")
515 << QString() << QWebSocketProtocol::CloseCodePolicyViolated;
516 QTest::newRow("Close frame with close code PROTOCOL ERROR and no reason")
517 << QString() << QWebSocketProtocol::CloseCodeProtocolError;
518 QTest::newRow("Close frame with close code TOO MUCH DATA and no reason")
519 << QString() << QWebSocketProtocol::CloseCodeTooMuchData;
520 QTest::newRow("Close frame with close code WRONG DATATYPE and no reason")
521 << QString() << QWebSocketProtocol::CloseCodeWrongDatatype;
522 QTest::newRow("Close frame with close code 3000 and no reason")
523 << QString() << QWebSocketProtocol::CloseCode(3000);
524 QTest::newRow("Close frame with close code 3999 and no reason")
525 << QString() << QWebSocketProtocol::CloseCode(3999);
526 QTest::newRow("Close frame with close code 4000 and no reason")
527 << QString() << QWebSocketProtocol::CloseCode(4000);
528 QTest::newRow("Close frame with close code 4999 and no reason")
529 << QString() << QWebSocketProtocol::CloseCode(4999);
531 QTest::newRow("Close frame with no close code and no reason")
532 << QString() << QWebSocketProtocol::CloseCode(0);
535 void tst_DataProcessor::goodOpcodes_data()
537 QTest::addColumn<QWebSocketProtocol::OpCode>("opCode");
539 QTest::newRow("Frame with PING opcode") << QWebSocketProtocol::OpCodePing;
540 QTest::newRow("Frame with PONG opcode") << QWebSocketProtocol::OpCodePong;
541 QTest::newRow("Frame with TEXT opcode") << QWebSocketProtocol::OpCodeText;
542 QTest::newRow("Frame with BINARY opcode") << QWebSocketProtocol::OpCodeBinary;
543 QTest::newRow("Frame with CLOSE opcode") << QWebSocketProtocol::OpCodeClose;
546 void tst_DataProcessor::goodOpcodes()
550 QWebSocketDataProcessor dataProcessor;
551 QFETCH(QWebSocketProtocol::OpCode, opCode);
553 data.append((char)(FIN | opCode));
554 data.append(char(0)); //zero length
556 buffer.setData(data);
557 buffer.open(QIODevice::ReadOnly);
559 QSignalSpy errorReceivedSpy(&dataProcessor,
560 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
561 QSignalSpy closeReceivedSpy(&dataProcessor,
562 SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
563 QSignalSpy pingReceivedSpy(&dataProcessor,
564 SIGNAL(pingReceived(QByteArray)));
565 QSignalSpy pongReceivedSpy(&dataProcessor,
566 SIGNAL(pongReceived(QByteArray)));
567 QSignalSpy textFrameReceivedSpy(&dataProcessor,
568 SIGNAL(textFrameReceived(QString,bool)));
569 QSignalSpy textMessageReceivedSpy(&dataProcessor,
570 SIGNAL(textMessageReceived(QString)));
571 QSignalSpy binaryFrameReceivedSpy(&dataProcessor,
572 SIGNAL(binaryFrameReceived(QByteArray,bool)));
573 QSignalSpy binaryMessageReceivedSpy(&dataProcessor,
574 SIGNAL(binaryMessageReceived(QByteArray)));
576 dataProcessor.process(&buffer);
578 QCOMPARE(errorReceivedSpy.count(), 0);
579 QCOMPARE(pingReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodePing ? 1 : 0);
580 QCOMPARE(pongReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodePong ? 1 : 0);
581 QCOMPARE(closeReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodeClose ? 1 : 0);
582 QCOMPARE(textFrameReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodeText ? 1 : 0);
583 QCOMPARE(textMessageReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodeText ? 1 : 0);
584 QCOMPARE(binaryFrameReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodeBinary ? 1 : 0);
585 QCOMPARE(binaryMessageReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodeBinary ? 1 : 0);
590 void tst_DataProcessor::goodCloseFrame()
594 QWebSocketDataProcessor dataProcessor;
595 QFETCH(QString, payload);
596 QFETCH(QWebSocketProtocol::CloseCode, closeCode);
597 quint16 swapped = qToBigEndian<quint16>(closeCode);
598 const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
600 data.append((char)(FIN | QWebSocketProtocol::OpCodeClose));
603 data.append(char(payload.length() + 2)).append(wireRepresentation, 2).append(payload);
607 data.append(QChar::fromLatin1(0)); //payload length 0;
608 //dataprocessor emits a CloseCodeNormal close code when none is present
609 closeCode = QWebSocketProtocol::CloseCodeNormal;
611 buffer.setData(data);
612 buffer.open(QIODevice::ReadOnly);
614 QSignalSpy errorReceivedSpy(&dataProcessor,
615 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
616 QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
617 QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
618 QSignalSpy closeFrameReceivedSpy(&dataProcessor,
619 SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
620 QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
621 QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
622 QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
623 QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
625 dataProcessor.process(&buffer);
627 QCOMPARE(errorReceivedSpy.count(), 0);
628 QCOMPARE(pingReceivedSpy.count(), 0);
629 QCOMPARE(pongReceivedSpy.count(), 0);
630 QCOMPARE(closeFrameReceivedSpy.count(), 1);
631 QCOMPARE(textFrameReceivedSpy.count(), 0);
632 QCOMPARE(textMessageReceivedSpy.count(), 0);
633 QCOMPARE(binaryFrameReceivedSpy.count(), 0);
634 QCOMPARE(binaryMessageReceivedSpy.count(), 0);
635 QList<QVariant> arguments = closeFrameReceivedSpy.takeFirst();
636 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), closeCode);
637 QCOMPARE(arguments.at(1).toString().length(), payload.length());
641 void tst_DataProcessor::nonCharacterCodes_data()
643 QTest::addColumn<quint8>("firstByte");
644 QTest::addColumn<quint8>("secondByte");
645 QTest::addColumn<QByteArray>("payload");
646 QTest::addColumn<bool>("isContinuationFrame");
648 nonCharacterSequence("efbfbe");
649 nonCharacterSequence("efbfbf");
650 nonCharacterSequence("f09fbfbe");
651 nonCharacterSequence("f09fbfbf");
652 nonCharacterSequence("f0afbfbe");
653 nonCharacterSequence("f0afbfbf");
654 nonCharacterSequence("f0bfbfbe");
655 nonCharacterSequence("f0bfbfbf");
656 nonCharacterSequence("f18fbfbe");
657 nonCharacterSequence("f18fbfbf");
658 nonCharacterSequence("f19fbfbe");
659 nonCharacterSequence("f19fbfbf");
660 nonCharacterSequence("f1afbfbe");
661 nonCharacterSequence("f1afbfbf");
662 nonCharacterSequence("f1bfbfbe");
663 nonCharacterSequence("f1bfbfbf");
664 nonCharacterSequence("f28fbfbe");
665 nonCharacterSequence("f28fbfbf");
666 nonCharacterSequence("f29fbfbe");
667 nonCharacterSequence("f29fbfbf");
668 nonCharacterSequence("f2afbfbe");
669 nonCharacterSequence("f2afbfbf");
670 nonCharacterSequence("f2bfbfbe");
671 nonCharacterSequence("f2bfbfbf");
672 nonCharacterSequence("f38fbfbe");
673 nonCharacterSequence("f38fbfbf");
674 nonCharacterSequence("f39fbfbe");
675 nonCharacterSequence("f39fbfbf");
676 nonCharacterSequence("f3afbfbe");
677 nonCharacterSequence("f3afbfbf");
678 nonCharacterSequence("f3bfbfbe");
679 nonCharacterSequence("f3bfbfbf");
680 nonCharacterSequence("f48fbfbe");
681 nonCharacterSequence("f48fbfbf");
684 void tst_DataProcessor::nonCharacterCodes()
686 QFETCH(quint8, firstByte);
687 QFETCH(quint8, secondByte);
688 QFETCH(QByteArray, payload);
689 QFETCH(bool, isContinuationFrame);
691 if (!isContinuationFrame)
695 QWebSocketDataProcessor dataProcessor;
696 QSignalSpy errorSpy(&dataProcessor,
697 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
698 QSignalSpy closeSpy(&dataProcessor,
699 SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
700 QSignalSpy pingFrameSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
701 QSignalSpy pongFrameSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
702 QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
703 QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
704 QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
705 QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
707 data.append(firstByte).append(secondByte);
708 data.append(payload);
709 buffer.setData(data);
710 buffer.open(QIODevice::ReadOnly);
711 dataProcessor.process(&buffer);
713 QCOMPARE(errorSpy.count(), 0);
714 QCOMPARE(closeSpy.count(), 0);
715 QCOMPARE(pingFrameSpy.count(), 0);
716 QCOMPARE(pongFrameSpy.count(), 0);
717 QCOMPARE(textFrameSpy.count(), 1);
718 QCOMPARE(textMessageSpy.count(), 1);
719 QCOMPARE(binaryFrameSpy.count(), 0);
720 QCOMPARE(binaryMessageSpy.count(), 0);
722 QVariantList arguments = textFrameSpy.takeFirst();
723 QCOMPARE(arguments.at(0).value<QString>().toUtf8(), payload);
724 QCOMPARE(arguments.at(1).value<bool>(), !isContinuationFrame);
725 arguments = textMessageSpy.takeFirst();
726 QCOMPARE(arguments.at(0).value<QString>().toUtf8(), payload);
731 void tst_DataProcessor::frameTooSmall()
735 QWebSocketDataProcessor dataProcessor;
736 QByteArray firstFrame;
738 firstFrame.append(quint8(QWebSocketProtocol::OpCodeText)).append(char(1))
739 .append(QByteArray(1, 'a'));
741 //with nothing in the buffer, the dataProcessor should time out
742 //and the error should be CloseCodeGoingAway meaning the socket will be closed
743 buffer.setData(data);
744 buffer.open(QIODevice::ReadOnly);
745 QSignalSpy errorSpy(&dataProcessor,
746 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
747 QSignalSpy closeSpy(&dataProcessor,
748 SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
749 QSignalSpy pingMessageSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
750 QSignalSpy pongMessageSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
751 QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
752 QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
753 QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
754 QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
756 dataProcessor.process(&buffer);
758 QCOMPARE(errorSpy.count(), 1);
759 QCOMPARE(closeSpy.count(), 0);
760 QCOMPARE(pingMessageSpy.count(), 0);
761 QCOMPARE(pongMessageSpy.count(), 0);
762 QCOMPARE(textMessageSpy.count(), 0);
763 QCOMPARE(binaryMessageSpy.count(), 0);
764 QCOMPARE(textFrameSpy.count(), 0);
765 QCOMPARE(binaryFrameSpy.count(), 0);
767 QList<QVariant> arguments = errorSpy.takeFirst();
768 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(),
769 QWebSocketProtocol::CloseCodeGoingAway);
772 pingMessageSpy.clear();
773 pongMessageSpy.clear();
774 textMessageSpy.clear();
775 binaryMessageSpy.clear();
776 textFrameSpy.clear();
777 binaryFrameSpy.clear();
781 //only one byte; this is far too little;
782 //should get a time out as well and the error should be CloseCodeGoingAway
783 //meaning the socket will be closed
784 data.append(quint8('1')); //put 1 byte in the buffer; this is too little
785 buffer.setData(data);
786 buffer.open(QIODevice::ReadOnly);
788 dataProcessor.process(&buffer);
790 QCOMPARE(errorSpy.count(), 1);
791 QCOMPARE(closeSpy.count(), 0);
792 QCOMPARE(pingMessageSpy.count(), 0);
793 QCOMPARE(pongMessageSpy.count(), 0);
794 QCOMPARE(textMessageSpy.count(), 0);
795 QCOMPARE(binaryMessageSpy.count(), 0);
796 QCOMPARE(textFrameSpy.count(), 0);
797 QCOMPARE(binaryFrameSpy.count(), 0);
799 arguments = errorSpy.takeFirst();
800 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(),
801 QWebSocketProtocol::CloseCodeGoingAway);
805 pingMessageSpy.clear();
806 pongMessageSpy.clear();
807 textMessageSpy.clear();
808 binaryMessageSpy.clear();
809 textFrameSpy.clear();
810 binaryFrameSpy.clear();
815 //text frame with final bit not set
816 data.append((char)(QWebSocketProtocol::OpCodeText)).append(char(0x0));
817 buffer.setData(data);
818 buffer.open(QIODevice::ReadOnly);
820 dataProcessor.process(&buffer);
825 //with nothing in the buffer,
826 //the dataProcessor should time out and the error should be CloseCodeGoingAway
827 //meaning the socket will be closed
828 buffer.setData(data);
829 buffer.open(QIODevice::ReadOnly);
830 QSignalSpy errorSpy(&dataProcessor,
831 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
832 dataProcessor.process(&buffer);
834 QCOMPARE(errorSpy.count(), 1);
835 QCOMPARE(closeSpy.count(), 0);
836 QCOMPARE(pingMessageSpy.count(), 0);
837 QCOMPARE(pongMessageSpy.count(), 0);
838 QCOMPARE(textMessageSpy.count(), 0);
839 QCOMPARE(binaryMessageSpy.count(), 0);
840 QCOMPARE(textFrameSpy.count(), 1);
841 QCOMPARE(binaryFrameSpy.count(), 0);
843 QList<QVariant> arguments = errorSpy.takeFirst();
844 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(),
845 QWebSocketProtocol::CloseCodeGoingAway);
848 pingMessageSpy.clear();
849 pongMessageSpy.clear();
850 textMessageSpy.clear();
851 binaryMessageSpy.clear();
852 textFrameSpy.clear();
853 binaryFrameSpy.clear();
857 //text frame with final bit not set
858 data.append((char)(QWebSocketProtocol::OpCodeText)).append(char(0x0));
859 buffer.setData(data);
860 buffer.open(QIODevice::ReadOnly);
861 dataProcessor.process(&buffer);
863 QCOMPARE(errorSpy.count(), 1);
864 QCOMPARE(closeSpy.count(), 0);
865 QCOMPARE(pingMessageSpy.count(), 0);
866 QCOMPARE(pongMessageSpy.count(), 0);
867 QCOMPARE(textMessageSpy.count(), 0);
868 QCOMPARE(binaryMessageSpy.count(), 0);
869 QCOMPARE(textFrameSpy.count(), 1);
870 QCOMPARE(binaryFrameSpy.count(), 0);
877 pingMessageSpy.clear();
878 pongMessageSpy.clear();
879 textMessageSpy.clear();
880 binaryMessageSpy.clear();
881 textFrameSpy.clear();
882 binaryFrameSpy.clear();
884 //only 1 byte follows in continuation frame;
885 //should time out with close code CloseCodeGoingAway
887 buffer.setData(data);
888 buffer.open(QIODevice::ReadOnly);
890 dataProcessor.process(&buffer);
891 QCOMPARE(errorSpy.count(), 1);
892 QCOMPARE(closeSpy.count(), 0);
893 QCOMPARE(pingMessageSpy.count(), 0);
894 QCOMPARE(pongMessageSpy.count(), 0);
895 QCOMPARE(textMessageSpy.count(), 0);
896 QCOMPARE(binaryMessageSpy.count(), 0);
897 QCOMPARE(textFrameSpy.count(), 0);
898 QCOMPARE(binaryFrameSpy.count(), 0);
899 arguments = errorSpy.takeFirst();
900 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(),
901 QWebSocketProtocol::CloseCodeGoingAway);
906 void tst_DataProcessor::frameTooBig_data()
908 QTest::addColumn<quint8>("firstByte");
909 QTest::addColumn<quint8>("secondByte");
910 QTest::addColumn<QByteArray>("payload");
911 QTest::addColumn<bool>("isContinuationFrame");
912 QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
914 quint64 swapped64 = 0;
915 const char *wireRepresentation = 0;
917 //only data frames are checked for being too big
918 //control frames have explicit checking on a maximum payload size of 125,
919 //which is tested elsewhere
921 swapped64 = qToBigEndian<quint64>(QWebSocketDataProcessor::maxFrameSize() + 1);
922 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
923 QTest::newRow("Text frame with payload size > INT_MAX")
924 << quint8(FIN | QWebSocketProtocol::OpCodeText)
926 << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a'))
928 << QWebSocketProtocol::CloseCodeTooMuchData;
930 swapped64 = qToBigEndian<quint64>(QWebSocketDataProcessor::maxFrameSize() + 1);
931 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
932 QTest::newRow("Binary frame with payload size > INT_MAX")
933 << quint8(FIN | QWebSocketProtocol::OpCodeBinary)
935 << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a'))
937 << QWebSocketProtocol::CloseCodeTooMuchData;
939 swapped64 = qToBigEndian<quint64>(QWebSocketDataProcessor::maxFrameSize() + 1);
940 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
941 QTest::newRow("Continuation frame with payload size > INT_MAX")
942 << quint8(FIN | QWebSocketProtocol::OpCodeContinue)
944 << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a'))
946 << QWebSocketProtocol::CloseCodeTooMuchData;
949 void tst_DataProcessor::frameTooBig()
954 void tst_DataProcessor::invalidHeader_data()
956 //The first byte contain the FIN, RSV1, RSV2, RSV3 and the Opcode
957 //The second byte contains the MaskFlag and the length of the frame
958 QTest::addColumn<quint8>("firstByte");
959 QTest::addColumn<quint8>("secondByte");
960 //superfluous, but present to be able to call doTest(), which expects a payload field
961 QTest::addColumn<QByteArray>("payload");
962 QTest::addColumn<bool>("isContinuationFrame");
963 QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
966 invalidField("RSV1 set", RSV1);
967 invalidField("RSV2 set", RSV2);
968 invalidField("RSV3 set", RSV3);
969 invalidField("RSV1 and RSV2 set", RSV1 | RSV2);
970 invalidField("RSV1 and RSV3 set", RSV1 | RSV3);
971 invalidField("RSV2 and RSV3 set", RSV2 | RSV3);
972 invalidField("RSV1, RSV2 and RSV3 set", RSV1 | RSV2 | RSV3);
975 invalidField("Invalid OpCode 3", QWebSocketProtocol::OpCodeReserved3);
976 invalidField("Invalid OpCode 4", QWebSocketProtocol::OpCodeReserved4);
977 invalidField("Invalid OpCode 5", QWebSocketProtocol::OpCodeReserved5);
978 invalidField("Invalid OpCode 6", QWebSocketProtocol::OpCodeReserved6);
979 invalidField("Invalid OpCode 7", QWebSocketProtocol::OpCodeReserved7);
980 invalidField("Invalid OpCode B", QWebSocketProtocol::OpCodeReservedB);
981 invalidField("Invalid OpCode C", QWebSocketProtocol::OpCodeReservedC);
982 invalidField("Invalid OpCode D", QWebSocketProtocol::OpCodeReservedD);
983 invalidField("Invalid OpCode E", QWebSocketProtocol::OpCodeReservedE);
984 invalidField("Invalid OpCode F", QWebSocketProtocol::OpCodeReservedF);
987 void tst_DataProcessor::invalidHeader()
992 void tst_DataProcessor::invalidControlFrame_data()
994 QTest::addColumn<quint8>("firstByte");
995 QTest::addColumn<quint8>("secondByte");
996 QTest::addColumn<QByteArray>("payload");
997 QTest::addColumn<bool>("isContinuationFrame");
998 QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
1001 QTest::newRow("Close control frame with payload size 126")
1002 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1006 << QWebSocketProtocol::CloseCodeProtocolError;
1007 QTest::newRow("Ping control frame with payload size 126")
1008 << quint8(FIN | QWebSocketProtocol::OpCodePing)
1012 << QWebSocketProtocol::CloseCodeProtocolError;
1013 QTest::newRow("Close control frame with payload size 126")
1014 << quint8(FIN | QWebSocketProtocol::OpCodePong)
1018 << QWebSocketProtocol::CloseCodeProtocolError;
1020 QTest::newRow("Non-final close control frame (fragmented)")
1021 << quint8(QWebSocketProtocol::OpCodeClose)
1025 << QWebSocketProtocol::CloseCodeProtocolError;
1026 QTest::newRow("Non-final ping control frame (fragmented)")
1027 << quint8(QWebSocketProtocol::OpCodePing)
1028 << quint8(32) << QByteArray()
1030 << QWebSocketProtocol::CloseCodeProtocolError;
1031 QTest::newRow("Non-final pong control frame (fragmented)")
1032 << quint8(QWebSocketProtocol::OpCodePong)
1036 << QWebSocketProtocol::CloseCodeProtocolError;
1039 void tst_DataProcessor::invalidControlFrame()
1044 void tst_DataProcessor::invalidCloseFrame_data()
1046 QTest::addColumn<quint8>("firstByte");
1047 QTest::addColumn<quint8>("secondByte");
1048 QTest::addColumn<QByteArray>("payload");
1049 QTest::addColumn<bool>("isContinuationFrame");
1050 QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
1052 QTest::newRow("Close control frame with payload size 1")
1053 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1055 << QByteArray(1, 'a')
1057 << QWebSocketProtocol::CloseCodeProtocolError;
1058 quint16 swapped = qToBigEndian<quint16>(QWebSocketProtocol::CloseCodeAbnormalDisconnection);
1059 const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1061 //Not allowed per RFC 6455 (see para 7.4.1)
1062 QTest::newRow("Close control frame close code ABNORMAL DISCONNECTION")
1063 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1065 << QByteArray(wireRepresentation, 2)
1067 << QWebSocketProtocol::CloseCodeProtocolError;
1068 swapped = qToBigEndian<quint16>(QWebSocketProtocol::CloseCodeMissingStatusCode);
1069 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1070 //Not allowed per RFC 6455 (see para 7.4.1)
1071 QTest::newRow("Close control frame close code MISSING STATUS CODE")
1072 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1074 << QByteArray(wireRepresentation, 2)
1076 << QWebSocketProtocol::CloseCodeProtocolError;
1077 swapped = qToBigEndian<quint16>(1004);
1078 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1079 QTest::newRow("Close control frame close code 1004")
1080 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1082 << QByteArray(wireRepresentation, 2)
1084 << QWebSocketProtocol::CloseCodeProtocolError;
1085 swapped = qToBigEndian<quint16>(QWebSocketProtocol::CloseCodeTlsHandshakeFailed);
1086 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1087 //Not allowed per RFC 6455 (see para 7.4.1)
1088 QTest::newRow("Close control frame close code TLS HANDSHAKE FAILED")
1089 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1091 << QByteArray(wireRepresentation, 2)
1093 << QWebSocketProtocol::CloseCodeProtocolError;
1094 swapped = qToBigEndian<quint16>(0);
1095 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1096 QTest::newRow("Close control frame close code 0")
1097 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1099 << QByteArray(wireRepresentation, 2)
1101 << QWebSocketProtocol::CloseCodeProtocolError;
1102 swapped = qToBigEndian<quint16>(999);
1103 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1104 QTest::newRow("Close control frame close code 999")
1105 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1107 << QByteArray(wireRepresentation, 2)
1109 << QWebSocketProtocol::CloseCodeProtocolError;
1110 swapped = qToBigEndian<quint16>(1012);
1111 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1112 QTest::newRow("Close control frame close code 1012")
1113 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1115 << QByteArray(wireRepresentation, 2)
1117 << QWebSocketProtocol::CloseCodeProtocolError;
1118 swapped = qToBigEndian<quint16>(1013);
1119 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1120 QTest::newRow("Close control frame close code 1013")
1121 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1123 << QByteArray(wireRepresentation, 2)
1125 << QWebSocketProtocol::CloseCodeProtocolError;
1126 swapped = qToBigEndian<quint16>(1014);
1127 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1128 QTest::newRow("Close control frame close code 1014")
1129 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1131 << QByteArray(wireRepresentation, 2)
1133 << QWebSocketProtocol::CloseCodeProtocolError;
1134 swapped = qToBigEndian<quint16>(1100);
1135 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1136 QTest::newRow("Close control frame close code 1100")
1137 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1139 << QByteArray(wireRepresentation, 2)
1141 << QWebSocketProtocol::CloseCodeProtocolError;
1142 swapped = qToBigEndian<quint16>(2000);
1143 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1144 QTest::newRow("Close control frame close code 2000")
1145 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1147 << QByteArray(wireRepresentation, 2)
1149 << QWebSocketProtocol::CloseCodeProtocolError;
1150 swapped = qToBigEndian<quint16>(2999);
1151 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1152 QTest::newRow("Close control frame close code 2999")
1153 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1155 << QByteArray(wireRepresentation, 2)
1157 << QWebSocketProtocol::CloseCodeProtocolError;
1158 swapped = qToBigEndian<quint16>(5000);
1159 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1160 QTest::newRow("Close control frame close code 5000")
1161 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1163 << QByteArray(wireRepresentation, 2)
1165 << QWebSocketProtocol::CloseCodeProtocolError;
1166 swapped = qToBigEndian<quint16>(65535u);
1167 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1168 QTest::newRow("Close control frame close code 65535")
1169 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1171 << QByteArray(wireRepresentation, 2)
1173 << QWebSocketProtocol::CloseCodeProtocolError;
1176 void tst_DataProcessor::invalidCloseFrame()
1181 void tst_DataProcessor::minimumSizeRequirement_data()
1183 QTest::addColumn<quint8>("firstByte");
1184 QTest::addColumn<quint8>("secondByte");
1185 QTest::addColumn<QByteArray>("payload");
1186 QTest::addColumn<bool>("isContinuationFrame");
1187 QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
1189 minimumSize16Bit(0);
1190 minimumSize16Bit(64);
1191 minimumSize16Bit(125);
1193 minimumSize64Bit(0);
1194 minimumSize64Bit(64);
1195 minimumSize64Bit(125);
1196 minimumSize64Bit(126);
1197 minimumSize64Bit(256);
1198 minimumSize64Bit(512);
1199 minimumSize64Bit(1024);
1200 minimumSize64Bit(2048);
1201 minimumSize64Bit(4096);
1202 minimumSize64Bit(8192);
1203 minimumSize64Bit(16384);
1204 minimumSize64Bit(32768);
1205 minimumSize64Bit(0xFFFFu);
1208 void tst_DataProcessor::minimumSizeRequirement()
1213 void tst_DataProcessor::invalidPayload_data(bool isControlFrame)
1215 QTest::addColumn<quint8>("firstByte");
1216 QTest::addColumn<quint8>("secondByte");
1217 QTest::addColumn<QByteArray>("payload");
1218 QTest::addColumn<bool>("isContinuationFrame");
1219 QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
1221 //6.3: invalid UTF-8 sequence
1222 invalidUTF8("case 6.3.1", "cebae1bdb9cf83cebcceb5eda080656469746564", isControlFrame);
1224 //6.4.: fail fast tests; invalid UTF-8 in middle of string
1225 invalidUTF8("case 6.4.1", "cebae1bdb9cf83cebcceb5f4908080656469746564", isControlFrame);
1226 invalidUTF8("case 6.4.4", "cebae1bdb9cf83cebcceb5eda080656469746564", isControlFrame);
1228 //6.6: All prefixes of a valid UTF-8 string that contains multi-byte code points
1229 invalidUTF8("case 6.6.1", "ce", isControlFrame);
1230 invalidUTF8("case 6.6.3", "cebae1", isControlFrame);
1231 invalidUTF8("case 6.6.4", "cebae1bd", isControlFrame);
1232 invalidUTF8("case 6.6.6", "cebae1bdb9cf", isControlFrame);
1233 invalidUTF8("case 6.6.8", "cebae1bdb9cf83ce", isControlFrame);
1234 invalidUTF8("case 6.6.10", "cebae1bdb9cf83cebcce", isControlFrame);
1236 //6.8: First possible sequence length 5/6 (invalid codepoints)
1237 invalidUTF8("case 6.8.1", "f888808080", isControlFrame);
1238 invalidUTF8("case 6.8.2", "fc8480808080", isControlFrame);
1240 //6.10: Last possible sequence length 4/5/6 (invalid codepoints)
1241 invalidUTF8("case 6.10.1", "f7bfbfbf", isControlFrame);
1242 invalidUTF8("case 6.10.2", "fbbfbfbfbf", isControlFrame);
1243 invalidUTF8("case 6.10.3", "fdbfbfbfbfbf", isControlFrame);
1245 //5.11: boundary conditions
1246 invalidUTF8("case 6.11.5", "f4908080", isControlFrame);
1248 //6.12: unexpected continuation bytes
1249 invalidUTF8("case 6.12.1", "80", isControlFrame);
1250 invalidUTF8("case 6.12.2", "bf", isControlFrame);
1251 invalidUTF8("case 6.12.3", "80bf", isControlFrame);
1252 invalidUTF8("case 6.12.4", "80bf80", isControlFrame);
1253 invalidUTF8("case 6.12.5", "80bf80bf", isControlFrame);
1254 invalidUTF8("case 6.12.6", "80bf80bf80", isControlFrame);
1255 invalidUTF8("case 6.12.7", "80bf80bf80bf", isControlFrame);
1256 invalidUTF8("case 6.12.8",
1257 "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a"
1258 "7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbe",
1261 //6.13: lonely start characters
1262 invalidUTF8("case 6.13.1",
1263 "c020c120c220c320c420c520c620c720c820c920ca20cb20cc20cd20ce20cf20d020d120d220"
1264 "d320d420d520d620d720d820d920da20db20dc20dd20de20",
1266 invalidUTF8("case 6.13.2", "e020e120e220e320e420e520e620e720e820e920ea20eb20ec20ed20ee20",
1268 invalidUTF8("case 6.13.3", "f020f120f220f320f420f520f620", isControlFrame);
1269 invalidUTF8("case 6.13.4", "f820f920fa20", isControlFrame);
1270 invalidUTF8("case 6.13.5", "fc20", isControlFrame);
1272 //6.14: sequences with last continuation byte missing
1273 invalidUTF8("case 6.14.1", "c0", isControlFrame);
1274 invalidUTF8("case 6.14.2", "e080", isControlFrame);
1275 invalidUTF8("case 6.14.3", "f08080", isControlFrame);
1276 invalidUTF8("case 6.14.4", "f8808080", isControlFrame);
1277 invalidUTF8("case 6.14.5", "fc80808080", isControlFrame);
1278 invalidUTF8("case 6.14.6", "df", isControlFrame);
1279 invalidUTF8("case 6.14.7", "efbf", isControlFrame);
1280 invalidUTF8("case 6.14.8", "f7bfbf", isControlFrame);
1281 invalidUTF8("case 6.14.9", "fbbfbfbf", isControlFrame);
1282 invalidUTF8("case 6.14.10", "fdbfbfbfbf", isControlFrame);
1284 //6.15: concatenation of incomplete sequences
1285 invalidUTF8("case 6.15.1",
1286 "c0e080f08080f8808080fc80808080dfefbff7bfbffbbfbfbffdbfbfbfbf", isControlFrame);
1288 //6.16: impossible bytes
1289 invalidUTF8("case 6.16.1", "fe", isControlFrame);
1290 invalidUTF8("case 6.16.2", "ff", isControlFrame);
1291 invalidUTF8("case 6.16.3", "fefeffff", isControlFrame);
1293 //6.17: overlong ASCII characters
1294 invalidUTF8("case 6.17.1", "c0af", isControlFrame);
1295 invalidUTF8("case 6.17.2", "e080af", isControlFrame);
1296 invalidUTF8("case 6.17.3", "f08080af", isControlFrame);
1297 invalidUTF8("case 6.17.4", "f8808080af", isControlFrame);
1298 invalidUTF8("case 6.17.5", "fc80808080af", isControlFrame);
1300 //6.18: maximum overlong sequences
1301 invalidUTF8("case 6.18.1", "c1bf", isControlFrame);
1302 invalidUTF8("case 6.18.2", "e09fbf", isControlFrame);
1303 invalidUTF8("case 6.18.3", "f08fbfbf", isControlFrame);
1304 invalidUTF8("case 6.18.4", "f887bfbfbf", isControlFrame);
1305 invalidUTF8("case 6.18.5", "fc83bfbfbfbf", isControlFrame);
1307 //6.19: overlong presentation of the NUL character
1308 invalidUTF8("case 6.19.1", "c080", isControlFrame);
1309 invalidUTF8("case 6.19.2", "e08080", isControlFrame);
1310 invalidUTF8("case 6.19.3", "f0808080", isControlFrame);
1311 invalidUTF8("case 6.19.4", "f880808080", isControlFrame);
1312 invalidUTF8("case 6.19.5", "fc8080808080", isControlFrame);
1314 //6.20: Single UTF-16 surrogates
1315 invalidUTF8("case 6.20.1", "eda080", isControlFrame);
1316 invalidUTF8("case 6.20.2", "edadbf", isControlFrame);
1317 invalidUTF8("case 6.20.3", "edae80", isControlFrame);
1318 invalidUTF8("case 6.20.4", "edafbf", isControlFrame);
1319 invalidUTF8("case 6.20.5", "edb080", isControlFrame);
1320 invalidUTF8("case 6.20.6", "edbe80", isControlFrame);
1321 invalidUTF8("case 6.20.7", "edbfbf", isControlFrame);
1323 //6.21: Paired UTF-16 surrogates
1324 invalidUTF8("case 6.21.1", "eda080edb080", isControlFrame);
1325 invalidUTF8("case 6.21.2", "eda080edbfbf", isControlFrame);
1326 invalidUTF8("case 6.21.3", "edadbfedb080", isControlFrame);
1327 invalidUTF8("case 6.21.4", "edadbfedbfbf", isControlFrame);
1328 invalidUTF8("case 6.21.5", "edae80edb080", isControlFrame);
1329 invalidUTF8("case 6.21.6", "edae80edbfbf", isControlFrame);
1330 invalidUTF8("case 6.21.7", "edafbfedb080", isControlFrame);
1331 invalidUTF8("case 6.21.8", "edafbfedbfbf", isControlFrame);
1334 void tst_DataProcessor::invalidPayload()
1339 void tst_DataProcessor::invalidPayloadInCloseFrame_data()
1341 invalidPayload_data(true);
1344 void tst_DataProcessor::invalidPayloadInCloseFrame()
1346 QFETCH(quint8, firstByte);
1347 QFETCH(quint8, secondByte);
1348 QFETCH(QByteArray, payload);
1349 QFETCH(bool, isContinuationFrame);
1350 QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
1352 Q_UNUSED(isContinuationFrame)
1356 QWebSocketDataProcessor dataProcessor;
1357 QSignalSpy closeSpy(&dataProcessor,
1358 SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
1359 QSignalSpy errorSpy(&dataProcessor,
1360 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
1361 QSignalSpy pingMessageSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
1362 QSignalSpy pongMessageSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
1363 QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
1364 QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
1365 QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
1366 QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
1368 data.append(firstByte).append(secondByte);
1369 data.append(payload);
1370 buffer.setData(data);
1371 buffer.open(QIODevice::ReadOnly);
1372 dataProcessor.process(&buffer);
1373 QCOMPARE(closeSpy.count(), 1);
1374 QCOMPARE(errorSpy.count(), 0);
1375 QCOMPARE(pingMessageSpy.count(), 0);
1376 QCOMPARE(pongMessageSpy.count(), 0);
1377 QCOMPARE(textMessageSpy.count(), 0);
1378 QCOMPARE(binaryMessageSpy.count(), 0);
1379 QCOMPARE(textFrameSpy.count(), 0);
1380 QCOMPARE(binaryFrameSpy.count(), 0);
1381 QVariantList arguments = closeSpy.takeFirst();
1382 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), expectedCloseCode);
1386 void tst_DataProcessor::incompletePayload_data()
1388 QTest::addColumn<quint8>("firstByte");
1389 QTest::addColumn<quint8>("secondByte");
1390 QTest::addColumn<QByteArray>("payload");
1391 QTest::addColumn<bool>("isContinuationFrame");
1392 QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
1394 incompleteFrame(QWebSocketProtocol::OpCodeText, 125, 0);
1395 incompleteFrame(QWebSocketProtocol::OpCodeText, 64, 32);
1396 incompleteFrame(QWebSocketProtocol::OpCodeText, 256, 32);
1397 incompleteFrame(QWebSocketProtocol::OpCodeText, 128000, 32);
1398 incompleteFrame(QWebSocketProtocol::OpCodeBinary, 125, 0);
1399 incompleteFrame(QWebSocketProtocol::OpCodeBinary, 64, 32);
1400 incompleteFrame(QWebSocketProtocol::OpCodeBinary, 256, 32);
1401 incompleteFrame(QWebSocketProtocol::OpCodeBinary, 128000, 32);
1402 incompleteFrame(QWebSocketProtocol::OpCodeContinue, 125, 0);
1403 incompleteFrame(QWebSocketProtocol::OpCodeContinue, 64, 32);
1404 incompleteFrame(QWebSocketProtocol::OpCodeContinue, 256, 32);
1405 incompleteFrame(QWebSocketProtocol::OpCodeContinue, 128000, 32);
1407 incompleteFrame(QWebSocketProtocol::OpCodeClose, 64, 32);
1408 incompleteFrame(QWebSocketProtocol::OpCodePing, 64, 32);
1409 incompleteFrame(QWebSocketProtocol::OpCodePong, 64, 32);
1412 void tst_DataProcessor::incompletePayload()
1417 void tst_DataProcessor::incompleteSizeField_data()
1419 QTest::addColumn<quint8>("firstByte");
1420 QTest::addColumn<quint8>("secondByte");
1421 QTest::addColumn<QByteArray>("payload");
1422 QTest::addColumn<bool>("isContinuationFrame");
1423 QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedCloseCode");
1425 //for a frame length value of 126
1426 //there should be 2 bytes following to form a 16-bit frame length
1427 insertIncompleteSizeFieldTest(126, 0);
1428 insertIncompleteSizeFieldTest(126, 1);
1430 //for a frame length value of 127
1431 //there should be 8 bytes following to form a 64-bit frame length
1432 insertIncompleteSizeFieldTest(127, 0);
1433 insertIncompleteSizeFieldTest(127, 1);
1434 insertIncompleteSizeFieldTest(127, 2);
1435 insertIncompleteSizeFieldTest(127, 3);
1436 insertIncompleteSizeFieldTest(127, 4);
1437 insertIncompleteSizeFieldTest(127, 5);
1438 insertIncompleteSizeFieldTest(127, 6);
1439 insertIncompleteSizeFieldTest(127, 7);
1442 void tst_DataProcessor::incompleteSizeField()
1447 //////////////////////////////////////////////////////////////////////////////////////////
1448 /// HELPER FUNCTIONS
1449 //////////////////////////////////////////////////////////////////////////////////////////
1450 void tst_DataProcessor::doTest()
1452 QFETCH(quint8, firstByte);
1453 QFETCH(quint8, secondByte);
1454 QFETCH(QByteArray, payload);
1455 QFETCH(bool, isContinuationFrame);
1456 QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
1460 QWebSocketDataProcessor dataProcessor;
1461 QSignalSpy errorSpy(&dataProcessor,
1462 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
1463 QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
1464 QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
1465 QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
1466 QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
1468 if (isContinuationFrame)
1470 data.append(quint8(QWebSocketProtocol::OpCodeText))
1472 .append(QByteArray(1, 'a'));
1474 data.append(firstByte).append(secondByte);
1475 data.append(payload);
1476 buffer.setData(data);
1477 buffer.open(QIODevice::ReadOnly);
1478 dataProcessor.process(&buffer);
1479 QCOMPARE(errorSpy.count(), 1);
1480 QCOMPARE(textMessageSpy.count(), 0);
1481 QCOMPARE(binaryMessageSpy.count(), 0);
1482 QCOMPARE(textFrameSpy.count(), isContinuationFrame ? 1 : 0);
1483 QCOMPARE(binaryFrameSpy.count(), 0);
1484 QVariantList arguments = errorSpy.takeFirst();
1485 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), expectedCloseCode);
1491 void tst_DataProcessor::doCloseFrameTest()
1493 QFETCH(quint8, firstByte);
1494 QFETCH(quint8, secondByte);
1495 QFETCH(QByteArray, payload);
1496 QFETCH(bool, isContinuationFrame);
1497 QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
1499 Q_UNUSED(isContinuationFrame)
1503 QWebSocketDataProcessor dataProcessor;
1504 QSignalSpy closeSpy(&dataProcessor,
1505 SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
1506 QSignalSpy errorSpy(&dataProcessor,
1507 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
1508 QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
1509 QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
1510 QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
1511 QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
1513 data.append(firstByte).append(secondByte);
1514 data.append(payload);
1515 buffer.setData(data);
1516 buffer.open(QIODevice::ReadOnly);
1517 dataProcessor.process(&buffer);
1518 QCOMPARE(closeSpy.count(), 1);
1519 QCOMPARE(errorSpy.count(), 0);
1520 QCOMPARE(textMessageSpy.count(), 0);
1521 QCOMPARE(binaryMessageSpy.count(), 0);
1522 QCOMPARE(textFrameSpy.count(), 0);
1523 QCOMPARE(binaryFrameSpy.count(), 0);
1524 QVariantList arguments = closeSpy.takeFirst();
1525 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), expectedCloseCode);
1529 QString tst_DataProcessor::opCodeToString(quint8 opCode)
1534 case QWebSocketProtocol::OpCodeBinary:
1536 frameType = QStringLiteral("Binary");
1539 case QWebSocketProtocol::OpCodeText:
1541 frameType = QStringLiteral("Text");
1544 case QWebSocketProtocol::OpCodePing:
1546 frameType = QStringLiteral("Ping");
1549 case QWebSocketProtocol::OpCodePong:
1551 frameType = QStringLiteral("Pong");
1554 case QWebSocketProtocol::OpCodeClose:
1556 frameType = QStringLiteral("Close");
1559 case QWebSocketProtocol::OpCodeContinue:
1561 frameType = QStringLiteral("Continuation");
1564 case QWebSocketProtocol::OpCodeReserved3:
1566 frameType = QStringLiteral("Reserved3");
1569 case QWebSocketProtocol::OpCodeReserved4:
1571 frameType = QStringLiteral("Reserved5");
1574 case QWebSocketProtocol::OpCodeReserved5:
1576 frameType = QStringLiteral("Reserved5");
1579 case QWebSocketProtocol::OpCodeReserved6:
1581 frameType = QStringLiteral("Reserved6");
1584 case QWebSocketProtocol::OpCodeReserved7:
1586 frameType = QStringLiteral("Reserved7");
1589 case QWebSocketProtocol::OpCodeReservedB:
1591 frameType = QStringLiteral("ReservedB");
1594 case QWebSocketProtocol::OpCodeReservedC:
1596 frameType = QStringLiteral("ReservedC");
1599 case QWebSocketProtocol::OpCodeReservedD:
1601 frameType = QStringLiteral("ReservedD");
1604 case QWebSocketProtocol::OpCodeReservedE:
1606 frameType = QStringLiteral("ReservedE");
1609 case QWebSocketProtocol::OpCodeReservedF:
1611 frameType = QStringLiteral("ReservedF");
1616 //should never come here
1623 void tst_DataProcessor::minimumSize16Bit(quint16 sizeInBytes)
1625 quint16 swapped16 = qToBigEndian<quint16>(sizeInBytes);
1626 const char *wireRepresentation
1627 = static_cast<const char *>(static_cast<const void *>(&swapped16));
1628 QTest::newRow(QStringLiteral("Text frame with payload size %1, represented in 2 bytes")
1629 .arg(sizeInBytes).toLatin1().constData())
1630 << quint8(FIN | QWebSocketProtocol::OpCodeText)
1632 << QByteArray(wireRepresentation, 2)
1634 << QWebSocketProtocol::CloseCodeProtocolError;
1635 QTest::newRow(QStringLiteral("Binary frame with payload size %1, represented in 2 bytes")
1636 .arg(sizeInBytes).toLatin1().constBegin())
1637 << quint8(FIN | QWebSocketProtocol::OpCodeBinary)
1639 << QByteArray(wireRepresentation, 2)
1641 << QWebSocketProtocol::CloseCodeProtocolError;
1642 QTest::newRow(QStringLiteral("Continuation frame with payload size %1, represented in 2 bytes")
1643 .arg(sizeInBytes).toLatin1().constData())
1644 << quint8(FIN | QWebSocketProtocol::OpCodeContinue)
1646 << QByteArray(wireRepresentation, 2)
1648 << QWebSocketProtocol::CloseCodeProtocolError;
1651 void tst_DataProcessor::minimumSize64Bit(quint64 sizeInBytes)
1653 quint64 swapped64 = qToBigEndian<quint64>(sizeInBytes);
1654 const char *wireRepresentation
1655 = static_cast<const char *>(static_cast<const void *>(&swapped64));
1657 QTest::newRow(QStringLiteral("Text frame with payload size %1, represented in 8 bytes")
1658 .arg(sizeInBytes).toLatin1().constData())
1659 << quint8(FIN | QWebSocketProtocol::OpCodeText)
1661 << QByteArray(wireRepresentation, 8)
1663 << QWebSocketProtocol::CloseCodeProtocolError;
1665 QTest::newRow(QStringLiteral("Binary frame with payload size %1, represented in 8 bytes")
1666 .arg(sizeInBytes).toLatin1().constData())
1667 << quint8(FIN | QWebSocketProtocol::OpCodeBinary)
1669 << QByteArray(wireRepresentation, 8)
1671 << QWebSocketProtocol::CloseCodeProtocolError;
1673 QTest::newRow(QStringLiteral("Continuation frame with payload size %1, represented in 8 bytes")
1674 .arg(sizeInBytes).toLatin1().constData())
1675 << quint8(FIN | QWebSocketProtocol::OpCodeContinue)
1677 << QByteArray(wireRepresentation, 8)
1679 << QWebSocketProtocol::CloseCodeProtocolError;
1682 void tst_DataProcessor::invalidUTF8(const char *dataTag, const char *utf8Sequence,
1685 QByteArray payload = QByteArray::fromHex(utf8Sequence);
1689 quint16 closeCode = qToBigEndian<quint16>(QWebSocketProtocol::CloseCodeNormal);
1690 const char *wireRepresentation
1691 = static_cast<const char *>(static_cast<const void *>(&closeCode));
1692 QTest::newRow(QStringLiteral("Close frame with invalid UTF8-sequence: %1")
1693 .arg(dataTag).toLatin1().constData())
1694 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1695 << quint8(payload.length() + 2)
1696 << QByteArray(wireRepresentation, 2).append(payload)
1698 << QWebSocketProtocol::CloseCodeWrongDatatype;
1702 QTest::newRow(QStringLiteral("Text frame with invalid UTF8-sequence: %1")
1703 .arg(dataTag).toLatin1().constData())
1704 << quint8(FIN | QWebSocketProtocol::OpCodeText)
1705 << quint8(payload.length())
1708 << QWebSocketProtocol::CloseCodeWrongDatatype;
1710 QTest::newRow(QStringLiteral("Continuation text frame with invalid UTF8-sequence: %1")
1711 .arg(dataTag).toLatin1().constData())
1712 << quint8(FIN | QWebSocketProtocol::OpCodeContinue)
1713 << quint8(payload.length())
1716 << QWebSocketProtocol::CloseCodeWrongDatatype;
1720 void tst_DataProcessor::invalidField(const char *dataTag, quint8 invalidFieldValue)
1722 QTest::newRow(dataTag) << quint8(FIN | invalidFieldValue)
1726 << QWebSocketProtocol::CloseCodeProtocolError;
1727 QTest::newRow(QString::fromLatin1(dataTag).append(QStringLiteral(" with continuation frame"))
1728 .toLatin1().constData())
1729 << quint8(FIN | invalidFieldValue)
1733 << QWebSocketProtocol::CloseCodeProtocolError;
1736 void tst_DataProcessor::incompleteFrame(quint8 controlCode, quint64 indicatedSize,
1737 quint64 actualPayloadSize)
1739 QVERIFY(!QWebSocketProtocol::isOpCodeReserved(QWebSocketProtocol::OpCode(controlCode)));
1740 QVERIFY(indicatedSize > actualPayloadSize);
1742 QString frameType = opCodeToString(controlCode);
1743 QByteArray firstFrame;
1745 if (indicatedSize < 126)
1747 //doing extensive QStringLiteral concatenations here, because
1748 //MSVC 2010 complains when using concatenation literal strings about
1749 //concatenation of wide and narrow strings (error C2308)
1750 QTest::newRow(frameType
1751 .append(QStringLiteral(" frame with payload size %1, but only %2 bytes") +
1752 QStringLiteral(" of data")
1753 .arg(indicatedSize).arg(actualPayloadSize)).toLatin1().constData())
1754 << quint8(FIN | controlCode)
1755 << quint8(indicatedSize)
1756 << firstFrame.append(QByteArray(actualPayloadSize, 'a'))
1757 << (controlCode == QWebSocketProtocol::OpCodeContinue)
1758 << QWebSocketProtocol::CloseCodeGoingAway;
1760 else if (indicatedSize <= 0xFFFFu)
1762 quint16 swapped16 = qToBigEndian<quint16>(static_cast<quint16>(indicatedSize));
1763 const char *wireRepresentation
1764 = static_cast<const char *>(static_cast<const void *>(&swapped16));
1766 frameType.append(QStringLiteral(" frame with payload size %1, but only ") +
1767 QStringLiteral("%2 bytes of data")
1769 .arg(actualPayloadSize)).toLatin1().constData())
1770 << quint8(FIN | controlCode)
1772 << firstFrame.append(QByteArray(wireRepresentation, 2)
1773 .append(QByteArray(actualPayloadSize, 'a')))
1774 << (controlCode == QWebSocketProtocol::OpCodeContinue)
1775 << QWebSocketProtocol::CloseCodeGoingAway;
1779 quint64 swapped64 = qToBigEndian<quint64>(indicatedSize);
1780 const char *wireRepresentation
1781 = static_cast<const char *>(static_cast<const void *>(&swapped64));
1782 QTest::newRow(frameType
1783 .append(QStringLiteral(" frame with payload size %1, but only %2 bytes ") +
1784 QStringLiteral("of data")
1785 .arg(indicatedSize).arg(actualPayloadSize)).toLatin1().constData())
1786 << quint8(FIN | controlCode)
1788 << firstFrame.append(QByteArray(wireRepresentation, 8)
1789 .append(QByteArray(actualPayloadSize, 'a')))
1790 << (controlCode == QWebSocketProtocol::OpCodeContinue)
1791 << QWebSocketProtocol::CloseCodeGoingAway;
1795 void tst_DataProcessor::nonCharacterSequence(const char *sequence)
1797 QByteArray utf8Sequence = QByteArray::fromHex(sequence);
1799 //doing extensive QStringLiteral concatenations here, because
1800 //MSVC 2010 complains when using concatenation literal strings about
1801 //concatenation of wide and narrow strings (error C2308)
1802 QTest::newRow((QStringLiteral("Text frame with payload containing the non-control character ") +
1803 QStringLiteral("sequence 0x%1"))
1804 .arg(QString::fromLocal8Bit(sequence)).toLatin1().constData())
1805 << quint8(FIN | QWebSocketProtocol::OpCodeText)
1806 << quint8(utf8Sequence.size())
1810 QTest::newRow((QStringLiteral("Continuation frame with payload containing the non-control ") +
1811 QStringLiteral("character sequence 0x%1"))
1812 .arg(QString::fromLocal8Bit(sequence)).toLatin1().constData())
1813 << quint8(FIN | QWebSocketProtocol::OpCodeContinue)
1814 << quint8(utf8Sequence.size())
1819 void tst_DataProcessor::insertIncompleteSizeFieldTest(quint8 payloadCode, quint8 numBytesFollowing)
1821 //doing extensive QStringLiteral concatenations here, because
1822 //MSVC 2010 complains when using concatenation literal strings about
1823 //concatenation of wide and narrow strings (error C2308)
1824 QTest::newRow(QStringLiteral("Text frame with payload size %1, with %2 bytes following.")
1825 .arg(payloadCode).arg(numBytesFollowing).toLatin1().constData())
1826 << quint8(FIN | QWebSocketProtocol::OpCodeText)
1827 << quint8(payloadCode)
1828 << QByteArray(numBytesFollowing, quint8(1))
1830 << QWebSocketProtocol::CloseCodeGoingAway;
1831 QTest::newRow(QStringLiteral("Binary frame with payload size %1, with %2 bytes following.")
1832 .arg(payloadCode).arg(numBytesFollowing).toLatin1().constData())
1833 << quint8(FIN | QWebSocketProtocol::OpCodeBinary)
1834 << quint8(payloadCode)
1835 << QByteArray(numBytesFollowing, quint8(1))
1837 << QWebSocketProtocol::CloseCodeGoingAway;
1838 QTest::newRow((QStringLiteral("Continuation frame with payload size %1, with %2 bytes ") +
1839 QStringLiteral("following."))
1840 .arg(payloadCode).arg(numBytesFollowing).toLatin1().constData())
1841 << quint8(FIN | QWebSocketProtocol::OpCodeContinue)
1842 << quint8(payloadCode)
1843 << QByteArray(numBytesFollowing, quint8(1))
1845 << QWebSocketProtocol::CloseCodeGoingAway;
1848 QTEST_MAIN(tst_DataProcessor)
1850 #include "tst_dataprocessor.moc"