1/****************************************************************************
2**
3** Copyright (C) 2016 Kurt Pattyn <pattyn.kurt@gmail.com>.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
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 The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28#include <QtTest/QtTest>
29#include <QtTest/qtestcase.h>
30#include <QtTest/QSignalSpy>
31#include <QtCore/QBuffer>
32#include <QtCore/QByteArray>
33#include <QtCore/QDebug>
34
35#include "private/qwebsocketdataprocessor_p.h"
36#include "private/qwebsocketprotocol_p.h"
37#include "QtWebSockets/qwebsocketprotocol.h"
38
39const quint8 FIN = 0x80;
40const quint8 RSV1 = 0x40;
41const quint8 RSV2 = 0x30;
42const quint8 RSV3 = 0x10;
43
44QT_USE_NAMESPACE
45
46Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode)
47Q_DECLARE_METATYPE(QWebSocketProtocol::OpCode)
48
49class tst_DataProcessor : public QObject
50{
51 Q_OBJECT
52
53public:
54 tst_DataProcessor();
55
56private Q_SLOTS:
57 void initTestCase();
58 void cleanupTestCase();
59 void init();
60 void cleanup();
61
62 /***************************************************************************
63 * Happy Flows
64 ***************************************************************************/
65 /*!
66 Tests all kinds of valid binary frames, including zero length frames
67 */
68 void goodBinaryFrame();
69 void goodBinaryFrame_data();
70
71 /*!
72 Tests all kinds of valid text frames, including zero length frames
73 */
74 void goodTextFrame();
75 void goodTextFrame_data();
76
77 /*!
78 * Test all kinds of valid control frames.
79 */
80 void goodControlFrame();
81
82 /*!
83 * Test all kinds of valid close frames.
84 */
85 void goodCloseFrame();
86 void goodCloseFrame_data();
87
88 /*!
89 * Test all valid opcodes
90 */
91 void goodOpcodes();
92 void goodOpcodes_data();
93
94 /*!
95 Tests the QWebSocketDataProcessor for the correct handling of non-charactercodes
96 Due to a workaround in QTextCodec, non-characters are treated as illegal.
97 This workaround is not necessary anymore, and hence code should be changed in Qt
98 to allow non-characters again.
99 */
100 void nonCharacterCodes();
101 void nonCharacterCodes_data();
102
103 /***************************************************************************
104 * Rainy Day Flows
105 ***************************************************************************/
106 /*!
107 Tests the QWebSocketDataProcessor for correct handling of frames that don't
108 contain the starting 2 bytes.
109 This test is a border case, where not enough bytes are received to even start parsing a
110 frame.
111 This test does not test sequences of frames, only single frames are tested
112 */
113 void frameTooSmall();
114
115 /*!
116 Tests the QWebSocketDataProcessor for correct handling of frames that are oversized.
117 This test does not test sequences of frames, only single frames are tested
118 */
119 void frameTooBig();
120 void frameTooBig_data();
121
122 /*!
123 Tests the QWebSocketDataProcessor for the correct handling of malformed frame headers.
124 This test does not test sequences of frames, only single frames are tested
125 */
126 void invalidHeader();
127 void invalidHeader_data();
128
129 /*!
130 Tests the QWebSocketDataProcessor for the correct handling of invalid control frames.
131 Invalid means: payload bigger than 125, frame is fragmented, ...
132 This test does not test sequences of frames, only single frames are tested
133 */
134 void invalidControlFrame();
135 void invalidControlFrame_data();
136
137 void invalidCloseFrame();
138 void invalidCloseFrame_data();
139
140 /*!
141 Tests the QWebSocketDataProcessor for the correct handling of incomplete size fields
142 for large and big payloads.
143 */
144 void incompleteSizeField();
145 void incompleteSizeField_data();
146
147 /*!
148 Tests the QWebSocketDataProcessor for the correct handling of incomplete payloads.
149 This includes:
150 - incomplete length bytes for large and big payloads (16- and 64-bit values),
151 - minimum size representation (see RFC 6455 paragraph 5.2),
152 - frames that are too large (larger than MAX_INT in bytes)
153 - incomplete payloads (less bytes than indicated in the size field)
154 This test does not test sequences of frames, only single frames are tested
155 */
156 void incompletePayload();
157 void incompletePayload_data();
158
159 /*!
160 Tests the QWebSocketDataProcessor for the correct handling of invalid UTF-8 payloads.
161 This test does not test sequences of frames, only single frames are tested
162 */
163 void invalidPayload();
164 void invalidPayload_data(bool isControlFrame = false);
165
166 void invalidPayloadInCloseFrame();
167 void invalidPayloadInCloseFrame_data();
168
169 /*!
170 Tests the QWebSocketDataProcessor for the correct handling of the minimum size representation
171 requirement of RFC 6455 (see paragraph 5.2)
172 */
173 void minimumSizeRequirement();
174 void minimumSizeRequirement_data();
175
176 void clearDataBuffers(); // qtbug-55506
177
178private:
179 //helper function that constructs a new row of test data for invalid UTF8 sequences
180 void invalidUTF8(const char *dataTag, const char *utf8Sequence, bool isCloseFrame);
181 //helper function that constructs a new row of test data for invalid leading field values
182 void invalidField(const char *dataTag, quint8 invalidFieldValue);
183 //helper functions that construct a new row of test data for size fields that do not adhere
184 //to the minimum size requirement
185 void minimumSize16Bit(quint16 sizeInBytes);
186 void minimumSize64Bit(quint64 sizeInBytes);
187 //helper function to construct a new row of test data containing frames with a payload size
188 //smaller than indicated in the header
189 void incompleteFrame(quint8 controlCode, quint64 indicatedSize, quint64 actualPayloadSize);
190 void insertIncompleteSizeFieldTest(quint8 payloadCode, quint8 numBytesFollowing);
191
192 //helper function to construct a new row of test data containing text frames containing
193 //sequences
194 void nonCharacterSequence(const char *sequence);
195
196 void doTest(int timeout = 0);
197 void doCloseFrameTest();
198
199 QString opCodeToString(quint8 opCode);
200};
201
202tst_DataProcessor::tst_DataProcessor()
203{
204}
205
206void tst_DataProcessor::initTestCase()
207{
208}
209
210void tst_DataProcessor::cleanupTestCase()
211{
212}
213
214void tst_DataProcessor::init()
215{
216 qRegisterMetaType<QWebSocketProtocol::OpCode>(typeName: "QWebSocketProtocol::OpCode");
217 qRegisterMetaType<QWebSocketProtocol::CloseCode>(typeName: "QWebSocketProtocol::CloseCode");
218}
219
220void tst_DataProcessor::cleanup()
221{
222}
223
224void tst_DataProcessor::goodBinaryFrame_data()
225{
226 QTest::addColumn<QByteArray>(name: "payload");
227 //be sure to get small (< 126 bytes), large (> 125 bytes & < 64K) and big (>64K) frames
228 for (int i = 0; i < (65536 + 256); i += 128)
229 {
230 QTest::newRow(QStringLiteral("Binary frame with %1 bytes").arg(a: i).toLatin1().constData())
231 << QByteArray(i, char(1));
232 }
233 for (int i = 0; i < 256; ++i) //test all possible bytes in the payload
234 {
235 QTest::newRow(QStringLiteral("Binary frame containing byte: '0x%1'")
236 .arg(a: QByteArray(1, char(i)).toHex().constData()).toLatin1().constData())
237 << QByteArray(i, char(1));
238 }
239}
240
241void tst_DataProcessor::goodBinaryFrame()
242{
243 QByteArray data;
244 QBuffer buffer;
245 QWebSocketDataProcessor dataProcessor;
246 QFETCH(QByteArray, payload);
247
248 data.append(c: char(FIN | QWebSocketProtocol::OpCodeBinary));
249
250 if (payload.length() < 126)
251 {
252 data.append(c: char(payload.length()));
253 }
254 else if (payload.length() < 65536)
255 {
256 quint16 swapped = qToBigEndian<quint16>(source: payload.length());
257 const char *wireRepresentation
258 = static_cast<const char *>(static_cast<const void *>(&swapped));
259 data.append(c: char(126)).append(s: wireRepresentation, len: 2);
260 }
261 else
262 {
263 quint64 swapped = qToBigEndian<quint64>(source: payload.length());
264 const char *wireRepresentation
265 = static_cast<const char *>(static_cast<const void *>(&swapped));
266 data.append(c: char(127)).append(s: wireRepresentation, len: 8);
267 }
268
269 data.append(a: payload);
270 buffer.setData(data);
271 buffer.open(openMode: QIODevice::ReadOnly);
272
273 QSignalSpy errorReceivedSpy(&dataProcessor,
274 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
275 QSignalSpy closeReceivedSpy(&dataProcessor,
276 SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
277 QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
278 QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
279 QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
280 QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
281 QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
282 QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
283 dataProcessor.process(pIoDevice: &buffer);
284 QCOMPARE(errorReceivedSpy.count(), 0);
285 QCOMPARE(pingReceivedSpy.count(), 0);
286 QCOMPARE(pongReceivedSpy.count(), 0);
287 QCOMPARE(closeReceivedSpy.count(), 0);
288 QCOMPARE(binaryFrameReceivedSpy.count(), 1);
289 QCOMPARE(binaryMessageReceivedSpy.count(), 1);
290 QCOMPARE(textFrameReceivedSpy.count(), 0);
291 QCOMPARE(textMessageReceivedSpy.count(), 0);
292 QList<QVariant> arguments = binaryFrameReceivedSpy.takeFirst();
293 QCOMPARE(arguments.at(0).toByteArray().length(), payload.length());
294 arguments = binaryMessageReceivedSpy.takeFirst();
295 QCOMPARE(arguments.at(0).toByteArray().length(), payload.length());
296 buffer.close();
297}
298
299void tst_DataProcessor::goodTextFrame_data()
300{
301 QTest::addColumn<QByteArray>(name: "payload");
302 QTest::addColumn<int>(name: "size");
303
304 //test frames with small (< 126), large ( < 65536) and big ( > 65535) payloads
305 for (int i = 0; i < (65536 + 256); i += 128)
306 {
307 QTest::newRow(QStringLiteral("Text frame with %1 ASCII characters")
308 .arg(a: i).toLatin1().constData()) << QByteArray(i, 'a') << i;
309 }
310 //test all valid ASCII characters
311 for (int i = 0; i < 128; ++i)
312 {
313 QTest::newRow(QStringLiteral("Text frame with containing ASCII character '0x%1'")
314 .arg(a: QByteArray(1, char(i)).toHex().constData()).toLatin1().constData())
315 << QByteArray(1, char(i)) << 1;
316 }
317
318 //the text string reads: Text frame containing Hello-µ@ßöäüàá-UTF-8!!
319 //Visual Studio doesn't like UTF-8 in source code, so we use escape codes for the string
320 //The number 22 refers to the length of the string;
321 //the length was incorrectly calculated on Visual Studio
322
323 //doing extensive QStringLiteral concatenations here, because
324 //MSVC 2010 complains when using concatenation literal strings about
325 //concatenation of wide and narrow strings:
326 //error C2308: concatenating mismatched strings
327 QTest::newRow(dataTag: (QStringLiteral("Text frame containing Hello-") +
328 QStringLiteral("\xC2\xB5\x40\xC3\x9F\xC3\xB6\xC3\xA4\xC3\xBC\xC3\xA0") +
329 QStringLiteral("\xC3\xA1-UTF-8!!")).toUtf8().constData())
330 << QByteArray::fromHex(hexEncoded: "48656c6c6f2dc2b540c39fc3b6c3a4c3bcc3a0c3a12d5554462d382121")
331 << 22;
332}
333
334void tst_DataProcessor::goodTextFrame()
335{
336 QByteArray data;
337 QBuffer buffer;
338 QWebSocketDataProcessor dataProcessor;
339 QFETCH(QByteArray, payload);
340 QFETCH(int, size);
341
342 data.append(c: char(FIN | QWebSocketProtocol::OpCodeText));
343
344 if (payload.length() < 126)
345 {
346 data.append(c: char(payload.length()));
347 }
348 else if (payload.length() < 65536)
349 {
350 quint16 swapped = qToBigEndian<quint16>(source: payload.length());
351 const char *wireRepresentation
352 = static_cast<const char *>(static_cast<const void *>(&swapped));
353 data.append(c: char(126)).append(s: wireRepresentation, len: 2);
354 }
355 else
356 {
357 quint64 swapped = qToBigEndian<quint64>(source: payload.length());
358 const char *wireRepresentation
359 = static_cast<const char *>(static_cast<const void *>(&swapped));
360 data.append(c: char(127)).append(s: wireRepresentation, len: 8);
361 }
362
363 data.append(a: payload);
364 buffer.setData(data);
365 buffer.open(openMode: QIODevice::ReadOnly);
366
367 QSignalSpy errorReceivedSpy(&dataProcessor,
368 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
369 QSignalSpy closeReceivedSpy(&dataProcessor,
370 SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
371 QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
372 QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
373 QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
374 QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
375 QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
376 QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
377
378 dataProcessor.process(pIoDevice: &buffer);
379
380 QCOMPARE(errorReceivedSpy.count(), 0);
381 QCOMPARE(pingReceivedSpy.count(), 0);
382 QCOMPARE(pongReceivedSpy.count(), 0);
383 QCOMPARE(closeReceivedSpy.count(), 0);
384 QCOMPARE(textFrameReceivedSpy.count(), 1);
385 QCOMPARE(textMessageReceivedSpy.count(), 1);
386 QCOMPARE(binaryFrameReceivedSpy.count(), 0);
387 QCOMPARE(binaryMessageReceivedSpy.count(), 0);
388 QList<QVariant> arguments = textFrameReceivedSpy.takeFirst();
389 QCOMPARE(arguments.at(0).toString().length(), size);
390 arguments = textMessageReceivedSpy.takeFirst();
391 QCOMPARE(arguments.at(0).toString().length(), size);
392 buffer.close();
393}
394
395void tst_DataProcessor::goodControlFrame()
396{
397 QByteArray data;
398 QBuffer buffer;
399 QWebSocketDataProcessor dataProcessor;
400
401 QSignalSpy closeFrameReceivedSpy(&dataProcessor,
402 SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
403 QSignalSpy errorReceivedSpy(&dataProcessor,
404 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
405 QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
406 QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
407 QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
408 QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
409 QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
410 QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
411
412 data.append(c: char(FIN | QWebSocketProtocol::OpCodePing));
413 data.append(s: QChar::fromLatin1(c: 0));
414 buffer.setData(data);
415 buffer.open(openMode: QIODevice::ReadOnly);
416 dataProcessor.process(pIoDevice: &buffer);
417 QCOMPARE(errorReceivedSpy.count(), 0);
418 QCOMPARE(textFrameReceivedSpy.count(), 0);
419 QCOMPARE(textMessageReceivedSpy.count(), 0);
420 QCOMPARE(binaryFrameReceivedSpy.count(), 0);
421 QCOMPARE(binaryMessageReceivedSpy.count(), 0);
422 QCOMPARE(closeFrameReceivedSpy.count(), 0);
423 QCOMPARE(pongReceivedSpy.count(), 0);
424 QCOMPARE(pingReceivedSpy.count(), 1);
425 buffer.close();
426
427 data.clear();
428 pingReceivedSpy.clear();
429 pongReceivedSpy.clear();
430 data.append(c: char(FIN | QWebSocketProtocol::OpCodePong));
431 data.append(s: QChar::fromLatin1(c: 0));
432 buffer.setData(data);
433 buffer.open(openMode: QIODevice::ReadOnly);
434 dataProcessor.process(pIoDevice: &buffer);
435 QCOMPARE(errorReceivedSpy.count(), 0);
436 QCOMPARE(textFrameReceivedSpy.count(), 0);
437 QCOMPARE(textMessageReceivedSpy.count(), 0);
438 QCOMPARE(binaryFrameReceivedSpy.count(), 0);
439 QCOMPARE(binaryMessageReceivedSpy.count(), 0);
440 QCOMPARE(closeFrameReceivedSpy.count(), 0);
441 QCOMPARE(pingReceivedSpy.count(), 0);
442 QCOMPARE(pongReceivedSpy.count(), 1);
443 buffer.close();
444}
445
446void tst_DataProcessor::goodCloseFrame_data()
447{
448 QTest::addColumn<QString>(name: "payload");
449 QTest::addColumn<QWebSocketProtocol::CloseCode>(name: "closeCode");
450 //control frame data cannot exceed 125 bytes; smaller than 124,
451 //because we also need a 2 byte close code
452 for (int i = 0; i < 124; ++i)
453 {
454 QTest::newRow(QStringLiteral("Close frame with %1 ASCII characters")
455 .arg(a: i).toLatin1().constData())
456 << QString(i, 'a')
457 << QWebSocketProtocol::CloseCodeNormal;
458 }
459 for (int i = 0; i < 126; ++i)
460 {
461 QTest::newRow(QStringLiteral("Text frame with containing ASCII character '0x%1'")
462 .arg(a: QByteArray(1, char(i)).toHex().constData()).toLatin1().constData())
463 << QString(1, char(i)) << QWebSocketProtocol::CloseCodeNormal;
464 }
465 QTest::newRow(dataTag: "Close frame with close code NORMAL")
466 << QString(1, 'a') << QWebSocketProtocol::CloseCodeNormal;
467 QTest::newRow(dataTag: "Close frame with close code BAD OPERATION")
468 << QString(1, 'a') << QWebSocketProtocol::CloseCodeBadOperation;
469 QTest::newRow(dataTag: "Close frame with close code DATATYPE NOT SUPPORTED")
470 << QString(1, 'a') << QWebSocketProtocol::CloseCodeDatatypeNotSupported;
471 QTest::newRow(dataTag: "Close frame with close code GOING AWAY")
472 << QString(1, 'a') << QWebSocketProtocol::CloseCodeGoingAway;
473 QTest::newRow(dataTag: "Close frame with close code MISSING EXTENSION")
474 << QString(1, 'a') << QWebSocketProtocol::CloseCodeMissingExtension;
475 QTest::newRow(dataTag: "Close frame with close code POLICY VIOLATED")
476 << QString(1, 'a') << QWebSocketProtocol::CloseCodePolicyViolated;
477 QTest::newRow(dataTag: "Close frame with close code PROTOCOL ERROR")
478 << QString(1, 'a') << QWebSocketProtocol::CloseCodeProtocolError;
479 QTest::newRow(dataTag: "Close frame with close code TOO MUCH DATA")
480 << QString(1, 'a') << QWebSocketProtocol::CloseCodeTooMuchData;
481 QTest::newRow(dataTag: "Close frame with close code WRONG DATATYPE")
482 << QString(1, 'a') << QWebSocketProtocol::CloseCodeWrongDatatype;
483 QTest::newRow(dataTag: "Close frame with close code 3000")
484 << QString(1, 'a') << QWebSocketProtocol::CloseCode(3000);
485 QTest::newRow(dataTag: "Close frame with close code 3999")
486 << QString(1, 'a') << QWebSocketProtocol::CloseCode(3999);
487 QTest::newRow(dataTag: "Close frame with close code 4000")
488 << QString(1, 'a') << QWebSocketProtocol::CloseCode(4000);
489 QTest::newRow(dataTag: "Close frame with close code 4999")
490 << QString(1, 'a') << QWebSocketProtocol::CloseCode(4999);
491
492 //close frames with no close reason
493 QTest::newRow(dataTag: "Close frame with close code NORMAL and no reason")
494 << QString() << QWebSocketProtocol::CloseCodeNormal;
495 QTest::newRow(dataTag: "Close frame with close code BAD OPERATION and no reason")
496 << QString() << QWebSocketProtocol::CloseCodeBadOperation;
497 QTest::newRow(dataTag: "Close frame with close code DATATYPE NOT SUPPORTED and no reason")
498 << QString() << QWebSocketProtocol::CloseCodeDatatypeNotSupported;
499 QTest::newRow(dataTag: "Close frame with close code GOING AWAY and no reason")
500 << QString() << QWebSocketProtocol::CloseCodeGoingAway;
501 QTest::newRow(dataTag: "Close frame with close code MISSING EXTENSION and no reason")
502 << QString() << QWebSocketProtocol::CloseCodeMissingExtension;
503 QTest::newRow(dataTag: "Close frame with close code POLICY VIOLATED and no reason")
504 << QString() << QWebSocketProtocol::CloseCodePolicyViolated;
505 QTest::newRow(dataTag: "Close frame with close code PROTOCOL ERROR and no reason")
506 << QString() << QWebSocketProtocol::CloseCodeProtocolError;
507 QTest::newRow(dataTag: "Close frame with close code TOO MUCH DATA and no reason")
508 << QString() << QWebSocketProtocol::CloseCodeTooMuchData;
509 QTest::newRow(dataTag: "Close frame with close code WRONG DATATYPE and no reason")
510 << QString() << QWebSocketProtocol::CloseCodeWrongDatatype;
511 QTest::newRow(dataTag: "Close frame with close code 3000 and no reason")
512 << QString() << QWebSocketProtocol::CloseCode(3000);
513 QTest::newRow(dataTag: "Close frame with close code 3999 and no reason")
514 << QString() << QWebSocketProtocol::CloseCode(3999);
515 QTest::newRow(dataTag: "Close frame with close code 4000 and no reason")
516 << QString() << QWebSocketProtocol::CloseCode(4000);
517 QTest::newRow(dataTag: "Close frame with close code 4999 and no reason")
518 << QString() << QWebSocketProtocol::CloseCode(4999);
519
520 QTest::newRow(dataTag: "Close frame with no close code and no reason")
521 << QString() << QWebSocketProtocol::CloseCode(0);
522}
523
524void tst_DataProcessor::goodOpcodes_data()
525{
526 QTest::addColumn<QWebSocketProtocol::OpCode>(name: "opCode");
527
528 QTest::newRow(dataTag: "Frame with PING opcode") << QWebSocketProtocol::OpCodePing;
529 QTest::newRow(dataTag: "Frame with PONG opcode") << QWebSocketProtocol::OpCodePong;
530 QTest::newRow(dataTag: "Frame with TEXT opcode") << QWebSocketProtocol::OpCodeText;
531 QTest::newRow(dataTag: "Frame with BINARY opcode") << QWebSocketProtocol::OpCodeBinary;
532 QTest::newRow(dataTag: "Frame with CLOSE opcode") << QWebSocketProtocol::OpCodeClose;
533}
534
535void tst_DataProcessor::goodOpcodes()
536{
537 QByteArray data;
538 QBuffer buffer;
539 QWebSocketDataProcessor dataProcessor;
540 QFETCH(QWebSocketProtocol::OpCode, opCode);
541
542 data.append(c: char(FIN | opCode));
543 data.append(c: char(0)); //zero length
544
545 buffer.setData(data);
546 buffer.open(openMode: QIODevice::ReadOnly);
547
548 QSignalSpy errorReceivedSpy(&dataProcessor,
549 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
550 QSignalSpy closeReceivedSpy(&dataProcessor,
551 SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
552 QSignalSpy pingReceivedSpy(&dataProcessor,
553 SIGNAL(pingReceived(QByteArray)));
554 QSignalSpy pongReceivedSpy(&dataProcessor,
555 SIGNAL(pongReceived(QByteArray)));
556 QSignalSpy textFrameReceivedSpy(&dataProcessor,
557 SIGNAL(textFrameReceived(QString,bool)));
558 QSignalSpy textMessageReceivedSpy(&dataProcessor,
559 SIGNAL(textMessageReceived(QString)));
560 QSignalSpy binaryFrameReceivedSpy(&dataProcessor,
561 SIGNAL(binaryFrameReceived(QByteArray,bool)));
562 QSignalSpy binaryMessageReceivedSpy(&dataProcessor,
563 SIGNAL(binaryMessageReceived(QByteArray)));
564
565 dataProcessor.process(pIoDevice: &buffer);
566
567 QCOMPARE(errorReceivedSpy.count(), 0);
568 QCOMPARE(pingReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodePing ? 1 : 0);
569 QCOMPARE(pongReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodePong ? 1 : 0);
570 QCOMPARE(closeReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodeClose ? 1 : 0);
571 QCOMPARE(textFrameReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodeText ? 1 : 0);
572 QCOMPARE(textMessageReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodeText ? 1 : 0);
573 QCOMPARE(binaryFrameReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodeBinary ? 1 : 0);
574 QCOMPARE(binaryMessageReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodeBinary ? 1 : 0);
575
576 buffer.close();
577}
578
579void tst_DataProcessor::goodCloseFrame()
580{
581 QByteArray data;
582 QBuffer buffer;
583 QWebSocketDataProcessor dataProcessor;
584 QFETCH(QString, payload);
585 QFETCH(QWebSocketProtocol::CloseCode, closeCode);
586 quint16 swapped = qToBigEndian<quint16>(source: closeCode);
587 const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
588
589 data.append(c: char(FIN | QWebSocketProtocol::OpCodeClose));
590 if (swapped != 0)
591 {
592 data.append(c: char(payload.length() + 2)).append(s: wireRepresentation, len: 2).append(s: payload);
593 }
594 else
595 {
596 data.append(s: QChar::fromLatin1(c: 0)); //payload length 0;
597 //dataprocessor emits a CloseCodeNormal close code when none is present
598 closeCode = QWebSocketProtocol::CloseCodeNormal;
599 }
600 buffer.setData(data);
601 buffer.open(openMode: QIODevice::ReadOnly);
602
603 QSignalSpy errorReceivedSpy(&dataProcessor,
604 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
605 QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
606 QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
607 QSignalSpy closeFrameReceivedSpy(&dataProcessor,
608 SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
609 QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
610 QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
611 QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
612 QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
613
614 dataProcessor.process(pIoDevice: &buffer);
615
616 QCOMPARE(errorReceivedSpy.count(), 0);
617 QCOMPARE(pingReceivedSpy.count(), 0);
618 QCOMPARE(pongReceivedSpy.count(), 0);
619 QCOMPARE(closeFrameReceivedSpy.count(), 1);
620 QCOMPARE(textFrameReceivedSpy.count(), 0);
621 QCOMPARE(textMessageReceivedSpy.count(), 0);
622 QCOMPARE(binaryFrameReceivedSpy.count(), 0);
623 QCOMPARE(binaryMessageReceivedSpy.count(), 0);
624 QList<QVariant> arguments = closeFrameReceivedSpy.takeFirst();
625 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), closeCode);
626 QCOMPARE(arguments.at(1).toString().length(), payload.length());
627 buffer.close();
628}
629
630void tst_DataProcessor::nonCharacterCodes_data()
631{
632 QTest::addColumn<quint8>(name: "firstByte");
633 QTest::addColumn<quint8>(name: "secondByte");
634 QTest::addColumn<QByteArray>(name: "payload");
635 QTest::addColumn<bool>(name: "isContinuationFrame");
636
637 nonCharacterSequence(sequence: "efbfbe");
638 nonCharacterSequence(sequence: "efbfbf");
639 nonCharacterSequence(sequence: "f09fbfbe");
640 nonCharacterSequence(sequence: "f09fbfbf");
641 nonCharacterSequence(sequence: "f0afbfbe");
642 nonCharacterSequence(sequence: "f0afbfbf");
643 nonCharacterSequence(sequence: "f0bfbfbe");
644 nonCharacterSequence(sequence: "f0bfbfbf");
645 nonCharacterSequence(sequence: "f18fbfbe");
646 nonCharacterSequence(sequence: "f18fbfbf");
647 nonCharacterSequence(sequence: "f19fbfbe");
648 nonCharacterSequence(sequence: "f19fbfbf");
649 nonCharacterSequence(sequence: "f1afbfbe");
650 nonCharacterSequence(sequence: "f1afbfbf");
651 nonCharacterSequence(sequence: "f1bfbfbe");
652 nonCharacterSequence(sequence: "f1bfbfbf");
653 nonCharacterSequence(sequence: "f28fbfbe");
654 nonCharacterSequence(sequence: "f28fbfbf");
655 nonCharacterSequence(sequence: "f29fbfbe");
656 nonCharacterSequence(sequence: "f29fbfbf");
657 nonCharacterSequence(sequence: "f2afbfbe");
658 nonCharacterSequence(sequence: "f2afbfbf");
659 nonCharacterSequence(sequence: "f2bfbfbe");
660 nonCharacterSequence(sequence: "f2bfbfbf");
661 nonCharacterSequence(sequence: "f38fbfbe");
662 nonCharacterSequence(sequence: "f38fbfbf");
663 nonCharacterSequence(sequence: "f39fbfbe");
664 nonCharacterSequence(sequence: "f39fbfbf");
665 nonCharacterSequence(sequence: "f3afbfbe");
666 nonCharacterSequence(sequence: "f3afbfbf");
667 nonCharacterSequence(sequence: "f3bfbfbe");
668 nonCharacterSequence(sequence: "f3bfbfbf");
669 nonCharacterSequence(sequence: "f48fbfbe");
670 nonCharacterSequence(sequence: "f48fbfbf");
671}
672
673void tst_DataProcessor::nonCharacterCodes()
674{
675 QFETCH(quint8, firstByte);
676 QFETCH(quint8, secondByte);
677 QFETCH(QByteArray, payload);
678 QFETCH(bool, isContinuationFrame);
679
680 if (!isContinuationFrame)
681 {
682 QByteArray data;
683 QBuffer buffer;
684 QWebSocketDataProcessor dataProcessor;
685 QSignalSpy errorSpy(&dataProcessor,
686 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
687 QSignalSpy closeSpy(&dataProcessor,
688 SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
689 QSignalSpy pingFrameSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
690 QSignalSpy pongFrameSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
691 QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
692 QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
693 QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
694 QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
695
696 data.append(c: firstByte).append(c: secondByte);
697 data.append(a: payload);
698 buffer.setData(data);
699 buffer.open(openMode: QIODevice::ReadOnly);
700 dataProcessor.process(pIoDevice: &buffer);
701
702 QCOMPARE(errorSpy.count(), 0);
703 QCOMPARE(closeSpy.count(), 0);
704 QCOMPARE(pingFrameSpy.count(), 0);
705 QCOMPARE(pongFrameSpy.count(), 0);
706 QCOMPARE(textFrameSpy.count(), 1);
707 QCOMPARE(textMessageSpy.count(), 1);
708 QCOMPARE(binaryFrameSpy.count(), 0);
709 QCOMPARE(binaryMessageSpy.count(), 0);
710
711 QVariantList arguments = textFrameSpy.takeFirst();
712 QCOMPARE(arguments.at(0).value<QString>().toUtf8(), payload);
713 QCOMPARE(arguments.at(1).value<bool>(), !isContinuationFrame);
714 arguments = textMessageSpy.takeFirst();
715 QCOMPARE(arguments.at(0).value<QString>().toUtf8(), payload);
716 buffer.close();
717 }
718}
719
720void tst_DataProcessor::frameTooSmall()
721{
722 QByteArray data;
723 QBuffer buffer;
724 QWebSocketDataProcessor dataProcessor;
725 QByteArray firstFrame;
726
727 firstFrame.append(c: quint8(QWebSocketProtocol::OpCodeText)).append(c: char(1))
728 .append(a: QByteArray(1, 'a'));
729
730 //with nothing in the buffer, the dataProcessor should time out
731 //and the error should be CloseCodeGoingAway meaning the socket will be closed
732 buffer.setData(data);
733 buffer.open(openMode: QIODevice::ReadOnly);
734 QSignalSpy errorSpy(&dataProcessor,
735 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
736 QSignalSpy closeSpy(&dataProcessor,
737 SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
738 QSignalSpy pingMessageSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
739 QSignalSpy pongMessageSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
740 QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
741 QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
742 QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
743 QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
744
745 dataProcessor.process(pIoDevice: &buffer);
746
747 QTRY_VERIFY_WITH_TIMEOUT(errorSpy.count(), 7000);
748 QCOMPARE(errorSpy.count(), 1);
749 QCOMPARE(closeSpy.count(), 0);
750 QCOMPARE(pingMessageSpy.count(), 0);
751 QCOMPARE(pongMessageSpy.count(), 0);
752 QCOMPARE(textMessageSpy.count(), 0);
753 QCOMPARE(binaryMessageSpy.count(), 0);
754 QCOMPARE(textFrameSpy.count(), 0);
755 QCOMPARE(binaryFrameSpy.count(), 0);
756
757 QList<QVariant> arguments = errorSpy.takeFirst();
758 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(),
759 QWebSocketProtocol::CloseCodeGoingAway);
760 errorSpy.clear();
761 closeSpy.clear();
762 pingMessageSpy.clear();
763 pongMessageSpy.clear();
764 textMessageSpy.clear();
765 binaryMessageSpy.clear();
766 textFrameSpy.clear();
767 binaryFrameSpy.clear();
768 buffer.close();
769 data.clear();
770
771 //only one byte; this is far too little;
772 //should get a time out as well and the error should be CloseCodeGoingAway
773 //meaning the socket will be closed
774 data.append(c: quint8('1')); //put 1 byte in the buffer; this is too little
775 buffer.setData(data);
776 buffer.open(openMode: QIODevice::ReadOnly);
777
778 dataProcessor.process(pIoDevice: &buffer);
779
780 QTRY_VERIFY_WITH_TIMEOUT(errorSpy.count(), 7000);
781 QCOMPARE(errorSpy.count(), 1);
782 QCOMPARE(closeSpy.count(), 0);
783 QCOMPARE(pingMessageSpy.count(), 0);
784 QCOMPARE(pongMessageSpy.count(), 0);
785 QCOMPARE(textMessageSpy.count(), 0);
786 QCOMPARE(binaryMessageSpy.count(), 0);
787 QCOMPARE(textFrameSpy.count(), 0);
788 QCOMPARE(binaryFrameSpy.count(), 0);
789
790 arguments = errorSpy.takeFirst();
791 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(),
792 QWebSocketProtocol::CloseCodeGoingAway);
793 buffer.close();
794 errorSpy.clear();
795 closeSpy.clear();
796 pingMessageSpy.clear();
797 pongMessageSpy.clear();
798 textMessageSpy.clear();
799 binaryMessageSpy.clear();
800 textFrameSpy.clear();
801 binaryFrameSpy.clear();
802 data.clear();
803
804
805 {
806 //text frame with final bit not set
807 data.append(c: char(QWebSocketProtocol::OpCodeText)).append(c: char(0x0));
808 buffer.setData(data);
809 buffer.open(openMode: QIODevice::ReadOnly);
810
811 dataProcessor.process(pIoDevice: &buffer);
812
813 QTRY_VERIFY_WITH_TIMEOUT(errorSpy.count(), 7000);
814 QCOMPARE(errorSpy.count(), 1);
815 QCOMPARE(closeSpy.count(), 0);
816 QCOMPARE(pingMessageSpy.count(), 0);
817 QCOMPARE(pongMessageSpy.count(), 0);
818 QCOMPARE(textMessageSpy.count(), 0);
819 QCOMPARE(binaryMessageSpy.count(), 0);
820 QCOMPARE(textFrameSpy.count(), 1);
821 QCOMPARE(binaryFrameSpy.count(), 0);
822
823 errorSpy.clear();
824 closeSpy.clear();
825 pingMessageSpy.clear();
826 pongMessageSpy.clear();
827 textMessageSpy.clear();
828 binaryMessageSpy.clear();
829 textFrameSpy.clear();
830 binaryFrameSpy.clear();
831 buffer.close();
832 data.clear();
833
834 //with nothing in the buffer,
835 //the dataProcessor should time out and the error should be CloseCodeGoingAway
836 //meaning the socket will be closed
837 buffer.setData(data);
838 buffer.open(openMode: QIODevice::ReadOnly);
839 dataProcessor.process(pIoDevice: &buffer);
840
841 QTRY_VERIFY_WITH_TIMEOUT(errorSpy.count(), 7000);
842 QCOMPARE(errorSpy.count(), 1);
843 QCOMPARE(closeSpy.count(), 0);
844 QCOMPARE(pingMessageSpy.count(), 0);
845 QCOMPARE(pongMessageSpy.count(), 0);
846 QCOMPARE(textMessageSpy.count(), 0);
847 QCOMPARE(binaryMessageSpy.count(), 0);
848 QCOMPARE(textFrameSpy.count(), 0);
849 QCOMPARE(binaryFrameSpy.count(), 0);
850
851 QList<QVariant> arguments = errorSpy.takeFirst();
852 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(),
853 QWebSocketProtocol::CloseCodeGoingAway);
854 errorSpy.clear();
855 closeSpy.clear();
856 pingMessageSpy.clear();
857 pongMessageSpy.clear();
858 textMessageSpy.clear();
859 binaryMessageSpy.clear();
860 textFrameSpy.clear();
861 binaryFrameSpy.clear();
862 buffer.close();
863 data.clear();
864
865 //text frame with final bit not set
866 data.append(c: char(QWebSocketProtocol::OpCodeText)).append(c: char(0x0));
867 buffer.setData(data);
868 buffer.open(openMode: QIODevice::ReadOnly);
869 dataProcessor.process(pIoDevice: &buffer);
870
871 QTRY_VERIFY_WITH_TIMEOUT(errorSpy.count(), 7000);
872 QCOMPARE(errorSpy.count(), 1);
873 QCOMPARE(closeSpy.count(), 0);
874 QCOMPARE(pingMessageSpy.count(), 0);
875 QCOMPARE(pongMessageSpy.count(), 0);
876 QCOMPARE(textMessageSpy.count(), 0);
877 QCOMPARE(binaryMessageSpy.count(), 0);
878 QCOMPARE(textFrameSpy.count(), 1);
879 QCOMPARE(binaryFrameSpy.count(), 0);
880
881 buffer.close();
882 data.clear();
883
884 errorSpy.clear();
885 closeSpy.clear();
886 pingMessageSpy.clear();
887 pongMessageSpy.clear();
888 textMessageSpy.clear();
889 binaryMessageSpy.clear();
890 textFrameSpy.clear();
891 binaryFrameSpy.clear();
892
893 //only 1 byte follows in continuation frame;
894 //should time out with close code CloseCodeGoingAway
895 data.append(c: 'a');
896 buffer.setData(data);
897 buffer.open(openMode: QIODevice::ReadOnly);
898
899 dataProcessor.process(pIoDevice: &buffer);
900 QTRY_VERIFY_WITH_TIMEOUT(errorSpy.count(), 7000);
901 QCOMPARE(errorSpy.count(), 1);
902 QCOMPARE(closeSpy.count(), 0);
903 QCOMPARE(pingMessageSpy.count(), 0);
904 QCOMPARE(pongMessageSpy.count(), 0);
905 QCOMPARE(textMessageSpy.count(), 0);
906 QCOMPARE(binaryMessageSpy.count(), 0);
907 QCOMPARE(textFrameSpy.count(), 0);
908 QCOMPARE(binaryFrameSpy.count(), 0);
909 arguments = errorSpy.takeFirst();
910 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(),
911 QWebSocketProtocol::CloseCodeGoingAway);
912 buffer.close();
913 }
914}
915
916void tst_DataProcessor::frameTooBig_data()
917{
918 QTest::addColumn<quint8>(name: "firstByte");
919 QTest::addColumn<quint8>(name: "secondByte");
920 QTest::addColumn<QByteArray>(name: "payload");
921 QTest::addColumn<bool>(name: "isContinuationFrame");
922 QTest::addColumn<QWebSocketProtocol::CloseCode>(name: "expectedCloseCode");
923
924 quint64 swapped64 = 0;
925 const char *wireRepresentation = nullptr;
926
927 //only data frames are checked for being too big
928 //control frames have explicit checking on a maximum payload size of 125,
929 //which is tested elsewhere
930
931 swapped64 = qToBigEndian<quint64>(source: QWebSocketDataProcessor::maxFrameSize() + 1);
932 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
933 QTest::newRow(dataTag: "Text frame with payload size > INT_MAX")
934 << quint8(FIN | QWebSocketProtocol::OpCodeText)
935 << quint8(127)
936 << QByteArray(wireRepresentation, 8).append(a: QByteArray(32, 'a'))
937 << false
938 << QWebSocketProtocol::CloseCodeTooMuchData;
939
940 swapped64 = qToBigEndian<quint64>(source: QWebSocketDataProcessor::maxFrameSize() + 1);
941 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
942 QTest::newRow(dataTag: "Binary frame with payload size > INT_MAX")
943 << quint8(FIN | QWebSocketProtocol::OpCodeBinary)
944 << quint8(127)
945 << QByteArray(wireRepresentation, 8).append(a: QByteArray(32, 'a'))
946 << false
947 << QWebSocketProtocol::CloseCodeTooMuchData;
948
949 swapped64 = qToBigEndian<quint64>(source: QWebSocketDataProcessor::maxFrameSize() + 1);
950 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped64));
951 QTest::newRow(dataTag: "Continuation frame with payload size > INT_MAX")
952 << quint8(FIN | QWebSocketProtocol::OpCodeContinue)
953 << quint8(127)
954 << QByteArray(wireRepresentation, 8).append(a: QByteArray(32, 'a'))
955 << true
956 << QWebSocketProtocol::CloseCodeTooMuchData;
957}
958
959void tst_DataProcessor::frameTooBig()
960{
961 doTest();
962}
963
964void tst_DataProcessor::invalidHeader_data()
965{
966 //The first byte contain the FIN, RSV1, RSV2, RSV3 and the Opcode
967 //The second byte contains the MaskFlag and the length of the frame
968 QTest::addColumn<quint8>(name: "firstByte");
969 QTest::addColumn<quint8>(name: "secondByte");
970 //superfluous, but present to be able to call doTest(), which expects a payload field
971 QTest::addColumn<QByteArray>(name: "payload");
972 QTest::addColumn<bool>(name: "isContinuationFrame");
973 QTest::addColumn<QWebSocketProtocol::CloseCode>(name: "expectedCloseCode");
974
975 //invalid bit fields
976 invalidField(dataTag: "RSV1 set", invalidFieldValue: RSV1);
977 invalidField(dataTag: "RSV2 set", invalidFieldValue: RSV2);
978 invalidField(dataTag: "RSV3 set", invalidFieldValue: RSV3);
979 invalidField(dataTag: "RSV1 and RSV2 set", invalidFieldValue: RSV1 | RSV2);
980 invalidField(dataTag: "RSV1 and RSV3 set", invalidFieldValue: RSV1 | RSV3);
981 invalidField(dataTag: "RSV2 and RSV3 set", invalidFieldValue: RSV2 | RSV3);
982 invalidField(dataTag: "RSV1, RSV2 and RSV3 set", invalidFieldValue: RSV1 | RSV2 | RSV3);
983
984 //invalid opcodes
985 invalidField(dataTag: "Invalid OpCode 3", invalidFieldValue: QWebSocketProtocol::OpCodeReserved3);
986 invalidField(dataTag: "Invalid OpCode 4", invalidFieldValue: QWebSocketProtocol::OpCodeReserved4);
987 invalidField(dataTag: "Invalid OpCode 5", invalidFieldValue: QWebSocketProtocol::OpCodeReserved5);
988 invalidField(dataTag: "Invalid OpCode 6", invalidFieldValue: QWebSocketProtocol::OpCodeReserved6);
989 invalidField(dataTag: "Invalid OpCode 7", invalidFieldValue: QWebSocketProtocol::OpCodeReserved7);
990 invalidField(dataTag: "Invalid OpCode B", invalidFieldValue: QWebSocketProtocol::OpCodeReservedB);
991 invalidField(dataTag: "Invalid OpCode C", invalidFieldValue: QWebSocketProtocol::OpCodeReservedC);
992 invalidField(dataTag: "Invalid OpCode D", invalidFieldValue: QWebSocketProtocol::OpCodeReservedD);
993 invalidField(dataTag: "Invalid OpCode E", invalidFieldValue: QWebSocketProtocol::OpCodeReservedE);
994 invalidField(dataTag: "Invalid OpCode F", invalidFieldValue: QWebSocketProtocol::OpCodeReservedF);
995}
996
997void tst_DataProcessor::invalidHeader()
998{
999 doTest();
1000}
1001
1002void tst_DataProcessor::invalidControlFrame_data()
1003{
1004 QTest::addColumn<quint8>(name: "firstByte");
1005 QTest::addColumn<quint8>(name: "secondByte");
1006 QTest::addColumn<QByteArray>(name: "payload");
1007 QTest::addColumn<bool>(name: "isContinuationFrame");
1008 QTest::addColumn<QWebSocketProtocol::CloseCode>(name: "expectedCloseCode");
1009
1010
1011 QTest::newRow(dataTag: "Close control frame with payload size 126")
1012 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1013 << quint8(126)
1014 << QByteArray()
1015 << false
1016 << QWebSocketProtocol::CloseCodeProtocolError;
1017 QTest::newRow(dataTag: "Ping control frame with payload size 126")
1018 << quint8(FIN | QWebSocketProtocol::OpCodePing)
1019 << quint8(126)
1020 << QByteArray()
1021 << false
1022 << QWebSocketProtocol::CloseCodeProtocolError;
1023 QTest::newRow(dataTag: "Close control frame with payload size 126")
1024 << quint8(FIN | QWebSocketProtocol::OpCodePong)
1025 << quint8(126)
1026 << QByteArray()
1027 << false
1028 << QWebSocketProtocol::CloseCodeProtocolError;
1029
1030 QTest::newRow(dataTag: "Non-final close control frame (fragmented)")
1031 << quint8(QWebSocketProtocol::OpCodeClose)
1032 << quint8(32)
1033 << QByteArray()
1034 << false
1035 << QWebSocketProtocol::CloseCodeProtocolError;
1036 QTest::newRow(dataTag: "Non-final ping control frame (fragmented)")
1037 << quint8(QWebSocketProtocol::OpCodePing)
1038 << quint8(32) << QByteArray()
1039 << false
1040 << QWebSocketProtocol::CloseCodeProtocolError;
1041 QTest::newRow(dataTag: "Non-final pong control frame (fragmented)")
1042 << quint8(QWebSocketProtocol::OpCodePong)
1043 << quint8(32)
1044 << QByteArray()
1045 << false
1046 << QWebSocketProtocol::CloseCodeProtocolError;
1047}
1048
1049void tst_DataProcessor::invalidControlFrame()
1050{
1051 doTest();
1052}
1053
1054void tst_DataProcessor::invalidCloseFrame_data()
1055{
1056 QTest::addColumn<quint8>(name: "firstByte");
1057 QTest::addColumn<quint8>(name: "secondByte");
1058 QTest::addColumn<QByteArray>(name: "payload");
1059 QTest::addColumn<bool>(name: "isContinuationFrame");
1060 QTest::addColumn<QWebSocketProtocol::CloseCode>(name: "expectedCloseCode");
1061
1062 QTest::newRow(dataTag: "Close control frame with payload size 1")
1063 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1064 << quint8(1)
1065 << QByteArray(1, 'a')
1066 << false
1067 << QWebSocketProtocol::CloseCodeProtocolError;
1068 quint16 swapped = qToBigEndian<quint16>(source: QWebSocketProtocol::CloseCodeAbnormalDisconnection);
1069 const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1070
1071 //Not allowed per RFC 6455 (see para 7.4.1)
1072 QTest::newRow(dataTag: "Close control frame close code ABNORMAL DISCONNECTION")
1073 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1074 << quint8(2)
1075 << QByteArray(wireRepresentation, 2)
1076 << false
1077 << QWebSocketProtocol::CloseCodeProtocolError;
1078 swapped = qToBigEndian<quint16>(source: QWebSocketProtocol::CloseCodeMissingStatusCode);
1079 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1080 //Not allowed per RFC 6455 (see para 7.4.1)
1081 QTest::newRow(dataTag: "Close control frame close code MISSING STATUS CODE")
1082 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1083 << quint8(2)
1084 << QByteArray(wireRepresentation, 2)
1085 << false
1086 << QWebSocketProtocol::CloseCodeProtocolError;
1087 swapped = qToBigEndian<quint16>(source: 1004);
1088 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1089 QTest::newRow(dataTag: "Close control frame close code 1004")
1090 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1091 << quint8(2)
1092 << QByteArray(wireRepresentation, 2)
1093 << false
1094 << QWebSocketProtocol::CloseCodeProtocolError;
1095 swapped = qToBigEndian<quint16>(source: QWebSocketProtocol::CloseCodeTlsHandshakeFailed);
1096 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1097 //Not allowed per RFC 6455 (see para 7.4.1)
1098 QTest::newRow(dataTag: "Close control frame close code TLS HANDSHAKE FAILED")
1099 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1100 << quint8(2)
1101 << QByteArray(wireRepresentation, 2)
1102 << false
1103 << QWebSocketProtocol::CloseCodeProtocolError;
1104 swapped = qToBigEndian<quint16>(source: 0);
1105 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1106 QTest::newRow(dataTag: "Close control frame close code 0")
1107 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1108 << quint8(2)
1109 << QByteArray(wireRepresentation, 2)
1110 << false
1111 << QWebSocketProtocol::CloseCodeProtocolError;
1112 swapped = qToBigEndian<quint16>(source: 999);
1113 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1114 QTest::newRow(dataTag: "Close control frame close code 999")
1115 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1116 << quint8(2)
1117 << QByteArray(wireRepresentation, 2)
1118 << false
1119 << QWebSocketProtocol::CloseCodeProtocolError;
1120 swapped = qToBigEndian<quint16>(source: 1012);
1121 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1122 QTest::newRow(dataTag: "Close control frame close code 1012")
1123 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1124 << quint8(2)
1125 << QByteArray(wireRepresentation, 2)
1126 << false
1127 << QWebSocketProtocol::CloseCodeProtocolError;
1128 swapped = qToBigEndian<quint16>(source: 1013);
1129 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1130 QTest::newRow(dataTag: "Close control frame close code 1013")
1131 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1132 << quint8(2)
1133 << QByteArray(wireRepresentation, 2)
1134 << false
1135 << QWebSocketProtocol::CloseCodeProtocolError;
1136 swapped = qToBigEndian<quint16>(source: 1014);
1137 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1138 QTest::newRow(dataTag: "Close control frame close code 1014")
1139 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1140 << quint8(2)
1141 << QByteArray(wireRepresentation, 2)
1142 << false
1143 << QWebSocketProtocol::CloseCodeProtocolError;
1144 swapped = qToBigEndian<quint16>(source: 1100);
1145 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1146 QTest::newRow(dataTag: "Close control frame close code 1100")
1147 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1148 << quint8(2)
1149 << QByteArray(wireRepresentation, 2)
1150 << false
1151 << QWebSocketProtocol::CloseCodeProtocolError;
1152 swapped = qToBigEndian<quint16>(source: 2000);
1153 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1154 QTest::newRow(dataTag: "Close control frame close code 2000")
1155 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1156 << quint8(2)
1157 << QByteArray(wireRepresentation, 2)
1158 << false
1159 << QWebSocketProtocol::CloseCodeProtocolError;
1160 swapped = qToBigEndian<quint16>(source: 2999);
1161 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1162 QTest::newRow(dataTag: "Close control frame close code 2999")
1163 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1164 << quint8(2)
1165 << QByteArray(wireRepresentation, 2)
1166 << false
1167 << QWebSocketProtocol::CloseCodeProtocolError;
1168 swapped = qToBigEndian<quint16>(source: 5000);
1169 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1170 QTest::newRow(dataTag: "Close control frame close code 5000")
1171 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1172 << quint8(2)
1173 << QByteArray(wireRepresentation, 2)
1174 << false
1175 << QWebSocketProtocol::CloseCodeProtocolError;
1176 swapped = qToBigEndian<quint16>(source: 65535u);
1177 wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1178 QTest::newRow(dataTag: "Close control frame close code 65535")
1179 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1180 << quint8(2)
1181 << QByteArray(wireRepresentation, 2)
1182 << false
1183 << QWebSocketProtocol::CloseCodeProtocolError;
1184}
1185
1186void tst_DataProcessor::invalidCloseFrame()
1187{
1188 doCloseFrameTest();
1189}
1190
1191void tst_DataProcessor::minimumSizeRequirement_data()
1192{
1193 QTest::addColumn<quint8>(name: "firstByte");
1194 QTest::addColumn<quint8>(name: "secondByte");
1195 QTest::addColumn<QByteArray>(name: "payload");
1196 QTest::addColumn<bool>(name: "isContinuationFrame");
1197 QTest::addColumn<QWebSocketProtocol::CloseCode>(name: "expectedCloseCode");
1198
1199 minimumSize16Bit(sizeInBytes: 0);
1200 minimumSize16Bit(sizeInBytes: 64);
1201 minimumSize16Bit(sizeInBytes: 125);
1202
1203 minimumSize64Bit(sizeInBytes: 0);
1204 minimumSize64Bit(sizeInBytes: 64);
1205 minimumSize64Bit(sizeInBytes: 125);
1206 minimumSize64Bit(sizeInBytes: 126);
1207 minimumSize64Bit(sizeInBytes: 256);
1208 minimumSize64Bit(sizeInBytes: 512);
1209 minimumSize64Bit(sizeInBytes: 1024);
1210 minimumSize64Bit(sizeInBytes: 2048);
1211 minimumSize64Bit(sizeInBytes: 4096);
1212 minimumSize64Bit(sizeInBytes: 8192);
1213 minimumSize64Bit(sizeInBytes: 16384);
1214 minimumSize64Bit(sizeInBytes: 32768);
1215 minimumSize64Bit(sizeInBytes: 0xFFFFu);
1216}
1217
1218void tst_DataProcessor::minimumSizeRequirement()
1219{
1220 doTest();
1221}
1222
1223void tst_DataProcessor::invalidPayload_data(bool isControlFrame)
1224{
1225 QTest::addColumn<quint8>(name: "firstByte");
1226 QTest::addColumn<quint8>(name: "secondByte");
1227 QTest::addColumn<QByteArray>(name: "payload");
1228 QTest::addColumn<bool>(name: "isContinuationFrame");
1229 QTest::addColumn<QWebSocketProtocol::CloseCode>(name: "expectedCloseCode");
1230
1231 //6.3: invalid UTF-8 sequence
1232 invalidUTF8(dataTag: "case 6.3.1", utf8Sequence: "cebae1bdb9cf83cebcceb5eda080656469746564", isCloseFrame: isControlFrame);
1233
1234 //6.4.: fail fast tests; invalid UTF-8 in middle of string
1235 invalidUTF8(dataTag: "case 6.4.1", utf8Sequence: "cebae1bdb9cf83cebcceb5f4908080656469746564", isCloseFrame: isControlFrame);
1236 invalidUTF8(dataTag: "case 6.4.4", utf8Sequence: "cebae1bdb9cf83cebcceb5eda080656469746564", isCloseFrame: isControlFrame);
1237
1238 //6.6: All prefixes of a valid UTF-8 string that contains multi-byte code points
1239 invalidUTF8(dataTag: "case 6.6.1", utf8Sequence: "ce", isCloseFrame: isControlFrame);
1240 invalidUTF8(dataTag: "case 6.6.3", utf8Sequence: "cebae1", isCloseFrame: isControlFrame);
1241 invalidUTF8(dataTag: "case 6.6.4", utf8Sequence: "cebae1bd", isCloseFrame: isControlFrame);
1242 invalidUTF8(dataTag: "case 6.6.6", utf8Sequence: "cebae1bdb9cf", isCloseFrame: isControlFrame);
1243 invalidUTF8(dataTag: "case 6.6.8", utf8Sequence: "cebae1bdb9cf83ce", isCloseFrame: isControlFrame);
1244 invalidUTF8(dataTag: "case 6.6.10", utf8Sequence: "cebae1bdb9cf83cebcce", isCloseFrame: isControlFrame);
1245
1246 //6.8: First possible sequence length 5/6 (invalid codepoints)
1247 invalidUTF8(dataTag: "case 6.8.1", utf8Sequence: "f888808080", isCloseFrame: isControlFrame);
1248 invalidUTF8(dataTag: "case 6.8.2", utf8Sequence: "fc8480808080", isCloseFrame: isControlFrame);
1249
1250 //6.10: Last possible sequence length 4/5/6 (invalid codepoints)
1251 invalidUTF8(dataTag: "case 6.10.1", utf8Sequence: "f7bfbfbf", isCloseFrame: isControlFrame);
1252 invalidUTF8(dataTag: "case 6.10.2", utf8Sequence: "fbbfbfbfbf", isCloseFrame: isControlFrame);
1253 invalidUTF8(dataTag: "case 6.10.3", utf8Sequence: "fdbfbfbfbfbf", isCloseFrame: isControlFrame);
1254
1255 //5.11: boundary conditions
1256 invalidUTF8(dataTag: "case 6.11.5", utf8Sequence: "f4908080", isCloseFrame: isControlFrame);
1257
1258 //6.12: unexpected continuation bytes
1259 invalidUTF8(dataTag: "case 6.12.1", utf8Sequence: "80", isCloseFrame: isControlFrame);
1260 invalidUTF8(dataTag: "case 6.12.2", utf8Sequence: "bf", isCloseFrame: isControlFrame);
1261 invalidUTF8(dataTag: "case 6.12.3", utf8Sequence: "80bf", isCloseFrame: isControlFrame);
1262 invalidUTF8(dataTag: "case 6.12.4", utf8Sequence: "80bf80", isCloseFrame: isControlFrame);
1263 invalidUTF8(dataTag: "case 6.12.5", utf8Sequence: "80bf80bf", isCloseFrame: isControlFrame);
1264 invalidUTF8(dataTag: "case 6.12.6", utf8Sequence: "80bf80bf80", isCloseFrame: isControlFrame);
1265 invalidUTF8(dataTag: "case 6.12.7", utf8Sequence: "80bf80bf80bf", isCloseFrame: isControlFrame);
1266 invalidUTF8(dataTag: "case 6.12.8",
1267 utf8Sequence: "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a"
1268 "7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbe",
1269 isCloseFrame: isControlFrame);
1270
1271 //6.13: lonely start characters
1272 invalidUTF8(dataTag: "case 6.13.1",
1273 utf8Sequence: "c020c120c220c320c420c520c620c720c820c920ca20cb20cc20cd20ce20cf20d020d120d220"
1274 "d320d420d520d620d720d820d920da20db20dc20dd20de20",
1275 isCloseFrame: isControlFrame);
1276 invalidUTF8(dataTag: "case 6.13.2", utf8Sequence: "e020e120e220e320e420e520e620e720e820e920ea20eb20ec20ed20ee20",
1277 isCloseFrame: isControlFrame);
1278 invalidUTF8(dataTag: "case 6.13.3", utf8Sequence: "f020f120f220f320f420f520f620", isCloseFrame: isControlFrame);
1279 invalidUTF8(dataTag: "case 6.13.4", utf8Sequence: "f820f920fa20", isCloseFrame: isControlFrame);
1280 invalidUTF8(dataTag: "case 6.13.5", utf8Sequence: "fc20", isCloseFrame: isControlFrame);
1281
1282 //6.14: sequences with last continuation byte missing
1283 invalidUTF8(dataTag: "case 6.14.1", utf8Sequence: "c0", isCloseFrame: isControlFrame);
1284 invalidUTF8(dataTag: "case 6.14.2", utf8Sequence: "e080", isCloseFrame: isControlFrame);
1285 invalidUTF8(dataTag: "case 6.14.3", utf8Sequence: "f08080", isCloseFrame: isControlFrame);
1286 invalidUTF8(dataTag: "case 6.14.4", utf8Sequence: "f8808080", isCloseFrame: isControlFrame);
1287 invalidUTF8(dataTag: "case 6.14.5", utf8Sequence: "fc80808080", isCloseFrame: isControlFrame);
1288 invalidUTF8(dataTag: "case 6.14.6", utf8Sequence: "df", isCloseFrame: isControlFrame);
1289 invalidUTF8(dataTag: "case 6.14.7", utf8Sequence: "efbf", isCloseFrame: isControlFrame);
1290 invalidUTF8(dataTag: "case 6.14.8", utf8Sequence: "f7bfbf", isCloseFrame: isControlFrame);
1291 invalidUTF8(dataTag: "case 6.14.9", utf8Sequence: "fbbfbfbf", isCloseFrame: isControlFrame);
1292 invalidUTF8(dataTag: "case 6.14.10", utf8Sequence: "fdbfbfbfbf", isCloseFrame: isControlFrame);
1293
1294 //6.15: concatenation of incomplete sequences
1295 invalidUTF8(dataTag: "case 6.15.1",
1296 utf8Sequence: "c0e080f08080f8808080fc80808080dfefbff7bfbffbbfbfbffdbfbfbfbf", isCloseFrame: isControlFrame);
1297
1298 //6.16: impossible bytes
1299 invalidUTF8(dataTag: "case 6.16.1", utf8Sequence: "fe", isCloseFrame: isControlFrame);
1300 invalidUTF8(dataTag: "case 6.16.2", utf8Sequence: "ff", isCloseFrame: isControlFrame);
1301 invalidUTF8(dataTag: "case 6.16.3", utf8Sequence: "fefeffff", isCloseFrame: isControlFrame);
1302
1303 //6.17: overlong ASCII characters
1304 invalidUTF8(dataTag: "case 6.17.1", utf8Sequence: "c0af", isCloseFrame: isControlFrame);
1305 invalidUTF8(dataTag: "case 6.17.2", utf8Sequence: "e080af", isCloseFrame: isControlFrame);
1306 invalidUTF8(dataTag: "case 6.17.3", utf8Sequence: "f08080af", isCloseFrame: isControlFrame);
1307 invalidUTF8(dataTag: "case 6.17.4", utf8Sequence: "f8808080af", isCloseFrame: isControlFrame);
1308 invalidUTF8(dataTag: "case 6.17.5", utf8Sequence: "fc80808080af", isCloseFrame: isControlFrame);
1309
1310 //6.18: maximum overlong sequences
1311 invalidUTF8(dataTag: "case 6.18.1", utf8Sequence: "c1bf", isCloseFrame: isControlFrame);
1312 invalidUTF8(dataTag: "case 6.18.2", utf8Sequence: "e09fbf", isCloseFrame: isControlFrame);
1313 invalidUTF8(dataTag: "case 6.18.3", utf8Sequence: "f08fbfbf", isCloseFrame: isControlFrame);
1314 invalidUTF8(dataTag: "case 6.18.4", utf8Sequence: "f887bfbfbf", isCloseFrame: isControlFrame);
1315 invalidUTF8(dataTag: "case 6.18.5", utf8Sequence: "fc83bfbfbfbf", isCloseFrame: isControlFrame);
1316
1317 //6.19: overlong presentation of the NUL character
1318 invalidUTF8(dataTag: "case 6.19.1", utf8Sequence: "c080", isCloseFrame: isControlFrame);
1319 invalidUTF8(dataTag: "case 6.19.2", utf8Sequence: "e08080", isCloseFrame: isControlFrame);
1320 invalidUTF8(dataTag: "case 6.19.3", utf8Sequence: "f0808080", isCloseFrame: isControlFrame);
1321 invalidUTF8(dataTag: "case 6.19.4", utf8Sequence: "f880808080", isCloseFrame: isControlFrame);
1322 invalidUTF8(dataTag: "case 6.19.5", utf8Sequence: "fc8080808080", isCloseFrame: isControlFrame);
1323
1324 //6.20: Single UTF-16 surrogates
1325 invalidUTF8(dataTag: "case 6.20.1", utf8Sequence: "eda080", isCloseFrame: isControlFrame);
1326 invalidUTF8(dataTag: "case 6.20.2", utf8Sequence: "edadbf", isCloseFrame: isControlFrame);
1327 invalidUTF8(dataTag: "case 6.20.3", utf8Sequence: "edae80", isCloseFrame: isControlFrame);
1328 invalidUTF8(dataTag: "case 6.20.4", utf8Sequence: "edafbf", isCloseFrame: isControlFrame);
1329 invalidUTF8(dataTag: "case 6.20.5", utf8Sequence: "edb080", isCloseFrame: isControlFrame);
1330 invalidUTF8(dataTag: "case 6.20.6", utf8Sequence: "edbe80", isCloseFrame: isControlFrame);
1331 invalidUTF8(dataTag: "case 6.20.7", utf8Sequence: "edbfbf", isCloseFrame: isControlFrame);
1332
1333 //6.21: Paired UTF-16 surrogates
1334 invalidUTF8(dataTag: "case 6.21.1", utf8Sequence: "eda080edb080", isCloseFrame: isControlFrame);
1335 invalidUTF8(dataTag: "case 6.21.2", utf8Sequence: "eda080edbfbf", isCloseFrame: isControlFrame);
1336 invalidUTF8(dataTag: "case 6.21.3", utf8Sequence: "edadbfedb080", isCloseFrame: isControlFrame);
1337 invalidUTF8(dataTag: "case 6.21.4", utf8Sequence: "edadbfedbfbf", isCloseFrame: isControlFrame);
1338 invalidUTF8(dataTag: "case 6.21.5", utf8Sequence: "edae80edb080", isCloseFrame: isControlFrame);
1339 invalidUTF8(dataTag: "case 6.21.6", utf8Sequence: "edae80edbfbf", isCloseFrame: isControlFrame);
1340 invalidUTF8(dataTag: "case 6.21.7", utf8Sequence: "edafbfedb080", isCloseFrame: isControlFrame);
1341 invalidUTF8(dataTag: "case 6.21.8", utf8Sequence: "edafbfedbfbf", isCloseFrame: isControlFrame);
1342}
1343
1344void tst_DataProcessor::invalidPayload()
1345{
1346 doTest();
1347}
1348
1349void tst_DataProcessor::invalidPayloadInCloseFrame_data()
1350{
1351 invalidPayload_data(isControlFrame: true);
1352}
1353
1354void tst_DataProcessor::invalidPayloadInCloseFrame()
1355{
1356 QFETCH(quint8, firstByte);
1357 QFETCH(quint8, secondByte);
1358 QFETCH(QByteArray, payload);
1359 QFETCH(bool, isContinuationFrame);
1360 QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
1361
1362 Q_UNUSED(isContinuationFrame)
1363
1364 QByteArray data;
1365 QBuffer buffer;
1366 QWebSocketDataProcessor dataProcessor;
1367 QSignalSpy closeSpy(&dataProcessor,
1368 SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
1369 QSignalSpy errorSpy(&dataProcessor,
1370 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
1371 QSignalSpy pingMessageSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray)));
1372 QSignalSpy pongMessageSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray)));
1373 QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
1374 QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
1375 QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
1376 QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
1377
1378 data.append(c: firstByte).append(c: secondByte);
1379 data.append(a: payload);
1380 buffer.setData(data);
1381 buffer.open(openMode: QIODevice::ReadOnly);
1382 dataProcessor.process(pIoDevice: &buffer);
1383 QCOMPARE(closeSpy.count(), 1);
1384 QCOMPARE(errorSpy.count(), 0);
1385 QCOMPARE(pingMessageSpy.count(), 0);
1386 QCOMPARE(pongMessageSpy.count(), 0);
1387 QCOMPARE(textMessageSpy.count(), 0);
1388 QCOMPARE(binaryMessageSpy.count(), 0);
1389 QCOMPARE(textFrameSpy.count(), 0);
1390 QCOMPARE(binaryFrameSpy.count(), 0);
1391 QVariantList arguments = closeSpy.takeFirst();
1392 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), expectedCloseCode);
1393 buffer.close();
1394}
1395
1396void tst_DataProcessor::incompletePayload_data()
1397{
1398 QTest::addColumn<quint8>(name: "firstByte");
1399 QTest::addColumn<quint8>(name: "secondByte");
1400 QTest::addColumn<QByteArray>(name: "payload");
1401 QTest::addColumn<bool>(name: "isContinuationFrame");
1402 QTest::addColumn<QWebSocketProtocol::CloseCode>(name: "expectedCloseCode");
1403
1404 incompleteFrame(controlCode: QWebSocketProtocol::OpCodeText, indicatedSize: 125, actualPayloadSize: 0);
1405 incompleteFrame(controlCode: QWebSocketProtocol::OpCodeText, indicatedSize: 64, actualPayloadSize: 32);
1406 incompleteFrame(controlCode: QWebSocketProtocol::OpCodeText, indicatedSize: 256, actualPayloadSize: 32);
1407 incompleteFrame(controlCode: QWebSocketProtocol::OpCodeText, indicatedSize: 128000, actualPayloadSize: 32);
1408 incompleteFrame(controlCode: QWebSocketProtocol::OpCodeBinary, indicatedSize: 125, actualPayloadSize: 0);
1409 incompleteFrame(controlCode: QWebSocketProtocol::OpCodeBinary, indicatedSize: 64, actualPayloadSize: 32);
1410 incompleteFrame(controlCode: QWebSocketProtocol::OpCodeBinary, indicatedSize: 256, actualPayloadSize: 32);
1411 incompleteFrame(controlCode: QWebSocketProtocol::OpCodeBinary, indicatedSize: 128000, actualPayloadSize: 32);
1412 incompleteFrame(controlCode: QWebSocketProtocol::OpCodeContinue, indicatedSize: 125, actualPayloadSize: 0);
1413 incompleteFrame(controlCode: QWebSocketProtocol::OpCodeContinue, indicatedSize: 64, actualPayloadSize: 32);
1414 incompleteFrame(controlCode: QWebSocketProtocol::OpCodeContinue, indicatedSize: 256, actualPayloadSize: 32);
1415 incompleteFrame(controlCode: QWebSocketProtocol::OpCodeContinue, indicatedSize: 128000, actualPayloadSize: 32);
1416
1417 incompleteFrame(controlCode: QWebSocketProtocol::OpCodeClose, indicatedSize: 64, actualPayloadSize: 32);
1418 incompleteFrame(controlCode: QWebSocketProtocol::OpCodePing, indicatedSize: 64, actualPayloadSize: 32);
1419 incompleteFrame(controlCode: QWebSocketProtocol::OpCodePong, indicatedSize: 64, actualPayloadSize: 32);
1420}
1421
1422void tst_DataProcessor::incompletePayload()
1423{
1424 doTest(timeout: 7000);
1425}
1426
1427void tst_DataProcessor::incompleteSizeField_data()
1428{
1429 QTest::addColumn<quint8>(name: "firstByte");
1430 QTest::addColumn<quint8>(name: "secondByte");
1431 QTest::addColumn<QByteArray>(name: "payload");
1432 QTest::addColumn<bool>(name: "isContinuationFrame");
1433 QTest::addColumn<QWebSocketProtocol::CloseCode>(name: "expectedCloseCode");
1434
1435 //for a frame length value of 126
1436 //there should be 2 bytes following to form a 16-bit frame length
1437 insertIncompleteSizeFieldTest(payloadCode: 126, numBytesFollowing: 0);
1438 insertIncompleteSizeFieldTest(payloadCode: 126, numBytesFollowing: 1);
1439
1440 //for a frame length value of 127
1441 //there should be 8 bytes following to form a 64-bit frame length
1442 insertIncompleteSizeFieldTest(payloadCode: 127, numBytesFollowing: 0);
1443 insertIncompleteSizeFieldTest(payloadCode: 127, numBytesFollowing: 1);
1444 insertIncompleteSizeFieldTest(payloadCode: 127, numBytesFollowing: 2);
1445 insertIncompleteSizeFieldTest(payloadCode: 127, numBytesFollowing: 3);
1446 insertIncompleteSizeFieldTest(payloadCode: 127, numBytesFollowing: 4);
1447 insertIncompleteSizeFieldTest(payloadCode: 127, numBytesFollowing: 5);
1448 insertIncompleteSizeFieldTest(payloadCode: 127, numBytesFollowing: 6);
1449 insertIncompleteSizeFieldTest(payloadCode: 127, numBytesFollowing: 7);
1450}
1451
1452void tst_DataProcessor::incompleteSizeField()
1453{
1454 doTest(timeout: 7000);
1455}
1456
1457//////////////////////////////////////////////////////////////////////////////////////////
1458/// HELPER FUNCTIONS
1459//////////////////////////////////////////////////////////////////////////////////////////
1460void tst_DataProcessor::doTest(int timeout)
1461{
1462 QFETCH(quint8, firstByte);
1463 QFETCH(quint8, secondByte);
1464 QFETCH(QByteArray, payload);
1465 QFETCH(bool, isContinuationFrame);
1466 QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
1467
1468 QByteArray data;
1469 QBuffer buffer;
1470 QWebSocketDataProcessor dataProcessor;
1471 QSignalSpy errorSpy(&dataProcessor,
1472 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
1473 QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
1474 QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
1475 QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
1476 QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
1477
1478 if (isContinuationFrame)
1479 {
1480 data.append(c: quint8(QWebSocketProtocol::OpCodeText))
1481 .append(c: char(1))
1482 .append(a: QByteArray(1, 'a'));
1483 }
1484 data.append(c: firstByte).append(c: secondByte);
1485 data.append(a: payload);
1486 buffer.setData(data);
1487 buffer.open(openMode: QIODevice::ReadOnly);
1488 dataProcessor.process(pIoDevice: &buffer);
1489 QTRY_VERIFY_WITH_TIMEOUT(errorSpy.count(), timeout);
1490 QCOMPARE(errorSpy.count(), 1);
1491 QCOMPARE(textMessageSpy.count(), 0);
1492 QCOMPARE(binaryMessageSpy.count(), 0);
1493 QCOMPARE(textFrameSpy.count(), isContinuationFrame ? 1 : 0);
1494 QCOMPARE(binaryFrameSpy.count(), 0);
1495 QVariantList arguments = errorSpy.takeFirst();
1496 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), expectedCloseCode);
1497 buffer.close();
1498 errorSpy.clear();
1499 data.clear();
1500}
1501
1502void tst_DataProcessor::doCloseFrameTest()
1503{
1504 QFETCH(quint8, firstByte);
1505 QFETCH(quint8, secondByte);
1506 QFETCH(QByteArray, payload);
1507 QFETCH(bool, isContinuationFrame);
1508 QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
1509
1510 Q_UNUSED(isContinuationFrame)
1511
1512 QByteArray data;
1513 QBuffer buffer;
1514 QWebSocketDataProcessor dataProcessor;
1515 QSignalSpy closeSpy(&dataProcessor,
1516 SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString)));
1517 QSignalSpy errorSpy(&dataProcessor,
1518 SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString)));
1519 QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString)));
1520 QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray)));
1521 QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool)));
1522 QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool)));
1523
1524 data.append(c: firstByte).append(c: secondByte);
1525 data.append(a: payload);
1526 buffer.setData(data);
1527 buffer.open(openMode: QIODevice::ReadOnly);
1528 dataProcessor.process(pIoDevice: &buffer);
1529 QCOMPARE(closeSpy.count(), 1);
1530 QCOMPARE(errorSpy.count(), 0);
1531 QCOMPARE(textMessageSpy.count(), 0);
1532 QCOMPARE(binaryMessageSpy.count(), 0);
1533 QCOMPARE(textFrameSpy.count(), 0);
1534 QCOMPARE(binaryFrameSpy.count(), 0);
1535 QVariantList arguments = closeSpy.takeFirst();
1536 QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(), expectedCloseCode);
1537 buffer.close();
1538}
1539
1540QString tst_DataProcessor::opCodeToString(quint8 opCode)
1541{
1542 QString frameType;
1543 switch (opCode)
1544 {
1545 case QWebSocketProtocol::OpCodeBinary:
1546 {
1547 frameType = QStringLiteral("Binary");
1548 break;
1549 }
1550 case QWebSocketProtocol::OpCodeText:
1551 {
1552 frameType = QStringLiteral("Text");
1553 break;
1554 }
1555 case QWebSocketProtocol::OpCodePing:
1556 {
1557 frameType = QStringLiteral("Ping");
1558 break;
1559 }
1560 case QWebSocketProtocol::OpCodePong:
1561 {
1562 frameType = QStringLiteral("Pong");
1563 break;
1564 }
1565 case QWebSocketProtocol::OpCodeClose:
1566 {
1567 frameType = QStringLiteral("Close");
1568 break;
1569 }
1570 case QWebSocketProtocol::OpCodeContinue:
1571 {
1572 frameType = QStringLiteral("Continuation");
1573 break;
1574 }
1575 case QWebSocketProtocol::OpCodeReserved3:
1576 {
1577 frameType = QStringLiteral("Reserved3");
1578 break;
1579 }
1580 case QWebSocketProtocol::OpCodeReserved4:
1581 {
1582 frameType = QStringLiteral("Reserved5");
1583 break;
1584 }
1585 case QWebSocketProtocol::OpCodeReserved5:
1586 {
1587 frameType = QStringLiteral("Reserved5");
1588 break;
1589 }
1590 case QWebSocketProtocol::OpCodeReserved6:
1591 {
1592 frameType = QStringLiteral("Reserved6");
1593 break;
1594 }
1595 case QWebSocketProtocol::OpCodeReserved7:
1596 {
1597 frameType = QStringLiteral("Reserved7");
1598 break;
1599 }
1600 case QWebSocketProtocol::OpCodeReservedB:
1601 {
1602 frameType = QStringLiteral("ReservedB");
1603 break;
1604 }
1605 case QWebSocketProtocol::OpCodeReservedC:
1606 {
1607 frameType = QStringLiteral("ReservedC");
1608 break;
1609 }
1610 case QWebSocketProtocol::OpCodeReservedD:
1611 {
1612 frameType = QStringLiteral("ReservedD");
1613 break;
1614 }
1615 case QWebSocketProtocol::OpCodeReservedE:
1616 {
1617 frameType = QStringLiteral("ReservedE");
1618 break;
1619 }
1620 case QWebSocketProtocol::OpCodeReservedF:
1621 {
1622 frameType = QStringLiteral("ReservedF");
1623 break;
1624 }
1625 default:
1626 {
1627 //should never come here
1628 Q_ASSERT(false);
1629 }
1630 }
1631 return frameType;
1632}
1633
1634void tst_DataProcessor::minimumSize16Bit(quint16 sizeInBytes)
1635{
1636 quint16 swapped16 = qToBigEndian<quint16>(source: sizeInBytes);
1637 const char *wireRepresentation
1638 = static_cast<const char *>(static_cast<const void *>(&swapped16));
1639 QTest::newRow(QStringLiteral("Text frame with payload size %1, represented in 2 bytes")
1640 .arg(a: sizeInBytes).toLatin1().constData())
1641 << quint8(FIN | QWebSocketProtocol::OpCodeText)
1642 << quint8(126)
1643 << QByteArray(wireRepresentation, 2)
1644 << false
1645 << QWebSocketProtocol::CloseCodeProtocolError;
1646 QTest::newRow(QStringLiteral("Binary frame with payload size %1, represented in 2 bytes")
1647 .arg(a: sizeInBytes).toLatin1().constBegin())
1648 << quint8(FIN | QWebSocketProtocol::OpCodeBinary)
1649 << quint8(126)
1650 << QByteArray(wireRepresentation, 2)
1651 << false
1652 << QWebSocketProtocol::CloseCodeProtocolError;
1653 QTest::newRow(QStringLiteral("Continuation frame with payload size %1, represented in 2 bytes")
1654 .arg(a: sizeInBytes).toLatin1().constData())
1655 << quint8(FIN | QWebSocketProtocol::OpCodeContinue)
1656 << quint8(126)
1657 << QByteArray(wireRepresentation, 2)
1658 << true
1659 << QWebSocketProtocol::CloseCodeProtocolError;
1660}
1661
1662void tst_DataProcessor::minimumSize64Bit(quint64 sizeInBytes)
1663{
1664 quint64 swapped64 = qToBigEndian<quint64>(source: sizeInBytes);
1665 const char *wireRepresentation
1666 = static_cast<const char *>(static_cast<const void *>(&swapped64));
1667
1668 QTest::newRow(QStringLiteral("Text frame with payload size %1, represented in 8 bytes")
1669 .arg(a: sizeInBytes).toLatin1().constData())
1670 << quint8(FIN | QWebSocketProtocol::OpCodeText)
1671 << quint8(127)
1672 << QByteArray(wireRepresentation, 8)
1673 << false
1674 << QWebSocketProtocol::CloseCodeProtocolError;
1675
1676 QTest::newRow(QStringLiteral("Binary frame with payload size %1, represented in 8 bytes")
1677 .arg(a: sizeInBytes).toLatin1().constData())
1678 << quint8(FIN | QWebSocketProtocol::OpCodeBinary)
1679 << quint8(127)
1680 << QByteArray(wireRepresentation, 8)
1681 << false
1682 << QWebSocketProtocol::CloseCodeProtocolError;
1683
1684 QTest::newRow(QStringLiteral("Continuation frame with payload size %1, represented in 8 bytes")
1685 .arg(a: sizeInBytes).toLatin1().constData())
1686 << quint8(FIN | QWebSocketProtocol::OpCodeContinue)
1687 << quint8(127)
1688 << QByteArray(wireRepresentation, 8)
1689 << true
1690 << QWebSocketProtocol::CloseCodeProtocolError;
1691}
1692
1693void tst_DataProcessor::invalidUTF8(const char *dataTag, const char *utf8Sequence,
1694 bool isCloseFrame)
1695{
1696 QByteArray payload = QByteArray::fromHex(hexEncoded: utf8Sequence);
1697
1698 if (isCloseFrame)
1699 {
1700 quint16 closeCode = qToBigEndian<quint16>(source: QWebSocketProtocol::CloseCodeNormal);
1701 const char *wireRepresentation
1702 = static_cast<const char *>(static_cast<const void *>(&closeCode));
1703 QTest::newRow(QStringLiteral("Close frame with invalid UTF8-sequence: %1")
1704 .arg(a: dataTag).toLatin1().constData())
1705 << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1706 << quint8(payload.length() + 2)
1707 << QByteArray(wireRepresentation, 2).append(a: payload)
1708 << false
1709 << QWebSocketProtocol::CloseCodeWrongDatatype;
1710 }
1711 else
1712 {
1713 QTest::newRow(QStringLiteral("Text frame with invalid UTF8-sequence: %1")
1714 .arg(a: dataTag).toLatin1().constData())
1715 << quint8(FIN | QWebSocketProtocol::OpCodeText)
1716 << quint8(payload.length())
1717 << payload
1718 << false
1719 << QWebSocketProtocol::CloseCodeWrongDatatype;
1720
1721 QTest::newRow(QStringLiteral("Continuation text frame with invalid UTF8-sequence: %1")
1722 .arg(a: dataTag).toLatin1().constData())
1723 << quint8(FIN | QWebSocketProtocol::OpCodeContinue)
1724 << quint8(payload.length())
1725 << payload
1726 << true
1727 << QWebSocketProtocol::CloseCodeWrongDatatype;
1728 }
1729}
1730
1731void tst_DataProcessor::invalidField(const char *dataTag, quint8 invalidFieldValue)
1732{
1733 QTest::newRow(dataTag) << quint8(FIN | invalidFieldValue)
1734 << quint8(0x00)
1735 << QByteArray()
1736 << false
1737 << QWebSocketProtocol::CloseCodeProtocolError;
1738 QTest::newRow(dataTag: QString::fromLatin1(str: dataTag).append(QStringLiteral(" with continuation frame"))
1739 .toLatin1().constData())
1740 << quint8(FIN | invalidFieldValue)
1741 << quint8(0x00)
1742 << QByteArray()
1743 << true
1744 << QWebSocketProtocol::CloseCodeProtocolError;
1745}
1746
1747void tst_DataProcessor::incompleteFrame(quint8 controlCode, quint64 indicatedSize,
1748 quint64 actualPayloadSize)
1749{
1750 QVERIFY(!QWebSocketProtocol::isOpCodeReserved(QWebSocketProtocol::OpCode(controlCode)));
1751 QVERIFY(indicatedSize > actualPayloadSize);
1752
1753 QString frameType = opCodeToString(opCode: controlCode);
1754 QByteArray firstFrame;
1755
1756 if (indicatedSize < 126)
1757 {
1758 //doing extensive QStringLiteral concatenations here, because
1759 //MSVC 2010 complains when using concatenation literal strings about
1760 //concatenation of wide and narrow strings (error C2308)
1761 QTest::newRow(dataTag: frameType
1762 .append(QStringLiteral(" frame with payload size %1, but only %2 bytes") +
1763 QStringLiteral(" of data")
1764 .arg(a: indicatedSize).arg(a: actualPayloadSize)).toLatin1().constData())
1765 << quint8(FIN | controlCode)
1766 << quint8(indicatedSize)
1767 << firstFrame.append(a: QByteArray(actualPayloadSize, 'a'))
1768 << (controlCode == QWebSocketProtocol::OpCodeContinue)
1769 << QWebSocketProtocol::CloseCodeGoingAway;
1770 }
1771 else if (indicatedSize <= 0xFFFFu)
1772 {
1773 quint16 swapped16 = qToBigEndian<quint16>(source: static_cast<quint16>(indicatedSize));
1774 const char *wireRepresentation
1775 = static_cast<const char *>(static_cast<const void *>(&swapped16));
1776 QTest::newRow(
1777 dataTag: frameType.append(QStringLiteral(" frame with payload size %1, but only ") +
1778 QStringLiteral("%2 bytes of data")
1779 .arg(a: indicatedSize)
1780 .arg(a: actualPayloadSize)).toLatin1().constData())
1781 << quint8(FIN | controlCode)
1782 << quint8(126)
1783 << firstFrame.append(a: QByteArray(wireRepresentation, 2)
1784 .append(a: QByteArray(actualPayloadSize, 'a')))
1785 << (controlCode == QWebSocketProtocol::OpCodeContinue)
1786 << QWebSocketProtocol::CloseCodeGoingAway;
1787 }
1788 else
1789 {
1790 quint64 swapped64 = qToBigEndian<quint64>(source: indicatedSize);
1791 const char *wireRepresentation
1792 = static_cast<const char *>(static_cast<const void *>(&swapped64));
1793 QTest::newRow(dataTag: frameType
1794 .append(QStringLiteral(" frame with payload size %1, but only %2 bytes ") +
1795 QStringLiteral("of data")
1796 .arg(a: indicatedSize).arg(a: actualPayloadSize)).toLatin1().constData())
1797 << quint8(FIN | controlCode)
1798 << quint8(127)
1799 << firstFrame.append(a: QByteArray(wireRepresentation, 8)
1800 .append(a: QByteArray(actualPayloadSize, 'a')))
1801 << (controlCode == QWebSocketProtocol::OpCodeContinue)
1802 << QWebSocketProtocol::CloseCodeGoingAway;
1803 }
1804}
1805
1806void tst_DataProcessor::nonCharacterSequence(const char *sequence)
1807{
1808 QByteArray utf8Sequence = QByteArray::fromHex(hexEncoded: sequence);
1809
1810 //doing extensive QStringLiteral concatenations here, because
1811 //MSVC 2010 complains when using concatenation literal strings about
1812 //concatenation of wide and narrow strings (error C2308)
1813 QTest::newRow(dataTag: (QStringLiteral("Text frame with payload containing the non-control character ") +
1814 QStringLiteral("sequence 0x%1"))
1815 .arg(a: QString::fromLocal8Bit(str: sequence)).toLatin1().constData())
1816 << quint8(FIN | QWebSocketProtocol::OpCodeText)
1817 << quint8(utf8Sequence.size())
1818 << utf8Sequence
1819 << false;
1820
1821 QTest::newRow(dataTag: (QStringLiteral("Continuation frame with payload containing the non-control ") +
1822 QStringLiteral("character sequence 0x%1"))
1823 .arg(a: QString::fromLocal8Bit(str: sequence)).toLatin1().constData())
1824 << quint8(FIN | QWebSocketProtocol::OpCodeContinue)
1825 << quint8(utf8Sequence.size())
1826 << utf8Sequence
1827 << true;
1828}
1829
1830void tst_DataProcessor::insertIncompleteSizeFieldTest(quint8 payloadCode, quint8 numBytesFollowing)
1831{
1832 //doing extensive QStringLiteral concatenations here, because
1833 //MSVC 2010 complains when using concatenation literal strings about
1834 //concatenation of wide and narrow strings (error C2308)
1835 QTest::newRow(QStringLiteral("Text frame with payload size %1, with %2 bytes following.")
1836 .arg(a: payloadCode).arg(a: numBytesFollowing).toLatin1().constData())
1837 << quint8(FIN | QWebSocketProtocol::OpCodeText)
1838 << quint8(payloadCode)
1839 << QByteArray(numBytesFollowing, quint8(1))
1840 << false
1841 << QWebSocketProtocol::CloseCodeGoingAway;
1842 QTest::newRow(QStringLiteral("Binary frame with payload size %1, with %2 bytes following.")
1843 .arg(a: payloadCode).arg(a: numBytesFollowing).toLatin1().constData())
1844 << quint8(FIN | QWebSocketProtocol::OpCodeBinary)
1845 << quint8(payloadCode)
1846 << QByteArray(numBytesFollowing, quint8(1))
1847 << false
1848 << QWebSocketProtocol::CloseCodeGoingAway;
1849 QTest::newRow(dataTag: (QStringLiteral("Continuation frame with payload size %1, with %2 bytes ") +
1850 QStringLiteral("following."))
1851 .arg(a: payloadCode).arg(a: numBytesFollowing).toLatin1().constData())
1852 << quint8(FIN | QWebSocketProtocol::OpCodeContinue)
1853 << quint8(payloadCode)
1854 << QByteArray(numBytesFollowing, quint8(1))
1855 << true
1856 << QWebSocketProtocol::CloseCodeGoingAway;
1857}
1858
1859void tst_DataProcessor::clearDataBuffers()
1860{
1861 const QByteArray binaryData("Hello!");
1862 QByteArray data;
1863 data.append(c: char(FIN | QWebSocketProtocol::OpCodeBinary));
1864 data.append(c: char(binaryData.length()));
1865 data.append(a: binaryData);
1866
1867 QWebSocketDataProcessor dataProcessor;
1868 connect(sender: &dataProcessor, signal: &QWebSocketDataProcessor::binaryMessageReceived,
1869 slot: [&binaryData](const QByteArray &message)
1870 {
1871 QCOMPARE(message, binaryData);
1872 QEventLoop loop;
1873 QTimer::singleShot(msec: 2000, receiver: &loop, SLOT(quit()));
1874 loop.exec();
1875 });
1876
1877 QBuffer buffer;
1878 buffer.setData(data);
1879 auto processData = [&dataProcessor, &buffer]()
1880 {
1881 buffer.open(openMode: QIODevice::ReadOnly);
1882 dataProcessor.process(pIoDevice: &buffer);
1883 buffer.close();
1884 };
1885
1886 QTimer timer;
1887 timer.setSingleShot(true);
1888 connect(sender: &timer, signal: &QTimer::timeout, slot: processData);
1889
1890 timer.start(msec: 1000);
1891 processData();
1892 QTest::qWait(ms: 2000);
1893}
1894
1895QTEST_MAIN(tst_DataProcessor)
1896
1897#include "tst_dataprocessor.moc"
1898

source code of qtwebsockets/tests/auto/websockets/dataprocessor/tst_dataprocessor.cpp