Remove unused variable
[contrib/qtwebsockets.git] / tests / auto / dataprocessor / tst_dataprocessor.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Kurt Pattyn <pattyn.kurt@gmail.com>.
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
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.
16 **
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.
24 **
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.
28 **
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.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
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>
47
48 #include "private/qwebsocketdataprocessor_p.h"
49 #include "private/qwebsocketprotocol_p.h"
50 #include "QtWebSockets/qwebsocketprotocol.h"
51
52 const quint8 FIN = 0x80;
53 const quint8 RSV1 = 0x40;
54 const quint8 RSV2 = 0x30;
55 const quint8 RSV3 = 0x10;
56
57 QT_USE_NAMESPACE
58
59 Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode)
60 Q_DECLARE_METATYPE(QWebSocketProtocol::OpCode)
61
62 class tst_DataProcessor : public QObject
63 {
64     Q_OBJECT
65
66 public:
67     tst_DataProcessor();
68
69 private Q_SLOTS:
70     void initTestCase();
71     void cleanupTestCase();
72     void init();
73     void cleanup();
74
75     /***************************************************************************
76      * Happy Flows
77      ***************************************************************************/
78     /*!
79       Tests all kinds of valid binary frames, including zero length frames
80       */
81     void goodBinaryFrame();
82     void goodBinaryFrame_data();
83
84     /*!
85       Tests all kinds of valid text frames, including zero length frames
86       */
87     void goodTextFrame();
88     void goodTextFrame_data();
89
90     /*!
91      * Test all kinds of valid control frames.
92      */
93     void goodControlFrame();
94
95     /*!
96      * Test all kinds of valid close frames.
97      */
98     void goodCloseFrame();
99     void goodCloseFrame_data();
100
101     /*!
102      * Test all valid opcodes
103      */
104     void goodOpcodes();
105     void goodOpcodes_data();
106
107     /*!
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.
112      */
113     void nonCharacterCodes();
114     void nonCharacterCodes_data();
115
116     /***************************************************************************
117      * Rainy Day Flows
118      ***************************************************************************/
119     /*!
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
123         frame.
124         This test does not test sequences of frames, only single frames are tested
125      */
126     void frameTooSmall();
127
128     /*!
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
131      */
132     void frameTooBig();
133     void frameTooBig_data();
134
135     /*!
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
138      */
139     void invalidHeader();
140     void invalidHeader_data();
141
142     /*!
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
146      */
147     void invalidControlFrame();
148     void invalidControlFrame_data();
149
150     void invalidCloseFrame();
151     void invalidCloseFrame_data();
152
153     /*!
154         Tests the QWebSocketDataProcessor for the correct handling of incomplete size fields
155         for large and big payloads.
156      */
157     void incompleteSizeField();
158     void incompleteSizeField_data();
159
160     /*!
161         Tests the QWebSocketDataProcessor for the correct handling of incomplete payloads.
162         This includes:
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
168      */
169     void incompletePayload();
170     void incompletePayload_data();
171
172     /*!
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
175      */
176     void invalidPayload();
177     void invalidPayload_data(bool isControlFrame = false);
178
179     void invalidPayloadInCloseFrame();
180     void invalidPayloadInCloseFrame_data();
181
182     /*!
183       Tests the QWebSocketDataProcessor for the correct handling of the minimum size representation
184       requirement of RFC 6455 (see paragraph 5.2)
185      */
186     void minimumSizeRequirement();
187     void minimumSizeRequirement_data();
188
189 private:
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);
202
203     //helper function to construct a new row of test data containing text frames containing
204     //sequences
205     void nonCharacterSequence(const char *sequence);
206
207     void doTest();
208     void doCloseFrameTest();
209
210     QString opCodeToString(quint8 opCode);
211 };
212
213 tst_DataProcessor::tst_DataProcessor()
214 {
215 }
216
217 void tst_DataProcessor::initTestCase()
218 {
219 }
220
221 void tst_DataProcessor::cleanupTestCase()
222 {
223 }
224
225 void tst_DataProcessor::init()
226 {
227     qRegisterMetaType<QWebSocketProtocol::OpCode>("QWebSocketProtocol::OpCode");
228     qRegisterMetaType<QWebSocketProtocol::CloseCode>("QWebSocketProtocol::CloseCode");
229 }
230
231 void tst_DataProcessor::cleanup()
232 {
233 }
234
235 void tst_DataProcessor::goodBinaryFrame_data()
236 {
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)
240     {
241         QTest::newRow(QStringLiteral("Binary frame with %1 bytes").arg(i).toLatin1().constData())
242                 << QByteArray(i, char(1));
243     }
244     for (int i = 0; i < 256; ++i)   //test all possible bytes in the payload
245     {
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));
249     }
250 }
251
252 void tst_DataProcessor::goodBinaryFrame()
253 {
254     QByteArray data;
255     QBuffer buffer;
256     QWebSocketDataProcessor dataProcessor;
257     QFETCH(QByteArray, payload);
258
259     data.append((char)(FIN | QWebSocketProtocol::OpCodeBinary));
260
261     if (payload.length() < 126)
262     {
263         data.append(char(payload.length()));
264     }
265     else if (payload.length() < 65536)
266     {
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);
271     }
272     else
273     {
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);
278     }
279
280     data.append(payload);
281     buffer.setData(data);
282     buffer.open(QIODevice::ReadOnly);
283
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());
307     buffer.close();
308 }
309
310 void tst_DataProcessor::goodTextFrame_data()
311 {
312     QTest::addColumn<QByteArray>("payload");
313     QTest::addColumn<int>("size");
314
315     //test frames with small (< 126), large ( < 65536) and big ( > 65535) payloads
316     for (int i = 0; i < (65536 + 256); i += 128)
317     {
318         QTest::newRow(QStringLiteral("Text frame with %1 ASCII characters")
319                       .arg(i).toLatin1().constData()) << QByteArray(i, 'a') << i;
320     }
321     //test all valid ASCII characters
322     for (int i = 0; i < 128; ++i)
323     {
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;
327     }
328
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
333
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")
342             << 22;
343 }
344
345 void tst_DataProcessor::goodTextFrame()
346 {
347     QByteArray data;
348     QBuffer buffer;
349     QWebSocketDataProcessor dataProcessor;
350     QFETCH(QByteArray, payload);
351     QFETCH(int, size);
352
353     data.append((char)(FIN | QWebSocketProtocol::OpCodeText));
354
355     if (payload.length() < 126)
356     {
357         data.append(char(payload.length()));
358     }
359     else if (payload.length() < 65536)
360     {
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);
365     }
366     else
367     {
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);
372     }
373
374     data.append(payload);
375     buffer.setData(data);
376     buffer.open(QIODevice::ReadOnly);
377
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)));
388
389     dataProcessor.process(&buffer);
390
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);
403     buffer.close();
404 }
405
406 void tst_DataProcessor::goodControlFrame()
407 {
408     QByteArray data;
409     QBuffer buffer;
410     QWebSocketDataProcessor dataProcessor;
411
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)));
422
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);
436     buffer.close();
437
438     data.clear();
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);
454     buffer.close();
455 }
456
457 void tst_DataProcessor::goodCloseFrame_data()
458 {
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)
464     {
465         QTest::newRow(QStringLiteral("Close frame with %1 ASCII characters")
466                       .arg(i).toLatin1().constData())
467                 << QString(i, 'a')
468                 << QWebSocketProtocol::CloseCodeNormal;
469     }
470     for (int i = 0; i < 126; ++i)
471     {
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;
475     }
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);
502
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);
530
531     QTest::newRow("Close frame with no close code and no reason")
532             << QString() << QWebSocketProtocol::CloseCode(0);
533 }
534
535 void tst_DataProcessor::goodOpcodes_data()
536 {
537     QTest::addColumn<QWebSocketProtocol::OpCode>("opCode");
538
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;
544 }
545
546 void tst_DataProcessor::goodOpcodes()
547 {
548     QByteArray data;
549     QBuffer buffer;
550     QWebSocketDataProcessor dataProcessor;
551     QFETCH(QWebSocketProtocol::OpCode, opCode);
552
553     data.append((char)(FIN | opCode));
554     data.append(char(0));   //zero length
555
556     buffer.setData(data);
557     buffer.open(QIODevice::ReadOnly);
558
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)));
575
576     dataProcessor.process(&buffer);
577
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);
586
587     buffer.close();
588 }
589
590 void tst_DataProcessor::goodCloseFrame()
591 {
592     QByteArray data;
593     QBuffer buffer;
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));
599
600     data.append((char)(FIN | QWebSocketProtocol::OpCodeClose));
601     if (swapped != 0)
602     {
603         data.append(char(payload.length() + 2)).append(wireRepresentation, 2).append(payload);
604     }
605     else
606     {
607         data.append(QChar::fromLatin1(0));  //payload length 0;
608         //dataprocessor emits a CloseCodeNormal close code when none is present
609         closeCode = QWebSocketProtocol::CloseCodeNormal;
610     }
611     buffer.setData(data);
612     buffer.open(QIODevice::ReadOnly);
613
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)));
624
625     dataProcessor.process(&buffer);
626
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());
638     buffer.close();
639 }
640
641 void tst_DataProcessor::nonCharacterCodes_data()
642 {
643     QTest::addColumn<quint8>("firstByte");
644     QTest::addColumn<quint8>("secondByte");
645     QTest::addColumn<QByteArray>("payload");
646     QTest::addColumn<bool>("isContinuationFrame");
647
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");
682 }
683
684 void tst_DataProcessor::nonCharacterCodes()
685 {
686     QFETCH(quint8, firstByte);
687     QFETCH(quint8, secondByte);
688     QFETCH(QByteArray, payload);
689     QFETCH(bool, isContinuationFrame);
690
691     if (!isContinuationFrame)
692     {
693         QByteArray data;
694         QBuffer buffer;
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)));
706
707         data.append(firstByte).append(secondByte);
708         data.append(payload);
709         buffer.setData(data);
710         buffer.open(QIODevice::ReadOnly);
711         dataProcessor.process(&buffer);
712
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);
721
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);
727         buffer.close();
728     }
729 }
730
731 void tst_DataProcessor::frameTooSmall()
732 {
733     QByteArray data;
734     QBuffer buffer;
735     QWebSocketDataProcessor dataProcessor;
736     QByteArray firstFrame;
737
738     firstFrame.append(quint8(QWebSocketProtocol::OpCodeText)).append(char(1))
739             .append(QByteArray(1, 'a'));
740
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)));
755
756     dataProcessor.process(&buffer);
757
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);
766
767     QList<QVariant> arguments = errorSpy.takeFirst();
768     QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(),
769              QWebSocketProtocol::CloseCodeGoingAway);
770     errorSpy.clear();
771     closeSpy.clear();
772     pingMessageSpy.clear();
773     pongMessageSpy.clear();
774     textMessageSpy.clear();
775     binaryMessageSpy.clear();
776     textFrameSpy.clear();
777     binaryFrameSpy.clear();
778     buffer.close();
779     data.clear();
780
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);
787
788     dataProcessor.process(&buffer);
789
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);
798
799     arguments = errorSpy.takeFirst();
800     QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(),
801              QWebSocketProtocol::CloseCodeGoingAway);
802     buffer.close();
803     errorSpy.clear();
804     closeSpy.clear();
805     pingMessageSpy.clear();
806     pongMessageSpy.clear();
807     textMessageSpy.clear();
808     binaryMessageSpy.clear();
809     textFrameSpy.clear();
810     binaryFrameSpy.clear();
811     data.clear();
812
813
814     {
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);
819
820         dataProcessor.process(&buffer);
821
822         buffer.close();
823         data.clear();
824
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);
833
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);
842
843         QList<QVariant> arguments = errorSpy.takeFirst();
844         QCOMPARE(arguments.at(0).value<QWebSocketProtocol::CloseCode>(),
845                  QWebSocketProtocol::CloseCodeGoingAway);
846         errorSpy.clear();
847         closeSpy.clear();
848         pingMessageSpy.clear();
849         pongMessageSpy.clear();
850         textMessageSpy.clear();
851         binaryMessageSpy.clear();
852         textFrameSpy.clear();
853         binaryFrameSpy.clear();
854         buffer.close();
855         data.clear();
856
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);
862
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);
871
872         buffer.close();
873         data.clear();
874
875         errorSpy.clear();
876         closeSpy.clear();
877         pingMessageSpy.clear();
878         pongMessageSpy.clear();
879         textMessageSpy.clear();
880         binaryMessageSpy.clear();
881         textFrameSpy.clear();
882         binaryFrameSpy.clear();
883
884         //only 1 byte follows in continuation frame;
885         //should time out with close code CloseCodeGoingAway
886         data.append('a');
887         buffer.setData(data);
888         buffer.open(QIODevice::ReadOnly);
889
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);
902         buffer.close();
903     }
904 }
905
906 void tst_DataProcessor::frameTooBig_data()
907 {
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");
913
914     quint64 swapped64 = 0;
915     const char *wireRepresentation = 0;
916
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
920
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)
925             << quint8(127)
926             << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a'))
927             << false
928             << QWebSocketProtocol::CloseCodeTooMuchData;
929
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)
934             << quint8(127)
935             << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a'))
936             << false
937             << QWebSocketProtocol::CloseCodeTooMuchData;
938
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)
943             << quint8(127)
944             << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a'))
945             << true
946             << QWebSocketProtocol::CloseCodeTooMuchData;
947 }
948
949 void tst_DataProcessor::frameTooBig()
950 {
951     doTest();
952 }
953
954 void tst_DataProcessor::invalidHeader_data()
955 {
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");
964
965     //invalid bit fields
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);
973
974     //invalid opcodes
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);
985 }
986
987 void tst_DataProcessor::invalidHeader()
988 {
989     doTest();
990 }
991
992 void tst_DataProcessor::invalidControlFrame_data()
993 {
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");
999
1000
1001     QTest::newRow("Close control frame with payload size 126")
1002             << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1003             << quint8(126)
1004             << QByteArray()
1005             << false
1006             << QWebSocketProtocol::CloseCodeProtocolError;
1007     QTest::newRow("Ping control frame with payload size 126")
1008             << quint8(FIN | QWebSocketProtocol::OpCodePing)
1009             << quint8(126)
1010             << QByteArray()
1011             << false
1012             << QWebSocketProtocol::CloseCodeProtocolError;
1013     QTest::newRow("Close control frame with payload size 126")
1014             << quint8(FIN | QWebSocketProtocol::OpCodePong)
1015             << quint8(126)
1016             << QByteArray()
1017             << false
1018             << QWebSocketProtocol::CloseCodeProtocolError;
1019
1020     QTest::newRow("Non-final close control frame (fragmented)")
1021             << quint8(QWebSocketProtocol::OpCodeClose)
1022             << quint8(32)
1023             << QByteArray()
1024             << false
1025             << QWebSocketProtocol::CloseCodeProtocolError;
1026     QTest::newRow("Non-final ping control frame (fragmented)")
1027             << quint8(QWebSocketProtocol::OpCodePing)
1028             << quint8(32) << QByteArray()
1029             << false
1030             << QWebSocketProtocol::CloseCodeProtocolError;
1031     QTest::newRow("Non-final pong control frame (fragmented)")
1032             << quint8(QWebSocketProtocol::OpCodePong)
1033             << quint8(32)
1034             << QByteArray()
1035             << false
1036             << QWebSocketProtocol::CloseCodeProtocolError;
1037 }
1038
1039 void tst_DataProcessor::invalidControlFrame()
1040 {
1041     doTest();
1042 }
1043
1044 void tst_DataProcessor::invalidCloseFrame_data()
1045 {
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");
1051
1052     QTest::newRow("Close control frame with payload size 1")
1053             << quint8(FIN | QWebSocketProtocol::OpCodeClose)
1054             << quint8(1)
1055             << QByteArray(1, 'a')
1056             << false
1057             << QWebSocketProtocol::CloseCodeProtocolError;
1058     quint16 swapped = qToBigEndian<quint16>(QWebSocketProtocol::CloseCodeAbnormalDisconnection);
1059     const char *wireRepresentation = static_cast<const char *>(static_cast<const void *>(&swapped));
1060
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)
1064             << quint8(2)
1065             << QByteArray(wireRepresentation, 2)
1066             << false
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)
1073             << quint8(2)
1074             << QByteArray(wireRepresentation, 2)
1075             << false
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)
1081             << quint8(2)
1082             << QByteArray(wireRepresentation, 2)
1083             << false
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)
1090             << quint8(2)
1091             << QByteArray(wireRepresentation, 2)
1092             << false
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)
1098             << quint8(2)
1099             << QByteArray(wireRepresentation, 2)
1100             << false
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)
1106             << quint8(2)
1107             << QByteArray(wireRepresentation, 2)
1108             << false
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)
1114             << quint8(2)
1115             << QByteArray(wireRepresentation, 2)
1116             << false
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)
1122             << quint8(2)
1123             << QByteArray(wireRepresentation, 2)
1124             << false
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)
1130             << quint8(2)
1131             << QByteArray(wireRepresentation, 2)
1132             << false
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)
1138             << quint8(2)
1139             << QByteArray(wireRepresentation, 2)
1140             << false
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)
1146             << quint8(2)
1147             << QByteArray(wireRepresentation, 2)
1148             << false
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)
1154             << quint8(2)
1155             << QByteArray(wireRepresentation, 2)
1156             << false
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)
1162             << quint8(2)
1163             << QByteArray(wireRepresentation, 2)
1164             << false
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)
1170             << quint8(2)
1171             << QByteArray(wireRepresentation, 2)
1172             << false
1173             << QWebSocketProtocol::CloseCodeProtocolError;
1174 }
1175
1176 void tst_DataProcessor::invalidCloseFrame()
1177 {
1178     doCloseFrameTest();
1179 }
1180
1181 void tst_DataProcessor::minimumSizeRequirement_data()
1182 {
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");
1188
1189     minimumSize16Bit(0);
1190     minimumSize16Bit(64);
1191     minimumSize16Bit(125);
1192
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);
1206 }
1207
1208 void tst_DataProcessor::minimumSizeRequirement()
1209 {
1210     doTest();
1211 }
1212
1213 void tst_DataProcessor::invalidPayload_data(bool isControlFrame)
1214 {
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");
1220
1221     //6.3: invalid UTF-8 sequence
1222     invalidUTF8("case 6.3.1",   "cebae1bdb9cf83cebcceb5eda080656469746564", isControlFrame);
1223
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);
1227
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);
1235
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);
1239
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);
1244
1245     //5.11: boundary conditions
1246     invalidUTF8("case 6.11.5",  "f4908080", isControlFrame);
1247
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",
1259                 isControlFrame);
1260
1261     //6.13: lonely start characters
1262     invalidUTF8("case 6.13.1",
1263                 "c020c120c220c320c420c520c620c720c820c920ca20cb20cc20cd20ce20cf20d020d120d220"
1264                 "d320d420d520d620d720d820d920da20db20dc20dd20de20",
1265                 isControlFrame);
1266     invalidUTF8("case 6.13.2",  "e020e120e220e320e420e520e620e720e820e920ea20eb20ec20ed20ee20",
1267                 isControlFrame);
1268     invalidUTF8("case 6.13.3",  "f020f120f220f320f420f520f620", isControlFrame);
1269     invalidUTF8("case 6.13.4",  "f820f920fa20", isControlFrame);
1270     invalidUTF8("case 6.13.5",  "fc20", isControlFrame);
1271
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);
1283
1284     //6.15: concatenation of incomplete sequences
1285     invalidUTF8("case 6.15.1",
1286                 "c0e080f08080f8808080fc80808080dfefbff7bfbffbbfbfbffdbfbfbfbf", isControlFrame);
1287
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);
1292
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);
1299
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);
1306
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);
1313
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);
1322
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);
1332 }
1333
1334 void tst_DataProcessor::invalidPayload()
1335 {
1336     doTest();
1337 }
1338
1339 void tst_DataProcessor::invalidPayloadInCloseFrame_data()
1340 {
1341     invalidPayload_data(true);
1342 }
1343
1344 void tst_DataProcessor::invalidPayloadInCloseFrame()
1345 {
1346     QFETCH(quint8, firstByte);
1347     QFETCH(quint8, secondByte);
1348     QFETCH(QByteArray, payload);
1349     QFETCH(bool, isContinuationFrame);
1350     QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
1351
1352     Q_UNUSED(isContinuationFrame)
1353
1354     QByteArray data;
1355     QBuffer buffer;
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)));
1367
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);
1383     buffer.close();
1384 }
1385
1386 void tst_DataProcessor::incompletePayload_data()
1387 {
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");
1393
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);
1406
1407     incompleteFrame(QWebSocketProtocol::OpCodeClose, 64, 32);
1408     incompleteFrame(QWebSocketProtocol::OpCodePing, 64, 32);
1409     incompleteFrame(QWebSocketProtocol::OpCodePong, 64, 32);
1410 }
1411
1412 void tst_DataProcessor::incompletePayload()
1413 {
1414     doTest();
1415 }
1416
1417 void tst_DataProcessor::incompleteSizeField_data()
1418 {
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");
1424
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);
1429
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);
1440 }
1441
1442 void tst_DataProcessor::incompleteSizeField()
1443 {
1444     doTest();
1445 }
1446
1447 //////////////////////////////////////////////////////////////////////////////////////////
1448 /// HELPER FUNCTIONS
1449 //////////////////////////////////////////////////////////////////////////////////////////
1450 void tst_DataProcessor::doTest()
1451 {
1452     QFETCH(quint8, firstByte);
1453     QFETCH(quint8, secondByte);
1454     QFETCH(QByteArray, payload);
1455     QFETCH(bool, isContinuationFrame);
1456     QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
1457
1458     QByteArray data;
1459     QBuffer buffer;
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)));
1467
1468     if (isContinuationFrame)
1469     {
1470         data.append(quint8(QWebSocketProtocol::OpCodeText))
1471             .append(char(1))
1472             .append(QByteArray(1, 'a'));
1473     }
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);
1486     buffer.close();
1487     errorSpy.clear();
1488     data.clear();
1489 }
1490
1491 void tst_DataProcessor::doCloseFrameTest()
1492 {
1493     QFETCH(quint8, firstByte);
1494     QFETCH(quint8, secondByte);
1495     QFETCH(QByteArray, payload);
1496     QFETCH(bool, isContinuationFrame);
1497     QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode);
1498
1499     Q_UNUSED(isContinuationFrame)
1500
1501     QByteArray data;
1502     QBuffer buffer;
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)));
1512
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);
1526     buffer.close();
1527 }
1528
1529 QString tst_DataProcessor::opCodeToString(quint8 opCode)
1530 {
1531     QString frameType;
1532     switch (opCode)
1533     {
1534         case QWebSocketProtocol::OpCodeBinary:
1535         {
1536             frameType = QStringLiteral("Binary");
1537             break;
1538         }
1539         case QWebSocketProtocol::OpCodeText:
1540         {
1541             frameType = QStringLiteral("Text");
1542             break;
1543         }
1544         case QWebSocketProtocol::OpCodePing:
1545         {
1546             frameType = QStringLiteral("Ping");
1547             break;
1548         }
1549         case QWebSocketProtocol::OpCodePong:
1550         {
1551             frameType = QStringLiteral("Pong");
1552             break;
1553         }
1554         case QWebSocketProtocol::OpCodeClose:
1555         {
1556             frameType = QStringLiteral("Close");
1557             break;
1558         }
1559         case QWebSocketProtocol::OpCodeContinue:
1560         {
1561             frameType = QStringLiteral("Continuation");
1562             break;
1563         }
1564         case QWebSocketProtocol::OpCodeReserved3:
1565         {
1566             frameType = QStringLiteral("Reserved3");
1567             break;
1568         }
1569         case QWebSocketProtocol::OpCodeReserved4:
1570         {
1571             frameType = QStringLiteral("Reserved5");
1572             break;
1573         }
1574         case QWebSocketProtocol::OpCodeReserved5:
1575         {
1576             frameType = QStringLiteral("Reserved5");
1577             break;
1578         }
1579         case QWebSocketProtocol::OpCodeReserved6:
1580         {
1581             frameType = QStringLiteral("Reserved6");
1582             break;
1583         }
1584         case QWebSocketProtocol::OpCodeReserved7:
1585         {
1586             frameType = QStringLiteral("Reserved7");
1587             break;
1588         }
1589         case QWebSocketProtocol::OpCodeReservedB:
1590         {
1591             frameType = QStringLiteral("ReservedB");
1592             break;
1593         }
1594         case QWebSocketProtocol::OpCodeReservedC:
1595         {
1596             frameType = QStringLiteral("ReservedC");
1597             break;
1598         }
1599         case QWebSocketProtocol::OpCodeReservedD:
1600         {
1601             frameType = QStringLiteral("ReservedD");
1602             break;
1603         }
1604         case QWebSocketProtocol::OpCodeReservedE:
1605         {
1606             frameType = QStringLiteral("ReservedE");
1607             break;
1608         }
1609         case QWebSocketProtocol::OpCodeReservedF:
1610         {
1611             frameType = QStringLiteral("ReservedF");
1612             break;
1613         }
1614         default:
1615         {
1616             //should never come here
1617             Q_ASSERT(false);
1618         }
1619     }
1620     return frameType;
1621 }
1622
1623 void tst_DataProcessor::minimumSize16Bit(quint16 sizeInBytes)
1624 {
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)
1631             << quint8(126)
1632             << QByteArray(wireRepresentation, 2)
1633             << false
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)
1638             << quint8(126)
1639             << QByteArray(wireRepresentation, 2)
1640             << false
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)
1645             << quint8(126)
1646             << QByteArray(wireRepresentation, 2)
1647             << true
1648             << QWebSocketProtocol::CloseCodeProtocolError;
1649 }
1650
1651 void tst_DataProcessor::minimumSize64Bit(quint64 sizeInBytes)
1652 {
1653     quint64 swapped64 = qToBigEndian<quint64>(sizeInBytes);
1654     const char *wireRepresentation
1655             = static_cast<const char *>(static_cast<const void *>(&swapped64));
1656
1657     QTest::newRow(QStringLiteral("Text frame with payload size %1, represented in 8 bytes")
1658                   .arg(sizeInBytes).toLatin1().constData())
1659             << quint8(FIN | QWebSocketProtocol::OpCodeText)
1660             << quint8(127)
1661             << QByteArray(wireRepresentation, 8)
1662             << false
1663             << QWebSocketProtocol::CloseCodeProtocolError;
1664
1665     QTest::newRow(QStringLiteral("Binary frame with payload size %1, represented in 8 bytes")
1666                   .arg(sizeInBytes).toLatin1().constData())
1667             << quint8(FIN | QWebSocketProtocol::OpCodeBinary)
1668             << quint8(127)
1669             << QByteArray(wireRepresentation, 8)
1670             << false
1671             << QWebSocketProtocol::CloseCodeProtocolError;
1672
1673     QTest::newRow(QStringLiteral("Continuation frame with payload size %1, represented in 8 bytes")
1674                   .arg(sizeInBytes).toLatin1().constData())
1675             << quint8(FIN | QWebSocketProtocol::OpCodeContinue)
1676             << quint8(127)
1677             << QByteArray(wireRepresentation, 8)
1678             << true
1679             << QWebSocketProtocol::CloseCodeProtocolError;
1680 }
1681
1682 void tst_DataProcessor::invalidUTF8(const char *dataTag, const char *utf8Sequence,
1683                                     bool isCloseFrame)
1684 {
1685     QByteArray payload = QByteArray::fromHex(utf8Sequence);
1686
1687     if (isCloseFrame)
1688     {
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)
1697                 << false
1698                 << QWebSocketProtocol::CloseCodeWrongDatatype;
1699     }
1700     else
1701     {
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())
1706                 << payload
1707                 << false
1708                 << QWebSocketProtocol::CloseCodeWrongDatatype;
1709
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())
1714                 << payload
1715                 << true
1716                 << QWebSocketProtocol::CloseCodeWrongDatatype;
1717     }
1718 }
1719
1720 void tst_DataProcessor::invalidField(const char *dataTag, quint8 invalidFieldValue)
1721 {
1722     QTest::newRow(dataTag) << quint8(FIN | invalidFieldValue)
1723                            << quint8(0x00)
1724                            << QByteArray()
1725                            << false
1726                            << QWebSocketProtocol::CloseCodeProtocolError;
1727     QTest::newRow(QString::fromLatin1(dataTag).append(QStringLiteral(" with continuation frame"))
1728                   .toLatin1().constData())
1729                             << quint8(FIN | invalidFieldValue)
1730                             << quint8(0x00)
1731                             << QByteArray()
1732                             << true
1733                             << QWebSocketProtocol::CloseCodeProtocolError;
1734 }
1735
1736 void tst_DataProcessor::incompleteFrame(quint8 controlCode, quint64 indicatedSize,
1737                                         quint64 actualPayloadSize)
1738 {
1739     QVERIFY(!QWebSocketProtocol::isOpCodeReserved(QWebSocketProtocol::OpCode(controlCode)));
1740     QVERIFY(indicatedSize > actualPayloadSize);
1741
1742     QString frameType = opCodeToString(controlCode);
1743     QByteArray firstFrame;
1744
1745     if (indicatedSize < 126)
1746     {
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;
1759     }
1760     else if (indicatedSize <= 0xFFFFu)
1761     {
1762         quint16 swapped16 = qToBigEndian<quint16>(static_cast<quint16>(indicatedSize));
1763         const char *wireRepresentation
1764                 = static_cast<const char *>(static_cast<const void *>(&swapped16));
1765         QTest::newRow(
1766                     frameType.append(QStringLiteral(" frame with payload size %1, but only ") +
1767                                      QStringLiteral("%2 bytes of data")
1768                                      .arg(indicatedSize)
1769                                      .arg(actualPayloadSize)).toLatin1().constData())
1770                 << quint8(FIN | controlCode)
1771                 << quint8(126)
1772                 << firstFrame.append(QByteArray(wireRepresentation, 2)
1773                                      .append(QByteArray(actualPayloadSize, 'a')))
1774                 << (controlCode == QWebSocketProtocol::OpCodeContinue)
1775                 << QWebSocketProtocol::CloseCodeGoingAway;
1776     }
1777     else
1778     {
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)
1787                 << quint8(127)
1788                 << firstFrame.append(QByteArray(wireRepresentation, 8)
1789                                      .append(QByteArray(actualPayloadSize, 'a')))
1790                 << (controlCode == QWebSocketProtocol::OpCodeContinue)
1791                 << QWebSocketProtocol::CloseCodeGoingAway;
1792     }
1793 }
1794
1795 void tst_DataProcessor::nonCharacterSequence(const char *sequence)
1796 {
1797     QByteArray utf8Sequence = QByteArray::fromHex(sequence);
1798
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())
1807             << utf8Sequence
1808             << false;
1809
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())
1815             << utf8Sequence
1816             << true;
1817 }
1818
1819 void tst_DataProcessor::insertIncompleteSizeFieldTest(quint8 payloadCode, quint8 numBytesFollowing)
1820 {
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))
1829             << false
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))
1836             << false
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))
1844             << true
1845             << QWebSocketProtocol::CloseCodeGoingAway;
1846 }
1847
1848 QTEST_MAIN(tst_DataProcessor)
1849
1850 #include "tst_dataprocessor.moc"