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