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