Adapt copyright header
[contrib/qtwebsockets.git] / tests / auto / websocketframe / tst_websocketframe.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 <QDebug>
44 #include <QByteArray>
45 #include <QtEndian>
46
47 #include "private/qwebsocketframe_p.h"
48 #include "private/qwebsocketprotocol_p.h"
49 #include "qwebsocketprotocol.h"
50
51 QT_USE_NAMESPACE
52
53 Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode)
54 Q_DECLARE_METATYPE(QWebSocketProtocol::OpCode)
55
56 /*!
57  * \brief class FrameHelper is used to encode a single frame.
58  *
59  * \internal
60  */
61 class FrameHelper
62 {
63 public:
64     FrameHelper();
65
66     QByteArray wireRepresentation();
67
68     void setRsv1(int value) { m_rsv1 = value; }
69     void setRsv2(int value) { m_rsv2 = value; }
70     void setRsv3(int value) { m_rsv3 = value; }
71     void setMask(quint32 mask) { m_mask = mask; }
72     void setOpCode(QWebSocketProtocol::OpCode opCode) { m_opCode = opCode; }
73     void setPayload(const QByteArray &payload) { m_payload = payload; }
74     void setFinalFrame(bool isFinal) { m_isFinalFrame = isFinal; }
75
76 private:
77     int m_rsv1;
78     int m_rsv2;
79     int m_rsv3;
80     quint32 m_mask;
81     QWebSocketProtocol::OpCode m_opCode;
82     QByteArray m_payload;
83     bool m_isFinalFrame;
84 };
85
86 FrameHelper::FrameHelper() :
87     m_rsv1(0), m_rsv2(0), m_rsv3(0),
88     m_mask(0), m_opCode(QWebSocketProtocol::OpCodeReserved3),
89     m_payload(), m_isFinalFrame(false)
90 {}
91
92 QByteArray FrameHelper::wireRepresentation()
93 {
94     quint8 byte = 0x00;
95     QByteArray wireRep;
96     quint64 payloadLength = m_payload.length();
97
98     //FIN, opcode
99     byte = static_cast<quint8>((m_opCode & 0x0F) | (m_isFinalFrame ? 0x80 : 0x00)); //FIN, opcode
100     //RSV1-3
101     byte |= static_cast<quint8>(((m_rsv1 & 0x01) << 6) | ((m_rsv2 & 0x01) << 5) |
102                                 ((m_rsv3 & 0x01) << 4));
103     wireRep.append(static_cast<char>(byte));
104
105     byte = 0x00;
106     if (m_mask != 0)
107     {
108         byte |= 0x80;
109     }
110     if (payloadLength <= 125)
111     {
112         byte |= static_cast<quint8>(payloadLength);
113         wireRep.append(static_cast<char>(byte));
114     }
115     else if (payloadLength <= 0xFFFFU)
116     {
117         byte |= 126;
118         wireRep.append(static_cast<char>(byte));
119         quint16 swapped = qToBigEndian<quint16>(static_cast<quint16>(payloadLength));
120         wireRep.append(static_cast<const char *>(static_cast<const void *>(&swapped)), 2);
121     }
122     else
123     {
124         byte |= 127;
125         wireRep.append(static_cast<char>(byte));
126         quint64 swapped = qToBigEndian<quint64>(payloadLength);
127         wireRep.append(static_cast<const char *>(static_cast<const void *>(&swapped)), 8);
128     }
129     //Write mask
130     if (m_mask != 0)
131     {
132         wireRep.append(static_cast<const char *>(static_cast<const void *>(&m_mask)),
133                        sizeof(quint32));
134     }
135     QByteArray tmpData = m_payload;
136     if (m_mask)
137     {
138         tmpData.detach();
139         QWebSocketProtocol::mask(&tmpData, m_mask);
140     }
141     wireRep.append(tmpData);
142     return wireRep;
143 }
144
145 class tst_WebSocketFrame : public QObject
146 {
147     Q_OBJECT
148
149 public:
150     tst_WebSocketFrame();
151
152 private Q_SLOTS:
153     void initTestCase();
154     void cleanupTestCase();
155     void init();
156     void cleanup();
157
158     void tst_initialization();
159     void tst_copyConstructorAndAssignment();
160
161     void tst_goodFrames_data();
162     void tst_goodFrames();
163
164     void tst_invalidFrames_data();
165     void tst_invalidFrames();
166
167     void tst_malformedFrames_data();
168     void tst_malformedFrames();
169 };
170
171 tst_WebSocketFrame::tst_WebSocketFrame()
172 {}
173
174 void tst_WebSocketFrame::initTestCase()
175 {
176 }
177
178 void tst_WebSocketFrame::cleanupTestCase()
179 {}
180
181 void tst_WebSocketFrame::init()
182 {
183     qRegisterMetaType<QWebSocketProtocol::OpCode>("QWebSocketProtocol::OpCode");
184     qRegisterMetaType<QWebSocketProtocol::CloseCode>("QWebSocketProtocol::CloseCode");
185 }
186
187 void tst_WebSocketFrame::cleanup()
188 {
189 }
190
191 void tst_WebSocketFrame::tst_initialization()
192 {
193     QWebSocketFrame frame;
194     QVERIFY(!frame.isValid());
195     QCOMPARE(frame.payload().length(), 0);
196 }
197
198 void tst_WebSocketFrame::tst_copyConstructorAndAssignment()
199 {
200     FrameHelper frameHelper;
201     frameHelper.setRsv1(0);
202     frameHelper.setRsv2(0);
203     frameHelper.setRsv3(0);
204     frameHelper.setFinalFrame(true);
205     frameHelper.setMask(1234u);
206     frameHelper.setOpCode(QWebSocketProtocol::OpCodeBinary);
207     frameHelper.setPayload(QByteArrayLiteral("12345"));
208
209     QByteArray payload = frameHelper.wireRepresentation();
210     QBuffer buffer(&payload);
211     buffer.open(QIODevice::ReadOnly);
212
213     QWebSocketFrame frame = QWebSocketFrame::readFrame(&buffer);
214     buffer.close();
215
216     {
217         QWebSocketFrame other(frame);
218         QCOMPARE(other.closeCode(), frame.closeCode());
219         QCOMPARE(other.closeReason(), frame.closeReason());
220         QCOMPARE(other.hasMask(), frame.hasMask());
221         QCOMPARE(other.isContinuationFrame(), frame.isContinuationFrame());
222         QCOMPARE(other.isControlFrame(), frame.isControlFrame());
223         QCOMPARE(other.isDataFrame(), frame.isDataFrame());
224         QCOMPARE(other.isFinalFrame(), frame.isFinalFrame());
225         QCOMPARE(other.isValid(), frame.isValid());
226         QCOMPARE(other.mask(), frame.mask());
227         QCOMPARE(other.opCode(), frame.opCode());
228         QCOMPARE(other.payload(), frame.payload());
229         QCOMPARE(other.rsv1(), frame.rsv1());
230         QCOMPARE(other.rsv2(), frame.rsv2());
231         QCOMPARE(other.rsv3(), frame.rsv3());
232     }
233     {
234         QWebSocketFrame other;
235         other = frame;
236         QCOMPARE(other.closeCode(), frame.closeCode());
237         QCOMPARE(other.closeReason(), frame.closeReason());
238         QCOMPARE(other.hasMask(), frame.hasMask());
239         QCOMPARE(other.isContinuationFrame(), frame.isContinuationFrame());
240         QCOMPARE(other.isControlFrame(), frame.isControlFrame());
241         QCOMPARE(other.isDataFrame(), frame.isDataFrame());
242         QCOMPARE(other.isFinalFrame(), frame.isFinalFrame());
243         QCOMPARE(other.isValid(), frame.isValid());
244         QCOMPARE(other.mask(), frame.mask());
245         QCOMPARE(other.opCode(), frame.opCode());
246         QCOMPARE(other.payload(), frame.payload());
247         QCOMPARE(other.rsv1(), frame.rsv1());
248         QCOMPARE(other.rsv2(), frame.rsv2());
249         QCOMPARE(other.rsv3(), frame.rsv3());
250     }
251 }
252
253 void tst_WebSocketFrame::tst_goodFrames_data()
254 {
255     QTest::addColumn<int>("rsv1");
256     QTest::addColumn<int>("rsv2");
257     QTest::addColumn<int>("rsv3");
258     QTest::addColumn<quint32>("mask");
259     QTest::addColumn<QWebSocketProtocol::OpCode>("opCode");
260     QTest::addColumn<bool>("isFinal");
261     QTest::addColumn<QByteArray>("payload");
262     QTest::addColumn<bool>("isControlFrame");
263     QTest::addColumn<bool>("isDataFrame");
264     QTest::addColumn<bool>("isContinuationFrame");
265
266     QTest::newRow("Non masked final text frame with small payload")
267             << 0 << 0 << 0
268             << 0U << QWebSocketProtocol::OpCodeText
269             << true << QStringLiteral("Hello world!").toUtf8()
270             << false << true << false;
271     QTest::newRow("Non masked final binary frame with small payload")
272             << 0 << 0 << 0
273             << 0U << QWebSocketProtocol::OpCodeBinary
274             << true << QByteArrayLiteral("\x00\x01\x02\x03\x04")
275             << false << true << false;
276     QTest::newRow("Non masked final text frame with no payload")
277             << 0 << 0 << 0
278             << 0U << QWebSocketProtocol::OpCodeText
279             << true << QByteArray()
280             << false << true << false;
281     QTest::newRow("Non masked final binary frame with no payload")
282             << 0 << 0 << 0
283             << 0U << QWebSocketProtocol::OpCodeBinary
284             << true << QByteArray()
285             << false << true << false;
286
287     QTest::newRow("Non masked final close frame with small payload")
288             << 0 << 0 << 0
289             << 0U << QWebSocketProtocol::OpCodeClose
290             << true << QStringLiteral("Hello world!").toUtf8()
291             << true << false << false;
292     QTest::newRow("Non masked final close frame with no payload")
293             << 0 << 0 << 0
294             << 0U << QWebSocketProtocol::OpCodeClose
295             << true << QByteArray()
296             << true << false << false;
297     QTest::newRow("Non masked final ping frame with small payload")
298             << 0 << 0 << 0
299             << 0U << QWebSocketProtocol::OpCodePing
300             << true << QStringLiteral("Hello world!").toUtf8()
301             << true << false << false;
302     QTest::newRow("Non masked final pong frame with no payload")
303             << 0 << 0 << 0
304             << 0U << QWebSocketProtocol::OpCodePong
305             << true << QByteArray()
306             << true << false << false;
307
308     QTest::newRow("Non masked final continuation frame with small payload")
309             << 0 << 0 << 0
310             << 0U << QWebSocketProtocol::OpCodeContinue
311             << true << QStringLiteral("Hello world!").toUtf8()
312             << false << true << true;
313     QTest::newRow("Non masked non-final continuation frame with small payload")
314             << 0 << 0 << 0
315             << 0U << QWebSocketProtocol::OpCodeContinue
316             << false << QStringLiteral("Hello world!").toUtf8()
317             << false << true << true;
318 }
319
320 void tst_WebSocketFrame::tst_goodFrames()
321 {
322     QFETCH(int, rsv1);
323     QFETCH(int, rsv2);
324     QFETCH(int, rsv3);
325     QFETCH(quint32, mask);
326     QFETCH(QWebSocketProtocol::OpCode, opCode);
327     QFETCH(bool, isFinal);
328     QFETCH(QByteArray, payload);
329     QFETCH(bool, isControlFrame);
330     QFETCH(bool, isDataFrame);
331     QFETCH(bool, isContinuationFrame);
332
333     FrameHelper helper;
334     helper.setRsv1(rsv1);
335     helper.setRsv2(rsv2);
336     helper.setRsv3(rsv3);
337     helper.setMask(mask);
338     helper.setOpCode(opCode);
339     helper.setFinalFrame(isFinal);
340     helper.setPayload(payload);
341
342     QByteArray wireRepresentation = helper.wireRepresentation();
343     QBuffer buffer;
344     buffer.setData(wireRepresentation);
345     buffer.open(QIODevice::ReadOnly);
346     QWebSocketFrame frame = QWebSocketFrame::readFrame(&buffer);
347     buffer.close();
348     QVERIFY(frame.isValid());
349     QCOMPARE(frame.rsv1(), rsv1);
350     QCOMPARE(frame.rsv2(), rsv2);
351     QCOMPARE(frame.rsv3(), rsv3);
352     QCOMPARE(frame.hasMask(), (mask != 0));
353     QCOMPARE(frame.opCode(), opCode);
354     QCOMPARE(frame.isFinalFrame(), isFinal);
355     QCOMPARE(frame.isControlFrame(), isControlFrame);
356     QCOMPARE(frame.isDataFrame(), isDataFrame);
357     QCOMPARE(frame.isContinuationFrame(), isContinuationFrame);
358     QCOMPARE(frame.payload().length(), payload.length());
359     QCOMPARE(frame.payload(), payload);
360 }
361
362 void tst_WebSocketFrame::tst_invalidFrames_data()
363 {
364     QTest::addColumn<int>("rsv1");
365     QTest::addColumn<int>("rsv2");
366     QTest::addColumn<int>("rsv3");
367     QTest::addColumn<quint32>("mask");
368     QTest::addColumn<QWebSocketProtocol::OpCode>("opCode");
369     QTest::addColumn<bool>("isFinal");
370     QTest::addColumn<QByteArray>("payload");
371     QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedError");
372
373     QTest::newRow("RSV1 != 0")
374             << 1 << 0 << 0
375             << 0U << QWebSocketProtocol::OpCodeText
376             << true << QStringLiteral("Hello world!").toUtf8()
377             << QWebSocketProtocol::CloseCodeProtocolError;
378     QTest::newRow("RSV2 != 0")
379             << 0 << 1 << 0
380             << 0U << QWebSocketProtocol::OpCodeText
381             << true << QStringLiteral("Hello world!").toUtf8()
382             << QWebSocketProtocol::CloseCodeProtocolError;
383     QTest::newRow("RSV3 != 0")
384             << 0 << 0 << 1
385             << 0U << QWebSocketProtocol::OpCodeText
386             << true << QStringLiteral("Hello world!").toUtf8()
387             << QWebSocketProtocol::CloseCodeProtocolError;
388     QTest::newRow("RSV1 != 0 and RSV2 != 0")
389             << 1 << 1 << 0
390             << 0U << QWebSocketProtocol::OpCodeText
391             << true << QStringLiteral("Hello world!").toUtf8()
392             << QWebSocketProtocol::CloseCodeProtocolError;
393     QTest::newRow("RSV1 != 0 and RSV3 != 0")
394             << 1 << 0 << 1
395             << 0U << QWebSocketProtocol::OpCodeText
396             << true << QStringLiteral("Hello world!").toUtf8()
397             << QWebSocketProtocol::CloseCodeProtocolError;
398     QTest::newRow("RSV2 != 0 and RSV3 != 0")
399             << 0 << 1 << 1
400             << 0U << QWebSocketProtocol::OpCodeText
401             << true << QStringLiteral("Hello world!").toUtf8()
402             << QWebSocketProtocol::CloseCodeProtocolError;
403
404     QTest::newRow("Reserved OpCode 3")
405             << 0 << 0 << 0
406             << 0U << QWebSocketProtocol::OpCodeReserved3
407             << true << QStringLiteral("Hello world!").toUtf8()
408             << QWebSocketProtocol::CloseCodeProtocolError;
409     QTest::newRow("Reserved OpCode 4")
410             << 0 << 0 << 0
411             << 0U << QWebSocketProtocol::OpCodeReserved4
412             << true << QStringLiteral("Hello world!").toUtf8()
413             << QWebSocketProtocol::CloseCodeProtocolError;
414     QTest::newRow("Reserved OpCode 5")
415             << 0 << 0 << 0
416             << 0U << QWebSocketProtocol::OpCodeReserved5
417             << true << QStringLiteral("Hello world!").toUtf8()
418             << QWebSocketProtocol::CloseCodeProtocolError;
419     QTest::newRow("Reserved OpCode 6")
420             << 0 << 0 << 0
421             << 0U << QWebSocketProtocol::OpCodeReserved6
422             << true << QStringLiteral("Hello world!").toUtf8()
423             << QWebSocketProtocol::CloseCodeProtocolError;
424     QTest::newRow("Reserved OpCode 7")
425             << 0 << 0 << 0
426             << 0U << QWebSocketProtocol::OpCodeReserved7
427             << true << QStringLiteral("Hello world!").toUtf8()
428             << QWebSocketProtocol::CloseCodeProtocolError;
429     QTest::newRow("Reserved OpCode B")
430             << 0 << 0 << 0
431             << 0U << QWebSocketProtocol::OpCodeReservedB
432             << true << QStringLiteral("Hello world!").toUtf8()
433             << QWebSocketProtocol::CloseCodeProtocolError;
434     QTest::newRow("Reserved OpCode C")
435             << 0 << 0 << 0
436             << 0U << QWebSocketProtocol::OpCodeReservedC
437             << true << QStringLiteral("Hello world!").toUtf8()
438             << QWebSocketProtocol::CloseCodeProtocolError;
439     QTest::newRow("Reserved OpCode D")
440             << 0 << 0 << 0
441             << 0U << QWebSocketProtocol::OpCodeReservedD
442             << true << QStringLiteral("Hello world!").toUtf8()
443             << QWebSocketProtocol::CloseCodeProtocolError;
444     QTest::newRow("Reserved OpCode E")
445             << 0 << 0 << 0
446             << 0U << QWebSocketProtocol::OpCodeReservedE
447             << true << QStringLiteral("Hello world!").toUtf8()
448             << QWebSocketProtocol::CloseCodeProtocolError;
449     QTest::newRow("Reserved OpCode F")
450             << 0 << 0 << 0
451             << 0U << QWebSocketProtocol::OpCodeReservedF
452             << true << QStringLiteral("Hello world!").toUtf8()
453             << QWebSocketProtocol::CloseCodeProtocolError;
454
455     QTest::newRow("Close Frame with payload > 125 bytes")
456             << 0 << 0 << 0
457             << 0U << QWebSocketProtocol::OpCodeClose
458             << true << QString(126, 'a').toUtf8()
459             << QWebSocketProtocol::CloseCodeProtocolError;
460     QTest::newRow("Non-final Close Frame")
461             << 0 << 0 << 0
462             << 0U << QWebSocketProtocol::OpCodeClose
463             << false << QString(126, 'a').toUtf8()
464             << QWebSocketProtocol::CloseCodeProtocolError;
465     QTest::newRow("Ping Frame with payload > 125 bytes")
466             << 0 << 0 << 0
467             << 0U << QWebSocketProtocol::OpCodePing
468             << true << QString(126, 'a').toUtf8()
469             << QWebSocketProtocol::CloseCodeProtocolError;
470     QTest::newRow("Non-final Ping Frame")
471             << 0 << 0 << 0
472             << 0U << QWebSocketProtocol::OpCodePing
473             << false << QString(126, 'a').toUtf8()
474             << QWebSocketProtocol::CloseCodeProtocolError;
475     QTest::newRow("Pong Frame with payload > 125 bytes")
476             << 0 << 0 << 0
477             << 0U << QWebSocketProtocol::OpCodePong
478             << true << QString(126, 'a').toUtf8()
479             << QWebSocketProtocol::CloseCodeProtocolError;
480     QTest::newRow("Non-final Pong Frame")
481             << 0 << 0 << 0
482             << 0U << QWebSocketProtocol::OpCodePong
483             << false << QString(126, 'a').toUtf8()
484             << QWebSocketProtocol::CloseCodeProtocolError;
485 }
486
487 void tst_WebSocketFrame::tst_invalidFrames()
488 {
489     QFETCH(int, rsv1);
490     QFETCH(int, rsv2);
491     QFETCH(int, rsv3);
492     QFETCH(quint32, mask);
493     QFETCH(QWebSocketProtocol::OpCode, opCode);
494     QFETCH(bool, isFinal);
495     QFETCH(QByteArray, payload);
496     QFETCH(QWebSocketProtocol::CloseCode, expectedError);
497
498     FrameHelper helper;
499     helper.setRsv1(rsv1);
500     helper.setRsv2(rsv2);
501     helper.setRsv3(rsv3);
502     helper.setMask(mask);
503     helper.setOpCode(opCode);
504     helper.setFinalFrame(isFinal);
505     helper.setPayload(payload);
506
507     QByteArray wireRepresentation = helper.wireRepresentation();
508     QBuffer buffer;
509     buffer.setData(wireRepresentation);
510     buffer.open(QIODevice::ReadOnly);
511     QWebSocketFrame frame = QWebSocketFrame::readFrame(&buffer);
512     buffer.close();
513
514     QVERIFY(!frame.isValid());
515     QCOMPARE(frame.closeCode(), expectedError);
516 }
517
518
519 /*
520  * Incomplete or overly large frames
521  * Payload must be crafted manually
522  *
523     QTest::newRow("Frame Too Big")
524             << 0 << 0 << 0
525             << 0U << QWebSocketProtocol::OpCodeText
526             << true << QString(MAX_FRAME_SIZE_IN_BYTES + 1, 'a').toUtf8()
527             << QWebSocketProtocol::CloseCodeTooMuchData;
528
529  */
530 void tst_WebSocketFrame::tst_malformedFrames_data()
531 {
532     QTest::addColumn<QByteArray>("payload");
533     QTest::addColumn<QWebSocketProtocol::CloseCode>("expectedError");
534
535     //too little data
536     QTest::newRow("No data") << QByteArray() << QWebSocketProtocol::CloseCodeGoingAway;
537     FrameHelper helper;
538     helper.setRsv1(0);
539     helper.setRsv2(0);
540     helper.setRsv3(0);
541     helper.setMask(0U);
542     helper.setOpCode(QWebSocketProtocol::OpCodeText);
543     helper.setFinalFrame(true);
544     helper.setPayload(QString(10, 'a').toUtf8());
545     QByteArray wireRep = helper.wireRepresentation();
546
547     //too little data
548     //header + payload should be 12 bytes for non-masked payloads < 126 bytes
549     for (int i = 1; i < 12; ++i)
550     {
551         QTest::newRow(QStringLiteral("Header too small - %1 byte(s)").arg(i).toLatin1().constData())
552                 << wireRep.left(i)
553                 << QWebSocketProtocol::CloseCodeGoingAway;
554     }
555     //too much data
556     {
557         const char bigpayloadIndicator = char(127);
558         const quint64 payloadSize = MAX_FRAME_SIZE_IN_BYTES + 1;
559         uchar swapped[8] = {0};
560         qToBigEndian<quint64>(payloadSize, swapped);
561         QTest::newRow("Frame too big")
562                 << wireRep.left(1).append(bigpayloadIndicator)
563                                   .append(reinterpret_cast<char *>(swapped), 8)
564                 << QWebSocketProtocol::CloseCodeTooMuchData;
565     }
566     //invalid size field
567     {
568         const char bigpayloadIndicator = char(127);
569         quint64 payloadSize = quint64(1) << 63;
570         uchar swapped[8] = {0};
571         qToBigEndian<quint64>(payloadSize, swapped);
572         QTest::newRow("Highest bit of payload length is set")
573                 << wireRep.left(1).append(bigpayloadIndicator)
574                                   .append(reinterpret_cast<char *>(swapped), 8)
575                 << QWebSocketProtocol::CloseCodeProtocolError;
576
577         payloadSize = 256;
578         qToBigEndian<quint64>(payloadSize, swapped);
579         QTest::newRow("Overlong 64-bit size field; should be 16-bit")
580                 << wireRep.left(1).append(bigpayloadIndicator)
581                                   .append(reinterpret_cast<char *>(swapped), 8)
582                 << QWebSocketProtocol::CloseCodeProtocolError;
583     }
584     //overlong size field
585     {
586         const char largepayloadIndicator = char(126);
587         const quint16 payloadSize = 120;
588         uchar swapped[2] = {0};
589         qToBigEndian<quint16>(payloadSize, swapped);
590         QTest::newRow("Overlong 16-bit size field")
591                 << wireRep.left(1).append(largepayloadIndicator)
592                                   .append(reinterpret_cast<char *>(swapped), 2)
593                 << QWebSocketProtocol::CloseCodeProtocolError;
594     }
595     {
596         const char bigpayloadIndicator = char(127);
597         quint64 payloadSize = 120;
598         uchar swapped[8] = {0};
599         qToBigEndian<quint64>(payloadSize, swapped);
600         QTest::newRow("Overlong 64-bit size field; should be 7-bit")
601                 << wireRep.left(1).append(bigpayloadIndicator)
602                                   .append(reinterpret_cast<char *>(swapped), 8)
603                 << QWebSocketProtocol::CloseCodeProtocolError;
604
605         payloadSize = 256;
606         qToBigEndian<quint64>(payloadSize, swapped);
607         QTest::newRow("Overlong 64-bit size field; should be 16-bit")
608                 << wireRep.left(1).append(bigpayloadIndicator)
609                                   .append(reinterpret_cast<char *>(swapped), 8)
610                 << QWebSocketProtocol::CloseCodeProtocolError;
611     }
612 }
613
614 void tst_WebSocketFrame::tst_malformedFrames()
615 {
616     QFETCH(QByteArray, payload);
617     QFETCH(QWebSocketProtocol::CloseCode, expectedError);
618
619     QBuffer buffer;
620     buffer.setData(payload);
621     buffer.open(QIODevice::ReadOnly);
622     QWebSocketFrame frame = QWebSocketFrame::readFrame(&buffer);
623     buffer.close();
624
625     QVERIFY(!frame.isValid());
626     QCOMPARE(frame.closeCode(), expectedError);
627 }
628
629 QTEST_MAIN(tst_WebSocketFrame)
630
631 #include "tst_websocketframe.moc"
632