From faab6ff98dafa564f2c58bd95689ffba6d3a4e32 Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Wed, 20 May 2015 14:34:48 +0200 Subject: tests: move all auto tests to websockets sub directory cmake is not included. Change-Id: I9ab6244d8b6b3752f26070b0b15ae70c0cab6d82 Reviewed-by: Alex Blasche --- tests/auto/auto.pro | 15 +- tests/auto/dataprocessor/dataprocessor.pro | 14 - tests/auto/dataprocessor/tst_dataprocessor.cpp | 1842 -------------------- tests/auto/handshakerequest/handshakerequest.pro | 14 - .../auto/handshakerequest/tst_handshakerequest.cpp | 317 ---- tests/auto/handshakeresponse/handshakeresponse.pro | 14 - .../handshakeresponse/tst_handshakeresponse.cpp | 112 -- .../qdefaultmaskgenerator.pro | 14 - .../tst_defaultmaskgenerator.cpp | 150 -- tests/auto/qwebsocket/qwebsocket.pro | 13 - tests/auto/qwebsocket/tst_qwebsocket.cpp | 605 ------- .../qwebsocketcorsauthenticator.pro | 13 - .../tst_qwebsocketcorsauthenticator.cpp | 112 -- tests/auto/qwebsocketserver/qwebsocketserver.pro | 13 - .../auto/qwebsocketserver/tst_qwebsocketserver.cpp | 390 ----- tests/auto/websocketframe/tst_websocketframe.cpp | 624 ------- tests/auto/websocketframe/websocketframe.pro | 14 - .../websocketprotocol/tst_websocketprotocol.cpp | 289 --- tests/auto/websocketprotocol/websocketprotocol.pro | 14 - .../websockets/dataprocessor/dataprocessor.pro | 14 + .../websockets/dataprocessor/tst_dataprocessor.cpp | 1842 ++++++++++++++++++++ .../handshakerequest/handshakerequest.pro | 14 + .../handshakerequest/tst_handshakerequest.cpp | 317 ++++ .../handshakeresponse/handshakeresponse.pro | 14 + .../handshakeresponse/tst_handshakeresponse.cpp | 112 ++ .../qdefaultmaskgenerator.pro | 14 + .../tst_defaultmaskgenerator.cpp | 150 ++ tests/auto/websockets/qwebsocket/qwebsocket.pro | 13 + .../auto/websockets/qwebsocket/tst_qwebsocket.cpp | 605 +++++++ .../qwebsocketcorsauthenticator.pro | 13 + .../tst_qwebsocketcorsauthenticator.cpp | 112 ++ .../qwebsocketserver/qwebsocketserver.pro | 13 + .../qwebsocketserver/tst_qwebsocketserver.cpp | 390 +++++ .../websocketframe/tst_websocketframe.cpp | 624 +++++++ .../websockets/websocketframe/websocketframe.pro | 14 + .../websocketprotocol/tst_websocketprotocol.cpp | 289 +++ .../websocketprotocol/websocketprotocol.pro | 14 + tests/auto/websockets/websockets.pro | 16 + 38 files changed, 4581 insertions(+), 4578 deletions(-) delete mode 100644 tests/auto/dataprocessor/dataprocessor.pro delete mode 100644 tests/auto/dataprocessor/tst_dataprocessor.cpp delete mode 100644 tests/auto/handshakerequest/handshakerequest.pro delete mode 100644 tests/auto/handshakerequest/tst_handshakerequest.cpp delete mode 100644 tests/auto/handshakeresponse/handshakeresponse.pro delete mode 100644 tests/auto/handshakeresponse/tst_handshakeresponse.cpp delete mode 100644 tests/auto/qdefaultmaskgenerator/qdefaultmaskgenerator.pro delete mode 100644 tests/auto/qdefaultmaskgenerator/tst_defaultmaskgenerator.cpp delete mode 100644 tests/auto/qwebsocket/qwebsocket.pro delete mode 100644 tests/auto/qwebsocket/tst_qwebsocket.cpp delete mode 100644 tests/auto/qwebsocketcorsauthenticator/qwebsocketcorsauthenticator.pro delete mode 100644 tests/auto/qwebsocketcorsauthenticator/tst_qwebsocketcorsauthenticator.cpp delete mode 100644 tests/auto/qwebsocketserver/qwebsocketserver.pro delete mode 100644 tests/auto/qwebsocketserver/tst_qwebsocketserver.cpp delete mode 100644 tests/auto/websocketframe/tst_websocketframe.cpp delete mode 100644 tests/auto/websocketframe/websocketframe.pro delete mode 100644 tests/auto/websocketprotocol/tst_websocketprotocol.cpp delete mode 100644 tests/auto/websocketprotocol/websocketprotocol.pro create mode 100644 tests/auto/websockets/dataprocessor/dataprocessor.pro create mode 100644 tests/auto/websockets/dataprocessor/tst_dataprocessor.cpp create mode 100644 tests/auto/websockets/handshakerequest/handshakerequest.pro create mode 100644 tests/auto/websockets/handshakerequest/tst_handshakerequest.cpp create mode 100644 tests/auto/websockets/handshakeresponse/handshakeresponse.pro create mode 100644 tests/auto/websockets/handshakeresponse/tst_handshakeresponse.cpp create mode 100644 tests/auto/websockets/qdefaultmaskgenerator/qdefaultmaskgenerator.pro create mode 100644 tests/auto/websockets/qdefaultmaskgenerator/tst_defaultmaskgenerator.cpp create mode 100644 tests/auto/websockets/qwebsocket/qwebsocket.pro create mode 100644 tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp create mode 100644 tests/auto/websockets/qwebsocketcorsauthenticator/qwebsocketcorsauthenticator.pro create mode 100644 tests/auto/websockets/qwebsocketcorsauthenticator/tst_qwebsocketcorsauthenticator.cpp create mode 100644 tests/auto/websockets/qwebsocketserver/qwebsocketserver.pro create mode 100644 tests/auto/websockets/qwebsocketserver/tst_qwebsocketserver.cpp create mode 100644 tests/auto/websockets/websocketframe/tst_websocketframe.cpp create mode 100644 tests/auto/websockets/websocketframe/websocketframe.pro create mode 100644 tests/auto/websockets/websocketprotocol/tst_websocketprotocol.cpp create mode 100644 tests/auto/websockets/websocketprotocol/websocketprotocol.pro create mode 100644 tests/auto/websockets/websockets.pro (limited to 'tests/auto') diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 4698cd0..634e44b 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -1,16 +1,3 @@ TEMPLATE = subdirs -SUBDIRS = \ - qwebsocketcorsauthenticator - -contains(QT_CONFIG, private_tests): SUBDIRS += \ - websocketprotocol \ - dataprocessor \ - websocketframe \ - handshakerequest \ - handshakeresponse \ - qdefaultmaskgenerator - -SUBDIRS += \ - qwebsocket \ - qwebsocketserver +SUBDIRS += websockets diff --git a/tests/auto/dataprocessor/dataprocessor.pro b/tests/auto/dataprocessor/dataprocessor.pro deleted file mode 100644 index ac5ba5c..0000000 --- a/tests/auto/dataprocessor/dataprocessor.pro +++ /dev/null @@ -1,14 +0,0 @@ -CONFIG += console -CONFIG += testcase -CONFIG -= app_bundle - -TEMPLATE = app - -TARGET = tst_dataprocessor - -QT = core testlib websockets websockets-private - -SOURCES += tst_dataprocessor.cpp - -requires(contains(QT_CONFIG, private_tests)) -DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/dataprocessor/tst_dataprocessor.cpp b/tests/auto/dataprocessor/tst_dataprocessor.cpp deleted file mode 100644 index 660d8eb..0000000 --- a/tests/auto/dataprocessor/tst_dataprocessor.cpp +++ /dev/null @@ -1,1842 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Kurt Pattyn . -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include -#include -#include -#include -#include -#include - -#include "private/qwebsocketdataprocessor_p.h" -#include "private/qwebsocketprotocol_p.h" -#include "QtWebSockets/qwebsocketprotocol.h" - -const quint8 FIN = 0x80; -const quint8 RSV1 = 0x40; -const quint8 RSV2 = 0x30; -const quint8 RSV3 = 0x10; - -QT_USE_NAMESPACE - -Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode) -Q_DECLARE_METATYPE(QWebSocketProtocol::OpCode) - -class tst_DataProcessor : public QObject -{ - Q_OBJECT - -public: - tst_DataProcessor(); - -private Q_SLOTS: - void initTestCase(); - void cleanupTestCase(); - void init(); - void cleanup(); - - /*************************************************************************** - * Happy Flows - ***************************************************************************/ - /*! - Tests all kinds of valid binary frames, including zero length frames - */ - void goodBinaryFrame(); - void goodBinaryFrame_data(); - - /*! - Tests all kinds of valid text frames, including zero length frames - */ - void goodTextFrame(); - void goodTextFrame_data(); - - /*! - * Test all kinds of valid control frames. - */ - void goodControlFrame(); - - /*! - * Test all kinds of valid close frames. - */ - void goodCloseFrame(); - void goodCloseFrame_data(); - - /*! - * Test all valid opcodes - */ - void goodOpcodes(); - void goodOpcodes_data(); - - /*! - Tests the QWebSocketDataProcessor for the correct handling of non-charactercodes - Due to a workaround in QTextCodec, non-characters are treated as illegal. - This workaround is not necessary anymore, and hence code should be changed in Qt - to allow non-characters again. - */ - void nonCharacterCodes(); - void nonCharacterCodes_data(); - - /*************************************************************************** - * Rainy Day Flows - ***************************************************************************/ - /*! - Tests the QWebSocketDataProcessor for correct handling of frames that don't - contain the starting 2 bytes. - This test is a border case, where not enough bytes are received to even start parsing a - frame. - This test does not test sequences of frames, only single frames are tested - */ - void frameTooSmall(); - - /*! - Tests the QWebSocketDataProcessor for correct handling of frames that are oversized. - This test does not test sequences of frames, only single frames are tested - */ - void frameTooBig(); - void frameTooBig_data(); - - /*! - Tests the QWebSocketDataProcessor for the correct handling of malformed frame headers. - This test does not test sequences of frames, only single frames are tested - */ - void invalidHeader(); - void invalidHeader_data(); - - /*! - Tests the QWebSocketDataProcessor for the correct handling of invalid control frames. - Invalid means: payload bigger than 125, frame is fragmented, ... - This test does not test sequences of frames, only single frames are tested - */ - void invalidControlFrame(); - void invalidControlFrame_data(); - - void invalidCloseFrame(); - void invalidCloseFrame_data(); - - /*! - Tests the QWebSocketDataProcessor for the correct handling of incomplete size fields - for large and big payloads. - */ - void incompleteSizeField(); - void incompleteSizeField_data(); - - /*! - Tests the QWebSocketDataProcessor for the correct handling of incomplete payloads. - This includes: - - incomplete length bytes for large and big payloads (16- and 64-bit values), - - minimum size representation (see RFC 6455 paragraph 5.2), - - frames that are too large (larger than MAX_INT in bytes) - - incomplete payloads (less bytes than indicated in the size field) - This test does not test sequences of frames, only single frames are tested - */ - void incompletePayload(); - void incompletePayload_data(); - - /*! - Tests the QWebSocketDataProcessor for the correct handling of invalid UTF-8 payloads. - This test does not test sequences of frames, only single frames are tested - */ - void invalidPayload(); - void invalidPayload_data(bool isControlFrame = false); - - void invalidPayloadInCloseFrame(); - void invalidPayloadInCloseFrame_data(); - - /*! - Tests the QWebSocketDataProcessor for the correct handling of the minimum size representation - requirement of RFC 6455 (see paragraph 5.2) - */ - void minimumSizeRequirement(); - void minimumSizeRequirement_data(); - -private: - //helper function that constructs a new row of test data for invalid UTF8 sequences - void invalidUTF8(const char *dataTag, const char *utf8Sequence, bool isCloseFrame); - //helper function that constructs a new row of test data for invalid leading field values - void invalidField(const char *dataTag, quint8 invalidFieldValue); - //helper functions that construct a new row of test data for size fields that do not adhere - //to the minimum size requirement - void minimumSize16Bit(quint16 sizeInBytes); - void minimumSize64Bit(quint64 sizeInBytes); - //helper function to construct a new row of test data containing frames with a payload size - //smaller than indicated in the header - void incompleteFrame(quint8 controlCode, quint64 indicatedSize, quint64 actualPayloadSize); - void insertIncompleteSizeFieldTest(quint8 payloadCode, quint8 numBytesFollowing); - - //helper function to construct a new row of test data containing text frames containing - //sequences - void nonCharacterSequence(const char *sequence); - - void doTest(); - void doCloseFrameTest(); - - QString opCodeToString(quint8 opCode); -}; - -tst_DataProcessor::tst_DataProcessor() -{ -} - -void tst_DataProcessor::initTestCase() -{ -} - -void tst_DataProcessor::cleanupTestCase() -{ -} - -void tst_DataProcessor::init() -{ - qRegisterMetaType("QWebSocketProtocol::OpCode"); - qRegisterMetaType("QWebSocketProtocol::CloseCode"); -} - -void tst_DataProcessor::cleanup() -{ -} - -void tst_DataProcessor::goodBinaryFrame_data() -{ - QTest::addColumn("payload"); - //be sure to get small (< 126 bytes), large (> 125 bytes & < 64K) and big (>64K) frames - for (int i = 0; i < (65536 + 256); i += 128) - { - QTest::newRow(QStringLiteral("Binary frame with %1 bytes").arg(i).toLatin1().constData()) - << QByteArray(i, char(1)); - } - for (int i = 0; i < 256; ++i) //test all possible bytes in the payload - { - QTest::newRow(QStringLiteral("Binary frame containing byte: '0x%1'") - .arg(QByteArray(1, char(i)).toHex().constData()).toLatin1().constData()) - << QByteArray(i, char(1)); - } -} - -void tst_DataProcessor::goodBinaryFrame() -{ - QByteArray data; - QBuffer buffer; - QWebSocketDataProcessor dataProcessor; - QFETCH(QByteArray, payload); - - data.append((char)(FIN | QWebSocketProtocol::OpCodeBinary)); - - if (payload.length() < 126) - { - data.append(char(payload.length())); - } - else if (payload.length() < 65536) - { - quint16 swapped = qToBigEndian(payload.length()); - const char *wireRepresentation - = static_cast(static_cast(&swapped)); - data.append(char(126)).append(wireRepresentation, 2); - } - else - { - quint64 swapped = qToBigEndian(payload.length()); - const char *wireRepresentation - = static_cast(static_cast(&swapped)); - data.append(char(127)).append(wireRepresentation, 8); - } - - data.append(payload); - buffer.setData(data); - buffer.open(QIODevice::ReadOnly); - - QSignalSpy errorReceivedSpy(&dataProcessor, - SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString))); - QSignalSpy closeReceivedSpy(&dataProcessor, - SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString))); - QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray))); - QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray))); - QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool))); - QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray))); - QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool))); - QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString))); - dataProcessor.process(&buffer); - QCOMPARE(errorReceivedSpy.count(), 0); - QCOMPARE(pingReceivedSpy.count(), 0); - QCOMPARE(pongReceivedSpy.count(), 0); - QCOMPARE(closeReceivedSpy.count(), 0); - QCOMPARE(binaryFrameReceivedSpy.count(), 1); - QCOMPARE(binaryMessageReceivedSpy.count(), 1); - QCOMPARE(textFrameReceivedSpy.count(), 0); - QCOMPARE(textMessageReceivedSpy.count(), 0); - QList arguments = binaryFrameReceivedSpy.takeFirst(); - QCOMPARE(arguments.at(0).toByteArray().length(), payload.length()); - arguments = binaryMessageReceivedSpy.takeFirst(); - QCOMPARE(arguments.at(0).toByteArray().length(), payload.length()); - buffer.close(); -} - -void tst_DataProcessor::goodTextFrame_data() -{ - QTest::addColumn("payload"); - QTest::addColumn("size"); - - //test frames with small (< 126), large ( < 65536) and big ( > 65535) payloads - for (int i = 0; i < (65536 + 256); i += 128) - { - QTest::newRow(QStringLiteral("Text frame with %1 ASCII characters") - .arg(i).toLatin1().constData()) << QByteArray(i, 'a') << i; - } - //test all valid ASCII characters - for (int i = 0; i < 128; ++i) - { - QTest::newRow(QStringLiteral("Text frame with containing ASCII character '0x%1'") - .arg(QByteArray(1, char(i)).toHex().constData()).toLatin1().constData()) - << QByteArray(1, char(i)) << 1; - } - - //the text string reads: Text frame containing Hello-µ@ßöäüàá-UTF-8!! - //Visual Studio doesn't like UTF-8 in source code, so we use escape codes for the string - //The number 22 refers to the length of the string; - //the length was incorrectly calculated on Visual Studio - - //doing extensive QStringLiteral concatenations here, because - //MSVC 2010 complains when using concatenation literal strings about - //concatenation of wide and narrow strings: - //error C2308: concatenating mismatched strings - QTest::newRow((QStringLiteral("Text frame containing Hello-") + - QStringLiteral("\xC2\xB5\x40\xC3\x9F\xC3\xB6\xC3\xA4\xC3\xBC\xC3\xA0") + - QStringLiteral("\xC3\xA1-UTF-8!!")).toLatin1().constData()) - << QByteArray::fromHex("48656c6c6f2dc2b540c39fc3b6c3a4c3bcc3a0c3a12d5554462d382121") - << 22; -} - -void tst_DataProcessor::goodTextFrame() -{ - QByteArray data; - QBuffer buffer; - QWebSocketDataProcessor dataProcessor; - QFETCH(QByteArray, payload); - QFETCH(int, size); - - data.append((char)(FIN | QWebSocketProtocol::OpCodeText)); - - if (payload.length() < 126) - { - data.append(char(payload.length())); - } - else if (payload.length() < 65536) - { - quint16 swapped = qToBigEndian(payload.length()); - const char *wireRepresentation - = static_cast(static_cast(&swapped)); - data.append(char(126)).append(wireRepresentation, 2); - } - else - { - quint64 swapped = qToBigEndian(payload.length()); - const char *wireRepresentation - = static_cast(static_cast(&swapped)); - data.append(char(127)).append(wireRepresentation, 8); - } - - data.append(payload); - buffer.setData(data); - buffer.open(QIODevice::ReadOnly); - - QSignalSpy errorReceivedSpy(&dataProcessor, - SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString))); - QSignalSpy closeReceivedSpy(&dataProcessor, - SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString))); - QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray))); - QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray))); - QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool))); - QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString))); - QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool))); - QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray))); - - dataProcessor.process(&buffer); - - QCOMPARE(errorReceivedSpy.count(), 0); - QCOMPARE(pingReceivedSpy.count(), 0); - QCOMPARE(pongReceivedSpy.count(), 0); - QCOMPARE(closeReceivedSpy.count(), 0); - QCOMPARE(textFrameReceivedSpy.count(), 1); - QCOMPARE(textMessageReceivedSpy.count(), 1); - QCOMPARE(binaryFrameReceivedSpy.count(), 0); - QCOMPARE(binaryMessageReceivedSpy.count(), 0); - QList arguments = textFrameReceivedSpy.takeFirst(); - QCOMPARE(arguments.at(0).toString().length(), size); - arguments = textMessageReceivedSpy.takeFirst(); - QCOMPARE(arguments.at(0).toString().length(), size); - buffer.close(); -} - -void tst_DataProcessor::goodControlFrame() -{ - QByteArray data; - QBuffer buffer; - QWebSocketDataProcessor dataProcessor; - - QSignalSpy closeFrameReceivedSpy(&dataProcessor, - SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString))); - QSignalSpy errorReceivedSpy(&dataProcessor, - SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString))); - QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool))); - QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString))); - QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool))); - QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray))); - QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray))); - QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray))); - - data.append((char)(FIN | QWebSocketProtocol::OpCodePing)); - data.append(QChar::fromLatin1(0)); - buffer.setData(data); - buffer.open(QIODevice::ReadOnly); - dataProcessor.process(&buffer); - QCOMPARE(errorReceivedSpy.count(), 0); - QCOMPARE(textFrameReceivedSpy.count(), 0); - QCOMPARE(textMessageReceivedSpy.count(), 0); - QCOMPARE(binaryFrameReceivedSpy.count(), 0); - QCOMPARE(binaryMessageReceivedSpy.count(), 0); - QCOMPARE(closeFrameReceivedSpy.count(), 0); - QCOMPARE(pongReceivedSpy.count(), 0); - QCOMPARE(pingReceivedSpy.count(), 1); - buffer.close(); - - data.clear(); - pingReceivedSpy.clear(); - pongReceivedSpy.clear(); - data.append((char)(FIN | QWebSocketProtocol::OpCodePong)); - data.append(QChar::fromLatin1(0)); - buffer.setData(data); - buffer.open(QIODevice::ReadOnly); - dataProcessor.process(&buffer); - QCOMPARE(errorReceivedSpy.count(), 0); - QCOMPARE(textFrameReceivedSpy.count(), 0); - QCOMPARE(textMessageReceivedSpy.count(), 0); - QCOMPARE(binaryFrameReceivedSpy.count(), 0); - QCOMPARE(binaryMessageReceivedSpy.count(), 0); - QCOMPARE(closeFrameReceivedSpy.count(), 0); - QCOMPARE(pingReceivedSpy.count(), 0); - QCOMPARE(pongReceivedSpy.count(), 1); - buffer.close(); -} - -void tst_DataProcessor::goodCloseFrame_data() -{ - QTest::addColumn("payload"); - QTest::addColumn("closeCode"); - //control frame data cannot exceed 125 bytes; smaller than 124, - //because we also need a 2 byte close code - for (int i = 0; i < 124; ++i) - { - QTest::newRow(QStringLiteral("Close frame with %1 ASCII characters") - .arg(i).toLatin1().constData()) - << QString(i, 'a') - << QWebSocketProtocol::CloseCodeNormal; - } - for (int i = 0; i < 126; ++i) - { - QTest::newRow(QStringLiteral("Text frame with containing ASCII character '0x%1'") - .arg(QByteArray(1, char(i)).toHex().constData()).toLatin1().constData()) - << QString(1, char(i)) << QWebSocketProtocol::CloseCodeNormal; - } - QTest::newRow("Close frame with close code NORMAL") - << QString(1, 'a') << QWebSocketProtocol::CloseCodeNormal; - QTest::newRow("Close frame with close code BAD OPERATION") - << QString(1, 'a') << QWebSocketProtocol::CloseCodeBadOperation; - QTest::newRow("Close frame with close code DATATYPE NOT SUPPORTED") - << QString(1, 'a') << QWebSocketProtocol::CloseCodeDatatypeNotSupported; - QTest::newRow("Close frame with close code GOING AWAY") - << QString(1, 'a') << QWebSocketProtocol::CloseCodeGoingAway; - QTest::newRow("Close frame with close code MISSING EXTENSION") - << QString(1, 'a') << QWebSocketProtocol::CloseCodeMissingExtension; - QTest::newRow("Close frame with close code POLICY VIOLATED") - << QString(1, 'a') << QWebSocketProtocol::CloseCodePolicyViolated; - QTest::newRow("Close frame with close code PROTOCOL ERROR") - << QString(1, 'a') << QWebSocketProtocol::CloseCodeProtocolError; - QTest::newRow("Close frame with close code TOO MUCH DATA") - << QString(1, 'a') << QWebSocketProtocol::CloseCodeTooMuchData; - QTest::newRow("Close frame with close code WRONG DATATYPE") - << QString(1, 'a') << QWebSocketProtocol::CloseCodeWrongDatatype; - QTest::newRow("Close frame with close code 3000") - << QString(1, 'a') << QWebSocketProtocol::CloseCode(3000); - QTest::newRow("Close frame with close code 3999") - << QString(1, 'a') << QWebSocketProtocol::CloseCode(3999); - QTest::newRow("Close frame with close code 4000") - << QString(1, 'a') << QWebSocketProtocol::CloseCode(4000); - QTest::newRow("Close frame with close code 4999") - << QString(1, 'a') << QWebSocketProtocol::CloseCode(4999); - - //close frames with no close reason - QTest::newRow("Close frame with close code NORMAL and no reason") - << QString() << QWebSocketProtocol::CloseCodeNormal; - QTest::newRow("Close frame with close code BAD OPERATION and no reason") - << QString() << QWebSocketProtocol::CloseCodeBadOperation; - QTest::newRow("Close frame with close code DATATYPE NOT SUPPORTED and no reason") - << QString() << QWebSocketProtocol::CloseCodeDatatypeNotSupported; - QTest::newRow("Close frame with close code GOING AWAY and no reason") - << QString() << QWebSocketProtocol::CloseCodeGoingAway; - QTest::newRow("Close frame with close code MISSING EXTENSION and no reason") - << QString() << QWebSocketProtocol::CloseCodeMissingExtension; - QTest::newRow("Close frame with close code POLICY VIOLATED and no reason") - << QString() << QWebSocketProtocol::CloseCodePolicyViolated; - QTest::newRow("Close frame with close code PROTOCOL ERROR and no reason") - << QString() << QWebSocketProtocol::CloseCodeProtocolError; - QTest::newRow("Close frame with close code TOO MUCH DATA and no reason") - << QString() << QWebSocketProtocol::CloseCodeTooMuchData; - QTest::newRow("Close frame with close code WRONG DATATYPE and no reason") - << QString() << QWebSocketProtocol::CloseCodeWrongDatatype; - QTest::newRow("Close frame with close code 3000 and no reason") - << QString() << QWebSocketProtocol::CloseCode(3000); - QTest::newRow("Close frame with close code 3999 and no reason") - << QString() << QWebSocketProtocol::CloseCode(3999); - QTest::newRow("Close frame with close code 4000 and no reason") - << QString() << QWebSocketProtocol::CloseCode(4000); - QTest::newRow("Close frame with close code 4999 and no reason") - << QString() << QWebSocketProtocol::CloseCode(4999); - - QTest::newRow("Close frame with no close code and no reason") - << QString() << QWebSocketProtocol::CloseCode(0); -} - -void tst_DataProcessor::goodOpcodes_data() -{ - QTest::addColumn("opCode"); - - QTest::newRow("Frame with PING opcode") << QWebSocketProtocol::OpCodePing; - QTest::newRow("Frame with PONG opcode") << QWebSocketProtocol::OpCodePong; - QTest::newRow("Frame with TEXT opcode") << QWebSocketProtocol::OpCodeText; - QTest::newRow("Frame with BINARY opcode") << QWebSocketProtocol::OpCodeBinary; - QTest::newRow("Frame with CLOSE opcode") << QWebSocketProtocol::OpCodeClose; -} - -void tst_DataProcessor::goodOpcodes() -{ - QByteArray data; - QBuffer buffer; - QWebSocketDataProcessor dataProcessor; - QFETCH(QWebSocketProtocol::OpCode, opCode); - - data.append((char)(FIN | opCode)); - data.append(char(0)); //zero length - - buffer.setData(data); - buffer.open(QIODevice::ReadOnly); - - QSignalSpy errorReceivedSpy(&dataProcessor, - SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString))); - QSignalSpy closeReceivedSpy(&dataProcessor, - SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString))); - QSignalSpy pingReceivedSpy(&dataProcessor, - SIGNAL(pingReceived(QByteArray))); - QSignalSpy pongReceivedSpy(&dataProcessor, - SIGNAL(pongReceived(QByteArray))); - QSignalSpy textFrameReceivedSpy(&dataProcessor, - SIGNAL(textFrameReceived(QString,bool))); - QSignalSpy textMessageReceivedSpy(&dataProcessor, - SIGNAL(textMessageReceived(QString))); - QSignalSpy binaryFrameReceivedSpy(&dataProcessor, - SIGNAL(binaryFrameReceived(QByteArray,bool))); - QSignalSpy binaryMessageReceivedSpy(&dataProcessor, - SIGNAL(binaryMessageReceived(QByteArray))); - - dataProcessor.process(&buffer); - - QCOMPARE(errorReceivedSpy.count(), 0); - QCOMPARE(pingReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodePing ? 1 : 0); - QCOMPARE(pongReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodePong ? 1 : 0); - QCOMPARE(closeReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodeClose ? 1 : 0); - QCOMPARE(textFrameReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodeText ? 1 : 0); - QCOMPARE(textMessageReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodeText ? 1 : 0); - QCOMPARE(binaryFrameReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodeBinary ? 1 : 0); - QCOMPARE(binaryMessageReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodeBinary ? 1 : 0); - - buffer.close(); -} - -void tst_DataProcessor::goodCloseFrame() -{ - QByteArray data; - QBuffer buffer; - QWebSocketDataProcessor dataProcessor; - QFETCH(QString, payload); - QFETCH(QWebSocketProtocol::CloseCode, closeCode); - quint16 swapped = qToBigEndian(closeCode); - const char *wireRepresentation = static_cast(static_cast(&swapped)); - - data.append((char)(FIN | QWebSocketProtocol::OpCodeClose)); - if (swapped != 0) - { - data.append(char(payload.length() + 2)).append(wireRepresentation, 2).append(payload); - } - else - { - data.append(QChar::fromLatin1(0)); //payload length 0; - //dataprocessor emits a CloseCodeNormal close code when none is present - closeCode = QWebSocketProtocol::CloseCodeNormal; - } - buffer.setData(data); - buffer.open(QIODevice::ReadOnly); - - QSignalSpy errorReceivedSpy(&dataProcessor, - SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString))); - QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray))); - QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray))); - QSignalSpy closeFrameReceivedSpy(&dataProcessor, - SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString))); - QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool))); - QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString))); - QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool))); - QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray))); - - dataProcessor.process(&buffer); - - QCOMPARE(errorReceivedSpy.count(), 0); - QCOMPARE(pingReceivedSpy.count(), 0); - QCOMPARE(pongReceivedSpy.count(), 0); - QCOMPARE(closeFrameReceivedSpy.count(), 1); - QCOMPARE(textFrameReceivedSpy.count(), 0); - QCOMPARE(textMessageReceivedSpy.count(), 0); - QCOMPARE(binaryFrameReceivedSpy.count(), 0); - QCOMPARE(binaryMessageReceivedSpy.count(), 0); - QList arguments = closeFrameReceivedSpy.takeFirst(); - QCOMPARE(arguments.at(0).value(), closeCode); - QCOMPARE(arguments.at(1).toString().length(), payload.length()); - buffer.close(); -} - -void tst_DataProcessor::nonCharacterCodes_data() -{ - QTest::addColumn("firstByte"); - QTest::addColumn("secondByte"); - QTest::addColumn("payload"); - QTest::addColumn("isContinuationFrame"); - - nonCharacterSequence("efbfbe"); - nonCharacterSequence("efbfbf"); - nonCharacterSequence("f09fbfbe"); - nonCharacterSequence("f09fbfbf"); - nonCharacterSequence("f0afbfbe"); - nonCharacterSequence("f0afbfbf"); - nonCharacterSequence("f0bfbfbe"); - nonCharacterSequence("f0bfbfbf"); - nonCharacterSequence("f18fbfbe"); - nonCharacterSequence("f18fbfbf"); - nonCharacterSequence("f19fbfbe"); - nonCharacterSequence("f19fbfbf"); - nonCharacterSequence("f1afbfbe"); - nonCharacterSequence("f1afbfbf"); - nonCharacterSequence("f1bfbfbe"); - nonCharacterSequence("f1bfbfbf"); - nonCharacterSequence("f28fbfbe"); - nonCharacterSequence("f28fbfbf"); - nonCharacterSequence("f29fbfbe"); - nonCharacterSequence("f29fbfbf"); - nonCharacterSequence("f2afbfbe"); - nonCharacterSequence("f2afbfbf"); - nonCharacterSequence("f2bfbfbe"); - nonCharacterSequence("f2bfbfbf"); - nonCharacterSequence("f38fbfbe"); - nonCharacterSequence("f38fbfbf"); - nonCharacterSequence("f39fbfbe"); - nonCharacterSequence("f39fbfbf"); - nonCharacterSequence("f3afbfbe"); - nonCharacterSequence("f3afbfbf"); - nonCharacterSequence("f3bfbfbe"); - nonCharacterSequence("f3bfbfbf"); - nonCharacterSequence("f48fbfbe"); - nonCharacterSequence("f48fbfbf"); -} - -void tst_DataProcessor::nonCharacterCodes() -{ - QFETCH(quint8, firstByte); - QFETCH(quint8, secondByte); - QFETCH(QByteArray, payload); - QFETCH(bool, isContinuationFrame); - - if (!isContinuationFrame) - { - QByteArray data; - QBuffer buffer; - QWebSocketDataProcessor dataProcessor; - QSignalSpy errorSpy(&dataProcessor, - SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString))); - QSignalSpy closeSpy(&dataProcessor, - SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString))); - QSignalSpy pingFrameSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray))); - QSignalSpy pongFrameSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray))); - QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool))); - QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString))); - QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool))); - QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray))); - - data.append(firstByte).append(secondByte); - data.append(payload); - buffer.setData(data); - buffer.open(QIODevice::ReadOnly); - dataProcessor.process(&buffer); - - QCOMPARE(errorSpy.count(), 0); - QCOMPARE(closeSpy.count(), 0); - QCOMPARE(pingFrameSpy.count(), 0); - QCOMPARE(pongFrameSpy.count(), 0); - QCOMPARE(textFrameSpy.count(), 1); - QCOMPARE(textMessageSpy.count(), 1); - QCOMPARE(binaryFrameSpy.count(), 0); - QCOMPARE(binaryMessageSpy.count(), 0); - - QVariantList arguments = textFrameSpy.takeFirst(); - QCOMPARE(arguments.at(0).value().toUtf8(), payload); - QCOMPARE(arguments.at(1).value(), !isContinuationFrame); - arguments = textMessageSpy.takeFirst(); - QCOMPARE(arguments.at(0).value().toUtf8(), payload); - buffer.close(); - } -} - -void tst_DataProcessor::frameTooSmall() -{ - QByteArray data; - QBuffer buffer; - QWebSocketDataProcessor dataProcessor; - QByteArray firstFrame; - - firstFrame.append(quint8(QWebSocketProtocol::OpCodeText)).append(char(1)) - .append(QByteArray(1, 'a')); - - //with nothing in the buffer, the dataProcessor should time out - //and the error should be CloseCodeGoingAway meaning the socket will be closed - buffer.setData(data); - buffer.open(QIODevice::ReadOnly); - QSignalSpy errorSpy(&dataProcessor, - SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString))); - QSignalSpy closeSpy(&dataProcessor, - SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString))); - QSignalSpy pingMessageSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray))); - QSignalSpy pongMessageSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray))); - QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString))); - QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray))); - QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool))); - QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool))); - - dataProcessor.process(&buffer); - - QCOMPARE(errorSpy.count(), 1); - QCOMPARE(closeSpy.count(), 0); - QCOMPARE(pingMessageSpy.count(), 0); - QCOMPARE(pongMessageSpy.count(), 0); - QCOMPARE(textMessageSpy.count(), 0); - QCOMPARE(binaryMessageSpy.count(), 0); - QCOMPARE(textFrameSpy.count(), 0); - QCOMPARE(binaryFrameSpy.count(), 0); - - QList arguments = errorSpy.takeFirst(); - QCOMPARE(arguments.at(0).value(), - QWebSocketProtocol::CloseCodeGoingAway); - errorSpy.clear(); - closeSpy.clear(); - pingMessageSpy.clear(); - pongMessageSpy.clear(); - textMessageSpy.clear(); - binaryMessageSpy.clear(); - textFrameSpy.clear(); - binaryFrameSpy.clear(); - buffer.close(); - data.clear(); - - //only one byte; this is far too little; - //should get a time out as well and the error should be CloseCodeGoingAway - //meaning the socket will be closed - data.append(quint8('1')); //put 1 byte in the buffer; this is too little - buffer.setData(data); - buffer.open(QIODevice::ReadOnly); - - dataProcessor.process(&buffer); - - QCOMPARE(errorSpy.count(), 1); - QCOMPARE(closeSpy.count(), 0); - QCOMPARE(pingMessageSpy.count(), 0); - QCOMPARE(pongMessageSpy.count(), 0); - QCOMPARE(textMessageSpy.count(), 0); - QCOMPARE(binaryMessageSpy.count(), 0); - QCOMPARE(textFrameSpy.count(), 0); - QCOMPARE(binaryFrameSpy.count(), 0); - - arguments = errorSpy.takeFirst(); - QCOMPARE(arguments.at(0).value(), - QWebSocketProtocol::CloseCodeGoingAway); - buffer.close(); - errorSpy.clear(); - closeSpy.clear(); - pingMessageSpy.clear(); - pongMessageSpy.clear(); - textMessageSpy.clear(); - binaryMessageSpy.clear(); - textFrameSpy.clear(); - binaryFrameSpy.clear(); - data.clear(); - - - { - //text frame with final bit not set - data.append((char)(QWebSocketProtocol::OpCodeText)).append(char(0x0)); - buffer.setData(data); - buffer.open(QIODevice::ReadOnly); - - dataProcessor.process(&buffer); - - buffer.close(); - data.clear(); - - //with nothing in the buffer, - //the dataProcessor should time out and the error should be CloseCodeGoingAway - //meaning the socket will be closed - buffer.setData(data); - buffer.open(QIODevice::ReadOnly); - QSignalSpy errorSpy(&dataProcessor, - SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString))); - dataProcessor.process(&buffer); - - QCOMPARE(errorSpy.count(), 1); - QCOMPARE(closeSpy.count(), 0); - QCOMPARE(pingMessageSpy.count(), 0); - QCOMPARE(pongMessageSpy.count(), 0); - QCOMPARE(textMessageSpy.count(), 0); - QCOMPARE(binaryMessageSpy.count(), 0); - QCOMPARE(textFrameSpy.count(), 1); - QCOMPARE(binaryFrameSpy.count(), 0); - - QList arguments = errorSpy.takeFirst(); - QCOMPARE(arguments.at(0).value(), - QWebSocketProtocol::CloseCodeGoingAway); - errorSpy.clear(); - closeSpy.clear(); - pingMessageSpy.clear(); - pongMessageSpy.clear(); - textMessageSpy.clear(); - binaryMessageSpy.clear(); - textFrameSpy.clear(); - binaryFrameSpy.clear(); - buffer.close(); - data.clear(); - - //text frame with final bit not set - data.append((char)(QWebSocketProtocol::OpCodeText)).append(char(0x0)); - buffer.setData(data); - buffer.open(QIODevice::ReadOnly); - dataProcessor.process(&buffer); - - QCOMPARE(errorSpy.count(), 1); - QCOMPARE(closeSpy.count(), 0); - QCOMPARE(pingMessageSpy.count(), 0); - QCOMPARE(pongMessageSpy.count(), 0); - QCOMPARE(textMessageSpy.count(), 0); - QCOMPARE(binaryMessageSpy.count(), 0); - QCOMPARE(textFrameSpy.count(), 1); - QCOMPARE(binaryFrameSpy.count(), 0); - - buffer.close(); - data.clear(); - - errorSpy.clear(); - closeSpy.clear(); - pingMessageSpy.clear(); - pongMessageSpy.clear(); - textMessageSpy.clear(); - binaryMessageSpy.clear(); - textFrameSpy.clear(); - binaryFrameSpy.clear(); - - //only 1 byte follows in continuation frame; - //should time out with close code CloseCodeGoingAway - data.append('a'); - buffer.setData(data); - buffer.open(QIODevice::ReadOnly); - - dataProcessor.process(&buffer); - QCOMPARE(errorSpy.count(), 1); - QCOMPARE(closeSpy.count(), 0); - QCOMPARE(pingMessageSpy.count(), 0); - QCOMPARE(pongMessageSpy.count(), 0); - QCOMPARE(textMessageSpy.count(), 0); - QCOMPARE(binaryMessageSpy.count(), 0); - QCOMPARE(textFrameSpy.count(), 0); - QCOMPARE(binaryFrameSpy.count(), 0); - arguments = errorSpy.takeFirst(); - QCOMPARE(arguments.at(0).value(), - QWebSocketProtocol::CloseCodeGoingAway); - buffer.close(); - } -} - -void tst_DataProcessor::frameTooBig_data() -{ - QTest::addColumn("firstByte"); - QTest::addColumn("secondByte"); - QTest::addColumn("payload"); - QTest::addColumn("isContinuationFrame"); - QTest::addColumn("expectedCloseCode"); - - quint64 swapped64 = 0; - const char *wireRepresentation = 0; - - //only data frames are checked for being too big - //control frames have explicit checking on a maximum payload size of 125, - //which is tested elsewhere - - swapped64 = qToBigEndian(QWebSocketDataProcessor::maxFrameSize() + 1); - wireRepresentation = static_cast(static_cast(&swapped64)); - QTest::newRow("Text frame with payload size > INT_MAX") - << quint8(FIN | QWebSocketProtocol::OpCodeText) - << quint8(127) - << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a')) - << false - << QWebSocketProtocol::CloseCodeTooMuchData; - - swapped64 = qToBigEndian(QWebSocketDataProcessor::maxFrameSize() + 1); - wireRepresentation = static_cast(static_cast(&swapped64)); - QTest::newRow("Binary frame with payload size > INT_MAX") - << quint8(FIN | QWebSocketProtocol::OpCodeBinary) - << quint8(127) - << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a')) - << false - << QWebSocketProtocol::CloseCodeTooMuchData; - - swapped64 = qToBigEndian(QWebSocketDataProcessor::maxFrameSize() + 1); - wireRepresentation = static_cast(static_cast(&swapped64)); - QTest::newRow("Continuation frame with payload size > INT_MAX") - << quint8(FIN | QWebSocketProtocol::OpCodeContinue) - << quint8(127) - << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a')) - << true - << QWebSocketProtocol::CloseCodeTooMuchData; -} - -void tst_DataProcessor::frameTooBig() -{ - doTest(); -} - -void tst_DataProcessor::invalidHeader_data() -{ - //The first byte contain the FIN, RSV1, RSV2, RSV3 and the Opcode - //The second byte contains the MaskFlag and the length of the frame - QTest::addColumn("firstByte"); - QTest::addColumn("secondByte"); - //superfluous, but present to be able to call doTest(), which expects a payload field - QTest::addColumn("payload"); - QTest::addColumn("isContinuationFrame"); - QTest::addColumn("expectedCloseCode"); - - //invalid bit fields - invalidField("RSV1 set", RSV1); - invalidField("RSV2 set", RSV2); - invalidField("RSV3 set", RSV3); - invalidField("RSV1 and RSV2 set", RSV1 | RSV2); - invalidField("RSV1 and RSV3 set", RSV1 | RSV3); - invalidField("RSV2 and RSV3 set", RSV2 | RSV3); - invalidField("RSV1, RSV2 and RSV3 set", RSV1 | RSV2 | RSV3); - - //invalid opcodes - invalidField("Invalid OpCode 3", QWebSocketProtocol::OpCodeReserved3); - invalidField("Invalid OpCode 4", QWebSocketProtocol::OpCodeReserved4); - invalidField("Invalid OpCode 5", QWebSocketProtocol::OpCodeReserved5); - invalidField("Invalid OpCode 6", QWebSocketProtocol::OpCodeReserved6); - invalidField("Invalid OpCode 7", QWebSocketProtocol::OpCodeReserved7); - invalidField("Invalid OpCode B", QWebSocketProtocol::OpCodeReservedB); - invalidField("Invalid OpCode C", QWebSocketProtocol::OpCodeReservedC); - invalidField("Invalid OpCode D", QWebSocketProtocol::OpCodeReservedD); - invalidField("Invalid OpCode E", QWebSocketProtocol::OpCodeReservedE); - invalidField("Invalid OpCode F", QWebSocketProtocol::OpCodeReservedF); -} - -void tst_DataProcessor::invalidHeader() -{ - doTest(); -} - -void tst_DataProcessor::invalidControlFrame_data() -{ - QTest::addColumn("firstByte"); - QTest::addColumn("secondByte"); - QTest::addColumn("payload"); - QTest::addColumn("isContinuationFrame"); - QTest::addColumn("expectedCloseCode"); - - - QTest::newRow("Close control frame with payload size 126") - << quint8(FIN | QWebSocketProtocol::OpCodeClose) - << quint8(126) - << QByteArray() - << false - << QWebSocketProtocol::CloseCodeProtocolError; - QTest::newRow("Ping control frame with payload size 126") - << quint8(FIN | QWebSocketProtocol::OpCodePing) - << quint8(126) - << QByteArray() - << false - << QWebSocketProtocol::CloseCodeProtocolError; - QTest::newRow("Close control frame with payload size 126") - << quint8(FIN | QWebSocketProtocol::OpCodePong) - << quint8(126) - << QByteArray() - << false - << QWebSocketProtocol::CloseCodeProtocolError; - - QTest::newRow("Non-final close control frame (fragmented)") - << quint8(QWebSocketProtocol::OpCodeClose) - << quint8(32) - << QByteArray() - << false - << QWebSocketProtocol::CloseCodeProtocolError; - QTest::newRow("Non-final ping control frame (fragmented)") - << quint8(QWebSocketProtocol::OpCodePing) - << quint8(32) << QByteArray() - << false - << QWebSocketProtocol::CloseCodeProtocolError; - QTest::newRow("Non-final pong control frame (fragmented)") - << quint8(QWebSocketProtocol::OpCodePong) - << quint8(32) - << QByteArray() - << false - << QWebSocketProtocol::CloseCodeProtocolError; -} - -void tst_DataProcessor::invalidControlFrame() -{ - doTest(); -} - -void tst_DataProcessor::invalidCloseFrame_data() -{ - QTest::addColumn("firstByte"); - QTest::addColumn("secondByte"); - QTest::addColumn("payload"); - QTest::addColumn("isContinuationFrame"); - QTest::addColumn("expectedCloseCode"); - - QTest::newRow("Close control frame with payload size 1") - << quint8(FIN | QWebSocketProtocol::OpCodeClose) - << quint8(1) - << QByteArray(1, 'a') - << false - << QWebSocketProtocol::CloseCodeProtocolError; - quint16 swapped = qToBigEndian(QWebSocketProtocol::CloseCodeAbnormalDisconnection); - const char *wireRepresentation = static_cast(static_cast(&swapped)); - - //Not allowed per RFC 6455 (see para 7.4.1) - QTest::newRow("Close control frame close code ABNORMAL DISCONNECTION") - << quint8(FIN | QWebSocketProtocol::OpCodeClose) - << quint8(2) - << QByteArray(wireRepresentation, 2) - << false - << QWebSocketProtocol::CloseCodeProtocolError; - swapped = qToBigEndian(QWebSocketProtocol::CloseCodeMissingStatusCode); - wireRepresentation = static_cast(static_cast(&swapped)); - //Not allowed per RFC 6455 (see para 7.4.1) - QTest::newRow("Close control frame close code MISSING STATUS CODE") - << quint8(FIN | QWebSocketProtocol::OpCodeClose) - << quint8(2) - << QByteArray(wireRepresentation, 2) - << false - << QWebSocketProtocol::CloseCodeProtocolError; - swapped = qToBigEndian(1004); - wireRepresentation = static_cast(static_cast(&swapped)); - QTest::newRow("Close control frame close code 1004") - << quint8(FIN | QWebSocketProtocol::OpCodeClose) - << quint8(2) - << QByteArray(wireRepresentation, 2) - << false - << QWebSocketProtocol::CloseCodeProtocolError; - swapped = qToBigEndian(QWebSocketProtocol::CloseCodeTlsHandshakeFailed); - wireRepresentation = static_cast(static_cast(&swapped)); - //Not allowed per RFC 6455 (see para 7.4.1) - QTest::newRow("Close control frame close code TLS HANDSHAKE FAILED") - << quint8(FIN | QWebSocketProtocol::OpCodeClose) - << quint8(2) - << QByteArray(wireRepresentation, 2) - << false - << QWebSocketProtocol::CloseCodeProtocolError; - swapped = qToBigEndian(0); - wireRepresentation = static_cast(static_cast(&swapped)); - QTest::newRow("Close control frame close code 0") - << quint8(FIN | QWebSocketProtocol::OpCodeClose) - << quint8(2) - << QByteArray(wireRepresentation, 2) - << false - << QWebSocketProtocol::CloseCodeProtocolError; - swapped = qToBigEndian(999); - wireRepresentation = static_cast(static_cast(&swapped)); - QTest::newRow("Close control frame close code 999") - << quint8(FIN | QWebSocketProtocol::OpCodeClose) - << quint8(2) - << QByteArray(wireRepresentation, 2) - << false - << QWebSocketProtocol::CloseCodeProtocolError; - swapped = qToBigEndian(1012); - wireRepresentation = static_cast(static_cast(&swapped)); - QTest::newRow("Close control frame close code 1012") - << quint8(FIN | QWebSocketProtocol::OpCodeClose) - << quint8(2) - << QByteArray(wireRepresentation, 2) - << false - << QWebSocketProtocol::CloseCodeProtocolError; - swapped = qToBigEndian(1013); - wireRepresentation = static_cast(static_cast(&swapped)); - QTest::newRow("Close control frame close code 1013") - << quint8(FIN | QWebSocketProtocol::OpCodeClose) - << quint8(2) - << QByteArray(wireRepresentation, 2) - << false - << QWebSocketProtocol::CloseCodeProtocolError; - swapped = qToBigEndian(1014); - wireRepresentation = static_cast(static_cast(&swapped)); - QTest::newRow("Close control frame close code 1014") - << quint8(FIN | QWebSocketProtocol::OpCodeClose) - << quint8(2) - << QByteArray(wireRepresentation, 2) - << false - << QWebSocketProtocol::CloseCodeProtocolError; - swapped = qToBigEndian(1100); - wireRepresentation = static_cast(static_cast(&swapped)); - QTest::newRow("Close control frame close code 1100") - << quint8(FIN | QWebSocketProtocol::OpCodeClose) - << quint8(2) - << QByteArray(wireRepresentation, 2) - << false - << QWebSocketProtocol::CloseCodeProtocolError; - swapped = qToBigEndian(2000); - wireRepresentation = static_cast(static_cast(&swapped)); - QTest::newRow("Close control frame close code 2000") - << quint8(FIN | QWebSocketProtocol::OpCodeClose) - << quint8(2) - << QByteArray(wireRepresentation, 2) - << false - << QWebSocketProtocol::CloseCodeProtocolError; - swapped = qToBigEndian(2999); - wireRepresentation = static_cast(static_cast(&swapped)); - QTest::newRow("Close control frame close code 2999") - << quint8(FIN | QWebSocketProtocol::OpCodeClose) - << quint8(2) - << QByteArray(wireRepresentation, 2) - << false - << QWebSocketProtocol::CloseCodeProtocolError; - swapped = qToBigEndian(5000); - wireRepresentation = static_cast(static_cast(&swapped)); - QTest::newRow("Close control frame close code 5000") - << quint8(FIN | QWebSocketProtocol::OpCodeClose) - << quint8(2) - << QByteArray(wireRepresentation, 2) - << false - << QWebSocketProtocol::CloseCodeProtocolError; - swapped = qToBigEndian(65535u); - wireRepresentation = static_cast(static_cast(&swapped)); - QTest::newRow("Close control frame close code 65535") - << quint8(FIN | QWebSocketProtocol::OpCodeClose) - << quint8(2) - << QByteArray(wireRepresentation, 2) - << false - << QWebSocketProtocol::CloseCodeProtocolError; -} - -void tst_DataProcessor::invalidCloseFrame() -{ - doCloseFrameTest(); -} - -void tst_DataProcessor::minimumSizeRequirement_data() -{ - QTest::addColumn("firstByte"); - QTest::addColumn("secondByte"); - QTest::addColumn("payload"); - QTest::addColumn("isContinuationFrame"); - QTest::addColumn("expectedCloseCode"); - - minimumSize16Bit(0); - minimumSize16Bit(64); - minimumSize16Bit(125); - - minimumSize64Bit(0); - minimumSize64Bit(64); - minimumSize64Bit(125); - minimumSize64Bit(126); - minimumSize64Bit(256); - minimumSize64Bit(512); - minimumSize64Bit(1024); - minimumSize64Bit(2048); - minimumSize64Bit(4096); - minimumSize64Bit(8192); - minimumSize64Bit(16384); - minimumSize64Bit(32768); - minimumSize64Bit(0xFFFFu); -} - -void tst_DataProcessor::minimumSizeRequirement() -{ - doTest(); -} - -void tst_DataProcessor::invalidPayload_data(bool isControlFrame) -{ - QTest::addColumn("firstByte"); - QTest::addColumn("secondByte"); - QTest::addColumn("payload"); - QTest::addColumn("isContinuationFrame"); - QTest::addColumn("expectedCloseCode"); - - //6.3: invalid UTF-8 sequence - invalidUTF8("case 6.3.1", "cebae1bdb9cf83cebcceb5eda080656469746564", isControlFrame); - - //6.4.: fail fast tests; invalid UTF-8 in middle of string - invalidUTF8("case 6.4.1", "cebae1bdb9cf83cebcceb5f4908080656469746564", isControlFrame); - invalidUTF8("case 6.4.4", "cebae1bdb9cf83cebcceb5eda080656469746564", isControlFrame); - - //6.6: All prefixes of a valid UTF-8 string that contains multi-byte code points - invalidUTF8("case 6.6.1", "ce", isControlFrame); - invalidUTF8("case 6.6.3", "cebae1", isControlFrame); - invalidUTF8("case 6.6.4", "cebae1bd", isControlFrame); - invalidUTF8("case 6.6.6", "cebae1bdb9cf", isControlFrame); - invalidUTF8("case 6.6.8", "cebae1bdb9cf83ce", isControlFrame); - invalidUTF8("case 6.6.10", "cebae1bdb9cf83cebcce", isControlFrame); - - //6.8: First possible sequence length 5/6 (invalid codepoints) - invalidUTF8("case 6.8.1", "f888808080", isControlFrame); - invalidUTF8("case 6.8.2", "fc8480808080", isControlFrame); - - //6.10: Last possible sequence length 4/5/6 (invalid codepoints) - invalidUTF8("case 6.10.1", "f7bfbfbf", isControlFrame); - invalidUTF8("case 6.10.2", "fbbfbfbfbf", isControlFrame); - invalidUTF8("case 6.10.3", "fdbfbfbfbfbf", isControlFrame); - - //5.11: boundary conditions - invalidUTF8("case 6.11.5", "f4908080", isControlFrame); - - //6.12: unexpected continuation bytes - invalidUTF8("case 6.12.1", "80", isControlFrame); - invalidUTF8("case 6.12.2", "bf", isControlFrame); - invalidUTF8("case 6.12.3", "80bf", isControlFrame); - invalidUTF8("case 6.12.4", "80bf80", isControlFrame); - invalidUTF8("case 6.12.5", "80bf80bf", isControlFrame); - invalidUTF8("case 6.12.6", "80bf80bf80", isControlFrame); - invalidUTF8("case 6.12.7", "80bf80bf80bf", isControlFrame); - invalidUTF8("case 6.12.8", - "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a" - "7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbe", - isControlFrame); - - //6.13: lonely start characters - invalidUTF8("case 6.13.1", - "c020c120c220c320c420c520c620c720c820c920ca20cb20cc20cd20ce20cf20d020d120d220" - "d320d420d520d620d720d820d920da20db20dc20dd20de20", - isControlFrame); - invalidUTF8("case 6.13.2", "e020e120e220e320e420e520e620e720e820e920ea20eb20ec20ed20ee20", - isControlFrame); - invalidUTF8("case 6.13.3", "f020f120f220f320f420f520f620", isControlFrame); - invalidUTF8("case 6.13.4", "f820f920fa20", isControlFrame); - invalidUTF8("case 6.13.5", "fc20", isControlFrame); - - //6.14: sequences with last continuation byte missing - invalidUTF8("case 6.14.1", "c0", isControlFrame); - invalidUTF8("case 6.14.2", "e080", isControlFrame); - invalidUTF8("case 6.14.3", "f08080", isControlFrame); - invalidUTF8("case 6.14.4", "f8808080", isControlFrame); - invalidUTF8("case 6.14.5", "fc80808080", isControlFrame); - invalidUTF8("case 6.14.6", "df", isControlFrame); - invalidUTF8("case 6.14.7", "efbf", isControlFrame); - invalidUTF8("case 6.14.8", "f7bfbf", isControlFrame); - invalidUTF8("case 6.14.9", "fbbfbfbf", isControlFrame); - invalidUTF8("case 6.14.10", "fdbfbfbfbf", isControlFrame); - - //6.15: concatenation of incomplete sequences - invalidUTF8("case 6.15.1", - "c0e080f08080f8808080fc80808080dfefbff7bfbffbbfbfbffdbfbfbfbf", isControlFrame); - - //6.16: impossible bytes - invalidUTF8("case 6.16.1", "fe", isControlFrame); - invalidUTF8("case 6.16.2", "ff", isControlFrame); - invalidUTF8("case 6.16.3", "fefeffff", isControlFrame); - - //6.17: overlong ASCII characters - invalidUTF8("case 6.17.1", "c0af", isControlFrame); - invalidUTF8("case 6.17.2", "e080af", isControlFrame); - invalidUTF8("case 6.17.3", "f08080af", isControlFrame); - invalidUTF8("case 6.17.4", "f8808080af", isControlFrame); - invalidUTF8("case 6.17.5", "fc80808080af", isControlFrame); - - //6.18: maximum overlong sequences - invalidUTF8("case 6.18.1", "c1bf", isControlFrame); - invalidUTF8("case 6.18.2", "e09fbf", isControlFrame); - invalidUTF8("case 6.18.3", "f08fbfbf", isControlFrame); - invalidUTF8("case 6.18.4", "f887bfbfbf", isControlFrame); - invalidUTF8("case 6.18.5", "fc83bfbfbfbf", isControlFrame); - - //6.19: overlong presentation of the NUL character - invalidUTF8("case 6.19.1", "c080", isControlFrame); - invalidUTF8("case 6.19.2", "e08080", isControlFrame); - invalidUTF8("case 6.19.3", "f0808080", isControlFrame); - invalidUTF8("case 6.19.4", "f880808080", isControlFrame); - invalidUTF8("case 6.19.5", "fc8080808080", isControlFrame); - - //6.20: Single UTF-16 surrogates - invalidUTF8("case 6.20.1", "eda080", isControlFrame); - invalidUTF8("case 6.20.2", "edadbf", isControlFrame); - invalidUTF8("case 6.20.3", "edae80", isControlFrame); - invalidUTF8("case 6.20.4", "edafbf", isControlFrame); - invalidUTF8("case 6.20.5", "edb080", isControlFrame); - invalidUTF8("case 6.20.6", "edbe80", isControlFrame); - invalidUTF8("case 6.20.7", "edbfbf", isControlFrame); - - //6.21: Paired UTF-16 surrogates - invalidUTF8("case 6.21.1", "eda080edb080", isControlFrame); - invalidUTF8("case 6.21.2", "eda080edbfbf", isControlFrame); - invalidUTF8("case 6.21.3", "edadbfedb080", isControlFrame); - invalidUTF8("case 6.21.4", "edadbfedbfbf", isControlFrame); - invalidUTF8("case 6.21.5", "edae80edb080", isControlFrame); - invalidUTF8("case 6.21.6", "edae80edbfbf", isControlFrame); - invalidUTF8("case 6.21.7", "edafbfedb080", isControlFrame); - invalidUTF8("case 6.21.8", "edafbfedbfbf", isControlFrame); -} - -void tst_DataProcessor::invalidPayload() -{ - doTest(); -} - -void tst_DataProcessor::invalidPayloadInCloseFrame_data() -{ - invalidPayload_data(true); -} - -void tst_DataProcessor::invalidPayloadInCloseFrame() -{ - QFETCH(quint8, firstByte); - QFETCH(quint8, secondByte); - QFETCH(QByteArray, payload); - QFETCH(bool, isContinuationFrame); - QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode); - - Q_UNUSED(isContinuationFrame) - - QByteArray data; - QBuffer buffer; - QWebSocketDataProcessor dataProcessor; - QSignalSpy closeSpy(&dataProcessor, - SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString))); - QSignalSpy errorSpy(&dataProcessor, - SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString))); - QSignalSpy pingMessageSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray))); - QSignalSpy pongMessageSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray))); - QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString))); - QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray))); - QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool))); - QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool))); - - data.append(firstByte).append(secondByte); - data.append(payload); - buffer.setData(data); - buffer.open(QIODevice::ReadOnly); - dataProcessor.process(&buffer); - QCOMPARE(closeSpy.count(), 1); - QCOMPARE(errorSpy.count(), 0); - QCOMPARE(pingMessageSpy.count(), 0); - QCOMPARE(pongMessageSpy.count(), 0); - QCOMPARE(textMessageSpy.count(), 0); - QCOMPARE(binaryMessageSpy.count(), 0); - QCOMPARE(textFrameSpy.count(), 0); - QCOMPARE(binaryFrameSpy.count(), 0); - QVariantList arguments = closeSpy.takeFirst(); - QCOMPARE(arguments.at(0).value(), expectedCloseCode); - buffer.close(); -} - -void tst_DataProcessor::incompletePayload_data() -{ - QTest::addColumn("firstByte"); - QTest::addColumn("secondByte"); - QTest::addColumn("payload"); - QTest::addColumn("isContinuationFrame"); - QTest::addColumn("expectedCloseCode"); - - incompleteFrame(QWebSocketProtocol::OpCodeText, 125, 0); - incompleteFrame(QWebSocketProtocol::OpCodeText, 64, 32); - incompleteFrame(QWebSocketProtocol::OpCodeText, 256, 32); - incompleteFrame(QWebSocketProtocol::OpCodeText, 128000, 32); - incompleteFrame(QWebSocketProtocol::OpCodeBinary, 125, 0); - incompleteFrame(QWebSocketProtocol::OpCodeBinary, 64, 32); - incompleteFrame(QWebSocketProtocol::OpCodeBinary, 256, 32); - incompleteFrame(QWebSocketProtocol::OpCodeBinary, 128000, 32); - incompleteFrame(QWebSocketProtocol::OpCodeContinue, 125, 0); - incompleteFrame(QWebSocketProtocol::OpCodeContinue, 64, 32); - incompleteFrame(QWebSocketProtocol::OpCodeContinue, 256, 32); - incompleteFrame(QWebSocketProtocol::OpCodeContinue, 128000, 32); - - incompleteFrame(QWebSocketProtocol::OpCodeClose, 64, 32); - incompleteFrame(QWebSocketProtocol::OpCodePing, 64, 32); - incompleteFrame(QWebSocketProtocol::OpCodePong, 64, 32); -} - -void tst_DataProcessor::incompletePayload() -{ - doTest(); -} - -void tst_DataProcessor::incompleteSizeField_data() -{ - QTest::addColumn("firstByte"); - QTest::addColumn("secondByte"); - QTest::addColumn("payload"); - QTest::addColumn("isContinuationFrame"); - QTest::addColumn("expectedCloseCode"); - - //for a frame length value of 126 - //there should be 2 bytes following to form a 16-bit frame length - insertIncompleteSizeFieldTest(126, 0); - insertIncompleteSizeFieldTest(126, 1); - - //for a frame length value of 127 - //there should be 8 bytes following to form a 64-bit frame length - insertIncompleteSizeFieldTest(127, 0); - insertIncompleteSizeFieldTest(127, 1); - insertIncompleteSizeFieldTest(127, 2); - insertIncompleteSizeFieldTest(127, 3); - insertIncompleteSizeFieldTest(127, 4); - insertIncompleteSizeFieldTest(127, 5); - insertIncompleteSizeFieldTest(127, 6); - insertIncompleteSizeFieldTest(127, 7); -} - -void tst_DataProcessor::incompleteSizeField() -{ - doTest(); -} - -////////////////////////////////////////////////////////////////////////////////////////// -/// HELPER FUNCTIONS -////////////////////////////////////////////////////////////////////////////////////////// -void tst_DataProcessor::doTest() -{ - QFETCH(quint8, firstByte); - QFETCH(quint8, secondByte); - QFETCH(QByteArray, payload); - QFETCH(bool, isContinuationFrame); - QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode); - - QByteArray data; - QBuffer buffer; - QWebSocketDataProcessor dataProcessor; - QSignalSpy errorSpy(&dataProcessor, - SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString))); - QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString))); - QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray))); - QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool))); - QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool))); - - if (isContinuationFrame) - { - data.append(quint8(QWebSocketProtocol::OpCodeText)) - .append(char(1)) - .append(QByteArray(1, 'a')); - } - data.append(firstByte).append(secondByte); - data.append(payload); - buffer.setData(data); - buffer.open(QIODevice::ReadOnly); - dataProcessor.process(&buffer); - QCOMPARE(errorSpy.count(), 1); - QCOMPARE(textMessageSpy.count(), 0); - QCOMPARE(binaryMessageSpy.count(), 0); - QCOMPARE(textFrameSpy.count(), isContinuationFrame ? 1 : 0); - QCOMPARE(binaryFrameSpy.count(), 0); - QVariantList arguments = errorSpy.takeFirst(); - QCOMPARE(arguments.at(0).value(), expectedCloseCode); - buffer.close(); - errorSpy.clear(); - data.clear(); -} - -void tst_DataProcessor::doCloseFrameTest() -{ - QFETCH(quint8, firstByte); - QFETCH(quint8, secondByte); - QFETCH(QByteArray, payload); - QFETCH(bool, isContinuationFrame); - QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode); - - Q_UNUSED(isContinuationFrame) - - QByteArray data; - QBuffer buffer; - QWebSocketDataProcessor dataProcessor; - QSignalSpy closeSpy(&dataProcessor, - SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString))); - QSignalSpy errorSpy(&dataProcessor, - SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString))); - QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString))); - QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray))); - QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool))); - QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool))); - - data.append(firstByte).append(secondByte); - data.append(payload); - buffer.setData(data); - buffer.open(QIODevice::ReadOnly); - dataProcessor.process(&buffer); - QCOMPARE(closeSpy.count(), 1); - QCOMPARE(errorSpy.count(), 0); - QCOMPARE(textMessageSpy.count(), 0); - QCOMPARE(binaryMessageSpy.count(), 0); - QCOMPARE(textFrameSpy.count(), 0); - QCOMPARE(binaryFrameSpy.count(), 0); - QVariantList arguments = closeSpy.takeFirst(); - QCOMPARE(arguments.at(0).value(), expectedCloseCode); - buffer.close(); -} - -QString tst_DataProcessor::opCodeToString(quint8 opCode) -{ - QString frameType; - switch (opCode) - { - case QWebSocketProtocol::OpCodeBinary: - { - frameType = QStringLiteral("Binary"); - break; - } - case QWebSocketProtocol::OpCodeText: - { - frameType = QStringLiteral("Text"); - break; - } - case QWebSocketProtocol::OpCodePing: - { - frameType = QStringLiteral("Ping"); - break; - } - case QWebSocketProtocol::OpCodePong: - { - frameType = QStringLiteral("Pong"); - break; - } - case QWebSocketProtocol::OpCodeClose: - { - frameType = QStringLiteral("Close"); - break; - } - case QWebSocketProtocol::OpCodeContinue: - { - frameType = QStringLiteral("Continuation"); - break; - } - case QWebSocketProtocol::OpCodeReserved3: - { - frameType = QStringLiteral("Reserved3"); - break; - } - case QWebSocketProtocol::OpCodeReserved4: - { - frameType = QStringLiteral("Reserved5"); - break; - } - case QWebSocketProtocol::OpCodeReserved5: - { - frameType = QStringLiteral("Reserved5"); - break; - } - case QWebSocketProtocol::OpCodeReserved6: - { - frameType = QStringLiteral("Reserved6"); - break; - } - case QWebSocketProtocol::OpCodeReserved7: - { - frameType = QStringLiteral("Reserved7"); - break; - } - case QWebSocketProtocol::OpCodeReservedB: - { - frameType = QStringLiteral("ReservedB"); - break; - } - case QWebSocketProtocol::OpCodeReservedC: - { - frameType = QStringLiteral("ReservedC"); - break; - } - case QWebSocketProtocol::OpCodeReservedD: - { - frameType = QStringLiteral("ReservedD"); - break; - } - case QWebSocketProtocol::OpCodeReservedE: - { - frameType = QStringLiteral("ReservedE"); - break; - } - case QWebSocketProtocol::OpCodeReservedF: - { - frameType = QStringLiteral("ReservedF"); - break; - } - default: - { - //should never come here - Q_ASSERT(false); - } - } - return frameType; -} - -void tst_DataProcessor::minimumSize16Bit(quint16 sizeInBytes) -{ - quint16 swapped16 = qToBigEndian(sizeInBytes); - const char *wireRepresentation - = static_cast(static_cast(&swapped16)); - QTest::newRow(QStringLiteral("Text frame with payload size %1, represented in 2 bytes") - .arg(sizeInBytes).toLatin1().constData()) - << quint8(FIN | QWebSocketProtocol::OpCodeText) - << quint8(126) - << QByteArray(wireRepresentation, 2) - << false - << QWebSocketProtocol::CloseCodeProtocolError; - QTest::newRow(QStringLiteral("Binary frame with payload size %1, represented in 2 bytes") - .arg(sizeInBytes).toLatin1().constBegin()) - << quint8(FIN | QWebSocketProtocol::OpCodeBinary) - << quint8(126) - << QByteArray(wireRepresentation, 2) - << false - << QWebSocketProtocol::CloseCodeProtocolError; - QTest::newRow(QStringLiteral("Continuation frame with payload size %1, represented in 2 bytes") - .arg(sizeInBytes).toLatin1().constData()) - << quint8(FIN | QWebSocketProtocol::OpCodeContinue) - << quint8(126) - << QByteArray(wireRepresentation, 2) - << true - << QWebSocketProtocol::CloseCodeProtocolError; -} - -void tst_DataProcessor::minimumSize64Bit(quint64 sizeInBytes) -{ - quint64 swapped64 = qToBigEndian(sizeInBytes); - const char *wireRepresentation - = static_cast(static_cast(&swapped64)); - - QTest::newRow(QStringLiteral("Text frame with payload size %1, represented in 8 bytes") - .arg(sizeInBytes).toLatin1().constData()) - << quint8(FIN | QWebSocketProtocol::OpCodeText) - << quint8(127) - << QByteArray(wireRepresentation, 8) - << false - << QWebSocketProtocol::CloseCodeProtocolError; - - QTest::newRow(QStringLiteral("Binary frame with payload size %1, represented in 8 bytes") - .arg(sizeInBytes).toLatin1().constData()) - << quint8(FIN | QWebSocketProtocol::OpCodeBinary) - << quint8(127) - << QByteArray(wireRepresentation, 8) - << false - << QWebSocketProtocol::CloseCodeProtocolError; - - QTest::newRow(QStringLiteral("Continuation frame with payload size %1, represented in 8 bytes") - .arg(sizeInBytes).toLatin1().constData()) - << quint8(FIN | QWebSocketProtocol::OpCodeContinue) - << quint8(127) - << QByteArray(wireRepresentation, 8) - << true - << QWebSocketProtocol::CloseCodeProtocolError; -} - -void tst_DataProcessor::invalidUTF8(const char *dataTag, const char *utf8Sequence, - bool isCloseFrame) -{ - QByteArray payload = QByteArray::fromHex(utf8Sequence); - - if (isCloseFrame) - { - quint16 closeCode = qToBigEndian(QWebSocketProtocol::CloseCodeNormal); - const char *wireRepresentation - = static_cast(static_cast(&closeCode)); - QTest::newRow(QStringLiteral("Close frame with invalid UTF8-sequence: %1") - .arg(dataTag).toLatin1().constData()) - << quint8(FIN | QWebSocketProtocol::OpCodeClose) - << quint8(payload.length() + 2) - << QByteArray(wireRepresentation, 2).append(payload) - << false - << QWebSocketProtocol::CloseCodeWrongDatatype; - } - else - { - QTest::newRow(QStringLiteral("Text frame with invalid UTF8-sequence: %1") - .arg(dataTag).toLatin1().constData()) - << quint8(FIN | QWebSocketProtocol::OpCodeText) - << quint8(payload.length()) - << payload - << false - << QWebSocketProtocol::CloseCodeWrongDatatype; - - QTest::newRow(QStringLiteral("Continuation text frame with invalid UTF8-sequence: %1") - .arg(dataTag).toLatin1().constData()) - << quint8(FIN | QWebSocketProtocol::OpCodeContinue) - << quint8(payload.length()) - << payload - << true - << QWebSocketProtocol::CloseCodeWrongDatatype; - } -} - -void tst_DataProcessor::invalidField(const char *dataTag, quint8 invalidFieldValue) -{ - QTest::newRow(dataTag) << quint8(FIN | invalidFieldValue) - << quint8(0x00) - << QByteArray() - << false - << QWebSocketProtocol::CloseCodeProtocolError; - QTest::newRow(QString::fromLatin1(dataTag).append(QStringLiteral(" with continuation frame")) - .toLatin1().constData()) - << quint8(FIN | invalidFieldValue) - << quint8(0x00) - << QByteArray() - << true - << QWebSocketProtocol::CloseCodeProtocolError; -} - -void tst_DataProcessor::incompleteFrame(quint8 controlCode, quint64 indicatedSize, - quint64 actualPayloadSize) -{ - QVERIFY(!QWebSocketProtocol::isOpCodeReserved(QWebSocketProtocol::OpCode(controlCode))); - QVERIFY(indicatedSize > actualPayloadSize); - - QString frameType = opCodeToString(controlCode); - QByteArray firstFrame; - - if (indicatedSize < 126) - { - //doing extensive QStringLiteral concatenations here, because - //MSVC 2010 complains when using concatenation literal strings about - //concatenation of wide and narrow strings (error C2308) - QTest::newRow(frameType - .append(QStringLiteral(" frame with payload size %1, but only %2 bytes") + - QStringLiteral(" of data") - .arg(indicatedSize).arg(actualPayloadSize)).toLatin1().constData()) - << quint8(FIN | controlCode) - << quint8(indicatedSize) - << firstFrame.append(QByteArray(actualPayloadSize, 'a')) - << (controlCode == QWebSocketProtocol::OpCodeContinue) - << QWebSocketProtocol::CloseCodeGoingAway; - } - else if (indicatedSize <= 0xFFFFu) - { - quint16 swapped16 = qToBigEndian(static_cast(indicatedSize)); - const char *wireRepresentation - = static_cast(static_cast(&swapped16)); - QTest::newRow( - frameType.append(QStringLiteral(" frame with payload size %1, but only ") + - QStringLiteral("%2 bytes of data") - .arg(indicatedSize) - .arg(actualPayloadSize)).toLatin1().constData()) - << quint8(FIN | controlCode) - << quint8(126) - << firstFrame.append(QByteArray(wireRepresentation, 2) - .append(QByteArray(actualPayloadSize, 'a'))) - << (controlCode == QWebSocketProtocol::OpCodeContinue) - << QWebSocketProtocol::CloseCodeGoingAway; - } - else - { - quint64 swapped64 = qToBigEndian(indicatedSize); - const char *wireRepresentation - = static_cast(static_cast(&swapped64)); - QTest::newRow(frameType - .append(QStringLiteral(" frame with payload size %1, but only %2 bytes ") + - QStringLiteral("of data") - .arg(indicatedSize).arg(actualPayloadSize)).toLatin1().constData()) - << quint8(FIN | controlCode) - << quint8(127) - << firstFrame.append(QByteArray(wireRepresentation, 8) - .append(QByteArray(actualPayloadSize, 'a'))) - << (controlCode == QWebSocketProtocol::OpCodeContinue) - << QWebSocketProtocol::CloseCodeGoingAway; - } -} - -void tst_DataProcessor::nonCharacterSequence(const char *sequence) -{ - QByteArray utf8Sequence = QByteArray::fromHex(sequence); - - //doing extensive QStringLiteral concatenations here, because - //MSVC 2010 complains when using concatenation literal strings about - //concatenation of wide and narrow strings (error C2308) - QTest::newRow((QStringLiteral("Text frame with payload containing the non-control character ") + - QStringLiteral("sequence 0x%1")) - .arg(QString::fromLocal8Bit(sequence)).toLatin1().constData()) - << quint8(FIN | QWebSocketProtocol::OpCodeText) - << quint8(utf8Sequence.size()) - << utf8Sequence - << false; - - QTest::newRow((QStringLiteral("Continuation frame with payload containing the non-control ") + - QStringLiteral("character sequence 0x%1")) - .arg(QString::fromLocal8Bit(sequence)).toLatin1().constData()) - << quint8(FIN | QWebSocketProtocol::OpCodeContinue) - << quint8(utf8Sequence.size()) - << utf8Sequence - << true; -} - -void tst_DataProcessor::insertIncompleteSizeFieldTest(quint8 payloadCode, quint8 numBytesFollowing) -{ - //doing extensive QStringLiteral concatenations here, because - //MSVC 2010 complains when using concatenation literal strings about - //concatenation of wide and narrow strings (error C2308) - QTest::newRow(QStringLiteral("Text frame with payload size %1, with %2 bytes following.") - .arg(payloadCode).arg(numBytesFollowing).toLatin1().constData()) - << quint8(FIN | QWebSocketProtocol::OpCodeText) - << quint8(payloadCode) - << QByteArray(numBytesFollowing, quint8(1)) - << false - << QWebSocketProtocol::CloseCodeGoingAway; - QTest::newRow(QStringLiteral("Binary frame with payload size %1, with %2 bytes following.") - .arg(payloadCode).arg(numBytesFollowing).toLatin1().constData()) - << quint8(FIN | QWebSocketProtocol::OpCodeBinary) - << quint8(payloadCode) - << QByteArray(numBytesFollowing, quint8(1)) - << false - << QWebSocketProtocol::CloseCodeGoingAway; - QTest::newRow((QStringLiteral("Continuation frame with payload size %1, with %2 bytes ") + - QStringLiteral("following.")) - .arg(payloadCode).arg(numBytesFollowing).toLatin1().constData()) - << quint8(FIN | QWebSocketProtocol::OpCodeContinue) - << quint8(payloadCode) - << QByteArray(numBytesFollowing, quint8(1)) - << true - << QWebSocketProtocol::CloseCodeGoingAway; -} - -QTEST_MAIN(tst_DataProcessor) - -#include "tst_dataprocessor.moc" diff --git a/tests/auto/handshakerequest/handshakerequest.pro b/tests/auto/handshakerequest/handshakerequest.pro deleted file mode 100644 index d887cd6..0000000 --- a/tests/auto/handshakerequest/handshakerequest.pro +++ /dev/null @@ -1,14 +0,0 @@ -CONFIG += console -CONFIG += testcase -CONFIG -= app_bundle - -TEMPLATE = app - -TARGET = tst_handshakerequest - -QT = core testlib websockets websockets-private - -SOURCES += tst_handshakerequest.cpp - -requires(contains(QT_CONFIG, private_tests)) -DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/handshakerequest/tst_handshakerequest.cpp b/tests/auto/handshakerequest/tst_handshakerequest.cpp deleted file mode 100644 index 9c579bd..0000000 --- a/tests/auto/handshakerequest/tst_handshakerequest.cpp +++ /dev/null @@ -1,317 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Kurt Pattyn . -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include -#include -#include -#include -#include - -#include "private/qwebsockethandshakerequest_p.h" -#include "private/qwebsocketprotocol_p.h" -#include "QtWebSockets/qwebsocketprotocol.h" - -QT_USE_NAMESPACE - -Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode) -Q_DECLARE_METATYPE(QWebSocketProtocol::OpCode) - -class tst_HandshakeRequest : public QObject -{ - Q_OBJECT - -public: - tst_HandshakeRequest(); - -private Q_SLOTS: - void initTestCase(); - void cleanupTestCase(); - void init(); - void cleanup(); - - void tst_initialization(); - - void tst_invalidStream_data(); - void tst_invalidStream(); - - void tst_multipleValuesInConnectionHeader(); - void tst_multipleVersions(); - - void tst_qtbug_39355(); -}; - -tst_HandshakeRequest::tst_HandshakeRequest() -{} - -void tst_HandshakeRequest::initTestCase() -{ -} - -void tst_HandshakeRequest::cleanupTestCase() -{} - -void tst_HandshakeRequest::init() -{ - qRegisterMetaType("QWebSocketProtocol::OpCode"); - qRegisterMetaType("QWebSocketProtocol::CloseCode"); -} - -void tst_HandshakeRequest::cleanup() -{ -} - -void tst_HandshakeRequest::tst_initialization() -{ - { - QWebSocketHandshakeRequest request(0, false); - QCOMPARE(request.port(), 0); - QVERIFY(!request.isSecure()); - QVERIFY(!request.isValid()); - QCOMPARE(request.extensions().length(), 0); - QCOMPARE(request.protocols().length(), 0); - QCOMPARE(request.headers().size(), 0); - QCOMPARE(request.key().length(), 0); - QCOMPARE(request.origin().length(), 0); - QCOMPARE(request.host().length(), 0); - QVERIFY(request.requestUrl().isEmpty()); - QCOMPARE(request.resourceName().length(), 0); - QCOMPARE(request.versions().length(), 0); - } - { - QWebSocketHandshakeRequest request(80, true); - QCOMPARE(request.port(), 80); - QVERIFY(request.isSecure()); - QVERIFY(!request.isValid()); - QCOMPARE(request.extensions().length(), 0); - QCOMPARE(request.protocols().length(), 0); - QCOMPARE(request.headers().size(), 0); - QCOMPARE(request.key().length(), 0); - QCOMPARE(request.origin().length(), 0); - QCOMPARE(request.host().length(), 0); - QVERIFY(request.requestUrl().isEmpty()); - QCOMPARE(request.resourceName().length(), 0); - QCOMPARE(request.versions().length(), 0); - } - { - QWebSocketHandshakeRequest request(80, true); - request.clear(); - QCOMPARE(request.port(), 80); - QVERIFY(request.isSecure()); - QVERIFY(!request.isValid()); - QCOMPARE(request.extensions().length(), 0); - QCOMPARE(request.protocols().length(), 0); - QCOMPARE(request.headers().size(), 0); - QCOMPARE(request.key().length(), 0); - QCOMPARE(request.origin().length(), 0); - QCOMPARE(request.host().length(), 0); - QVERIFY(request.requestUrl().isEmpty()); - QCOMPARE(request.resourceName().length(), 0); - QCOMPARE(request.versions().length(), 0); - } -} - -void tst_HandshakeRequest::tst_invalidStream_data() -{ - QTest::addColumn("dataStream"); - - QTest::newRow("garbage on 2 lines") << QStringLiteral("foofoofoo\r\nfoofoo\r\n\r\n"); - QTest::newRow("garbage on 1 line") << QStringLiteral("foofoofoofoofoo"); - QTest::newRow("Correctly formatted but invalid fields") - << QStringLiteral("VERB RESOURCE PROTOCOL"); - - //internally the fields are parsed and indexes are used to convert - //to a http version for instance - //this test checks if there doesn't occur an out-of-bounds exception - QTest::newRow("Correctly formatted but invalid short fields") << QStringLiteral("V R P"); - QTest::newRow("Invalid \\0 character in header") << QStringLiteral("V R\0 P"); - QTest::newRow("Invalid HTTP version in header") << QStringLiteral("V R HTTP/invalid"); - QTest::newRow("Empty header field") << QStringLiteral("GET . HTTP/1.1\r\nHEADER: "); - QTest::newRow("All zeros") << QString::fromUtf8(QByteArray(10, char(0))); - QTest::newRow("Invalid hostname") << QStringLiteral("GET . HTTP/1.1\r\nHost: \xFF\xFF"); - //doing extensive QStringLiteral concatenations here, because - //MSVC 2010 complains when using concatenation literal strings about - //concatenation of wide and narrow strings (error C2308) - QTest::newRow("Complete header - Invalid WebSocket version") - << QStringLiteral("GET . HTTP/1.1\r\nHost: foo\r\nSec-WebSocket-Version: ") + - QStringLiteral("\xFF\xFF\r\n") + - QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") + - QStringLiteral("Upgrade: websocket\r\n") + - QStringLiteral("Connection: Upgrade\r\n\r\n"); - QTest::newRow("Complete header - Invalid verb") - << QStringLiteral("XXX . HTTP/1.1\r\nHost: foo\r\nSec-WebSocket-Version: 13\r\n") + - QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") + - QStringLiteral("Upgrade: websocket\r\n") + - QStringLiteral("Connection: Upgrade\r\n\r\n"); - QTest::newRow("Complete header - Invalid HTTP version") - << QStringLiteral("GET . HTTP/a.1\r\nHost: foo\r\nSec-WebSocket-Version: 13\r\n") + - QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") + - QStringLiteral("Upgrade: websocket\r\n") + - QStringLiteral("Connection: Upgrade\r\n\r\n"); - QTest::newRow("Complete header - Invalid connection") - << QStringLiteral("GET . HTTP/1.1\r\nHost: foo\r\nSec-WebSocket-Version: 13\r\n") + - QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") + - QStringLiteral("Upgrade: websocket\r\n") + - QStringLiteral("Connection: xxxxxxx\r\n\r\n"); - QTest::newRow("Complete header - Invalid upgrade") - << QStringLiteral("GET . HTTP/1.1\r\nHost: foo\r\nSec-WebSocket-Version: 13\r\n") + - QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") + - QStringLiteral("Upgrade: wabsocket\r\n") + - QStringLiteral("Connection: Upgrade\r\n\r\n"); - QTest::newRow("Complete header - Upgrade contains too many values") - << QStringLiteral("GET . HTTP/1.1\r\nHost: foo\r\nSec-WebSocket-Version: 13\r\n") + - QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") + - QStringLiteral("Upgrade: websocket,ftp\r\n") + - QStringLiteral("Connection: Upgrade\r\n\r\n"); -} - -void tst_HandshakeRequest::tst_invalidStream() -{ - QFETCH(QString, dataStream); - - QByteArray data; - QTextStream textStream(&data); - QWebSocketHandshakeRequest request(80, true); - - textStream << dataStream; - textStream.seek(0); - request.readHandshake(textStream); - - QVERIFY(!request.isValid()); - QCOMPARE(request.port(), 80); - QVERIFY(request.isSecure()); - QCOMPARE(request.extensions().length(), 0); - QCOMPARE(request.protocols().length(), 0); - QCOMPARE(request.headers().size(), 0); - QCOMPARE(request.key().length(), 0); - QCOMPARE(request.origin().length(), 0); - QCOMPARE(request.host().length(), 0); - QVERIFY(request.requestUrl().isEmpty()); - QCOMPARE(request.resourceName().length(), 0); - QCOMPARE(request.versions().length(), 0); -} - -/* - * This is a regression test - * Checks for validity when more than one value is present in Connection - */ -void tst_HandshakeRequest::tst_multipleValuesInConnectionHeader() -{ - //doing extensive QStringLiteral concatenations here, because - //MSVC 2010 complains when using concatenation literal strings about - //concatenation of wide and narrow strings (error C2308) - QString header = QStringLiteral("GET /test HTTP/1.1\r\nHost: ") + - QStringLiteral("foo.com\r\nSec-WebSocket-Version: 13\r\n") + - QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") + - QStringLiteral("Upgrade: websocket\r\n") + - QStringLiteral("Connection: Upgrade,keepalive\r\n\r\n"); - QByteArray data; - QTextStream textStream(&data); - QWebSocketHandshakeRequest request(80, false); - - textStream << header; - textStream.seek(0); - request.readHandshake(textStream); - - QVERIFY(request.isValid()); - QCOMPARE(request.port(), 80); - QVERIFY(!request.isSecure()); - QCOMPARE(request.extensions().length(), 0); - QCOMPARE(request.protocols().length(), 0); - QCOMPARE(request.headers().size(), 5); - QCOMPARE(request.key().length(), 9); - QCOMPARE(request.origin().length(), 0); - QCOMPARE(request.requestUrl(), QUrl("ws://foo.com/test")); - QCOMPARE(request.host(), QStringLiteral("foo.com")); - QCOMPARE(request.resourceName().length(), 5); - QCOMPARE(request.versions().length(), 1); - QCOMPARE(request.versions().at(0), QWebSocketProtocol::Version13); -} - -void tst_HandshakeRequest::tst_multipleVersions() -{ - QString header = QStringLiteral("GET /test HTTP/1.1\r\nHost: foo.com\r\n") + - QStringLiteral("Sec-WebSocket-Version: 4, 5, 6, 7, 8, 13\r\n") + - QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") + - QStringLiteral("Upgrade: websocket\r\n") + - QStringLiteral("Connection: Upgrade,keepalive\r\n\r\n"); - QByteArray data; - QTextStream textStream(&data); - QWebSocketHandshakeRequest request(80, false); - - textStream << header; - textStream.seek(0); - request.readHandshake(textStream); - - QVERIFY(request.isValid()); - QCOMPARE(request.port(), 80); - QVERIFY(!request.isSecure()); - QCOMPARE(request.extensions().length(), 0); - QCOMPARE(request.protocols().length(), 0); - QCOMPARE(request.headers().size(), 5); - QVERIFY(request.headers().contains(QStringLiteral("host"))); - QVERIFY(request.headers().contains(QStringLiteral("sec-websocket-version"))); - QVERIFY(request.headers().contains(QStringLiteral("sec-websocket-key"))); - QVERIFY(request.headers().contains(QStringLiteral("upgrade"))); - QVERIFY(request.headers().contains(QStringLiteral("connection"))); - QCOMPARE(request.key(), QStringLiteral("AVDFBDDFF")); - QCOMPARE(request.origin().length(), 0); - QCOMPARE(request.requestUrl(), QUrl("ws://foo.com/test")); - QCOMPARE(request.host(), QStringLiteral("foo.com")); - QCOMPARE(request.resourceName().length(), 5); - QCOMPARE(request.versions().length(), 6); - //should be 13 since the list is ordered in decreasing order - QCOMPARE(request.versions().at(0), QWebSocketProtocol::Version13); -} - -void tst_HandshakeRequest::tst_qtbug_39355() -{ - QString header = QStringLiteral("GET /ABC/DEF/ HTTP/1.1\r\nHost: localhost:1234\r\n") + - QStringLiteral("Sec-WebSocket-Version: 13\r\n") + - QStringLiteral("Sec-WebSocket-Key: 2Wg20829/4ziWlmsUAD8Dg==\r\n") + - QStringLiteral("Upgrade: websocket\r\n") + - QStringLiteral("Connection: Upgrade\r\n\r\n"); - QByteArray data; - QTextStream textStream(&data); - QWebSocketHandshakeRequest request(8080, false); - - textStream << header; - textStream.seek(0); - request.readHandshake(textStream); - - QVERIFY(request.isValid()); - QCOMPARE(request.port(), 1234); - QCOMPARE(request.host(), QStringLiteral("localhost")); -} - -QTEST_MAIN(tst_HandshakeRequest) - -#include "tst_handshakerequest.moc" diff --git a/tests/auto/handshakeresponse/handshakeresponse.pro b/tests/auto/handshakeresponse/handshakeresponse.pro deleted file mode 100644 index 4d7cd50..0000000 --- a/tests/auto/handshakeresponse/handshakeresponse.pro +++ /dev/null @@ -1,14 +0,0 @@ -CONFIG += console -CONFIG += testcase -CONFIG -= app_bundle - -TEMPLATE = app - -TARGET = tst_handshakeresponse - -QT = core testlib websockets websockets-private - -SOURCES += tst_handshakeresponse.cpp - -requires(contains(QT_CONFIG, private_tests)) -DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/handshakeresponse/tst_handshakeresponse.cpp b/tests/auto/handshakeresponse/tst_handshakeresponse.cpp deleted file mode 100644 index b5f103b..0000000 --- a/tests/auto/handshakeresponse/tst_handshakeresponse.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Kurt Pattyn . -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include -#include -#include -#include -#include - -#include "private/qwebsockethandshakerequest_p.h" -#include "private/qwebsockethandshakeresponse_p.h" -#include "private/qwebsocketprotocol_p.h" -#include "QtWebSockets/qwebsocketprotocol.h" - -QT_USE_NAMESPACE - -Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode) -Q_DECLARE_METATYPE(QWebSocketProtocol::OpCode) - -class tst_HandshakeResponse : public QObject -{ - Q_OBJECT - -public: - tst_HandshakeResponse(); - -private Q_SLOTS: - void initTestCase(); - void cleanupTestCase(); - void init(); - void cleanup(); - - void tst_date_response(); -}; - -tst_HandshakeResponse::tst_HandshakeResponse() -{} - -void tst_HandshakeResponse::initTestCase() -{ -} - -void tst_HandshakeResponse::cleanupTestCase() -{} - -void tst_HandshakeResponse::init() -{ - qRegisterMetaType("QWebSocketProtocol::OpCode"); - qRegisterMetaType("QWebSocketProtocol::CloseCode"); -} - -void tst_HandshakeResponse::cleanup() -{ -} - -void tst_HandshakeResponse::tst_date_response() -{ - QWebSocketHandshakeRequest request(80, false); - QString buffer; - QTextStream input(&buffer); - input << QStringLiteral("GET / HTTP/1.1\r\nHost: example.com\r\nSec-WebSocket-Version: 13\r\n") + - QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") + - QStringLiteral("Upgrade: websocket\r\n") + - QStringLiteral("Connection: Upgrade\r\n\r\n"); - request.readHandshake(input); - - QWebSocketHandshakeResponse response(request, "example.com", true, - QList() << QWebSocketProtocol::Version13, - QList(), - QList()); - QString data; - QTextStream output(&data); - output << response; - - QStringList list = data.split("\r\n"); - int index = list.indexOf(QRegExp("Date:.*")); - QVERIFY(index > -1); - QVERIFY(QLocale::c().toDateTime(list[index], "'Date:' ddd, dd MMM yyyy hh:mm:ss 'GMT'").isValid()); -} - -QTEST_MAIN(tst_HandshakeResponse) - -#include "tst_handshakeresponse.moc" diff --git a/tests/auto/qdefaultmaskgenerator/qdefaultmaskgenerator.pro b/tests/auto/qdefaultmaskgenerator/qdefaultmaskgenerator.pro deleted file mode 100644 index 3a951a7..0000000 --- a/tests/auto/qdefaultmaskgenerator/qdefaultmaskgenerator.pro +++ /dev/null @@ -1,14 +0,0 @@ -CONFIG += console -CONFIG += testcase -CONFIG -= app_bundle - -TEMPLATE = app - -TARGET = tst_defaultmaskgenerator - -QT = core testlib websockets websockets-private - -SOURCES += tst_defaultmaskgenerator.cpp - -requires(contains(QT_CONFIG, private_tests)) -DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/qdefaultmaskgenerator/tst_defaultmaskgenerator.cpp b/tests/auto/qdefaultmaskgenerator/tst_defaultmaskgenerator.cpp deleted file mode 100644 index f5fc5c4..0000000 --- a/tests/auto/qdefaultmaskgenerator/tst_defaultmaskgenerator.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Kurt Pattyn . -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include -#include -#include -#include -#include -#include - -#include "private/qdefaultmaskgenerator_p.h" - -QT_USE_NAMESPACE - -class tst_QDefaultMaskGenerator : public QObject -{ - Q_OBJECT - -public: - tst_QDefaultMaskGenerator(); - -private Q_SLOTS: - void initTestCase(); - void cleanupTestCase(); - void init(); - void cleanup(); - - void tst_randomnessWithoutSeed(); - void tst_randomnessWithSeed(); - -private: -}; - - - -tst_QDefaultMaskGenerator::tst_QDefaultMaskGenerator() -{ -} - -void tst_QDefaultMaskGenerator::initTestCase() -{ -} - -void tst_QDefaultMaskGenerator::cleanupTestCase() -{ -} - -void tst_QDefaultMaskGenerator::init() -{ -} - -void tst_QDefaultMaskGenerator::cleanup() -{ -} - -void tst_QDefaultMaskGenerator::tst_randomnessWithoutSeed() -{ - //generate two series of data, and see if they differ - { - QDefaultMaskGenerator generator; - - QVector series1, series2; - for (int i = 0; i < 1000; ++i) - series1 << generator.nextMask(); - for (int i = 0; i < 1000; ++i) - series2 << generator.nextMask(); - - QVERIFY(series1 != series2); - } -} - -void tst_QDefaultMaskGenerator::tst_randomnessWithSeed() -{ - //generate two series of data, and see if they differ - //the generator is seeded - { - QDefaultMaskGenerator generator; - generator.seed(); - - QVector series1, series2; - for (int i = 0; i < 1000; ++i) - series1 << generator.nextMask(); - for (int i = 0; i < 1000; ++i) - series2 << generator.nextMask(); - - QVERIFY(series1 != series2); - } - //generates two series of data with 2 distinct generators - //both generators are seeded - { - QDefaultMaskGenerator generator1, generator2; - generator1.seed(); - generator2.seed(); - - QVector series1, series2; - for (int i = 0; i < 1000; ++i) { - series1 << generator1.nextMask(); - series2 << generator2.nextMask(); - } - - QVERIFY(series1 != series2); - } - //generates two series of data with 2 distinct generators - //only one of the two is seeded - { - QDefaultMaskGenerator generator1, generator2; - generator1.seed(); - - QVector series1, series2; - for (int i = 0; i < 1000; ++i) { - series1 << generator1.nextMask(); - series2 << generator2.nextMask(); - } - - QVERIFY(series1 != series2); - } -} - -QTEST_MAIN(tst_QDefaultMaskGenerator) - -#include "tst_defaultmaskgenerator.moc" diff --git a/tests/auto/qwebsocket/qwebsocket.pro b/tests/auto/qwebsocket/qwebsocket.pro deleted file mode 100644 index 0155d08..0000000 --- a/tests/auto/qwebsocket/qwebsocket.pro +++ /dev/null @@ -1,13 +0,0 @@ -CONFIG += console -CONFIG += testcase -CONFIG -= app_bundle - -QT = core testlib websockets - -TARGET = tst_qwebsocket - -TEMPLATE = app - -SOURCES += tst_qwebsocket.cpp - -DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/qwebsocket/tst_qwebsocket.cpp b/tests/auto/qwebsocket/tst_qwebsocket.cpp deleted file mode 100644 index aca25d0..0000000 --- a/tests/auto/qwebsocket/tst_qwebsocket.cpp +++ /dev/null @@ -1,605 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Kurt Pattyn . -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include -#include -#include -#include -#include - -QT_USE_NAMESPACE - -Q_DECLARE_METATYPE(QWebSocketProtocol::Version) - -class EchoServer : public QObject -{ - Q_OBJECT -public: - explicit EchoServer(QObject *parent = Q_NULLPTR); - ~EchoServer(); - - QHostAddress hostAddress() const { return m_pWebSocketServer->serverAddress(); } - quint16 port() const { return m_pWebSocketServer->serverPort(); } - -Q_SIGNALS: - void newConnection(QUrl requestUrl); - -private Q_SLOTS: - void onNewConnection(); - void processTextMessage(QString message); - void processBinaryMessage(QByteArray message); - void socketDisconnected(); - -private: - QWebSocketServer *m_pWebSocketServer; - QList m_clients; -}; - -EchoServer::EchoServer(QObject *parent) : - QObject(parent), - m_pWebSocketServer(new QWebSocketServer(QStringLiteral("Echo Server"), - QWebSocketServer::NonSecureMode, this)), - m_clients() -{ - if (m_pWebSocketServer->listen(QHostAddress(QStringLiteral("127.0.0.1")))) { - connect(m_pWebSocketServer, SIGNAL(newConnection()), - this, SLOT(onNewConnection())); - } -} - -EchoServer::~EchoServer() -{ - m_pWebSocketServer->close(); - qDeleteAll(m_clients.begin(), m_clients.end()); -} - -void EchoServer::onNewConnection() -{ - QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection(); - - Q_EMIT newConnection(pSocket->requestUrl()); - - connect(pSocket, SIGNAL(textMessageReceived(QString)), this, SLOT(processTextMessage(QString))); - connect(pSocket, SIGNAL(binaryMessageReceived(QByteArray)), this, SLOT(processBinaryMessage(QByteArray))); - connect(pSocket, SIGNAL(disconnected()), this, SLOT(socketDisconnected())); - - m_clients << pSocket; -} - -void EchoServer::processTextMessage(QString message) -{ - QWebSocket *pClient = qobject_cast(sender()); - if (pClient) { - pClient->sendTextMessage(message); - } -} - -void EchoServer::processBinaryMessage(QByteArray message) -{ - QWebSocket *pClient = qobject_cast(sender()); - if (pClient) { - pClient->sendBinaryMessage(message); - } -} - -void EchoServer::socketDisconnected() -{ - QWebSocket *pClient = qobject_cast(sender()); - if (pClient) { - m_clients.removeAll(pClient); - pClient->deleteLater(); - } -} - -class tst_QWebSocket : public QObject -{ - Q_OBJECT - -public: - tst_QWebSocket(); - -private Q_SLOTS: - void init(); - void initTestCase(); - void cleanupTestCase(); - void tst_initialisation_data(); - void tst_initialisation(); - void tst_settersAndGetters(); - void tst_invalidOpen_data(); - void tst_invalidOpen(); - void tst_invalidOrigin(); - void tst_sendTextMessage(); - void tst_sendBinaryMessage(); - void tst_errorString(); -#ifndef QT_NO_NETWORKPROXY - void tst_setProxy(); -#endif -}; - -tst_QWebSocket::tst_QWebSocket() -{ -} - -void tst_QWebSocket::init() -{ - qRegisterMetaType("QWebSocketProtocol::Version"); -} - -void tst_QWebSocket::initTestCase() -{ -} - -void tst_QWebSocket::cleanupTestCase() -{ -} - -void tst_QWebSocket::tst_initialisation_data() -{ - QTest::addColumn("origin"); - QTest::addColumn("expectedOrigin"); - QTest::addColumn("version"); - QTest::addColumn("expectedVersion"); - - QTest::newRow("Default origin and version") - << QString() << QString() - << QWebSocketProtocol::VersionUnknown << QWebSocketProtocol::VersionLatest; - QTest::newRow("Specific origin and default version") - << QStringLiteral("qt-project.org") << QStringLiteral("qt-project.org") - << QWebSocketProtocol::VersionUnknown << QWebSocketProtocol::VersionLatest; - QTest::newRow("Specific origin and specific version") - << QStringLiteral("qt-project.org") << QStringLiteral("qt-project.org") - << QWebSocketProtocol::Version7 << QWebSocketProtocol::Version7; -} - -void tst_QWebSocket::tst_initialisation() -{ - QFETCH(QString, origin); - QFETCH(QString, expectedOrigin); - QFETCH(QWebSocketProtocol::Version, version); - QFETCH(QWebSocketProtocol::Version, expectedVersion); - - QScopedPointer socket; - - if (origin.isEmpty() && (version == QWebSocketProtocol::VersionUnknown)) - socket.reset(new QWebSocket); - else if (!origin.isEmpty() && (version == QWebSocketProtocol::VersionUnknown)) - socket.reset(new QWebSocket(origin)); - else - socket.reset(new QWebSocket(origin, version)); - - QCOMPARE(socket->origin(), expectedOrigin); - QCOMPARE(socket->version(), expectedVersion); - QCOMPARE(socket->error(), QAbstractSocket::UnknownSocketError); - QVERIFY(socket->errorString().isEmpty()); - QVERIFY(!socket->isValid()); - QVERIFY(socket->localAddress().isNull()); - QCOMPARE(socket->localPort(), quint16(0)); - QCOMPARE(socket->pauseMode(), QAbstractSocket::PauseNever); - QVERIFY(socket->peerAddress().isNull()); - QCOMPARE(socket->peerPort(), quint16(0)); - QVERIFY(socket->peerName().isEmpty()); - QCOMPARE(socket->state(), QAbstractSocket::UnconnectedState); - QCOMPARE(socket->readBufferSize(), 0); - QVERIFY(socket->resourceName().isEmpty()); - QVERIFY(!socket->requestUrl().isValid()); - QCOMPARE(socket->closeCode(), QWebSocketProtocol::CloseCodeNormal); - QVERIFY(socket->closeReason().isEmpty()); - QVERIFY(socket->flush()); - QCOMPARE(socket->sendTextMessage(QStringLiteral("A text message")), 0); - QCOMPARE(socket->sendBinaryMessage(QByteArrayLiteral("A binary message")), 0); -} - -void tst_QWebSocket::tst_settersAndGetters() -{ - QWebSocket socket; - - socket.setPauseMode(QAbstractSocket::PauseNever); - QCOMPARE(socket.pauseMode(), QAbstractSocket::PauseNever); - socket.setPauseMode(QAbstractSocket::PauseOnSslErrors); - QCOMPARE(socket.pauseMode(), QAbstractSocket::PauseOnSslErrors); - - socket.setReadBufferSize(0); - QCOMPARE(socket.readBufferSize(), 0); - socket.setReadBufferSize(128); - QCOMPARE(socket.readBufferSize(), 128); - socket.setReadBufferSize(-1); - QCOMPARE(socket.readBufferSize(), -1); -} - -void tst_QWebSocket::tst_invalidOpen_data() -{ - QTest::addColumn("url"); - QTest::addColumn("expectedUrl"); - QTest::addColumn("expectedPeerName"); - QTest::addColumn("expectedResourceName"); - QTest::addColumn("stateAfterOpenCall"); - QTest::addColumn("disconnectedCount"); - QTest::addColumn("stateChangedCount"); - - QTest::newRow("Illegal local address") - << QStringLiteral("ws://127.0.0.1:1/") << QStringLiteral("ws://127.0.0.1:1/") - << QStringLiteral("127.0.0.1") - << QStringLiteral("/") << QAbstractSocket::ConnectingState - << 1 - << 2; //going from connecting to disconnected - QTest::newRow("URL containing new line in the hostname") - << QStringLiteral("ws://myhacky\r\nserver/") << QString() - << QString() - << QString() << QAbstractSocket::UnconnectedState - << 0 << 0; - QTest::newRow("URL containing new line in the resource name") - << QStringLiteral("ws://127.0.0.1:1/tricky\r\npath") << QString() - << QString() - << QString() - << QAbstractSocket::UnconnectedState - << 0 << 0; -} - -void tst_QWebSocket::tst_invalidOpen() -{ - QFETCH(QString, url); - QFETCH(QString, expectedUrl); - QFETCH(QString, expectedPeerName); - QFETCH(QString, expectedResourceName); - QFETCH(QAbstractSocket::SocketState, stateAfterOpenCall); - QFETCH(int, disconnectedCount); - QFETCH(int, stateChangedCount); - QWebSocket socket; - QSignalSpy errorSpy(&socket, SIGNAL(error(QAbstractSocket::SocketError))); - QSignalSpy aboutToCloseSpy(&socket, SIGNAL(aboutToClose())); - QSignalSpy connectedSpy(&socket, SIGNAL(connected())); - QSignalSpy disconnectedSpy(&socket, SIGNAL(disconnected())); - QSignalSpy stateChangedSpy(&socket, SIGNAL(stateChanged(QAbstractSocket::SocketState))); - QSignalSpy readChannelFinishedSpy(&socket, SIGNAL(readChannelFinished())); - QSignalSpy textFrameReceivedSpy(&socket, SIGNAL(textFrameReceived(QString,bool))); - QSignalSpy binaryFrameReceivedSpy(&socket, SIGNAL(binaryFrameReceived(QByteArray,bool))); - QSignalSpy textMessageReceivedSpy(&socket, SIGNAL(textMessageReceived(QString))); - QSignalSpy binaryMessageReceivedSpy(&socket, SIGNAL(binaryMessageReceived(QByteArray))); - QSignalSpy pongSpy(&socket, SIGNAL(pong(quint64,QByteArray))); - QSignalSpy bytesWrittenSpy(&socket, SIGNAL(bytesWritten(qint64))); - - socket.open(QUrl(url)); - - QVERIFY(socket.origin().isEmpty()); - QCOMPARE(socket.version(), QWebSocketProtocol::VersionLatest); - //at this point the socket is in a connecting state - //so, there should no error at this point - QCOMPARE(socket.error(), QAbstractSocket::UnknownSocketError); - QVERIFY(!socket.errorString().isEmpty()); - QVERIFY(!socket.isValid()); - QVERIFY(socket.localAddress().isNull()); - QCOMPARE(socket.localPort(), quint16(0)); - QCOMPARE(socket.pauseMode(), QAbstractSocket::PauseNever); - QVERIFY(socket.peerAddress().isNull()); - QCOMPARE(socket.peerPort(), quint16(0)); - QCOMPARE(socket.peerName(), expectedPeerName); - QCOMPARE(socket.state(), stateAfterOpenCall); - QCOMPARE(socket.readBufferSize(), 0); - QCOMPARE(socket.resourceName(), expectedResourceName); - QCOMPARE(socket.requestUrl().toString(), expectedUrl); - QCOMPARE(socket.closeCode(), QWebSocketProtocol::CloseCodeNormal); - QVERIFY(socket.closeReason().isEmpty()); - QCOMPARE(socket.sendTextMessage(QStringLiteral("A text message")), 0); - QCOMPARE(socket.sendBinaryMessage(QByteArrayLiteral("A text message")), 0); - - if (errorSpy.count() == 0) - QVERIFY(errorSpy.wait()); - QCOMPARE(errorSpy.count(), 1); - QList arguments = errorSpy.takeFirst(); - QAbstractSocket::SocketError socketError = - qvariant_cast(arguments.at(0)); - QCOMPARE(socketError, QAbstractSocket::ConnectionRefusedError); - QCOMPARE(aboutToCloseSpy.count(), 0); - QCOMPARE(connectedSpy.count(), 0); - QCOMPARE(disconnectedSpy.count(), disconnectedCount); - QCOMPARE(stateChangedSpy.count(), stateChangedCount); - if (stateChangedCount == 2) { - arguments = stateChangedSpy.takeFirst(); - QAbstractSocket::SocketState socketState = - qvariant_cast(arguments.at(0)); - arguments = stateChangedSpy.takeFirst(); - socketState = qvariant_cast(arguments.at(0)); - QCOMPARE(socketState, QAbstractSocket::UnconnectedState); - } - QCOMPARE(readChannelFinishedSpy.count(), 0); - QCOMPARE(textFrameReceivedSpy.count(), 0); - QCOMPARE(binaryFrameReceivedSpy.count(), 0); - QCOMPARE(textMessageReceivedSpy.count(), 0); - QCOMPARE(binaryMessageReceivedSpy.count(), 0); - QCOMPARE(pongSpy.count(), 0); - QCOMPARE(bytesWrittenSpy.count(), 0); -} - -void tst_QWebSocket::tst_invalidOrigin() -{ - QWebSocket socket(QStringLiteral("My server\r\nin the wild.")); - - QSignalSpy errorSpy(&socket, SIGNAL(error(QAbstractSocket::SocketError))); - QSignalSpy aboutToCloseSpy(&socket, SIGNAL(aboutToClose())); - QSignalSpy connectedSpy(&socket, SIGNAL(connected())); - QSignalSpy disconnectedSpy(&socket, SIGNAL(disconnected())); - QSignalSpy stateChangedSpy(&socket, SIGNAL(stateChanged(QAbstractSocket::SocketState))); - QSignalSpy readChannelFinishedSpy(&socket, SIGNAL(readChannelFinished())); - QSignalSpy textFrameReceivedSpy(&socket, SIGNAL(textFrameReceived(QString,bool))); - QSignalSpy binaryFrameReceivedSpy(&socket, SIGNAL(binaryFrameReceived(QByteArray,bool))); - QSignalSpy textMessageReceivedSpy(&socket, SIGNAL(textMessageReceived(QString))); - QSignalSpy binaryMessageReceivedSpy(&socket, SIGNAL(binaryMessageReceived(QByteArray))); - QSignalSpy pongSpy(&socket, SIGNAL(pong(quint64,QByteArray))); - QSignalSpy bytesWrittenSpy(&socket, SIGNAL(bytesWritten(qint64))); - - socket.open(QUrl(QStringLiteral("ws://127.0.0.1:1/"))); - - //at this point the socket is in a connecting state - //so, there should no error at this point - QCOMPARE(socket.error(), QAbstractSocket::UnknownSocketError); - QVERIFY(!socket.errorString().isEmpty()); - QVERIFY(!socket.isValid()); - QVERIFY(socket.localAddress().isNull()); - QCOMPARE(socket.localPort(), quint16(0)); - QCOMPARE(socket.pauseMode(), QAbstractSocket::PauseNever); - QVERIFY(socket.peerAddress().isNull()); - QCOMPARE(socket.peerPort(), quint16(0)); - QCOMPARE(socket.peerName(), QStringLiteral("127.0.0.1")); - QCOMPARE(socket.state(), QAbstractSocket::ConnectingState); - QCOMPARE(socket.readBufferSize(), 0); - QCOMPARE(socket.resourceName(), QStringLiteral("/")); - QCOMPARE(socket.requestUrl(), QUrl(QStringLiteral("ws://127.0.0.1:1/"))); - QCOMPARE(socket.closeCode(), QWebSocketProtocol::CloseCodeNormal); - - QVERIFY(errorSpy.wait()); - - QCOMPARE(errorSpy.count(), 1); - QList arguments = errorSpy.takeFirst(); - QAbstractSocket::SocketError socketError = - qvariant_cast(arguments.at(0)); - QCOMPARE(socketError, QAbstractSocket::ConnectionRefusedError); - QCOMPARE(aboutToCloseSpy.count(), 0); - QCOMPARE(connectedSpy.count(), 0); - QCOMPARE(disconnectedSpy.count(), 1); - QCOMPARE(stateChangedSpy.count(), 2); //connectingstate, unconnectedstate - arguments = stateChangedSpy.takeFirst(); - QAbstractSocket::SocketState socketState = - qvariant_cast(arguments.at(0)); - arguments = stateChangedSpy.takeFirst(); - socketState = qvariant_cast(arguments.at(0)); - QCOMPARE(socketState, QAbstractSocket::UnconnectedState); - QCOMPARE(readChannelFinishedSpy.count(), 0); - QCOMPARE(textFrameReceivedSpy.count(), 0); - QCOMPARE(binaryFrameReceivedSpy.count(), 0); - QCOMPARE(textMessageReceivedSpy.count(), 0); - QCOMPARE(binaryMessageReceivedSpy.count(), 0); - QCOMPARE(pongSpy.count(), 0); - QCOMPARE(bytesWrittenSpy.count(), 0); -} - -void tst_QWebSocket::tst_sendTextMessage() -{ - EchoServer echoServer; - - QWebSocket socket; - - //should return 0 because socket is not open yet - QCOMPARE(socket.sendTextMessage(QStringLiteral("1234")), 0); - - QSignalSpy socketConnectedSpy(&socket, SIGNAL(connected())); - QSignalSpy serverConnectedSpy(&echoServer, SIGNAL(newConnection(QUrl))); - QSignalSpy textMessageReceived(&socket, SIGNAL(textMessageReceived(QString))); - QSignalSpy textFrameReceived(&socket, SIGNAL(textFrameReceived(QString,bool))); - QSignalSpy binaryMessageReceived(&socket, SIGNAL(binaryMessageReceived(QByteArray))); - QSignalSpy binaryFrameReceived(&socket, SIGNAL(binaryFrameReceived(QByteArray,bool))); - QSignalSpy socketError(&socket, SIGNAL(error(QAbstractSocket::SocketError))); - - QUrl url = QUrl(QStringLiteral("ws://") + echoServer.hostAddress().toString() + - QStringLiteral(":") + QString::number(echoServer.port())); - url.setPath("/segment/with spaces"); - url.addQueryItem("queryitem", "with encoded characters"); - - socket.open(url); - - if (socketConnectedSpy.count() == 0) - QVERIFY(socketConnectedSpy.wait(500)); - QCOMPARE(socketError.count(), 0); - QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); - QCOMPARE(serverConnectedSpy.count(), 1); - QList arguments = serverConnectedSpy.takeFirst(); - QUrl urlConnected = arguments.at(0).toUrl(); - QCOMPARE(urlConnected, url); - - socket.sendTextMessage(QStringLiteral("Hello world!")); - - QVERIFY(textMessageReceived.wait(500)); - QCOMPARE(textMessageReceived.count(), 1); - QCOMPARE(binaryMessageReceived.count(), 0); - QCOMPARE(binaryFrameReceived.count(), 0); - arguments = textMessageReceived.takeFirst(); - QString messageReceived = arguments.at(0).toString(); - QCOMPARE(messageReceived, QStringLiteral("Hello world!")); - - QCOMPARE(textFrameReceived.count(), 1); - arguments = textFrameReceived.takeFirst(); - QString frameReceived = arguments.at(0).toString(); - bool isLastFrame = arguments.at(1).toBool(); - QCOMPARE(frameReceived, QStringLiteral("Hello world!")); - QVERIFY(isLastFrame); - - socket.close(); - - //QTBUG-36762: QWebSocket emits multiplied signals when socket was reopened - socketConnectedSpy.clear(); - textMessageReceived.clear(); - textFrameReceived.clear(); - - socket.open(QUrl(QStringLiteral("ws://") + echoServer.hostAddress().toString() + - QStringLiteral(":") + QString::number(echoServer.port()))); - - if (socketConnectedSpy.count() == 0) - QVERIFY(socketConnectedSpy.wait(500)); - QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); - - socket.sendTextMessage(QStringLiteral("Hello world!")); - - QVERIFY(textMessageReceived.wait(500)); - QCOMPARE(textMessageReceived.count(), 1); - QCOMPARE(binaryMessageReceived.count(), 0); - QCOMPARE(binaryFrameReceived.count(), 0); - arguments = textMessageReceived.takeFirst(); - messageReceived = arguments.at(0).toString(); - QCOMPARE(messageReceived, QStringLiteral("Hello world!")); - - QCOMPARE(textFrameReceived.count(), 1); - arguments = textFrameReceived.takeFirst(); - frameReceived = arguments.at(0).toString(); - isLastFrame = arguments.at(1).toBool(); - QCOMPARE(frameReceived, QStringLiteral("Hello world!")); - QVERIFY(isLastFrame); - - QString reason = QStringLiteral("going away"); - socket.close(QWebSocketProtocol::CloseCodeGoingAway, reason); - QCOMPARE(socket.closeCode(), QWebSocketProtocol::CloseCodeGoingAway); - QCOMPARE(socket.closeReason(), reason); -} - -void tst_QWebSocket::tst_sendBinaryMessage() -{ - EchoServer echoServer; - - QWebSocket socket; - - //should return 0 because socket is not open yet - QCOMPARE(socket.sendBinaryMessage(QByteArrayLiteral("1234")), 0); - - QSignalSpy socketConnectedSpy(&socket, SIGNAL(connected())); - QSignalSpy textMessageReceived(&socket, SIGNAL(textMessageReceived(QString))); - QSignalSpy textFrameReceived(&socket, SIGNAL(textFrameReceived(QString,bool))); - QSignalSpy binaryMessageReceived(&socket, SIGNAL(binaryMessageReceived(QByteArray))); - QSignalSpy binaryFrameReceived(&socket, SIGNAL(binaryFrameReceived(QByteArray,bool))); - - socket.open(QUrl(QStringLiteral("ws://") + echoServer.hostAddress().toString() + - QStringLiteral(":") + QString::number(echoServer.port()))); - - if (socketConnectedSpy.count() == 0) - QVERIFY(socketConnectedSpy.wait(500)); - QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); - - socket.sendBinaryMessage(QByteArrayLiteral("Hello world!")); - - QVERIFY(binaryMessageReceived.wait(500)); - QCOMPARE(textMessageReceived.count(), 0); - QCOMPARE(textFrameReceived.count(), 0); - QCOMPARE(binaryMessageReceived.count(), 1); - QList arguments = binaryMessageReceived.takeFirst(); - QByteArray messageReceived = arguments.at(0).toByteArray(); - QCOMPARE(messageReceived, QByteArrayLiteral("Hello world!")); - - QCOMPARE(binaryFrameReceived.count(), 1); - arguments = binaryFrameReceived.takeFirst(); - QByteArray frameReceived = arguments.at(0).toByteArray(); - bool isLastFrame = arguments.at(1).toBool(); - QCOMPARE(frameReceived, QByteArrayLiteral("Hello world!")); - QVERIFY(isLastFrame); - - socket.close(); - - //QTBUG-36762: QWebSocket emits multiple signals when socket is reopened - socketConnectedSpy.clear(); - binaryMessageReceived.clear(); - binaryFrameReceived.clear(); - - socket.open(QUrl(QStringLiteral("ws://") + echoServer.hostAddress().toString() + - QStringLiteral(":") + QString::number(echoServer.port()))); - - if (socketConnectedSpy.count() == 0) - QVERIFY(socketConnectedSpy.wait(500)); - QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); - - socket.sendBinaryMessage(QByteArrayLiteral("Hello world!")); - - QVERIFY(binaryMessageReceived.wait(500)); - QCOMPARE(textMessageReceived.count(), 0); - QCOMPARE(textFrameReceived.count(), 0); - QCOMPARE(binaryMessageReceived.count(), 1); - arguments = binaryMessageReceived.takeFirst(); - messageReceived = arguments.at(0).toByteArray(); - QCOMPARE(messageReceived, QByteArrayLiteral("Hello world!")); - - QCOMPARE(binaryFrameReceived.count(), 1); - arguments = binaryFrameReceived.takeFirst(); - frameReceived = arguments.at(0).toByteArray(); - isLastFrame = arguments.at(1).toBool(); - QCOMPARE(frameReceived, QByteArrayLiteral("Hello world!")); - QVERIFY(isLastFrame); -} - -void tst_QWebSocket::tst_errorString() -{ - //Check for QTBUG-37228: QWebSocket returns "Unknown Error" for known errors - QWebSocket socket; - - //check that the default error string is empty - QVERIFY(socket.errorString().isEmpty()); - - QSignalSpy errorSpy(&socket, SIGNAL(error(QAbstractSocket::SocketError))); - - socket.open(QUrl(QStringLiteral("ws://someserver.on.mars:9999"))); - - if (errorSpy.count() == 0) - errorSpy.wait(500); - QCOMPARE(errorSpy.count(), 1); - QList arguments = errorSpy.takeFirst(); - QAbstractSocket::SocketError socketError = - qvariant_cast(arguments.at(0)); - QCOMPARE(socketError, QAbstractSocket::HostNotFoundError); - QCOMPARE(socket.errorString(), QStringLiteral("Host not found")); -} - -#ifndef QT_NO_NETWORKPROXY -void tst_QWebSocket::tst_setProxy() -{ - // check if property assignment works as expected. - QWebSocket socket; - QCOMPARE(socket.proxy(), QNetworkProxy(QNetworkProxy::DefaultProxy)); - - QNetworkProxy proxy; - proxy.setPort(123); - socket.setProxy(proxy); - QCOMPARE(socket.proxy(), proxy); - - proxy.setPort(321); - QCOMPARE(socket.proxy().port(), quint16(123)); - socket.setProxy(proxy); - QCOMPARE(socket.proxy(), proxy); -} -#endif // QT_NO_NETWORKPROXY - -QTEST_MAIN(tst_QWebSocket) - -#include "tst_qwebsocket.moc" diff --git a/tests/auto/qwebsocketcorsauthenticator/qwebsocketcorsauthenticator.pro b/tests/auto/qwebsocketcorsauthenticator/qwebsocketcorsauthenticator.pro deleted file mode 100644 index aa485fc..0000000 --- a/tests/auto/qwebsocketcorsauthenticator/qwebsocketcorsauthenticator.pro +++ /dev/null @@ -1,13 +0,0 @@ -CONFIG += console -CONFIG += testcase -CONFIG -= app_bundle - -TEMPLATE = app - -TARGET = tst_qwebsocketcorsauthenticator - -QT = core testlib websockets - -SOURCES += tst_qwebsocketcorsauthenticator.cpp - -DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/qwebsocketcorsauthenticator/tst_qwebsocketcorsauthenticator.cpp b/tests/auto/qwebsocketcorsauthenticator/tst_qwebsocketcorsauthenticator.cpp deleted file mode 100644 index 225adc8..0000000 --- a/tests/auto/qwebsocketcorsauthenticator/tst_qwebsocketcorsauthenticator.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Kurt Pattyn . -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include -#include -#include -#include -#include - -#include "QtWebSockets/qwebsocketcorsauthenticator.h" - -QT_USE_NAMESPACE - -class tst_QWebSocketCorsAuthenticator : public QObject -{ - Q_OBJECT - -public: - tst_QWebSocketCorsAuthenticator(); - -private Q_SLOTS: - void initTestCase(); - void cleanupTestCase(); - void init(); - void cleanup(); - - void tst_initialization(); -}; - -tst_QWebSocketCorsAuthenticator::tst_QWebSocketCorsAuthenticator() -{} - -void tst_QWebSocketCorsAuthenticator::initTestCase() -{ -} - -void tst_QWebSocketCorsAuthenticator::cleanupTestCase() -{} - -void tst_QWebSocketCorsAuthenticator::init() -{ -} - -void tst_QWebSocketCorsAuthenticator::cleanup() -{ -} - -void tst_QWebSocketCorsAuthenticator::tst_initialization() -{ - { - QWebSocketCorsAuthenticator authenticator((QString())); - - QCOMPARE(authenticator.allowed(), true); - QCOMPARE(authenticator.origin(), QString()); - } - { - QWebSocketCorsAuthenticator authenticator(QStringLiteral("com.somesite")); - - QCOMPARE(authenticator.allowed(), true); - QCOMPARE(authenticator.origin(), QStringLiteral("com.somesite")); - - QWebSocketCorsAuthenticator other(authenticator); - QCOMPARE(other.origin(), authenticator.origin()); - QCOMPARE(other.allowed(), authenticator.allowed()); - - authenticator.setAllowed(false); - QVERIFY(!authenticator.allowed()); - QCOMPARE(other.allowed(), true); //make sure other is a real copy - - authenticator.setAllowed(true); - QVERIFY(authenticator.allowed()); - - authenticator.setAllowed(false); - other = authenticator; - QCOMPARE(other.origin(), authenticator.origin()); - QCOMPARE(other.allowed(), authenticator.allowed()); - } -} - -QTEST_MAIN(tst_QWebSocketCorsAuthenticator) - -#include "tst_qwebsocketcorsauthenticator.moc" - diff --git a/tests/auto/qwebsocketserver/qwebsocketserver.pro b/tests/auto/qwebsocketserver/qwebsocketserver.pro deleted file mode 100644 index 25216d3..0000000 --- a/tests/auto/qwebsocketserver/qwebsocketserver.pro +++ /dev/null @@ -1,13 +0,0 @@ -CONFIG += console -CONFIG += testcase -CONFIG -= app_bundle - -QT = core testlib websockets - -TARGET = tst_qwebsocketserver - -TEMPLATE = app - -SOURCES += tst_qwebsocketserver.cpp - -DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/qwebsocketserver/tst_qwebsocketserver.cpp b/tests/auto/qwebsocketserver/tst_qwebsocketserver.cpp deleted file mode 100644 index c2ba842..0000000 --- a/tests/auto/qwebsocketserver/tst_qwebsocketserver.cpp +++ /dev/null @@ -1,390 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Kurt Pattyn . -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include -#include -#include -#include -#include -#include -#include - -QT_USE_NAMESPACE - -Q_DECLARE_METATYPE(QWebSocketProtocol::Version) -Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode) -Q_DECLARE_METATYPE(QWebSocketServer::SslMode) -Q_DECLARE_METATYPE(QWebSocketCorsAuthenticator *) -#ifndef QT_NO_SSL -Q_DECLARE_METATYPE(QSslError) -#endif - -class tst_QWebSocketServer : public QObject -{ - Q_OBJECT - -public: - tst_QWebSocketServer(); - -private Q_SLOTS: - void init(); - void initTestCase(); - void cleanupTestCase(); - void tst_initialisation(); - void tst_settersAndGetters(); - void tst_listening(); - void tst_connectivity(); - void tst_maxPendingConnections(); - void tst_serverDestroyedWhileSocketConnected(); -}; - -tst_QWebSocketServer::tst_QWebSocketServer() -{ -} - -void tst_QWebSocketServer::init() -{ - qRegisterMetaType("QWebSocketProtocol::Version"); - qRegisterMetaType("QWebSocketProtocol::CloseCode"); - qRegisterMetaType("QWebSocketServer::SslMode"); - qRegisterMetaType("QWebSocketCorsAuthenticator *"); -#ifndef QT_NO_SSL - qRegisterMetaType("QSslError"); -#endif -} - -void tst_QWebSocketServer::initTestCase() -{ -} - -void tst_QWebSocketServer::cleanupTestCase() -{ -} - -void tst_QWebSocketServer::tst_initialisation() -{ - { - QWebSocketServer server(QString(), QWebSocketServer::NonSecureMode); - - QVERIFY(server.serverName().isEmpty()); - QCOMPARE(server.secureMode(), QWebSocketServer::NonSecureMode); - QVERIFY(!server.isListening()); - QCOMPARE(server.maxPendingConnections(), 30); - QCOMPARE(server.serverPort(), quint16(0)); - QCOMPARE(server.serverAddress(), QHostAddress()); - QCOMPARE(server.socketDescriptor(), -1); - QVERIFY(!server.hasPendingConnections()); - QVERIFY(!server.nextPendingConnection()); - QCOMPARE(server.error(), QWebSocketProtocol::CloseCodeNormal); - QVERIFY(server.errorString().isEmpty()); - #ifndef QT_NO_NETWORKPROXY - QCOMPARE(server.proxy().type(), QNetworkProxy::DefaultProxy); - #endif - #ifndef QT_NO_SSL - QCOMPARE(server.sslConfiguration(), QSslConfiguration::defaultConfiguration()); - #endif - QCOMPARE(server.supportedVersions().count(), 1); - QCOMPARE(server.supportedVersions().at(0), QWebSocketProtocol::VersionLatest); - QCOMPARE(server.supportedVersions().at(0), QWebSocketProtocol::Version13); - - server.close(); - //closing a server should not affect any of the parameters - //certainly if the server was not opened before - - QVERIFY(server.serverName().isEmpty()); - QCOMPARE(server.secureMode(), QWebSocketServer::NonSecureMode); - QVERIFY(!server.isListening()); - QCOMPARE(server.maxPendingConnections(), 30); - QCOMPARE(server.serverPort(), quint16(0)); - QCOMPARE(server.serverAddress(), QHostAddress()); - QCOMPARE(server.socketDescriptor(), -1); - QVERIFY(!server.hasPendingConnections()); - QVERIFY(!server.nextPendingConnection()); - QCOMPARE(server.error(), QWebSocketProtocol::CloseCodeNormal); - QVERIFY(server.errorString().isEmpty()); - #ifndef QT_NO_NETWORKPROXY - QCOMPARE(server.proxy().type(), QNetworkProxy::DefaultProxy); - #endif - #ifndef QT_NO_SSL - QCOMPARE(server.sslConfiguration(), QSslConfiguration::defaultConfiguration()); - #endif - QCOMPARE(server.supportedVersions().count(), 1); - QCOMPARE(server.supportedVersions().at(0), QWebSocketProtocol::VersionLatest); - QCOMPARE(server.supportedVersions().at(0), QWebSocketProtocol::Version13); - QCOMPARE(server.serverUrl(), QUrl()); - } - - { -#ifndef QT_NO_SSL - QWebSocketServer sslServer(QString(), QWebSocketServer::SecureMode); - QCOMPARE(sslServer.secureMode(), QWebSocketServer::SecureMode); -#endif - } -} - -void tst_QWebSocketServer::tst_settersAndGetters() -{ - QWebSocketServer server(QString(), QWebSocketServer::NonSecureMode); - - server.setMaxPendingConnections(23); - QCOMPARE(server.maxPendingConnections(), 23); - server.setMaxPendingConnections(INT_MIN); - QCOMPARE(server.maxPendingConnections(), INT_MIN); - server.setMaxPendingConnections(INT_MAX); - QCOMPARE(server.maxPendingConnections(), INT_MAX); - - QVERIFY(!server.setSocketDescriptor(-2)); - QCOMPARE(server.socketDescriptor(), -1); - - server.setServerName(QStringLiteral("Qt WebSocketServer")); - QCOMPARE(server.serverName(), QStringLiteral("Qt WebSocketServer")); - -#ifndef QT_NO_NETWORKPROXY - QNetworkProxy proxy(QNetworkProxy::Socks5Proxy); - server.setProxy(proxy); - QCOMPARE(server.proxy(), proxy); -#endif -#ifndef QT_NO_SSL - //cannot set an ssl configuration on a non secure server - QSslConfiguration sslConfiguration = QSslConfiguration::defaultConfiguration(); - sslConfiguration.setPeerVerifyDepth(sslConfiguration.peerVerifyDepth() + 1); - server.setSslConfiguration(sslConfiguration); - QVERIFY(server.sslConfiguration() != sslConfiguration); - QCOMPARE(server.sslConfiguration(), QSslConfiguration::defaultConfiguration()); - - QWebSocketServer sslServer(QString(), QWebSocketServer::SecureMode); - sslServer.setSslConfiguration(sslConfiguration); - QCOMPARE(sslServer.sslConfiguration(), sslConfiguration); - QVERIFY(sslServer.sslConfiguration() != QSslConfiguration::defaultConfiguration()); -#endif -} - -void tst_QWebSocketServer::tst_listening() -{ - //These listening tests are not too extensive, as the implementation of QWebSocketServer - //relies on QTcpServer - - QWebSocketServer server(QString(), QWebSocketServer::NonSecureMode); - - QSignalSpy serverAcceptErrorSpy(&server, SIGNAL(acceptError(QAbstractSocket::SocketError))); - QSignalSpy serverConnectionSpy(&server, SIGNAL(newConnection())); - QSignalSpy serverErrorSpy(&server, - SIGNAL(serverError(QWebSocketProtocol::CloseCode))); - QSignalSpy corsAuthenticationSpy(&server, - SIGNAL(originAuthenticationRequired(QWebSocketCorsAuthenticator*))); - QSignalSpy serverClosedSpy(&server, SIGNAL(closed())); -#ifndef QT_NO_SSL - QSignalSpy peerVerifyErrorSpy(&server, SIGNAL(peerVerifyError(QSslError))); - QSignalSpy sslErrorsSpy(&server, SIGNAL(sslErrors(QList))); -#endif - - QVERIFY(server.listen()); //listen on all network interface, choose an appropriate port - QVERIFY(server.isListening()); - QCOMPARE(serverClosedSpy.count(), 0); - server.close(); - QVERIFY(serverClosedSpy.wait(1000)); - QVERIFY(!server.isListening()); - QCOMPARE(serverErrorSpy.count(), 0); - - QVERIFY(!server.listen(QHostAddress(QStringLiteral("1.2.3.4")), 0)); - QCOMPARE(server.error(), QWebSocketProtocol::CloseCodeAbnormalDisconnection); - QCOMPARE(server.errorString().toLatin1().constData(), "The address is not available"); - QVERIFY(!server.isListening()); - - QCOMPARE(serverAcceptErrorSpy.count(), 0); - QCOMPARE(serverConnectionSpy.count(), 0); - QCOMPARE(corsAuthenticationSpy.count(), 0); -#ifndef QT_NO_SSL - QCOMPARE(peerVerifyErrorSpy.count(), 0); - QCOMPARE(sslErrorsSpy.count(), 0); -#endif - QCOMPARE(serverErrorSpy.count(), 1); - QCOMPARE(serverClosedSpy.count(), 1); -} - -void tst_QWebSocketServer::tst_connectivity() -{ - QWebSocketServer server(QString(), QWebSocketServer::NonSecureMode); - QSignalSpy serverConnectionSpy(&server, SIGNAL(newConnection())); - QSignalSpy serverErrorSpy(&server, - SIGNAL(serverError(QWebSocketProtocol::CloseCode))); - QSignalSpy corsAuthenticationSpy(&server, - SIGNAL(originAuthenticationRequired(QWebSocketCorsAuthenticator*))); - QSignalSpy serverClosedSpy(&server, SIGNAL(closed())); -#ifndef QT_NO_SSL - QSignalSpy peerVerifyErrorSpy(&server, SIGNAL(peerVerifyError(QSslError))); - QSignalSpy sslErrorsSpy(&server, SIGNAL(sslErrors(QList))); -#endif - QWebSocket socket; - QSignalSpy socketConnectedSpy(&socket, SIGNAL(connected())); - - QVERIFY(server.listen()); - QCOMPARE(server.serverAddress(), QHostAddress(QHostAddress::Any)); - QCOMPARE(server.serverUrl(), QUrl(QStringLiteral("ws://") + QHostAddress(QHostAddress::LocalHost).toString() + - QStringLiteral(":").append(QString::number(server.serverPort())))); - - socket.open(server.serverUrl().toString()); - - if (socketConnectedSpy.count() == 0) - QVERIFY(socketConnectedSpy.wait()); - QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); - QCOMPARE(serverConnectionSpy.count(), 1); - QCOMPARE(corsAuthenticationSpy.count(), 1); - - QCOMPARE(serverClosedSpy.count(), 0); - - server.close(); - - QVERIFY(serverClosedSpy.wait()); - QCOMPARE(serverClosedSpy.count(), 1); -#ifndef QT_NO_SSL - QCOMPARE(peerVerifyErrorSpy.count(), 0); - QCOMPARE(sslErrorsSpy.count(), 0); -#endif - QCOMPARE(serverErrorSpy.count(), 0); -} - -void tst_QWebSocketServer::tst_maxPendingConnections() -{ - //tests if maximum connections are respected - //also checks if there are no side-effects like signals that are unexpectedly thrown - QWebSocketServer server(QString(), QWebSocketServer::NonSecureMode); - server.setMaxPendingConnections(2); - QSignalSpy serverConnectionSpy(&server, SIGNAL(newConnection())); - QSignalSpy serverErrorSpy(&server, - SIGNAL(serverError(QWebSocketProtocol::CloseCode))); - QSignalSpy corsAuthenticationSpy(&server, - SIGNAL(originAuthenticationRequired(QWebSocketCorsAuthenticator*))); - QSignalSpy serverClosedSpy(&server, SIGNAL(closed())); -#ifndef QT_NO_SSL - QSignalSpy peerVerifyErrorSpy(&server, SIGNAL(peerVerifyError(QSslError))); - QSignalSpy sslErrorsSpy(&server, SIGNAL(sslErrors(QList))); -#endif - QSignalSpy serverAcceptErrorSpy(&server, SIGNAL(acceptError(QAbstractSocket::SocketError))); - - QWebSocket socket1; - QWebSocket socket2; - QWebSocket socket3; - - QSignalSpy socket1ConnectedSpy(&socket1, SIGNAL(connected())); - QSignalSpy socket2ConnectedSpy(&socket2, SIGNAL(connected())); - QSignalSpy socket3ConnectedSpy(&socket3, SIGNAL(connected())); - - QVERIFY(server.listen()); - - socket1.open(server.serverUrl().toString()); - - if (socket1ConnectedSpy.count() == 0) - QVERIFY(socket1ConnectedSpy.wait()); - QCOMPARE(socket1.state(), QAbstractSocket::ConnectedState); - QCOMPARE(serverConnectionSpy.count(), 1); - QCOMPARE(corsAuthenticationSpy.count(), 1); - socket2.open(server.serverUrl().toString()); - if (socket2ConnectedSpy.count() == 0) - QVERIFY(socket2ConnectedSpy.wait()); - QCOMPARE(socket2.state(), QAbstractSocket::ConnectedState); - QCOMPARE(serverConnectionSpy.count(), 2); - QCOMPARE(corsAuthenticationSpy.count(), 2); - socket3.open(server.serverUrl().toString()); - if (socket3ConnectedSpy.count() == 0) - QVERIFY(!socket3ConnectedSpy.wait(250)); - QCOMPARE(socket3.state(), QAbstractSocket::UnconnectedState); - QCOMPARE(serverConnectionSpy.count(), 2); - QCOMPARE(corsAuthenticationSpy.count(), 2); - - QVERIFY(server.hasPendingConnections()); - QWebSocket *pSocket = server.nextPendingConnection(); - QVERIFY(pSocket); - delete pSocket; - QVERIFY(server.hasPendingConnections()); - pSocket = server.nextPendingConnection(); - QVERIFY(pSocket); - delete pSocket; - QVERIFY(!server.hasPendingConnections()); - QVERIFY(!server.nextPendingConnection()); - -//will resolve in another commit -#ifndef Q_OS_WIN - QCOMPARE(serverErrorSpy.count(), 1); - QCOMPARE(serverErrorSpy.at(0).at(0).value(), - QWebSocketProtocol::CloseCodeAbnormalDisconnection); -#endif - QCOMPARE(serverClosedSpy.count(), 0); - - server.close(); - - QVERIFY(serverClosedSpy.wait()); - QCOMPARE(serverClosedSpy.count(), 1); -#ifndef QT_NO_SSL - QCOMPARE(peerVerifyErrorSpy.count(), 0); - QCOMPARE(sslErrorsSpy.count(), 0); -#endif - QCOMPARE(serverAcceptErrorSpy.count(), 0); -} - -void tst_QWebSocketServer::tst_serverDestroyedWhileSocketConnected() -{ - QWebSocketServer * server = new QWebSocketServer(QString(), QWebSocketServer::NonSecureMode); - QSignalSpy serverConnectionSpy(server, SIGNAL(newConnection())); - QSignalSpy corsAuthenticationSpy(server, - SIGNAL(originAuthenticationRequired(QWebSocketCorsAuthenticator*))); - QSignalSpy serverClosedSpy(server, SIGNAL(closed())); - - QWebSocket socket; - QSignalSpy socketConnectedSpy(&socket, SIGNAL(connected())); - QSignalSpy socketDisconnectedSpy(&socket, SIGNAL(disconnected())); - - QVERIFY(server->listen()); - QCOMPARE(server->serverAddress(), QHostAddress(QHostAddress::Any)); - QCOMPARE(server->serverUrl(), QUrl(QStringLiteral("ws://") + QHostAddress(QHostAddress::LocalHost).toString() + - QStringLiteral(":").append(QString::number(server->serverPort())))); - - socket.open(server->serverUrl().toString()); - - if (socketConnectedSpy.count() == 0) - QVERIFY(socketConnectedSpy.wait()); - QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); - QCOMPARE(serverConnectionSpy.count(), 1); - QCOMPARE(corsAuthenticationSpy.count(), 1); - - QCOMPARE(serverClosedSpy.count(), 0); - - delete server; - - if (socketDisconnectedSpy.count() == 0) - QVERIFY(socketDisconnectedSpy.wait()); - QCOMPARE(socketDisconnectedSpy.count(), 1); -} - -QTEST_MAIN(tst_QWebSocketServer) - -#include "tst_qwebsocketserver.moc" diff --git a/tests/auto/websocketframe/tst_websocketframe.cpp b/tests/auto/websocketframe/tst_websocketframe.cpp deleted file mode 100644 index 5db82d5..0000000 --- a/tests/auto/websocketframe/tst_websocketframe.cpp +++ /dev/null @@ -1,624 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Kurt Pattyn . -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include -#include -#include -#include -#include - -#include "private/qwebsocketframe_p.h" -#include "private/qwebsocketprotocol_p.h" -#include "qwebsocketprotocol.h" - -QT_USE_NAMESPACE - -Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode) -Q_DECLARE_METATYPE(QWebSocketProtocol::OpCode) - -/*! - * \brief class FrameHelper is used to encode a single frame. - * - * \internal - */ -class FrameHelper -{ -public: - FrameHelper(); - - QByteArray wireRepresentation(); - - void setRsv1(int value) { m_rsv1 = value; } - void setRsv2(int value) { m_rsv2 = value; } - void setRsv3(int value) { m_rsv3 = value; } - void setMask(quint32 mask) { m_mask = mask; } - void setOpCode(QWebSocketProtocol::OpCode opCode) { m_opCode = opCode; } - void setPayload(const QByteArray &payload) { m_payload = payload; } - void setFinalFrame(bool isFinal) { m_isFinalFrame = isFinal; } - -private: - int m_rsv1; - int m_rsv2; - int m_rsv3; - quint32 m_mask; - QWebSocketProtocol::OpCode m_opCode; - QByteArray m_payload; - bool m_isFinalFrame; -}; - -FrameHelper::FrameHelper() : - m_rsv1(0), m_rsv2(0), m_rsv3(0), - m_mask(0), m_opCode(QWebSocketProtocol::OpCodeReserved3), - m_payload(), m_isFinalFrame(false) -{} - -QByteArray FrameHelper::wireRepresentation() -{ - quint8 byte = 0x00; - QByteArray wireRep; - quint64 payloadLength = m_payload.length(); - - //FIN, opcode - byte = static_cast((m_opCode & 0x0F) | (m_isFinalFrame ? 0x80 : 0x00)); //FIN, opcode - //RSV1-3 - byte |= static_cast(((m_rsv1 & 0x01) << 6) | ((m_rsv2 & 0x01) << 5) | - ((m_rsv3 & 0x01) << 4)); - wireRep.append(static_cast(byte)); - - byte = 0x00; - if (m_mask != 0) - { - byte |= 0x80; - } - if (payloadLength <= 125) - { - byte |= static_cast(payloadLength); - wireRep.append(static_cast(byte)); - } - else if (payloadLength <= 0xFFFFU) - { - byte |= 126; - wireRep.append(static_cast(byte)); - quint16 swapped = qToBigEndian(static_cast(payloadLength)); - wireRep.append(static_cast(static_cast(&swapped)), 2); - } - else - { - byte |= 127; - wireRep.append(static_cast(byte)); - quint64 swapped = qToBigEndian(payloadLength); - wireRep.append(static_cast(static_cast(&swapped)), 8); - } - //Write mask - if (m_mask != 0) - { - wireRep.append(static_cast(static_cast(&m_mask)), - sizeof(quint32)); - } - QByteArray tmpData = m_payload; - if (m_mask) - { - tmpData.detach(); - QWebSocketProtocol::mask(&tmpData, m_mask); - } - wireRep.append(tmpData); - return wireRep; -} - -class tst_WebSocketFrame : public QObject -{ - Q_OBJECT - -public: - tst_WebSocketFrame(); - -private Q_SLOTS: - void initTestCase(); - void cleanupTestCase(); - void init(); - void cleanup(); - - void tst_initialization(); - void tst_copyConstructorAndAssignment(); - - void tst_goodFrames_data(); - void tst_goodFrames(); - - void tst_invalidFrames_data(); - void tst_invalidFrames(); - - void tst_malformedFrames_data(); - void tst_malformedFrames(); -}; - -tst_WebSocketFrame::tst_WebSocketFrame() -{} - -void tst_WebSocketFrame::initTestCase() -{ -} - -void tst_WebSocketFrame::cleanupTestCase() -{} - -void tst_WebSocketFrame::init() -{ - qRegisterMetaType("QWebSocketProtocol::OpCode"); - qRegisterMetaType("QWebSocketProtocol::CloseCode"); -} - -void tst_WebSocketFrame::cleanup() -{ -} - -void tst_WebSocketFrame::tst_initialization() -{ - QWebSocketFrame frame; - QVERIFY(!frame.isValid()); - QCOMPARE(frame.payload().length(), 0); -} - -void tst_WebSocketFrame::tst_copyConstructorAndAssignment() -{ - FrameHelper frameHelper; - frameHelper.setRsv1(0); - frameHelper.setRsv2(0); - frameHelper.setRsv3(0); - frameHelper.setFinalFrame(true); - frameHelper.setMask(1234u); - frameHelper.setOpCode(QWebSocketProtocol::OpCodeBinary); - frameHelper.setPayload(QByteArrayLiteral("12345")); - - QByteArray payload = frameHelper.wireRepresentation(); - QBuffer buffer(&payload); - buffer.open(QIODevice::ReadOnly); - - QWebSocketFrame frame = QWebSocketFrame::readFrame(&buffer); - buffer.close(); - - { - QWebSocketFrame other(frame); - QCOMPARE(other.closeCode(), frame.closeCode()); - QCOMPARE(other.closeReason(), frame.closeReason()); - QCOMPARE(other.hasMask(), frame.hasMask()); - QCOMPARE(other.isContinuationFrame(), frame.isContinuationFrame()); - QCOMPARE(other.isControlFrame(), frame.isControlFrame()); - QCOMPARE(other.isDataFrame(), frame.isDataFrame()); - QCOMPARE(other.isFinalFrame(), frame.isFinalFrame()); - QCOMPARE(other.isValid(), frame.isValid()); - QCOMPARE(other.mask(), frame.mask()); - QCOMPARE(other.opCode(), frame.opCode()); - QCOMPARE(other.payload(), frame.payload()); - QCOMPARE(other.rsv1(), frame.rsv1()); - QCOMPARE(other.rsv2(), frame.rsv2()); - QCOMPARE(other.rsv3(), frame.rsv3()); - } - { - QWebSocketFrame other; - other = frame; - QCOMPARE(other.closeCode(), frame.closeCode()); - QCOMPARE(other.closeReason(), frame.closeReason()); - QCOMPARE(other.hasMask(), frame.hasMask()); - QCOMPARE(other.isContinuationFrame(), frame.isContinuationFrame()); - QCOMPARE(other.isControlFrame(), frame.isControlFrame()); - QCOMPARE(other.isDataFrame(), frame.isDataFrame()); - QCOMPARE(other.isFinalFrame(), frame.isFinalFrame()); - QCOMPARE(other.isValid(), frame.isValid()); - QCOMPARE(other.mask(), frame.mask()); - QCOMPARE(other.opCode(), frame.opCode()); - QCOMPARE(other.payload(), frame.payload()); - QCOMPARE(other.rsv1(), frame.rsv1()); - QCOMPARE(other.rsv2(), frame.rsv2()); - QCOMPARE(other.rsv3(), frame.rsv3()); - } -} - -void tst_WebSocketFrame::tst_goodFrames_data() -{ - QTest::addColumn("rsv1"); - QTest::addColumn("rsv2"); - QTest::addColumn("rsv3"); - QTest::addColumn("mask"); - QTest::addColumn("opCode"); - QTest::addColumn("isFinal"); - QTest::addColumn("payload"); - QTest::addColumn("isControlFrame"); - QTest::addColumn("isDataFrame"); - QTest::addColumn("isContinuationFrame"); - - QTest::newRow("Non masked final text frame with small payload") - << 0 << 0 << 0 - << 0U << QWebSocketProtocol::OpCodeText - << true << QStringLiteral("Hello world!").toUtf8() - << false << true << false; - QTest::newRow("Non masked final binary frame with small payload") - << 0 << 0 << 0 - << 0U << QWebSocketProtocol::OpCodeBinary - << true << QByteArrayLiteral("\x00\x01\x02\x03\x04") - << false << true << false; - QTest::newRow("Non masked final text frame with no payload") - << 0 << 0 << 0 - << 0U << QWebSocketProtocol::OpCodeText - << true << QByteArray() - << false << true << false; - QTest::newRow("Non masked final binary frame with no payload") - << 0 << 0 << 0 - << 0U << QWebSocketProtocol::OpCodeBinary - << true << QByteArray() - << false << true << false; - - QTest::newRow("Non masked final close frame with small payload") - << 0 << 0 << 0 - << 0U << QWebSocketProtocol::OpCodeClose - << true << QStringLiteral("Hello world!").toUtf8() - << true << false << false; - QTest::newRow("Non masked final close frame with no payload") - << 0 << 0 << 0 - << 0U << QWebSocketProtocol::OpCodeClose - << true << QByteArray() - << true << false << false; - QTest::newRow("Non masked final ping frame with small payload") - << 0 << 0 << 0 - << 0U << QWebSocketProtocol::OpCodePing - << true << QStringLiteral("Hello world!").toUtf8() - << true << false << false; - QTest::newRow("Non masked final pong frame with no payload") - << 0 << 0 << 0 - << 0U << QWebSocketProtocol::OpCodePong - << true << QByteArray() - << true << false << false; - - QTest::newRow("Non masked final continuation frame with small payload") - << 0 << 0 << 0 - << 0U << QWebSocketProtocol::OpCodeContinue - << true << QStringLiteral("Hello world!").toUtf8() - << false << true << true; - QTest::newRow("Non masked non-final continuation frame with small payload") - << 0 << 0 << 0 - << 0U << QWebSocketProtocol::OpCodeContinue - << false << QStringLiteral("Hello world!").toUtf8() - << false << true << true; -} - -void tst_WebSocketFrame::tst_goodFrames() -{ - QFETCH(int, rsv1); - QFETCH(int, rsv2); - QFETCH(int, rsv3); - QFETCH(quint32, mask); - QFETCH(QWebSocketProtocol::OpCode, opCode); - QFETCH(bool, isFinal); - QFETCH(QByteArray, payload); - QFETCH(bool, isControlFrame); - QFETCH(bool, isDataFrame); - QFETCH(bool, isContinuationFrame); - - FrameHelper helper; - helper.setRsv1(rsv1); - helper.setRsv2(rsv2); - helper.setRsv3(rsv3); - helper.setMask(mask); - helper.setOpCode(opCode); - helper.setFinalFrame(isFinal); - helper.setPayload(payload); - - QByteArray wireRepresentation = helper.wireRepresentation(); - QBuffer buffer; - buffer.setData(wireRepresentation); - buffer.open(QIODevice::ReadOnly); - QWebSocketFrame frame = QWebSocketFrame::readFrame(&buffer); - buffer.close(); - QVERIFY(frame.isValid()); - QCOMPARE(frame.rsv1(), rsv1); - QCOMPARE(frame.rsv2(), rsv2); - QCOMPARE(frame.rsv3(), rsv3); - QCOMPARE(frame.hasMask(), (mask != 0)); - QCOMPARE(frame.opCode(), opCode); - QCOMPARE(frame.isFinalFrame(), isFinal); - QCOMPARE(frame.isControlFrame(), isControlFrame); - QCOMPARE(frame.isDataFrame(), isDataFrame); - QCOMPARE(frame.isContinuationFrame(), isContinuationFrame); - QCOMPARE(frame.payload().length(), payload.length()); - QCOMPARE(frame.payload(), payload); -} - -void tst_WebSocketFrame::tst_invalidFrames_data() -{ - QTest::addColumn("rsv1"); - QTest::addColumn("rsv2"); - QTest::addColumn("rsv3"); - QTest::addColumn("mask"); - QTest::addColumn("opCode"); - QTest::addColumn("isFinal"); - QTest::addColumn("payload"); - QTest::addColumn("expectedError"); - - QTest::newRow("RSV1 != 0") - << 1 << 0 << 0 - << 0U << QWebSocketProtocol::OpCodeText - << true << QStringLiteral("Hello world!").toUtf8() - << QWebSocketProtocol::CloseCodeProtocolError; - QTest::newRow("RSV2 != 0") - << 0 << 1 << 0 - << 0U << QWebSocketProtocol::OpCodeText - << true << QStringLiteral("Hello world!").toUtf8() - << QWebSocketProtocol::CloseCodeProtocolError; - QTest::newRow("RSV3 != 0") - << 0 << 0 << 1 - << 0U << QWebSocketProtocol::OpCodeText - << true << QStringLiteral("Hello world!").toUtf8() - << QWebSocketProtocol::CloseCodeProtocolError; - QTest::newRow("RSV1 != 0 and RSV2 != 0") - << 1 << 1 << 0 - << 0U << QWebSocketProtocol::OpCodeText - << true << QStringLiteral("Hello world!").toUtf8() - << QWebSocketProtocol::CloseCodeProtocolError; - QTest::newRow("RSV1 != 0 and RSV3 != 0") - << 1 << 0 << 1 - << 0U << QWebSocketProtocol::OpCodeText - << true << QStringLiteral("Hello world!").toUtf8() - << QWebSocketProtocol::CloseCodeProtocolError; - QTest::newRow("RSV2 != 0 and RSV3 != 0") - << 0 << 1 << 1 - << 0U << QWebSocketProtocol::OpCodeText - << true << QStringLiteral("Hello world!").toUtf8() - << QWebSocketProtocol::CloseCodeProtocolError; - - QTest::newRow("Reserved OpCode 3") - << 0 << 0 << 0 - << 0U << QWebSocketProtocol::OpCodeReserved3 - << true << QStringLiteral("Hello world!").toUtf8() - << QWebSocketProtocol::CloseCodeProtocolError; - QTest::newRow("Reserved OpCode 4") - << 0 << 0 << 0 - << 0U << QWebSocketProtocol::OpCodeReserved4 - << true << QStringLiteral("Hello world!").toUtf8() - << QWebSocketProtocol::CloseCodeProtocolError; - QTest::newRow("Reserved OpCode 5") - << 0 << 0 << 0 - << 0U << QWebSocketProtocol::OpCodeReserved5 - << true << QStringLiteral("Hello world!").toUtf8() - << QWebSocketProtocol::CloseCodeProtocolError; - QTest::newRow("Reserved OpCode 6") - << 0 << 0 << 0 - << 0U << QWebSocketProtocol::OpCodeReserved6 - << true << QStringLiteral("Hello world!").toUtf8() - << QWebSocketProtocol::CloseCodeProtocolError; - QTest::newRow("Reserved OpCode 7") - << 0 << 0 << 0 - << 0U << QWebSocketProtocol::OpCodeReserved7 - << true << QStringLiteral("Hello world!").toUtf8() - << QWebSocketProtocol::CloseCodeProtocolError; - QTest::newRow("Reserved OpCode B") - << 0 << 0 << 0 - << 0U << QWebSocketProtocol::OpCodeReservedB - << true << QStringLiteral("Hello world!").toUtf8() - << QWebSocketProtocol::CloseCodeProtocolError; - QTest::newRow("Reserved OpCode C") - << 0 << 0 << 0 - << 0U << QWebSocketProtocol::OpCodeReservedC - << true << QStringLiteral("Hello world!").toUtf8() - << QWebSocketProtocol::CloseCodeProtocolError; - QTest::newRow("Reserved OpCode D") - << 0 << 0 << 0 - << 0U << QWebSocketProtocol::OpCodeReservedD - << true << QStringLiteral("Hello world!").toUtf8() - << QWebSocketProtocol::CloseCodeProtocolError; - QTest::newRow("Reserved OpCode E") - << 0 << 0 << 0 - << 0U << QWebSocketProtocol::OpCodeReservedE - << true << QStringLiteral("Hello world!").toUtf8() - << QWebSocketProtocol::CloseCodeProtocolError; - QTest::newRow("Reserved OpCode F") - << 0 << 0 << 0 - << 0U << QWebSocketProtocol::OpCodeReservedF - << true << QStringLiteral("Hello world!").toUtf8() - << QWebSocketProtocol::CloseCodeProtocolError; - - QTest::newRow("Close Frame with payload > 125 bytes") - << 0 << 0 << 0 - << 0U << QWebSocketProtocol::OpCodeClose - << true << QString(126, 'a').toUtf8() - << QWebSocketProtocol::CloseCodeProtocolError; - QTest::newRow("Non-final Close Frame") - << 0 << 0 << 0 - << 0U << QWebSocketProtocol::OpCodeClose - << false << QString(126, 'a').toUtf8() - << QWebSocketProtocol::CloseCodeProtocolError; - QTest::newRow("Ping Frame with payload > 125 bytes") - << 0 << 0 << 0 - << 0U << QWebSocketProtocol::OpCodePing - << true << QString(126, 'a').toUtf8() - << QWebSocketProtocol::CloseCodeProtocolError; - QTest::newRow("Non-final Ping Frame") - << 0 << 0 << 0 - << 0U << QWebSocketProtocol::OpCodePing - << false << QString(126, 'a').toUtf8() - << QWebSocketProtocol::CloseCodeProtocolError; - QTest::newRow("Pong Frame with payload > 125 bytes") - << 0 << 0 << 0 - << 0U << QWebSocketProtocol::OpCodePong - << true << QString(126, 'a').toUtf8() - << QWebSocketProtocol::CloseCodeProtocolError; - QTest::newRow("Non-final Pong Frame") - << 0 << 0 << 0 - << 0U << QWebSocketProtocol::OpCodePong - << false << QString(126, 'a').toUtf8() - << QWebSocketProtocol::CloseCodeProtocolError; -} - -void tst_WebSocketFrame::tst_invalidFrames() -{ - QFETCH(int, rsv1); - QFETCH(int, rsv2); - QFETCH(int, rsv3); - QFETCH(quint32, mask); - QFETCH(QWebSocketProtocol::OpCode, opCode); - QFETCH(bool, isFinal); - QFETCH(QByteArray, payload); - QFETCH(QWebSocketProtocol::CloseCode, expectedError); - - FrameHelper helper; - helper.setRsv1(rsv1); - helper.setRsv2(rsv2); - helper.setRsv3(rsv3); - helper.setMask(mask); - helper.setOpCode(opCode); - helper.setFinalFrame(isFinal); - helper.setPayload(payload); - - QByteArray wireRepresentation = helper.wireRepresentation(); - QBuffer buffer; - buffer.setData(wireRepresentation); - buffer.open(QIODevice::ReadOnly); - QWebSocketFrame frame = QWebSocketFrame::readFrame(&buffer); - buffer.close(); - - QVERIFY(!frame.isValid()); - QCOMPARE(frame.closeCode(), expectedError); -} - - -/* - * Incomplete or overly large frames - * Payload must be crafted manually - * - QTest::newRow("Frame Too Big") - << 0 << 0 << 0 - << 0U << QWebSocketProtocol::OpCodeText - << true << QString(MAX_FRAME_SIZE_IN_BYTES + 1, 'a').toUtf8() - << QWebSocketProtocol::CloseCodeTooMuchData; - - */ -void tst_WebSocketFrame::tst_malformedFrames_data() -{ - QTest::addColumn("payload"); - QTest::addColumn("expectedError"); - - //too little data - QTest::newRow("No data") << QByteArray() << QWebSocketProtocol::CloseCodeGoingAway; - FrameHelper helper; - helper.setRsv1(0); - helper.setRsv2(0); - helper.setRsv3(0); - helper.setMask(0U); - helper.setOpCode(QWebSocketProtocol::OpCodeText); - helper.setFinalFrame(true); - helper.setPayload(QString(10, 'a').toUtf8()); - QByteArray wireRep = helper.wireRepresentation(); - - //too little data - //header + payload should be 12 bytes for non-masked payloads < 126 bytes - for (int i = 1; i < 12; ++i) - { - QTest::newRow(QStringLiteral("Header too small - %1 byte(s)").arg(i).toLatin1().constData()) - << wireRep.left(i) - << QWebSocketProtocol::CloseCodeGoingAway; - } - //too much data - { - const char bigpayloadIndicator = char(127); - const quint64 payloadSize = MAX_FRAME_SIZE_IN_BYTES + 1; - uchar swapped[8] = {0}; - qToBigEndian(payloadSize, swapped); - QTest::newRow("Frame too big") - << wireRep.left(1).append(bigpayloadIndicator) - .append(reinterpret_cast(swapped), 8) - << QWebSocketProtocol::CloseCodeTooMuchData; - } - //invalid size field - { - const char bigpayloadIndicator = char(127); - quint64 payloadSize = quint64(1) << 63; - uchar swapped[8] = {0}; - qToBigEndian(payloadSize, swapped); - QTest::newRow("Highest bit of payload length is set") - << wireRep.left(1).append(bigpayloadIndicator) - .append(reinterpret_cast(swapped), 8) - << QWebSocketProtocol::CloseCodeProtocolError; - - payloadSize = 256; - qToBigEndian(payloadSize, swapped); - QTest::newRow("Overlong 64-bit size field; should be 16-bit") - << wireRep.left(1).append(bigpayloadIndicator) - .append(reinterpret_cast(swapped), 8) - << QWebSocketProtocol::CloseCodeProtocolError; - } - //overlong size field - { - const char largepayloadIndicator = char(126); - const quint16 payloadSize = 120; - uchar swapped[2] = {0}; - qToBigEndian(payloadSize, swapped); - QTest::newRow("Overlong 16-bit size field") - << wireRep.left(1).append(largepayloadIndicator) - .append(reinterpret_cast(swapped), 2) - << QWebSocketProtocol::CloseCodeProtocolError; - } - { - const char bigpayloadIndicator = char(127); - quint64 payloadSize = 120; - uchar swapped[8] = {0}; - qToBigEndian(payloadSize, swapped); - QTest::newRow("Overlong 64-bit size field; should be 7-bit") - << wireRep.left(1).append(bigpayloadIndicator) - .append(reinterpret_cast(swapped), 8) - << QWebSocketProtocol::CloseCodeProtocolError; - - payloadSize = 256; - qToBigEndian(payloadSize, swapped); - QTest::newRow("Overlong 64-bit size field; should be 16-bit") - << wireRep.left(1).append(bigpayloadIndicator) - .append(reinterpret_cast(swapped), 8) - << QWebSocketProtocol::CloseCodeProtocolError; - } -} - -void tst_WebSocketFrame::tst_malformedFrames() -{ - QFETCH(QByteArray, payload); - QFETCH(QWebSocketProtocol::CloseCode, expectedError); - - QBuffer buffer; - buffer.setData(payload); - buffer.open(QIODevice::ReadOnly); - QWebSocketFrame frame = QWebSocketFrame::readFrame(&buffer); - buffer.close(); - - QVERIFY(!frame.isValid()); - QCOMPARE(frame.closeCode(), expectedError); -} - -QTEST_MAIN(tst_WebSocketFrame) - -#include "tst_websocketframe.moc" - diff --git a/tests/auto/websocketframe/websocketframe.pro b/tests/auto/websocketframe/websocketframe.pro deleted file mode 100644 index 9682348..0000000 --- a/tests/auto/websocketframe/websocketframe.pro +++ /dev/null @@ -1,14 +0,0 @@ -CONFIG += console -CONFIG += testcase -CONFIG -= app_bundle - -TEMPLATE = app - -TARGET = tst_websocketframe - -QT = core testlib websockets websockets-private - -SOURCES += tst_websocketframe.cpp - -requires(contains(QT_CONFIG, private_tests)) -DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/websocketprotocol/tst_websocketprotocol.cpp b/tests/auto/websocketprotocol/tst_websocketprotocol.cpp deleted file mode 100644 index 94816de..0000000 --- a/tests/auto/websocketprotocol/tst_websocketprotocol.cpp +++ /dev/null @@ -1,289 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Kurt Pattyn . -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include -#include -#include - -#include - -#include "QtWebSockets/qwebsocketprotocol.h" -#include "private/qwebsocketprotocol_p.h" - -QT_USE_NAMESPACE - -Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode) -Q_DECLARE_METATYPE(QWebSocketProtocol::OpCode) -Q_DECLARE_METATYPE(QWebSocketProtocol::Version) - -class tst_WebSocketProtocol : public QObject -{ - Q_OBJECT - -public: - tst_WebSocketProtocol(); - -private Q_SLOTS: - void initTestCase(); - void cleanupTestCase(); - void init(); - void cleanup(); - - void tst_validMasks_data(); - void tst_validMasks(); - - void tst_opCodes_data(); - void tst_opCodes(); - - void tst_closeCodes_data(); - void tst_closeCodes(); - - void tst_versionFromString_data(); - void tst_versionFromString(); -}; - -tst_WebSocketProtocol::tst_WebSocketProtocol() -{} - -void tst_WebSocketProtocol::initTestCase() -{ -} - -void tst_WebSocketProtocol::cleanupTestCase() -{} - -void tst_WebSocketProtocol::init() -{ - qRegisterMetaType("QWebSocketProtocol::OpCode"); - qRegisterMetaType("QWebSocketProtocol::CloseCode"); -} - -void tst_WebSocketProtocol::cleanup() -{ -} - -void tst_WebSocketProtocol::tst_validMasks_data() -{ - QTest::addColumn("mask"); - QTest::addColumn("inputdata"); - QTest::addColumn("result"); - - QTest::newRow("Empty payload") << 0x12345678u << QString() << QByteArray(); - QTest::newRow("ASCII payload of 8 characters") - << 0x12345678u - << QStringLiteral("abcdefgh") - << QByteArrayLiteral("\x73\x56\x35\x1C\x77\x52\x31\x10"); - QTest::newRow("ASCII payload of 9 characters") - << 0x12345678u - << QStringLiteral("abcdefghi") - << QByteArrayLiteral("\x73\x56\x35\x1C\x77\x52\x31\x10\x7B"); - //MSVC doesn't like UTF-8 in source code; - //the following text is represented in the string below: ∫∂ƒ©øØ - QTest::newRow("UTF-8 payload") - << 0x12345678u - << QString::fromUtf8("\xE2\x88\xAB\xE2\x88\x82\xC6\x92\xC2\xA9\xC3\xB8\xC3\x98") - << QByteArrayLiteral("\x2D\x0B\x69\xD1\xEA\xEC"); -} - -void tst_WebSocketProtocol::tst_validMasks() -{ - QFETCH(quint32, mask); - QFETCH(QString, inputdata); - QFETCH(QByteArray, result); - - //put latin1 into an explicit array - //otherwise, the intermediate object is deleted and the data pointer becomes invalid - QByteArray latin1 = inputdata.toLatin1(); - char *data = latin1.data(); - - QWebSocketProtocol::mask(data, inputdata.size(), mask); - QCOMPARE(QByteArray::fromRawData(data, inputdata.size()), result); -} - -void tst_WebSocketProtocol::tst_opCodes_data() -{ - QTest::addColumn("opCode"); - QTest::addColumn("isReserved"); - - QTest::newRow("OpCodeBinary") << QWebSocketProtocol::OpCodeBinary << false; - QTest::newRow("OpCodeClose") << QWebSocketProtocol::OpCodeClose << false; - QTest::newRow("OpCodeContinue") << QWebSocketProtocol::OpCodeContinue << false; - QTest::newRow("OpCodePing") << QWebSocketProtocol::OpCodePing << false; - QTest::newRow("OpCodePong") << QWebSocketProtocol::OpCodePong << false; - QTest::newRow("OpCodeReserved3") << QWebSocketProtocol::OpCodeReserved3 << true; - QTest::newRow("OpCodeReserved4") << QWebSocketProtocol::OpCodeReserved4 << true; - QTest::newRow("OpCodeReserved5") << QWebSocketProtocol::OpCodeReserved5 << true; - QTest::newRow("OpCodeReserved6") << QWebSocketProtocol::OpCodeReserved6 << true; - QTest::newRow("OpCodeReserved7") << QWebSocketProtocol::OpCodeReserved7 << true; - QTest::newRow("OpCodeReserved8") << QWebSocketProtocol::OpCodeReservedB << true; - QTest::newRow("OpCodeReservedC") << QWebSocketProtocol::OpCodeReservedC << true; - QTest::newRow("OpCodeReservedD") << QWebSocketProtocol::OpCodeReservedD << true; - QTest::newRow("OpCodeReservedE") << QWebSocketProtocol::OpCodeReservedE << true; - QTest::newRow("OpCodeReservedF") << QWebSocketProtocol::OpCodeReservedF << true; - QTest::newRow("OpCodeText") << QWebSocketProtocol::OpCodeText << false; -} - -void tst_WebSocketProtocol::tst_opCodes() -{ - QFETCH(QWebSocketProtocol::OpCode, opCode); - QFETCH(bool, isReserved); - - bool result = QWebSocketProtocol::isOpCodeReserved(opCode); - - QCOMPARE(result, isReserved); -} - -void tst_WebSocketProtocol::tst_closeCodes_data() -{ - QTest::addColumn("closeCode"); - QTest::addColumn("isValid"); - - for (int i = 0; i < 1000; ++i) - { - QTest::newRow(QStringLiteral("Close code %1").arg(i).toLatin1().constData()) << i << false; - } - - for (int i = 1000; i < 1004; ++i) - { - QTest::newRow(QStringLiteral("Close code %1").arg(i).toLatin1().constData()) << i << true; - } - - QTest::newRow("Close code 1004") << 1004 << false; - QTest::newRow("Close code 1005") << 1005 << false; - QTest::newRow("Close code 1006") << 1006 << false; - - for (int i = 1007; i < 1012; ++i) - { - QTest::newRow(QStringLiteral("Close code %1").arg(i).toLatin1().constData()) << i << true; - } - - for (int i = 1013; i < 3000; ++i) - { - QTest::newRow(QStringLiteral("Close code %1").arg(i).toLatin1().constData()) << i << false; - } - - for (int i = 3000; i < 5000; ++i) - { - QTest::newRow(QStringLiteral("Close code %1").arg(i).toLatin1().constData()) << i << true; - } - - QTest::newRow("Close code 5000") << 1004 << false; - QTest::newRow("Close code 6000") << 1004 << false; - QTest::newRow("Close code 7000") << 1004 << false; -} - -void tst_WebSocketProtocol::tst_closeCodes() -{ - QFETCH(int, closeCode); - QFETCH(bool, isValid); - - bool result = QWebSocketProtocol::isCloseCodeValid(closeCode); - - QCOMPARE(result, isValid); -} - -void tst_WebSocketProtocol::tst_versionFromString_data() -{ - QTest::addColumn("version"); - QTest::addColumn("versionString"); - - //happy flow; good data - QTest::newRow("Version 0") - << QWebSocketProtocol::Version0 - << QStringLiteral("0"); - QTest::newRow("Version 4") - << QWebSocketProtocol::Version4 - << QStringLiteral("4"); - QTest::newRow("Version 5") - << QWebSocketProtocol::Version5 - << QStringLiteral("5"); - QTest::newRow("Version 6") - << QWebSocketProtocol::Version6 - << QStringLiteral("6"); - QTest::newRow("Version 7") - << QWebSocketProtocol::Version7 - << QStringLiteral("7"); - QTest::newRow("Version 8") - << QWebSocketProtocol::Version8 - << QStringLiteral("8"); - QTest::newRow("Version 13") - << QWebSocketProtocol::Version13 - << QStringLiteral("13"); - - //rainy flow; invalid data - QTest::newRow("Version -1") - << QWebSocketProtocol::VersionUnknown - << QStringLiteral("-1"); - QTest::newRow("Version 1") - << QWebSocketProtocol::VersionUnknown - << QStringLiteral("1"); - QTest::newRow("Version 2") - << QWebSocketProtocol::VersionUnknown - << QStringLiteral("2"); - QTest::newRow("Version 3") - << QWebSocketProtocol::VersionUnknown - << QStringLiteral("3"); - QTest::newRow("Version 9") - << QWebSocketProtocol::VersionUnknown - << QStringLiteral("9"); - QTest::newRow("Version 10") - << QWebSocketProtocol::VersionUnknown - << QStringLiteral("10"); - QTest::newRow("Version 11") - << QWebSocketProtocol::VersionUnknown - << QStringLiteral("11"); - QTest::newRow("Version 12") - << QWebSocketProtocol::VersionUnknown - << QStringLiteral("12"); - QTest::newRow("Version abcd") - << QWebSocketProtocol::VersionUnknown - << QStringLiteral("abcd"); - QTest::newRow("Version 1.6") - << QWebSocketProtocol::VersionUnknown - << QStringLiteral("1.6"); - QTest::newRow("Version empty") - << QWebSocketProtocol::VersionUnknown - << QString(); -} - -void tst_WebSocketProtocol::tst_versionFromString() -{ - QFETCH(QWebSocketProtocol::Version, version); - QFETCH(QString, versionString); - - QCOMPARE(QWebSocketProtocol::versionFromString(versionString), version); -} - -QTEST_MAIN(tst_WebSocketProtocol) - -#include "tst_websocketprotocol.moc" - diff --git a/tests/auto/websocketprotocol/websocketprotocol.pro b/tests/auto/websocketprotocol/websocketprotocol.pro deleted file mode 100644 index c21bb64..0000000 --- a/tests/auto/websocketprotocol/websocketprotocol.pro +++ /dev/null @@ -1,14 +0,0 @@ -CONFIG += console -CONFIG += testcase -CONFIG -= app_bundle - -TEMPLATE = app - -TARGET = tst_websocketprotocol - -QT = core testlib websockets websockets-private - -SOURCES += tst_websocketprotocol.cpp - -requires(contains(QT_CONFIG, private_tests)) -DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/websockets/dataprocessor/dataprocessor.pro b/tests/auto/websockets/dataprocessor/dataprocessor.pro new file mode 100644 index 0000000..ac5ba5c --- /dev/null +++ b/tests/auto/websockets/dataprocessor/dataprocessor.pro @@ -0,0 +1,14 @@ +CONFIG += console +CONFIG += testcase +CONFIG -= app_bundle + +TEMPLATE = app + +TARGET = tst_dataprocessor + +QT = core testlib websockets websockets-private + +SOURCES += tst_dataprocessor.cpp + +requires(contains(QT_CONFIG, private_tests)) +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/websockets/dataprocessor/tst_dataprocessor.cpp b/tests/auto/websockets/dataprocessor/tst_dataprocessor.cpp new file mode 100644 index 0000000..660d8eb --- /dev/null +++ b/tests/auto/websockets/dataprocessor/tst_dataprocessor.cpp @@ -0,0 +1,1842 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Kurt Pattyn . +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include +#include +#include +#include +#include + +#include "private/qwebsocketdataprocessor_p.h" +#include "private/qwebsocketprotocol_p.h" +#include "QtWebSockets/qwebsocketprotocol.h" + +const quint8 FIN = 0x80; +const quint8 RSV1 = 0x40; +const quint8 RSV2 = 0x30; +const quint8 RSV3 = 0x10; + +QT_USE_NAMESPACE + +Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode) +Q_DECLARE_METATYPE(QWebSocketProtocol::OpCode) + +class tst_DataProcessor : public QObject +{ + Q_OBJECT + +public: + tst_DataProcessor(); + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + + /*************************************************************************** + * Happy Flows + ***************************************************************************/ + /*! + Tests all kinds of valid binary frames, including zero length frames + */ + void goodBinaryFrame(); + void goodBinaryFrame_data(); + + /*! + Tests all kinds of valid text frames, including zero length frames + */ + void goodTextFrame(); + void goodTextFrame_data(); + + /*! + * Test all kinds of valid control frames. + */ + void goodControlFrame(); + + /*! + * Test all kinds of valid close frames. + */ + void goodCloseFrame(); + void goodCloseFrame_data(); + + /*! + * Test all valid opcodes + */ + void goodOpcodes(); + void goodOpcodes_data(); + + /*! + Tests the QWebSocketDataProcessor for the correct handling of non-charactercodes + Due to a workaround in QTextCodec, non-characters are treated as illegal. + This workaround is not necessary anymore, and hence code should be changed in Qt + to allow non-characters again. + */ + void nonCharacterCodes(); + void nonCharacterCodes_data(); + + /*************************************************************************** + * Rainy Day Flows + ***************************************************************************/ + /*! + Tests the QWebSocketDataProcessor for correct handling of frames that don't + contain the starting 2 bytes. + This test is a border case, where not enough bytes are received to even start parsing a + frame. + This test does not test sequences of frames, only single frames are tested + */ + void frameTooSmall(); + + /*! + Tests the QWebSocketDataProcessor for correct handling of frames that are oversized. + This test does not test sequences of frames, only single frames are tested + */ + void frameTooBig(); + void frameTooBig_data(); + + /*! + Tests the QWebSocketDataProcessor for the correct handling of malformed frame headers. + This test does not test sequences of frames, only single frames are tested + */ + void invalidHeader(); + void invalidHeader_data(); + + /*! + Tests the QWebSocketDataProcessor for the correct handling of invalid control frames. + Invalid means: payload bigger than 125, frame is fragmented, ... + This test does not test sequences of frames, only single frames are tested + */ + void invalidControlFrame(); + void invalidControlFrame_data(); + + void invalidCloseFrame(); + void invalidCloseFrame_data(); + + /*! + Tests the QWebSocketDataProcessor for the correct handling of incomplete size fields + for large and big payloads. + */ + void incompleteSizeField(); + void incompleteSizeField_data(); + + /*! + Tests the QWebSocketDataProcessor for the correct handling of incomplete payloads. + This includes: + - incomplete length bytes for large and big payloads (16- and 64-bit values), + - minimum size representation (see RFC 6455 paragraph 5.2), + - frames that are too large (larger than MAX_INT in bytes) + - incomplete payloads (less bytes than indicated in the size field) + This test does not test sequences of frames, only single frames are tested + */ + void incompletePayload(); + void incompletePayload_data(); + + /*! + Tests the QWebSocketDataProcessor for the correct handling of invalid UTF-8 payloads. + This test does not test sequences of frames, only single frames are tested + */ + void invalidPayload(); + void invalidPayload_data(bool isControlFrame = false); + + void invalidPayloadInCloseFrame(); + void invalidPayloadInCloseFrame_data(); + + /*! + Tests the QWebSocketDataProcessor for the correct handling of the minimum size representation + requirement of RFC 6455 (see paragraph 5.2) + */ + void minimumSizeRequirement(); + void minimumSizeRequirement_data(); + +private: + //helper function that constructs a new row of test data for invalid UTF8 sequences + void invalidUTF8(const char *dataTag, const char *utf8Sequence, bool isCloseFrame); + //helper function that constructs a new row of test data for invalid leading field values + void invalidField(const char *dataTag, quint8 invalidFieldValue); + //helper functions that construct a new row of test data for size fields that do not adhere + //to the minimum size requirement + void minimumSize16Bit(quint16 sizeInBytes); + void minimumSize64Bit(quint64 sizeInBytes); + //helper function to construct a new row of test data containing frames with a payload size + //smaller than indicated in the header + void incompleteFrame(quint8 controlCode, quint64 indicatedSize, quint64 actualPayloadSize); + void insertIncompleteSizeFieldTest(quint8 payloadCode, quint8 numBytesFollowing); + + //helper function to construct a new row of test data containing text frames containing + //sequences + void nonCharacterSequence(const char *sequence); + + void doTest(); + void doCloseFrameTest(); + + QString opCodeToString(quint8 opCode); +}; + +tst_DataProcessor::tst_DataProcessor() +{ +} + +void tst_DataProcessor::initTestCase() +{ +} + +void tst_DataProcessor::cleanupTestCase() +{ +} + +void tst_DataProcessor::init() +{ + qRegisterMetaType("QWebSocketProtocol::OpCode"); + qRegisterMetaType("QWebSocketProtocol::CloseCode"); +} + +void tst_DataProcessor::cleanup() +{ +} + +void tst_DataProcessor::goodBinaryFrame_data() +{ + QTest::addColumn("payload"); + //be sure to get small (< 126 bytes), large (> 125 bytes & < 64K) and big (>64K) frames + for (int i = 0; i < (65536 + 256); i += 128) + { + QTest::newRow(QStringLiteral("Binary frame with %1 bytes").arg(i).toLatin1().constData()) + << QByteArray(i, char(1)); + } + for (int i = 0; i < 256; ++i) //test all possible bytes in the payload + { + QTest::newRow(QStringLiteral("Binary frame containing byte: '0x%1'") + .arg(QByteArray(1, char(i)).toHex().constData()).toLatin1().constData()) + << QByteArray(i, char(1)); + } +} + +void tst_DataProcessor::goodBinaryFrame() +{ + QByteArray data; + QBuffer buffer; + QWebSocketDataProcessor dataProcessor; + QFETCH(QByteArray, payload); + + data.append((char)(FIN | QWebSocketProtocol::OpCodeBinary)); + + if (payload.length() < 126) + { + data.append(char(payload.length())); + } + else if (payload.length() < 65536) + { + quint16 swapped = qToBigEndian(payload.length()); + const char *wireRepresentation + = static_cast(static_cast(&swapped)); + data.append(char(126)).append(wireRepresentation, 2); + } + else + { + quint64 swapped = qToBigEndian(payload.length()); + const char *wireRepresentation + = static_cast(static_cast(&swapped)); + data.append(char(127)).append(wireRepresentation, 8); + } + + data.append(payload); + buffer.setData(data); + buffer.open(QIODevice::ReadOnly); + + QSignalSpy errorReceivedSpy(&dataProcessor, + SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString))); + QSignalSpy closeReceivedSpy(&dataProcessor, + SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString))); + QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray))); + QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray))); + QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool))); + QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray))); + QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool))); + QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString))); + dataProcessor.process(&buffer); + QCOMPARE(errorReceivedSpy.count(), 0); + QCOMPARE(pingReceivedSpy.count(), 0); + QCOMPARE(pongReceivedSpy.count(), 0); + QCOMPARE(closeReceivedSpy.count(), 0); + QCOMPARE(binaryFrameReceivedSpy.count(), 1); + QCOMPARE(binaryMessageReceivedSpy.count(), 1); + QCOMPARE(textFrameReceivedSpy.count(), 0); + QCOMPARE(textMessageReceivedSpy.count(), 0); + QList arguments = binaryFrameReceivedSpy.takeFirst(); + QCOMPARE(arguments.at(0).toByteArray().length(), payload.length()); + arguments = binaryMessageReceivedSpy.takeFirst(); + QCOMPARE(arguments.at(0).toByteArray().length(), payload.length()); + buffer.close(); +} + +void tst_DataProcessor::goodTextFrame_data() +{ + QTest::addColumn("payload"); + QTest::addColumn("size"); + + //test frames with small (< 126), large ( < 65536) and big ( > 65535) payloads + for (int i = 0; i < (65536 + 256); i += 128) + { + QTest::newRow(QStringLiteral("Text frame with %1 ASCII characters") + .arg(i).toLatin1().constData()) << QByteArray(i, 'a') << i; + } + //test all valid ASCII characters + for (int i = 0; i < 128; ++i) + { + QTest::newRow(QStringLiteral("Text frame with containing ASCII character '0x%1'") + .arg(QByteArray(1, char(i)).toHex().constData()).toLatin1().constData()) + << QByteArray(1, char(i)) << 1; + } + + //the text string reads: Text frame containing Hello-µ@ßöäüàá-UTF-8!! + //Visual Studio doesn't like UTF-8 in source code, so we use escape codes for the string + //The number 22 refers to the length of the string; + //the length was incorrectly calculated on Visual Studio + + //doing extensive QStringLiteral concatenations here, because + //MSVC 2010 complains when using concatenation literal strings about + //concatenation of wide and narrow strings: + //error C2308: concatenating mismatched strings + QTest::newRow((QStringLiteral("Text frame containing Hello-") + + QStringLiteral("\xC2\xB5\x40\xC3\x9F\xC3\xB6\xC3\xA4\xC3\xBC\xC3\xA0") + + QStringLiteral("\xC3\xA1-UTF-8!!")).toLatin1().constData()) + << QByteArray::fromHex("48656c6c6f2dc2b540c39fc3b6c3a4c3bcc3a0c3a12d5554462d382121") + << 22; +} + +void tst_DataProcessor::goodTextFrame() +{ + QByteArray data; + QBuffer buffer; + QWebSocketDataProcessor dataProcessor; + QFETCH(QByteArray, payload); + QFETCH(int, size); + + data.append((char)(FIN | QWebSocketProtocol::OpCodeText)); + + if (payload.length() < 126) + { + data.append(char(payload.length())); + } + else if (payload.length() < 65536) + { + quint16 swapped = qToBigEndian(payload.length()); + const char *wireRepresentation + = static_cast(static_cast(&swapped)); + data.append(char(126)).append(wireRepresentation, 2); + } + else + { + quint64 swapped = qToBigEndian(payload.length()); + const char *wireRepresentation + = static_cast(static_cast(&swapped)); + data.append(char(127)).append(wireRepresentation, 8); + } + + data.append(payload); + buffer.setData(data); + buffer.open(QIODevice::ReadOnly); + + QSignalSpy errorReceivedSpy(&dataProcessor, + SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString))); + QSignalSpy closeReceivedSpy(&dataProcessor, + SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString))); + QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray))); + QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray))); + QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool))); + QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString))); + QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool))); + QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray))); + + dataProcessor.process(&buffer); + + QCOMPARE(errorReceivedSpy.count(), 0); + QCOMPARE(pingReceivedSpy.count(), 0); + QCOMPARE(pongReceivedSpy.count(), 0); + QCOMPARE(closeReceivedSpy.count(), 0); + QCOMPARE(textFrameReceivedSpy.count(), 1); + QCOMPARE(textMessageReceivedSpy.count(), 1); + QCOMPARE(binaryFrameReceivedSpy.count(), 0); + QCOMPARE(binaryMessageReceivedSpy.count(), 0); + QList arguments = textFrameReceivedSpy.takeFirst(); + QCOMPARE(arguments.at(0).toString().length(), size); + arguments = textMessageReceivedSpy.takeFirst(); + QCOMPARE(arguments.at(0).toString().length(), size); + buffer.close(); +} + +void tst_DataProcessor::goodControlFrame() +{ + QByteArray data; + QBuffer buffer; + QWebSocketDataProcessor dataProcessor; + + QSignalSpy closeFrameReceivedSpy(&dataProcessor, + SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString))); + QSignalSpy errorReceivedSpy(&dataProcessor, + SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString))); + QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool))); + QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString))); + QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool))); + QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray))); + QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray))); + QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray))); + + data.append((char)(FIN | QWebSocketProtocol::OpCodePing)); + data.append(QChar::fromLatin1(0)); + buffer.setData(data); + buffer.open(QIODevice::ReadOnly); + dataProcessor.process(&buffer); + QCOMPARE(errorReceivedSpy.count(), 0); + QCOMPARE(textFrameReceivedSpy.count(), 0); + QCOMPARE(textMessageReceivedSpy.count(), 0); + QCOMPARE(binaryFrameReceivedSpy.count(), 0); + QCOMPARE(binaryMessageReceivedSpy.count(), 0); + QCOMPARE(closeFrameReceivedSpy.count(), 0); + QCOMPARE(pongReceivedSpy.count(), 0); + QCOMPARE(pingReceivedSpy.count(), 1); + buffer.close(); + + data.clear(); + pingReceivedSpy.clear(); + pongReceivedSpy.clear(); + data.append((char)(FIN | QWebSocketProtocol::OpCodePong)); + data.append(QChar::fromLatin1(0)); + buffer.setData(data); + buffer.open(QIODevice::ReadOnly); + dataProcessor.process(&buffer); + QCOMPARE(errorReceivedSpy.count(), 0); + QCOMPARE(textFrameReceivedSpy.count(), 0); + QCOMPARE(textMessageReceivedSpy.count(), 0); + QCOMPARE(binaryFrameReceivedSpy.count(), 0); + QCOMPARE(binaryMessageReceivedSpy.count(), 0); + QCOMPARE(closeFrameReceivedSpy.count(), 0); + QCOMPARE(pingReceivedSpy.count(), 0); + QCOMPARE(pongReceivedSpy.count(), 1); + buffer.close(); +} + +void tst_DataProcessor::goodCloseFrame_data() +{ + QTest::addColumn("payload"); + QTest::addColumn("closeCode"); + //control frame data cannot exceed 125 bytes; smaller than 124, + //because we also need a 2 byte close code + for (int i = 0; i < 124; ++i) + { + QTest::newRow(QStringLiteral("Close frame with %1 ASCII characters") + .arg(i).toLatin1().constData()) + << QString(i, 'a') + << QWebSocketProtocol::CloseCodeNormal; + } + for (int i = 0; i < 126; ++i) + { + QTest::newRow(QStringLiteral("Text frame with containing ASCII character '0x%1'") + .arg(QByteArray(1, char(i)).toHex().constData()).toLatin1().constData()) + << QString(1, char(i)) << QWebSocketProtocol::CloseCodeNormal; + } + QTest::newRow("Close frame with close code NORMAL") + << QString(1, 'a') << QWebSocketProtocol::CloseCodeNormal; + QTest::newRow("Close frame with close code BAD OPERATION") + << QString(1, 'a') << QWebSocketProtocol::CloseCodeBadOperation; + QTest::newRow("Close frame with close code DATATYPE NOT SUPPORTED") + << QString(1, 'a') << QWebSocketProtocol::CloseCodeDatatypeNotSupported; + QTest::newRow("Close frame with close code GOING AWAY") + << QString(1, 'a') << QWebSocketProtocol::CloseCodeGoingAway; + QTest::newRow("Close frame with close code MISSING EXTENSION") + << QString(1, 'a') << QWebSocketProtocol::CloseCodeMissingExtension; + QTest::newRow("Close frame with close code POLICY VIOLATED") + << QString(1, 'a') << QWebSocketProtocol::CloseCodePolicyViolated; + QTest::newRow("Close frame with close code PROTOCOL ERROR") + << QString(1, 'a') << QWebSocketProtocol::CloseCodeProtocolError; + QTest::newRow("Close frame with close code TOO MUCH DATA") + << QString(1, 'a') << QWebSocketProtocol::CloseCodeTooMuchData; + QTest::newRow("Close frame with close code WRONG DATATYPE") + << QString(1, 'a') << QWebSocketProtocol::CloseCodeWrongDatatype; + QTest::newRow("Close frame with close code 3000") + << QString(1, 'a') << QWebSocketProtocol::CloseCode(3000); + QTest::newRow("Close frame with close code 3999") + << QString(1, 'a') << QWebSocketProtocol::CloseCode(3999); + QTest::newRow("Close frame with close code 4000") + << QString(1, 'a') << QWebSocketProtocol::CloseCode(4000); + QTest::newRow("Close frame with close code 4999") + << QString(1, 'a') << QWebSocketProtocol::CloseCode(4999); + + //close frames with no close reason + QTest::newRow("Close frame with close code NORMAL and no reason") + << QString() << QWebSocketProtocol::CloseCodeNormal; + QTest::newRow("Close frame with close code BAD OPERATION and no reason") + << QString() << QWebSocketProtocol::CloseCodeBadOperation; + QTest::newRow("Close frame with close code DATATYPE NOT SUPPORTED and no reason") + << QString() << QWebSocketProtocol::CloseCodeDatatypeNotSupported; + QTest::newRow("Close frame with close code GOING AWAY and no reason") + << QString() << QWebSocketProtocol::CloseCodeGoingAway; + QTest::newRow("Close frame with close code MISSING EXTENSION and no reason") + << QString() << QWebSocketProtocol::CloseCodeMissingExtension; + QTest::newRow("Close frame with close code POLICY VIOLATED and no reason") + << QString() << QWebSocketProtocol::CloseCodePolicyViolated; + QTest::newRow("Close frame with close code PROTOCOL ERROR and no reason") + << QString() << QWebSocketProtocol::CloseCodeProtocolError; + QTest::newRow("Close frame with close code TOO MUCH DATA and no reason") + << QString() << QWebSocketProtocol::CloseCodeTooMuchData; + QTest::newRow("Close frame with close code WRONG DATATYPE and no reason") + << QString() << QWebSocketProtocol::CloseCodeWrongDatatype; + QTest::newRow("Close frame with close code 3000 and no reason") + << QString() << QWebSocketProtocol::CloseCode(3000); + QTest::newRow("Close frame with close code 3999 and no reason") + << QString() << QWebSocketProtocol::CloseCode(3999); + QTest::newRow("Close frame with close code 4000 and no reason") + << QString() << QWebSocketProtocol::CloseCode(4000); + QTest::newRow("Close frame with close code 4999 and no reason") + << QString() << QWebSocketProtocol::CloseCode(4999); + + QTest::newRow("Close frame with no close code and no reason") + << QString() << QWebSocketProtocol::CloseCode(0); +} + +void tst_DataProcessor::goodOpcodes_data() +{ + QTest::addColumn("opCode"); + + QTest::newRow("Frame with PING opcode") << QWebSocketProtocol::OpCodePing; + QTest::newRow("Frame with PONG opcode") << QWebSocketProtocol::OpCodePong; + QTest::newRow("Frame with TEXT opcode") << QWebSocketProtocol::OpCodeText; + QTest::newRow("Frame with BINARY opcode") << QWebSocketProtocol::OpCodeBinary; + QTest::newRow("Frame with CLOSE opcode") << QWebSocketProtocol::OpCodeClose; +} + +void tst_DataProcessor::goodOpcodes() +{ + QByteArray data; + QBuffer buffer; + QWebSocketDataProcessor dataProcessor; + QFETCH(QWebSocketProtocol::OpCode, opCode); + + data.append((char)(FIN | opCode)); + data.append(char(0)); //zero length + + buffer.setData(data); + buffer.open(QIODevice::ReadOnly); + + QSignalSpy errorReceivedSpy(&dataProcessor, + SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString))); + QSignalSpy closeReceivedSpy(&dataProcessor, + SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString))); + QSignalSpy pingReceivedSpy(&dataProcessor, + SIGNAL(pingReceived(QByteArray))); + QSignalSpy pongReceivedSpy(&dataProcessor, + SIGNAL(pongReceived(QByteArray))); + QSignalSpy textFrameReceivedSpy(&dataProcessor, + SIGNAL(textFrameReceived(QString,bool))); + QSignalSpy textMessageReceivedSpy(&dataProcessor, + SIGNAL(textMessageReceived(QString))); + QSignalSpy binaryFrameReceivedSpy(&dataProcessor, + SIGNAL(binaryFrameReceived(QByteArray,bool))); + QSignalSpy binaryMessageReceivedSpy(&dataProcessor, + SIGNAL(binaryMessageReceived(QByteArray))); + + dataProcessor.process(&buffer); + + QCOMPARE(errorReceivedSpy.count(), 0); + QCOMPARE(pingReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodePing ? 1 : 0); + QCOMPARE(pongReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodePong ? 1 : 0); + QCOMPARE(closeReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodeClose ? 1 : 0); + QCOMPARE(textFrameReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodeText ? 1 : 0); + QCOMPARE(textMessageReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodeText ? 1 : 0); + QCOMPARE(binaryFrameReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodeBinary ? 1 : 0); + QCOMPARE(binaryMessageReceivedSpy.count(), opCode == QWebSocketProtocol::OpCodeBinary ? 1 : 0); + + buffer.close(); +} + +void tst_DataProcessor::goodCloseFrame() +{ + QByteArray data; + QBuffer buffer; + QWebSocketDataProcessor dataProcessor; + QFETCH(QString, payload); + QFETCH(QWebSocketProtocol::CloseCode, closeCode); + quint16 swapped = qToBigEndian(closeCode); + const char *wireRepresentation = static_cast(static_cast(&swapped)); + + data.append((char)(FIN | QWebSocketProtocol::OpCodeClose)); + if (swapped != 0) + { + data.append(char(payload.length() + 2)).append(wireRepresentation, 2).append(payload); + } + else + { + data.append(QChar::fromLatin1(0)); //payload length 0; + //dataprocessor emits a CloseCodeNormal close code when none is present + closeCode = QWebSocketProtocol::CloseCodeNormal; + } + buffer.setData(data); + buffer.open(QIODevice::ReadOnly); + + QSignalSpy errorReceivedSpy(&dataProcessor, + SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString))); + QSignalSpy pingReceivedSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray))); + QSignalSpy pongReceivedSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray))); + QSignalSpy closeFrameReceivedSpy(&dataProcessor, + SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString))); + QSignalSpy textFrameReceivedSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool))); + QSignalSpy textMessageReceivedSpy(&dataProcessor, SIGNAL(textMessageReceived(QString))); + QSignalSpy binaryFrameReceivedSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool))); + QSignalSpy binaryMessageReceivedSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray))); + + dataProcessor.process(&buffer); + + QCOMPARE(errorReceivedSpy.count(), 0); + QCOMPARE(pingReceivedSpy.count(), 0); + QCOMPARE(pongReceivedSpy.count(), 0); + QCOMPARE(closeFrameReceivedSpy.count(), 1); + QCOMPARE(textFrameReceivedSpy.count(), 0); + QCOMPARE(textMessageReceivedSpy.count(), 0); + QCOMPARE(binaryFrameReceivedSpy.count(), 0); + QCOMPARE(binaryMessageReceivedSpy.count(), 0); + QList arguments = closeFrameReceivedSpy.takeFirst(); + QCOMPARE(arguments.at(0).value(), closeCode); + QCOMPARE(arguments.at(1).toString().length(), payload.length()); + buffer.close(); +} + +void tst_DataProcessor::nonCharacterCodes_data() +{ + QTest::addColumn("firstByte"); + QTest::addColumn("secondByte"); + QTest::addColumn("payload"); + QTest::addColumn("isContinuationFrame"); + + nonCharacterSequence("efbfbe"); + nonCharacterSequence("efbfbf"); + nonCharacterSequence("f09fbfbe"); + nonCharacterSequence("f09fbfbf"); + nonCharacterSequence("f0afbfbe"); + nonCharacterSequence("f0afbfbf"); + nonCharacterSequence("f0bfbfbe"); + nonCharacterSequence("f0bfbfbf"); + nonCharacterSequence("f18fbfbe"); + nonCharacterSequence("f18fbfbf"); + nonCharacterSequence("f19fbfbe"); + nonCharacterSequence("f19fbfbf"); + nonCharacterSequence("f1afbfbe"); + nonCharacterSequence("f1afbfbf"); + nonCharacterSequence("f1bfbfbe"); + nonCharacterSequence("f1bfbfbf"); + nonCharacterSequence("f28fbfbe"); + nonCharacterSequence("f28fbfbf"); + nonCharacterSequence("f29fbfbe"); + nonCharacterSequence("f29fbfbf"); + nonCharacterSequence("f2afbfbe"); + nonCharacterSequence("f2afbfbf"); + nonCharacterSequence("f2bfbfbe"); + nonCharacterSequence("f2bfbfbf"); + nonCharacterSequence("f38fbfbe"); + nonCharacterSequence("f38fbfbf"); + nonCharacterSequence("f39fbfbe"); + nonCharacterSequence("f39fbfbf"); + nonCharacterSequence("f3afbfbe"); + nonCharacterSequence("f3afbfbf"); + nonCharacterSequence("f3bfbfbe"); + nonCharacterSequence("f3bfbfbf"); + nonCharacterSequence("f48fbfbe"); + nonCharacterSequence("f48fbfbf"); +} + +void tst_DataProcessor::nonCharacterCodes() +{ + QFETCH(quint8, firstByte); + QFETCH(quint8, secondByte); + QFETCH(QByteArray, payload); + QFETCH(bool, isContinuationFrame); + + if (!isContinuationFrame) + { + QByteArray data; + QBuffer buffer; + QWebSocketDataProcessor dataProcessor; + QSignalSpy errorSpy(&dataProcessor, + SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString))); + QSignalSpy closeSpy(&dataProcessor, + SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString))); + QSignalSpy pingFrameSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray))); + QSignalSpy pongFrameSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray))); + QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool))); + QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString))); + QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool))); + QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray))); + + data.append(firstByte).append(secondByte); + data.append(payload); + buffer.setData(data); + buffer.open(QIODevice::ReadOnly); + dataProcessor.process(&buffer); + + QCOMPARE(errorSpy.count(), 0); + QCOMPARE(closeSpy.count(), 0); + QCOMPARE(pingFrameSpy.count(), 0); + QCOMPARE(pongFrameSpy.count(), 0); + QCOMPARE(textFrameSpy.count(), 1); + QCOMPARE(textMessageSpy.count(), 1); + QCOMPARE(binaryFrameSpy.count(), 0); + QCOMPARE(binaryMessageSpy.count(), 0); + + QVariantList arguments = textFrameSpy.takeFirst(); + QCOMPARE(arguments.at(0).value().toUtf8(), payload); + QCOMPARE(arguments.at(1).value(), !isContinuationFrame); + arguments = textMessageSpy.takeFirst(); + QCOMPARE(arguments.at(0).value().toUtf8(), payload); + buffer.close(); + } +} + +void tst_DataProcessor::frameTooSmall() +{ + QByteArray data; + QBuffer buffer; + QWebSocketDataProcessor dataProcessor; + QByteArray firstFrame; + + firstFrame.append(quint8(QWebSocketProtocol::OpCodeText)).append(char(1)) + .append(QByteArray(1, 'a')); + + //with nothing in the buffer, the dataProcessor should time out + //and the error should be CloseCodeGoingAway meaning the socket will be closed + buffer.setData(data); + buffer.open(QIODevice::ReadOnly); + QSignalSpy errorSpy(&dataProcessor, + SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString))); + QSignalSpy closeSpy(&dataProcessor, + SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString))); + QSignalSpy pingMessageSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray))); + QSignalSpy pongMessageSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray))); + QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString))); + QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray))); + QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool))); + QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool))); + + dataProcessor.process(&buffer); + + QCOMPARE(errorSpy.count(), 1); + QCOMPARE(closeSpy.count(), 0); + QCOMPARE(pingMessageSpy.count(), 0); + QCOMPARE(pongMessageSpy.count(), 0); + QCOMPARE(textMessageSpy.count(), 0); + QCOMPARE(binaryMessageSpy.count(), 0); + QCOMPARE(textFrameSpy.count(), 0); + QCOMPARE(binaryFrameSpy.count(), 0); + + QList arguments = errorSpy.takeFirst(); + QCOMPARE(arguments.at(0).value(), + QWebSocketProtocol::CloseCodeGoingAway); + errorSpy.clear(); + closeSpy.clear(); + pingMessageSpy.clear(); + pongMessageSpy.clear(); + textMessageSpy.clear(); + binaryMessageSpy.clear(); + textFrameSpy.clear(); + binaryFrameSpy.clear(); + buffer.close(); + data.clear(); + + //only one byte; this is far too little; + //should get a time out as well and the error should be CloseCodeGoingAway + //meaning the socket will be closed + data.append(quint8('1')); //put 1 byte in the buffer; this is too little + buffer.setData(data); + buffer.open(QIODevice::ReadOnly); + + dataProcessor.process(&buffer); + + QCOMPARE(errorSpy.count(), 1); + QCOMPARE(closeSpy.count(), 0); + QCOMPARE(pingMessageSpy.count(), 0); + QCOMPARE(pongMessageSpy.count(), 0); + QCOMPARE(textMessageSpy.count(), 0); + QCOMPARE(binaryMessageSpy.count(), 0); + QCOMPARE(textFrameSpy.count(), 0); + QCOMPARE(binaryFrameSpy.count(), 0); + + arguments = errorSpy.takeFirst(); + QCOMPARE(arguments.at(0).value(), + QWebSocketProtocol::CloseCodeGoingAway); + buffer.close(); + errorSpy.clear(); + closeSpy.clear(); + pingMessageSpy.clear(); + pongMessageSpy.clear(); + textMessageSpy.clear(); + binaryMessageSpy.clear(); + textFrameSpy.clear(); + binaryFrameSpy.clear(); + data.clear(); + + + { + //text frame with final bit not set + data.append((char)(QWebSocketProtocol::OpCodeText)).append(char(0x0)); + buffer.setData(data); + buffer.open(QIODevice::ReadOnly); + + dataProcessor.process(&buffer); + + buffer.close(); + data.clear(); + + //with nothing in the buffer, + //the dataProcessor should time out and the error should be CloseCodeGoingAway + //meaning the socket will be closed + buffer.setData(data); + buffer.open(QIODevice::ReadOnly); + QSignalSpy errorSpy(&dataProcessor, + SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString))); + dataProcessor.process(&buffer); + + QCOMPARE(errorSpy.count(), 1); + QCOMPARE(closeSpy.count(), 0); + QCOMPARE(pingMessageSpy.count(), 0); + QCOMPARE(pongMessageSpy.count(), 0); + QCOMPARE(textMessageSpy.count(), 0); + QCOMPARE(binaryMessageSpy.count(), 0); + QCOMPARE(textFrameSpy.count(), 1); + QCOMPARE(binaryFrameSpy.count(), 0); + + QList arguments = errorSpy.takeFirst(); + QCOMPARE(arguments.at(0).value(), + QWebSocketProtocol::CloseCodeGoingAway); + errorSpy.clear(); + closeSpy.clear(); + pingMessageSpy.clear(); + pongMessageSpy.clear(); + textMessageSpy.clear(); + binaryMessageSpy.clear(); + textFrameSpy.clear(); + binaryFrameSpy.clear(); + buffer.close(); + data.clear(); + + //text frame with final bit not set + data.append((char)(QWebSocketProtocol::OpCodeText)).append(char(0x0)); + buffer.setData(data); + buffer.open(QIODevice::ReadOnly); + dataProcessor.process(&buffer); + + QCOMPARE(errorSpy.count(), 1); + QCOMPARE(closeSpy.count(), 0); + QCOMPARE(pingMessageSpy.count(), 0); + QCOMPARE(pongMessageSpy.count(), 0); + QCOMPARE(textMessageSpy.count(), 0); + QCOMPARE(binaryMessageSpy.count(), 0); + QCOMPARE(textFrameSpy.count(), 1); + QCOMPARE(binaryFrameSpy.count(), 0); + + buffer.close(); + data.clear(); + + errorSpy.clear(); + closeSpy.clear(); + pingMessageSpy.clear(); + pongMessageSpy.clear(); + textMessageSpy.clear(); + binaryMessageSpy.clear(); + textFrameSpy.clear(); + binaryFrameSpy.clear(); + + //only 1 byte follows in continuation frame; + //should time out with close code CloseCodeGoingAway + data.append('a'); + buffer.setData(data); + buffer.open(QIODevice::ReadOnly); + + dataProcessor.process(&buffer); + QCOMPARE(errorSpy.count(), 1); + QCOMPARE(closeSpy.count(), 0); + QCOMPARE(pingMessageSpy.count(), 0); + QCOMPARE(pongMessageSpy.count(), 0); + QCOMPARE(textMessageSpy.count(), 0); + QCOMPARE(binaryMessageSpy.count(), 0); + QCOMPARE(textFrameSpy.count(), 0); + QCOMPARE(binaryFrameSpy.count(), 0); + arguments = errorSpy.takeFirst(); + QCOMPARE(arguments.at(0).value(), + QWebSocketProtocol::CloseCodeGoingAway); + buffer.close(); + } +} + +void tst_DataProcessor::frameTooBig_data() +{ + QTest::addColumn("firstByte"); + QTest::addColumn("secondByte"); + QTest::addColumn("payload"); + QTest::addColumn("isContinuationFrame"); + QTest::addColumn("expectedCloseCode"); + + quint64 swapped64 = 0; + const char *wireRepresentation = 0; + + //only data frames are checked for being too big + //control frames have explicit checking on a maximum payload size of 125, + //which is tested elsewhere + + swapped64 = qToBigEndian(QWebSocketDataProcessor::maxFrameSize() + 1); + wireRepresentation = static_cast(static_cast(&swapped64)); + QTest::newRow("Text frame with payload size > INT_MAX") + << quint8(FIN | QWebSocketProtocol::OpCodeText) + << quint8(127) + << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a')) + << false + << QWebSocketProtocol::CloseCodeTooMuchData; + + swapped64 = qToBigEndian(QWebSocketDataProcessor::maxFrameSize() + 1); + wireRepresentation = static_cast(static_cast(&swapped64)); + QTest::newRow("Binary frame with payload size > INT_MAX") + << quint8(FIN | QWebSocketProtocol::OpCodeBinary) + << quint8(127) + << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a')) + << false + << QWebSocketProtocol::CloseCodeTooMuchData; + + swapped64 = qToBigEndian(QWebSocketDataProcessor::maxFrameSize() + 1); + wireRepresentation = static_cast(static_cast(&swapped64)); + QTest::newRow("Continuation frame with payload size > INT_MAX") + << quint8(FIN | QWebSocketProtocol::OpCodeContinue) + << quint8(127) + << QByteArray(wireRepresentation, 8).append(QByteArray(32, 'a')) + << true + << QWebSocketProtocol::CloseCodeTooMuchData; +} + +void tst_DataProcessor::frameTooBig() +{ + doTest(); +} + +void tst_DataProcessor::invalidHeader_data() +{ + //The first byte contain the FIN, RSV1, RSV2, RSV3 and the Opcode + //The second byte contains the MaskFlag and the length of the frame + QTest::addColumn("firstByte"); + QTest::addColumn("secondByte"); + //superfluous, but present to be able to call doTest(), which expects a payload field + QTest::addColumn("payload"); + QTest::addColumn("isContinuationFrame"); + QTest::addColumn("expectedCloseCode"); + + //invalid bit fields + invalidField("RSV1 set", RSV1); + invalidField("RSV2 set", RSV2); + invalidField("RSV3 set", RSV3); + invalidField("RSV1 and RSV2 set", RSV1 | RSV2); + invalidField("RSV1 and RSV3 set", RSV1 | RSV3); + invalidField("RSV2 and RSV3 set", RSV2 | RSV3); + invalidField("RSV1, RSV2 and RSV3 set", RSV1 | RSV2 | RSV3); + + //invalid opcodes + invalidField("Invalid OpCode 3", QWebSocketProtocol::OpCodeReserved3); + invalidField("Invalid OpCode 4", QWebSocketProtocol::OpCodeReserved4); + invalidField("Invalid OpCode 5", QWebSocketProtocol::OpCodeReserved5); + invalidField("Invalid OpCode 6", QWebSocketProtocol::OpCodeReserved6); + invalidField("Invalid OpCode 7", QWebSocketProtocol::OpCodeReserved7); + invalidField("Invalid OpCode B", QWebSocketProtocol::OpCodeReservedB); + invalidField("Invalid OpCode C", QWebSocketProtocol::OpCodeReservedC); + invalidField("Invalid OpCode D", QWebSocketProtocol::OpCodeReservedD); + invalidField("Invalid OpCode E", QWebSocketProtocol::OpCodeReservedE); + invalidField("Invalid OpCode F", QWebSocketProtocol::OpCodeReservedF); +} + +void tst_DataProcessor::invalidHeader() +{ + doTest(); +} + +void tst_DataProcessor::invalidControlFrame_data() +{ + QTest::addColumn("firstByte"); + QTest::addColumn("secondByte"); + QTest::addColumn("payload"); + QTest::addColumn("isContinuationFrame"); + QTest::addColumn("expectedCloseCode"); + + + QTest::newRow("Close control frame with payload size 126") + << quint8(FIN | QWebSocketProtocol::OpCodeClose) + << quint8(126) + << QByteArray() + << false + << QWebSocketProtocol::CloseCodeProtocolError; + QTest::newRow("Ping control frame with payload size 126") + << quint8(FIN | QWebSocketProtocol::OpCodePing) + << quint8(126) + << QByteArray() + << false + << QWebSocketProtocol::CloseCodeProtocolError; + QTest::newRow("Close control frame with payload size 126") + << quint8(FIN | QWebSocketProtocol::OpCodePong) + << quint8(126) + << QByteArray() + << false + << QWebSocketProtocol::CloseCodeProtocolError; + + QTest::newRow("Non-final close control frame (fragmented)") + << quint8(QWebSocketProtocol::OpCodeClose) + << quint8(32) + << QByteArray() + << false + << QWebSocketProtocol::CloseCodeProtocolError; + QTest::newRow("Non-final ping control frame (fragmented)") + << quint8(QWebSocketProtocol::OpCodePing) + << quint8(32) << QByteArray() + << false + << QWebSocketProtocol::CloseCodeProtocolError; + QTest::newRow("Non-final pong control frame (fragmented)") + << quint8(QWebSocketProtocol::OpCodePong) + << quint8(32) + << QByteArray() + << false + << QWebSocketProtocol::CloseCodeProtocolError; +} + +void tst_DataProcessor::invalidControlFrame() +{ + doTest(); +} + +void tst_DataProcessor::invalidCloseFrame_data() +{ + QTest::addColumn("firstByte"); + QTest::addColumn("secondByte"); + QTest::addColumn("payload"); + QTest::addColumn("isContinuationFrame"); + QTest::addColumn("expectedCloseCode"); + + QTest::newRow("Close control frame with payload size 1") + << quint8(FIN | QWebSocketProtocol::OpCodeClose) + << quint8(1) + << QByteArray(1, 'a') + << false + << QWebSocketProtocol::CloseCodeProtocolError; + quint16 swapped = qToBigEndian(QWebSocketProtocol::CloseCodeAbnormalDisconnection); + const char *wireRepresentation = static_cast(static_cast(&swapped)); + + //Not allowed per RFC 6455 (see para 7.4.1) + QTest::newRow("Close control frame close code ABNORMAL DISCONNECTION") + << quint8(FIN | QWebSocketProtocol::OpCodeClose) + << quint8(2) + << QByteArray(wireRepresentation, 2) + << false + << QWebSocketProtocol::CloseCodeProtocolError; + swapped = qToBigEndian(QWebSocketProtocol::CloseCodeMissingStatusCode); + wireRepresentation = static_cast(static_cast(&swapped)); + //Not allowed per RFC 6455 (see para 7.4.1) + QTest::newRow("Close control frame close code MISSING STATUS CODE") + << quint8(FIN | QWebSocketProtocol::OpCodeClose) + << quint8(2) + << QByteArray(wireRepresentation, 2) + << false + << QWebSocketProtocol::CloseCodeProtocolError; + swapped = qToBigEndian(1004); + wireRepresentation = static_cast(static_cast(&swapped)); + QTest::newRow("Close control frame close code 1004") + << quint8(FIN | QWebSocketProtocol::OpCodeClose) + << quint8(2) + << QByteArray(wireRepresentation, 2) + << false + << QWebSocketProtocol::CloseCodeProtocolError; + swapped = qToBigEndian(QWebSocketProtocol::CloseCodeTlsHandshakeFailed); + wireRepresentation = static_cast(static_cast(&swapped)); + //Not allowed per RFC 6455 (see para 7.4.1) + QTest::newRow("Close control frame close code TLS HANDSHAKE FAILED") + << quint8(FIN | QWebSocketProtocol::OpCodeClose) + << quint8(2) + << QByteArray(wireRepresentation, 2) + << false + << QWebSocketProtocol::CloseCodeProtocolError; + swapped = qToBigEndian(0); + wireRepresentation = static_cast(static_cast(&swapped)); + QTest::newRow("Close control frame close code 0") + << quint8(FIN | QWebSocketProtocol::OpCodeClose) + << quint8(2) + << QByteArray(wireRepresentation, 2) + << false + << QWebSocketProtocol::CloseCodeProtocolError; + swapped = qToBigEndian(999); + wireRepresentation = static_cast(static_cast(&swapped)); + QTest::newRow("Close control frame close code 999") + << quint8(FIN | QWebSocketProtocol::OpCodeClose) + << quint8(2) + << QByteArray(wireRepresentation, 2) + << false + << QWebSocketProtocol::CloseCodeProtocolError; + swapped = qToBigEndian(1012); + wireRepresentation = static_cast(static_cast(&swapped)); + QTest::newRow("Close control frame close code 1012") + << quint8(FIN | QWebSocketProtocol::OpCodeClose) + << quint8(2) + << QByteArray(wireRepresentation, 2) + << false + << QWebSocketProtocol::CloseCodeProtocolError; + swapped = qToBigEndian(1013); + wireRepresentation = static_cast(static_cast(&swapped)); + QTest::newRow("Close control frame close code 1013") + << quint8(FIN | QWebSocketProtocol::OpCodeClose) + << quint8(2) + << QByteArray(wireRepresentation, 2) + << false + << QWebSocketProtocol::CloseCodeProtocolError; + swapped = qToBigEndian(1014); + wireRepresentation = static_cast(static_cast(&swapped)); + QTest::newRow("Close control frame close code 1014") + << quint8(FIN | QWebSocketProtocol::OpCodeClose) + << quint8(2) + << QByteArray(wireRepresentation, 2) + << false + << QWebSocketProtocol::CloseCodeProtocolError; + swapped = qToBigEndian(1100); + wireRepresentation = static_cast(static_cast(&swapped)); + QTest::newRow("Close control frame close code 1100") + << quint8(FIN | QWebSocketProtocol::OpCodeClose) + << quint8(2) + << QByteArray(wireRepresentation, 2) + << false + << QWebSocketProtocol::CloseCodeProtocolError; + swapped = qToBigEndian(2000); + wireRepresentation = static_cast(static_cast(&swapped)); + QTest::newRow("Close control frame close code 2000") + << quint8(FIN | QWebSocketProtocol::OpCodeClose) + << quint8(2) + << QByteArray(wireRepresentation, 2) + << false + << QWebSocketProtocol::CloseCodeProtocolError; + swapped = qToBigEndian(2999); + wireRepresentation = static_cast(static_cast(&swapped)); + QTest::newRow("Close control frame close code 2999") + << quint8(FIN | QWebSocketProtocol::OpCodeClose) + << quint8(2) + << QByteArray(wireRepresentation, 2) + << false + << QWebSocketProtocol::CloseCodeProtocolError; + swapped = qToBigEndian(5000); + wireRepresentation = static_cast(static_cast(&swapped)); + QTest::newRow("Close control frame close code 5000") + << quint8(FIN | QWebSocketProtocol::OpCodeClose) + << quint8(2) + << QByteArray(wireRepresentation, 2) + << false + << QWebSocketProtocol::CloseCodeProtocolError; + swapped = qToBigEndian(65535u); + wireRepresentation = static_cast(static_cast(&swapped)); + QTest::newRow("Close control frame close code 65535") + << quint8(FIN | QWebSocketProtocol::OpCodeClose) + << quint8(2) + << QByteArray(wireRepresentation, 2) + << false + << QWebSocketProtocol::CloseCodeProtocolError; +} + +void tst_DataProcessor::invalidCloseFrame() +{ + doCloseFrameTest(); +} + +void tst_DataProcessor::minimumSizeRequirement_data() +{ + QTest::addColumn("firstByte"); + QTest::addColumn("secondByte"); + QTest::addColumn("payload"); + QTest::addColumn("isContinuationFrame"); + QTest::addColumn("expectedCloseCode"); + + minimumSize16Bit(0); + minimumSize16Bit(64); + minimumSize16Bit(125); + + minimumSize64Bit(0); + minimumSize64Bit(64); + minimumSize64Bit(125); + minimumSize64Bit(126); + minimumSize64Bit(256); + minimumSize64Bit(512); + minimumSize64Bit(1024); + minimumSize64Bit(2048); + minimumSize64Bit(4096); + minimumSize64Bit(8192); + minimumSize64Bit(16384); + minimumSize64Bit(32768); + minimumSize64Bit(0xFFFFu); +} + +void tst_DataProcessor::minimumSizeRequirement() +{ + doTest(); +} + +void tst_DataProcessor::invalidPayload_data(bool isControlFrame) +{ + QTest::addColumn("firstByte"); + QTest::addColumn("secondByte"); + QTest::addColumn("payload"); + QTest::addColumn("isContinuationFrame"); + QTest::addColumn("expectedCloseCode"); + + //6.3: invalid UTF-8 sequence + invalidUTF8("case 6.3.1", "cebae1bdb9cf83cebcceb5eda080656469746564", isControlFrame); + + //6.4.: fail fast tests; invalid UTF-8 in middle of string + invalidUTF8("case 6.4.1", "cebae1bdb9cf83cebcceb5f4908080656469746564", isControlFrame); + invalidUTF8("case 6.4.4", "cebae1bdb9cf83cebcceb5eda080656469746564", isControlFrame); + + //6.6: All prefixes of a valid UTF-8 string that contains multi-byte code points + invalidUTF8("case 6.6.1", "ce", isControlFrame); + invalidUTF8("case 6.6.3", "cebae1", isControlFrame); + invalidUTF8("case 6.6.4", "cebae1bd", isControlFrame); + invalidUTF8("case 6.6.6", "cebae1bdb9cf", isControlFrame); + invalidUTF8("case 6.6.8", "cebae1bdb9cf83ce", isControlFrame); + invalidUTF8("case 6.6.10", "cebae1bdb9cf83cebcce", isControlFrame); + + //6.8: First possible sequence length 5/6 (invalid codepoints) + invalidUTF8("case 6.8.1", "f888808080", isControlFrame); + invalidUTF8("case 6.8.2", "fc8480808080", isControlFrame); + + //6.10: Last possible sequence length 4/5/6 (invalid codepoints) + invalidUTF8("case 6.10.1", "f7bfbfbf", isControlFrame); + invalidUTF8("case 6.10.2", "fbbfbfbfbf", isControlFrame); + invalidUTF8("case 6.10.3", "fdbfbfbfbfbf", isControlFrame); + + //5.11: boundary conditions + invalidUTF8("case 6.11.5", "f4908080", isControlFrame); + + //6.12: unexpected continuation bytes + invalidUTF8("case 6.12.1", "80", isControlFrame); + invalidUTF8("case 6.12.2", "bf", isControlFrame); + invalidUTF8("case 6.12.3", "80bf", isControlFrame); + invalidUTF8("case 6.12.4", "80bf80", isControlFrame); + invalidUTF8("case 6.12.5", "80bf80bf", isControlFrame); + invalidUTF8("case 6.12.6", "80bf80bf80", isControlFrame); + invalidUTF8("case 6.12.7", "80bf80bf80bf", isControlFrame); + invalidUTF8("case 6.12.8", + "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a" + "7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbe", + isControlFrame); + + //6.13: lonely start characters + invalidUTF8("case 6.13.1", + "c020c120c220c320c420c520c620c720c820c920ca20cb20cc20cd20ce20cf20d020d120d220" + "d320d420d520d620d720d820d920da20db20dc20dd20de20", + isControlFrame); + invalidUTF8("case 6.13.2", "e020e120e220e320e420e520e620e720e820e920ea20eb20ec20ed20ee20", + isControlFrame); + invalidUTF8("case 6.13.3", "f020f120f220f320f420f520f620", isControlFrame); + invalidUTF8("case 6.13.4", "f820f920fa20", isControlFrame); + invalidUTF8("case 6.13.5", "fc20", isControlFrame); + + //6.14: sequences with last continuation byte missing + invalidUTF8("case 6.14.1", "c0", isControlFrame); + invalidUTF8("case 6.14.2", "e080", isControlFrame); + invalidUTF8("case 6.14.3", "f08080", isControlFrame); + invalidUTF8("case 6.14.4", "f8808080", isControlFrame); + invalidUTF8("case 6.14.5", "fc80808080", isControlFrame); + invalidUTF8("case 6.14.6", "df", isControlFrame); + invalidUTF8("case 6.14.7", "efbf", isControlFrame); + invalidUTF8("case 6.14.8", "f7bfbf", isControlFrame); + invalidUTF8("case 6.14.9", "fbbfbfbf", isControlFrame); + invalidUTF8("case 6.14.10", "fdbfbfbfbf", isControlFrame); + + //6.15: concatenation of incomplete sequences + invalidUTF8("case 6.15.1", + "c0e080f08080f8808080fc80808080dfefbff7bfbffbbfbfbffdbfbfbfbf", isControlFrame); + + //6.16: impossible bytes + invalidUTF8("case 6.16.1", "fe", isControlFrame); + invalidUTF8("case 6.16.2", "ff", isControlFrame); + invalidUTF8("case 6.16.3", "fefeffff", isControlFrame); + + //6.17: overlong ASCII characters + invalidUTF8("case 6.17.1", "c0af", isControlFrame); + invalidUTF8("case 6.17.2", "e080af", isControlFrame); + invalidUTF8("case 6.17.3", "f08080af", isControlFrame); + invalidUTF8("case 6.17.4", "f8808080af", isControlFrame); + invalidUTF8("case 6.17.5", "fc80808080af", isControlFrame); + + //6.18: maximum overlong sequences + invalidUTF8("case 6.18.1", "c1bf", isControlFrame); + invalidUTF8("case 6.18.2", "e09fbf", isControlFrame); + invalidUTF8("case 6.18.3", "f08fbfbf", isControlFrame); + invalidUTF8("case 6.18.4", "f887bfbfbf", isControlFrame); + invalidUTF8("case 6.18.5", "fc83bfbfbfbf", isControlFrame); + + //6.19: overlong presentation of the NUL character + invalidUTF8("case 6.19.1", "c080", isControlFrame); + invalidUTF8("case 6.19.2", "e08080", isControlFrame); + invalidUTF8("case 6.19.3", "f0808080", isControlFrame); + invalidUTF8("case 6.19.4", "f880808080", isControlFrame); + invalidUTF8("case 6.19.5", "fc8080808080", isControlFrame); + + //6.20: Single UTF-16 surrogates + invalidUTF8("case 6.20.1", "eda080", isControlFrame); + invalidUTF8("case 6.20.2", "edadbf", isControlFrame); + invalidUTF8("case 6.20.3", "edae80", isControlFrame); + invalidUTF8("case 6.20.4", "edafbf", isControlFrame); + invalidUTF8("case 6.20.5", "edb080", isControlFrame); + invalidUTF8("case 6.20.6", "edbe80", isControlFrame); + invalidUTF8("case 6.20.7", "edbfbf", isControlFrame); + + //6.21: Paired UTF-16 surrogates + invalidUTF8("case 6.21.1", "eda080edb080", isControlFrame); + invalidUTF8("case 6.21.2", "eda080edbfbf", isControlFrame); + invalidUTF8("case 6.21.3", "edadbfedb080", isControlFrame); + invalidUTF8("case 6.21.4", "edadbfedbfbf", isControlFrame); + invalidUTF8("case 6.21.5", "edae80edb080", isControlFrame); + invalidUTF8("case 6.21.6", "edae80edbfbf", isControlFrame); + invalidUTF8("case 6.21.7", "edafbfedb080", isControlFrame); + invalidUTF8("case 6.21.8", "edafbfedbfbf", isControlFrame); +} + +void tst_DataProcessor::invalidPayload() +{ + doTest(); +} + +void tst_DataProcessor::invalidPayloadInCloseFrame_data() +{ + invalidPayload_data(true); +} + +void tst_DataProcessor::invalidPayloadInCloseFrame() +{ + QFETCH(quint8, firstByte); + QFETCH(quint8, secondByte); + QFETCH(QByteArray, payload); + QFETCH(bool, isContinuationFrame); + QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode); + + Q_UNUSED(isContinuationFrame) + + QByteArray data; + QBuffer buffer; + QWebSocketDataProcessor dataProcessor; + QSignalSpy closeSpy(&dataProcessor, + SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString))); + QSignalSpy errorSpy(&dataProcessor, + SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString))); + QSignalSpy pingMessageSpy(&dataProcessor, SIGNAL(pingReceived(QByteArray))); + QSignalSpy pongMessageSpy(&dataProcessor, SIGNAL(pongReceived(QByteArray))); + QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString))); + QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray))); + QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool))); + QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool))); + + data.append(firstByte).append(secondByte); + data.append(payload); + buffer.setData(data); + buffer.open(QIODevice::ReadOnly); + dataProcessor.process(&buffer); + QCOMPARE(closeSpy.count(), 1); + QCOMPARE(errorSpy.count(), 0); + QCOMPARE(pingMessageSpy.count(), 0); + QCOMPARE(pongMessageSpy.count(), 0); + QCOMPARE(textMessageSpy.count(), 0); + QCOMPARE(binaryMessageSpy.count(), 0); + QCOMPARE(textFrameSpy.count(), 0); + QCOMPARE(binaryFrameSpy.count(), 0); + QVariantList arguments = closeSpy.takeFirst(); + QCOMPARE(arguments.at(0).value(), expectedCloseCode); + buffer.close(); +} + +void tst_DataProcessor::incompletePayload_data() +{ + QTest::addColumn("firstByte"); + QTest::addColumn("secondByte"); + QTest::addColumn("payload"); + QTest::addColumn("isContinuationFrame"); + QTest::addColumn("expectedCloseCode"); + + incompleteFrame(QWebSocketProtocol::OpCodeText, 125, 0); + incompleteFrame(QWebSocketProtocol::OpCodeText, 64, 32); + incompleteFrame(QWebSocketProtocol::OpCodeText, 256, 32); + incompleteFrame(QWebSocketProtocol::OpCodeText, 128000, 32); + incompleteFrame(QWebSocketProtocol::OpCodeBinary, 125, 0); + incompleteFrame(QWebSocketProtocol::OpCodeBinary, 64, 32); + incompleteFrame(QWebSocketProtocol::OpCodeBinary, 256, 32); + incompleteFrame(QWebSocketProtocol::OpCodeBinary, 128000, 32); + incompleteFrame(QWebSocketProtocol::OpCodeContinue, 125, 0); + incompleteFrame(QWebSocketProtocol::OpCodeContinue, 64, 32); + incompleteFrame(QWebSocketProtocol::OpCodeContinue, 256, 32); + incompleteFrame(QWebSocketProtocol::OpCodeContinue, 128000, 32); + + incompleteFrame(QWebSocketProtocol::OpCodeClose, 64, 32); + incompleteFrame(QWebSocketProtocol::OpCodePing, 64, 32); + incompleteFrame(QWebSocketProtocol::OpCodePong, 64, 32); +} + +void tst_DataProcessor::incompletePayload() +{ + doTest(); +} + +void tst_DataProcessor::incompleteSizeField_data() +{ + QTest::addColumn("firstByte"); + QTest::addColumn("secondByte"); + QTest::addColumn("payload"); + QTest::addColumn("isContinuationFrame"); + QTest::addColumn("expectedCloseCode"); + + //for a frame length value of 126 + //there should be 2 bytes following to form a 16-bit frame length + insertIncompleteSizeFieldTest(126, 0); + insertIncompleteSizeFieldTest(126, 1); + + //for a frame length value of 127 + //there should be 8 bytes following to form a 64-bit frame length + insertIncompleteSizeFieldTest(127, 0); + insertIncompleteSizeFieldTest(127, 1); + insertIncompleteSizeFieldTest(127, 2); + insertIncompleteSizeFieldTest(127, 3); + insertIncompleteSizeFieldTest(127, 4); + insertIncompleteSizeFieldTest(127, 5); + insertIncompleteSizeFieldTest(127, 6); + insertIncompleteSizeFieldTest(127, 7); +} + +void tst_DataProcessor::incompleteSizeField() +{ + doTest(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +/// HELPER FUNCTIONS +////////////////////////////////////////////////////////////////////////////////////////// +void tst_DataProcessor::doTest() +{ + QFETCH(quint8, firstByte); + QFETCH(quint8, secondByte); + QFETCH(QByteArray, payload); + QFETCH(bool, isContinuationFrame); + QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode); + + QByteArray data; + QBuffer buffer; + QWebSocketDataProcessor dataProcessor; + QSignalSpy errorSpy(&dataProcessor, + SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString))); + QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString))); + QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray))); + QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool))); + QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool))); + + if (isContinuationFrame) + { + data.append(quint8(QWebSocketProtocol::OpCodeText)) + .append(char(1)) + .append(QByteArray(1, 'a')); + } + data.append(firstByte).append(secondByte); + data.append(payload); + buffer.setData(data); + buffer.open(QIODevice::ReadOnly); + dataProcessor.process(&buffer); + QCOMPARE(errorSpy.count(), 1); + QCOMPARE(textMessageSpy.count(), 0); + QCOMPARE(binaryMessageSpy.count(), 0); + QCOMPARE(textFrameSpy.count(), isContinuationFrame ? 1 : 0); + QCOMPARE(binaryFrameSpy.count(), 0); + QVariantList arguments = errorSpy.takeFirst(); + QCOMPARE(arguments.at(0).value(), expectedCloseCode); + buffer.close(); + errorSpy.clear(); + data.clear(); +} + +void tst_DataProcessor::doCloseFrameTest() +{ + QFETCH(quint8, firstByte); + QFETCH(quint8, secondByte); + QFETCH(QByteArray, payload); + QFETCH(bool, isContinuationFrame); + QFETCH(QWebSocketProtocol::CloseCode, expectedCloseCode); + + Q_UNUSED(isContinuationFrame) + + QByteArray data; + QBuffer buffer; + QWebSocketDataProcessor dataProcessor; + QSignalSpy closeSpy(&dataProcessor, + SIGNAL(closeReceived(QWebSocketProtocol::CloseCode,QString))); + QSignalSpy errorSpy(&dataProcessor, + SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString))); + QSignalSpy textMessageSpy(&dataProcessor, SIGNAL(textMessageReceived(QString))); + QSignalSpy binaryMessageSpy(&dataProcessor, SIGNAL(binaryMessageReceived(QByteArray))); + QSignalSpy textFrameSpy(&dataProcessor, SIGNAL(textFrameReceived(QString,bool))); + QSignalSpy binaryFrameSpy(&dataProcessor, SIGNAL(binaryFrameReceived(QByteArray,bool))); + + data.append(firstByte).append(secondByte); + data.append(payload); + buffer.setData(data); + buffer.open(QIODevice::ReadOnly); + dataProcessor.process(&buffer); + QCOMPARE(closeSpy.count(), 1); + QCOMPARE(errorSpy.count(), 0); + QCOMPARE(textMessageSpy.count(), 0); + QCOMPARE(binaryMessageSpy.count(), 0); + QCOMPARE(textFrameSpy.count(), 0); + QCOMPARE(binaryFrameSpy.count(), 0); + QVariantList arguments = closeSpy.takeFirst(); + QCOMPARE(arguments.at(0).value(), expectedCloseCode); + buffer.close(); +} + +QString tst_DataProcessor::opCodeToString(quint8 opCode) +{ + QString frameType; + switch (opCode) + { + case QWebSocketProtocol::OpCodeBinary: + { + frameType = QStringLiteral("Binary"); + break; + } + case QWebSocketProtocol::OpCodeText: + { + frameType = QStringLiteral("Text"); + break; + } + case QWebSocketProtocol::OpCodePing: + { + frameType = QStringLiteral("Ping"); + break; + } + case QWebSocketProtocol::OpCodePong: + { + frameType = QStringLiteral("Pong"); + break; + } + case QWebSocketProtocol::OpCodeClose: + { + frameType = QStringLiteral("Close"); + break; + } + case QWebSocketProtocol::OpCodeContinue: + { + frameType = QStringLiteral("Continuation"); + break; + } + case QWebSocketProtocol::OpCodeReserved3: + { + frameType = QStringLiteral("Reserved3"); + break; + } + case QWebSocketProtocol::OpCodeReserved4: + { + frameType = QStringLiteral("Reserved5"); + break; + } + case QWebSocketProtocol::OpCodeReserved5: + { + frameType = QStringLiteral("Reserved5"); + break; + } + case QWebSocketProtocol::OpCodeReserved6: + { + frameType = QStringLiteral("Reserved6"); + break; + } + case QWebSocketProtocol::OpCodeReserved7: + { + frameType = QStringLiteral("Reserved7"); + break; + } + case QWebSocketProtocol::OpCodeReservedB: + { + frameType = QStringLiteral("ReservedB"); + break; + } + case QWebSocketProtocol::OpCodeReservedC: + { + frameType = QStringLiteral("ReservedC"); + break; + } + case QWebSocketProtocol::OpCodeReservedD: + { + frameType = QStringLiteral("ReservedD"); + break; + } + case QWebSocketProtocol::OpCodeReservedE: + { + frameType = QStringLiteral("ReservedE"); + break; + } + case QWebSocketProtocol::OpCodeReservedF: + { + frameType = QStringLiteral("ReservedF"); + break; + } + default: + { + //should never come here + Q_ASSERT(false); + } + } + return frameType; +} + +void tst_DataProcessor::minimumSize16Bit(quint16 sizeInBytes) +{ + quint16 swapped16 = qToBigEndian(sizeInBytes); + const char *wireRepresentation + = static_cast(static_cast(&swapped16)); + QTest::newRow(QStringLiteral("Text frame with payload size %1, represented in 2 bytes") + .arg(sizeInBytes).toLatin1().constData()) + << quint8(FIN | QWebSocketProtocol::OpCodeText) + << quint8(126) + << QByteArray(wireRepresentation, 2) + << false + << QWebSocketProtocol::CloseCodeProtocolError; + QTest::newRow(QStringLiteral("Binary frame with payload size %1, represented in 2 bytes") + .arg(sizeInBytes).toLatin1().constBegin()) + << quint8(FIN | QWebSocketProtocol::OpCodeBinary) + << quint8(126) + << QByteArray(wireRepresentation, 2) + << false + << QWebSocketProtocol::CloseCodeProtocolError; + QTest::newRow(QStringLiteral("Continuation frame with payload size %1, represented in 2 bytes") + .arg(sizeInBytes).toLatin1().constData()) + << quint8(FIN | QWebSocketProtocol::OpCodeContinue) + << quint8(126) + << QByteArray(wireRepresentation, 2) + << true + << QWebSocketProtocol::CloseCodeProtocolError; +} + +void tst_DataProcessor::minimumSize64Bit(quint64 sizeInBytes) +{ + quint64 swapped64 = qToBigEndian(sizeInBytes); + const char *wireRepresentation + = static_cast(static_cast(&swapped64)); + + QTest::newRow(QStringLiteral("Text frame with payload size %1, represented in 8 bytes") + .arg(sizeInBytes).toLatin1().constData()) + << quint8(FIN | QWebSocketProtocol::OpCodeText) + << quint8(127) + << QByteArray(wireRepresentation, 8) + << false + << QWebSocketProtocol::CloseCodeProtocolError; + + QTest::newRow(QStringLiteral("Binary frame with payload size %1, represented in 8 bytes") + .arg(sizeInBytes).toLatin1().constData()) + << quint8(FIN | QWebSocketProtocol::OpCodeBinary) + << quint8(127) + << QByteArray(wireRepresentation, 8) + << false + << QWebSocketProtocol::CloseCodeProtocolError; + + QTest::newRow(QStringLiteral("Continuation frame with payload size %1, represented in 8 bytes") + .arg(sizeInBytes).toLatin1().constData()) + << quint8(FIN | QWebSocketProtocol::OpCodeContinue) + << quint8(127) + << QByteArray(wireRepresentation, 8) + << true + << QWebSocketProtocol::CloseCodeProtocolError; +} + +void tst_DataProcessor::invalidUTF8(const char *dataTag, const char *utf8Sequence, + bool isCloseFrame) +{ + QByteArray payload = QByteArray::fromHex(utf8Sequence); + + if (isCloseFrame) + { + quint16 closeCode = qToBigEndian(QWebSocketProtocol::CloseCodeNormal); + const char *wireRepresentation + = static_cast(static_cast(&closeCode)); + QTest::newRow(QStringLiteral("Close frame with invalid UTF8-sequence: %1") + .arg(dataTag).toLatin1().constData()) + << quint8(FIN | QWebSocketProtocol::OpCodeClose) + << quint8(payload.length() + 2) + << QByteArray(wireRepresentation, 2).append(payload) + << false + << QWebSocketProtocol::CloseCodeWrongDatatype; + } + else + { + QTest::newRow(QStringLiteral("Text frame with invalid UTF8-sequence: %1") + .arg(dataTag).toLatin1().constData()) + << quint8(FIN | QWebSocketProtocol::OpCodeText) + << quint8(payload.length()) + << payload + << false + << QWebSocketProtocol::CloseCodeWrongDatatype; + + QTest::newRow(QStringLiteral("Continuation text frame with invalid UTF8-sequence: %1") + .arg(dataTag).toLatin1().constData()) + << quint8(FIN | QWebSocketProtocol::OpCodeContinue) + << quint8(payload.length()) + << payload + << true + << QWebSocketProtocol::CloseCodeWrongDatatype; + } +} + +void tst_DataProcessor::invalidField(const char *dataTag, quint8 invalidFieldValue) +{ + QTest::newRow(dataTag) << quint8(FIN | invalidFieldValue) + << quint8(0x00) + << QByteArray() + << false + << QWebSocketProtocol::CloseCodeProtocolError; + QTest::newRow(QString::fromLatin1(dataTag).append(QStringLiteral(" with continuation frame")) + .toLatin1().constData()) + << quint8(FIN | invalidFieldValue) + << quint8(0x00) + << QByteArray() + << true + << QWebSocketProtocol::CloseCodeProtocolError; +} + +void tst_DataProcessor::incompleteFrame(quint8 controlCode, quint64 indicatedSize, + quint64 actualPayloadSize) +{ + QVERIFY(!QWebSocketProtocol::isOpCodeReserved(QWebSocketProtocol::OpCode(controlCode))); + QVERIFY(indicatedSize > actualPayloadSize); + + QString frameType = opCodeToString(controlCode); + QByteArray firstFrame; + + if (indicatedSize < 126) + { + //doing extensive QStringLiteral concatenations here, because + //MSVC 2010 complains when using concatenation literal strings about + //concatenation of wide and narrow strings (error C2308) + QTest::newRow(frameType + .append(QStringLiteral(" frame with payload size %1, but only %2 bytes") + + QStringLiteral(" of data") + .arg(indicatedSize).arg(actualPayloadSize)).toLatin1().constData()) + << quint8(FIN | controlCode) + << quint8(indicatedSize) + << firstFrame.append(QByteArray(actualPayloadSize, 'a')) + << (controlCode == QWebSocketProtocol::OpCodeContinue) + << QWebSocketProtocol::CloseCodeGoingAway; + } + else if (indicatedSize <= 0xFFFFu) + { + quint16 swapped16 = qToBigEndian(static_cast(indicatedSize)); + const char *wireRepresentation + = static_cast(static_cast(&swapped16)); + QTest::newRow( + frameType.append(QStringLiteral(" frame with payload size %1, but only ") + + QStringLiteral("%2 bytes of data") + .arg(indicatedSize) + .arg(actualPayloadSize)).toLatin1().constData()) + << quint8(FIN | controlCode) + << quint8(126) + << firstFrame.append(QByteArray(wireRepresentation, 2) + .append(QByteArray(actualPayloadSize, 'a'))) + << (controlCode == QWebSocketProtocol::OpCodeContinue) + << QWebSocketProtocol::CloseCodeGoingAway; + } + else + { + quint64 swapped64 = qToBigEndian(indicatedSize); + const char *wireRepresentation + = static_cast(static_cast(&swapped64)); + QTest::newRow(frameType + .append(QStringLiteral(" frame with payload size %1, but only %2 bytes ") + + QStringLiteral("of data") + .arg(indicatedSize).arg(actualPayloadSize)).toLatin1().constData()) + << quint8(FIN | controlCode) + << quint8(127) + << firstFrame.append(QByteArray(wireRepresentation, 8) + .append(QByteArray(actualPayloadSize, 'a'))) + << (controlCode == QWebSocketProtocol::OpCodeContinue) + << QWebSocketProtocol::CloseCodeGoingAway; + } +} + +void tst_DataProcessor::nonCharacterSequence(const char *sequence) +{ + QByteArray utf8Sequence = QByteArray::fromHex(sequence); + + //doing extensive QStringLiteral concatenations here, because + //MSVC 2010 complains when using concatenation literal strings about + //concatenation of wide and narrow strings (error C2308) + QTest::newRow((QStringLiteral("Text frame with payload containing the non-control character ") + + QStringLiteral("sequence 0x%1")) + .arg(QString::fromLocal8Bit(sequence)).toLatin1().constData()) + << quint8(FIN | QWebSocketProtocol::OpCodeText) + << quint8(utf8Sequence.size()) + << utf8Sequence + << false; + + QTest::newRow((QStringLiteral("Continuation frame with payload containing the non-control ") + + QStringLiteral("character sequence 0x%1")) + .arg(QString::fromLocal8Bit(sequence)).toLatin1().constData()) + << quint8(FIN | QWebSocketProtocol::OpCodeContinue) + << quint8(utf8Sequence.size()) + << utf8Sequence + << true; +} + +void tst_DataProcessor::insertIncompleteSizeFieldTest(quint8 payloadCode, quint8 numBytesFollowing) +{ + //doing extensive QStringLiteral concatenations here, because + //MSVC 2010 complains when using concatenation literal strings about + //concatenation of wide and narrow strings (error C2308) + QTest::newRow(QStringLiteral("Text frame with payload size %1, with %2 bytes following.") + .arg(payloadCode).arg(numBytesFollowing).toLatin1().constData()) + << quint8(FIN | QWebSocketProtocol::OpCodeText) + << quint8(payloadCode) + << QByteArray(numBytesFollowing, quint8(1)) + << false + << QWebSocketProtocol::CloseCodeGoingAway; + QTest::newRow(QStringLiteral("Binary frame with payload size %1, with %2 bytes following.") + .arg(payloadCode).arg(numBytesFollowing).toLatin1().constData()) + << quint8(FIN | QWebSocketProtocol::OpCodeBinary) + << quint8(payloadCode) + << QByteArray(numBytesFollowing, quint8(1)) + << false + << QWebSocketProtocol::CloseCodeGoingAway; + QTest::newRow((QStringLiteral("Continuation frame with payload size %1, with %2 bytes ") + + QStringLiteral("following.")) + .arg(payloadCode).arg(numBytesFollowing).toLatin1().constData()) + << quint8(FIN | QWebSocketProtocol::OpCodeContinue) + << quint8(payloadCode) + << QByteArray(numBytesFollowing, quint8(1)) + << true + << QWebSocketProtocol::CloseCodeGoingAway; +} + +QTEST_MAIN(tst_DataProcessor) + +#include "tst_dataprocessor.moc" diff --git a/tests/auto/websockets/handshakerequest/handshakerequest.pro b/tests/auto/websockets/handshakerequest/handshakerequest.pro new file mode 100644 index 0000000..d887cd6 --- /dev/null +++ b/tests/auto/websockets/handshakerequest/handshakerequest.pro @@ -0,0 +1,14 @@ +CONFIG += console +CONFIG += testcase +CONFIG -= app_bundle + +TEMPLATE = app + +TARGET = tst_handshakerequest + +QT = core testlib websockets websockets-private + +SOURCES += tst_handshakerequest.cpp + +requires(contains(QT_CONFIG, private_tests)) +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/websockets/handshakerequest/tst_handshakerequest.cpp b/tests/auto/websockets/handshakerequest/tst_handshakerequest.cpp new file mode 100644 index 0000000..9c579bd --- /dev/null +++ b/tests/auto/websockets/handshakerequest/tst_handshakerequest.cpp @@ -0,0 +1,317 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Kurt Pattyn . +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include +#include +#include +#include + +#include "private/qwebsockethandshakerequest_p.h" +#include "private/qwebsocketprotocol_p.h" +#include "QtWebSockets/qwebsocketprotocol.h" + +QT_USE_NAMESPACE + +Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode) +Q_DECLARE_METATYPE(QWebSocketProtocol::OpCode) + +class tst_HandshakeRequest : public QObject +{ + Q_OBJECT + +public: + tst_HandshakeRequest(); + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + + void tst_initialization(); + + void tst_invalidStream_data(); + void tst_invalidStream(); + + void tst_multipleValuesInConnectionHeader(); + void tst_multipleVersions(); + + void tst_qtbug_39355(); +}; + +tst_HandshakeRequest::tst_HandshakeRequest() +{} + +void tst_HandshakeRequest::initTestCase() +{ +} + +void tst_HandshakeRequest::cleanupTestCase() +{} + +void tst_HandshakeRequest::init() +{ + qRegisterMetaType("QWebSocketProtocol::OpCode"); + qRegisterMetaType("QWebSocketProtocol::CloseCode"); +} + +void tst_HandshakeRequest::cleanup() +{ +} + +void tst_HandshakeRequest::tst_initialization() +{ + { + QWebSocketHandshakeRequest request(0, false); + QCOMPARE(request.port(), 0); + QVERIFY(!request.isSecure()); + QVERIFY(!request.isValid()); + QCOMPARE(request.extensions().length(), 0); + QCOMPARE(request.protocols().length(), 0); + QCOMPARE(request.headers().size(), 0); + QCOMPARE(request.key().length(), 0); + QCOMPARE(request.origin().length(), 0); + QCOMPARE(request.host().length(), 0); + QVERIFY(request.requestUrl().isEmpty()); + QCOMPARE(request.resourceName().length(), 0); + QCOMPARE(request.versions().length(), 0); + } + { + QWebSocketHandshakeRequest request(80, true); + QCOMPARE(request.port(), 80); + QVERIFY(request.isSecure()); + QVERIFY(!request.isValid()); + QCOMPARE(request.extensions().length(), 0); + QCOMPARE(request.protocols().length(), 0); + QCOMPARE(request.headers().size(), 0); + QCOMPARE(request.key().length(), 0); + QCOMPARE(request.origin().length(), 0); + QCOMPARE(request.host().length(), 0); + QVERIFY(request.requestUrl().isEmpty()); + QCOMPARE(request.resourceName().length(), 0); + QCOMPARE(request.versions().length(), 0); + } + { + QWebSocketHandshakeRequest request(80, true); + request.clear(); + QCOMPARE(request.port(), 80); + QVERIFY(request.isSecure()); + QVERIFY(!request.isValid()); + QCOMPARE(request.extensions().length(), 0); + QCOMPARE(request.protocols().length(), 0); + QCOMPARE(request.headers().size(), 0); + QCOMPARE(request.key().length(), 0); + QCOMPARE(request.origin().length(), 0); + QCOMPARE(request.host().length(), 0); + QVERIFY(request.requestUrl().isEmpty()); + QCOMPARE(request.resourceName().length(), 0); + QCOMPARE(request.versions().length(), 0); + } +} + +void tst_HandshakeRequest::tst_invalidStream_data() +{ + QTest::addColumn("dataStream"); + + QTest::newRow("garbage on 2 lines") << QStringLiteral("foofoofoo\r\nfoofoo\r\n\r\n"); + QTest::newRow("garbage on 1 line") << QStringLiteral("foofoofoofoofoo"); + QTest::newRow("Correctly formatted but invalid fields") + << QStringLiteral("VERB RESOURCE PROTOCOL"); + + //internally the fields are parsed and indexes are used to convert + //to a http version for instance + //this test checks if there doesn't occur an out-of-bounds exception + QTest::newRow("Correctly formatted but invalid short fields") << QStringLiteral("V R P"); + QTest::newRow("Invalid \\0 character in header") << QStringLiteral("V R\0 P"); + QTest::newRow("Invalid HTTP version in header") << QStringLiteral("V R HTTP/invalid"); + QTest::newRow("Empty header field") << QStringLiteral("GET . HTTP/1.1\r\nHEADER: "); + QTest::newRow("All zeros") << QString::fromUtf8(QByteArray(10, char(0))); + QTest::newRow("Invalid hostname") << QStringLiteral("GET . HTTP/1.1\r\nHost: \xFF\xFF"); + //doing extensive QStringLiteral concatenations here, because + //MSVC 2010 complains when using concatenation literal strings about + //concatenation of wide and narrow strings (error C2308) + QTest::newRow("Complete header - Invalid WebSocket version") + << QStringLiteral("GET . HTTP/1.1\r\nHost: foo\r\nSec-WebSocket-Version: ") + + QStringLiteral("\xFF\xFF\r\n") + + QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") + + QStringLiteral("Upgrade: websocket\r\n") + + QStringLiteral("Connection: Upgrade\r\n\r\n"); + QTest::newRow("Complete header - Invalid verb") + << QStringLiteral("XXX . HTTP/1.1\r\nHost: foo\r\nSec-WebSocket-Version: 13\r\n") + + QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") + + QStringLiteral("Upgrade: websocket\r\n") + + QStringLiteral("Connection: Upgrade\r\n\r\n"); + QTest::newRow("Complete header - Invalid HTTP version") + << QStringLiteral("GET . HTTP/a.1\r\nHost: foo\r\nSec-WebSocket-Version: 13\r\n") + + QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") + + QStringLiteral("Upgrade: websocket\r\n") + + QStringLiteral("Connection: Upgrade\r\n\r\n"); + QTest::newRow("Complete header - Invalid connection") + << QStringLiteral("GET . HTTP/1.1\r\nHost: foo\r\nSec-WebSocket-Version: 13\r\n") + + QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") + + QStringLiteral("Upgrade: websocket\r\n") + + QStringLiteral("Connection: xxxxxxx\r\n\r\n"); + QTest::newRow("Complete header - Invalid upgrade") + << QStringLiteral("GET . HTTP/1.1\r\nHost: foo\r\nSec-WebSocket-Version: 13\r\n") + + QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") + + QStringLiteral("Upgrade: wabsocket\r\n") + + QStringLiteral("Connection: Upgrade\r\n\r\n"); + QTest::newRow("Complete header - Upgrade contains too many values") + << QStringLiteral("GET . HTTP/1.1\r\nHost: foo\r\nSec-WebSocket-Version: 13\r\n") + + QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") + + QStringLiteral("Upgrade: websocket,ftp\r\n") + + QStringLiteral("Connection: Upgrade\r\n\r\n"); +} + +void tst_HandshakeRequest::tst_invalidStream() +{ + QFETCH(QString, dataStream); + + QByteArray data; + QTextStream textStream(&data); + QWebSocketHandshakeRequest request(80, true); + + textStream << dataStream; + textStream.seek(0); + request.readHandshake(textStream); + + QVERIFY(!request.isValid()); + QCOMPARE(request.port(), 80); + QVERIFY(request.isSecure()); + QCOMPARE(request.extensions().length(), 0); + QCOMPARE(request.protocols().length(), 0); + QCOMPARE(request.headers().size(), 0); + QCOMPARE(request.key().length(), 0); + QCOMPARE(request.origin().length(), 0); + QCOMPARE(request.host().length(), 0); + QVERIFY(request.requestUrl().isEmpty()); + QCOMPARE(request.resourceName().length(), 0); + QCOMPARE(request.versions().length(), 0); +} + +/* + * This is a regression test + * Checks for validity when more than one value is present in Connection + */ +void tst_HandshakeRequest::tst_multipleValuesInConnectionHeader() +{ + //doing extensive QStringLiteral concatenations here, because + //MSVC 2010 complains when using concatenation literal strings about + //concatenation of wide and narrow strings (error C2308) + QString header = QStringLiteral("GET /test HTTP/1.1\r\nHost: ") + + QStringLiteral("foo.com\r\nSec-WebSocket-Version: 13\r\n") + + QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") + + QStringLiteral("Upgrade: websocket\r\n") + + QStringLiteral("Connection: Upgrade,keepalive\r\n\r\n"); + QByteArray data; + QTextStream textStream(&data); + QWebSocketHandshakeRequest request(80, false); + + textStream << header; + textStream.seek(0); + request.readHandshake(textStream); + + QVERIFY(request.isValid()); + QCOMPARE(request.port(), 80); + QVERIFY(!request.isSecure()); + QCOMPARE(request.extensions().length(), 0); + QCOMPARE(request.protocols().length(), 0); + QCOMPARE(request.headers().size(), 5); + QCOMPARE(request.key().length(), 9); + QCOMPARE(request.origin().length(), 0); + QCOMPARE(request.requestUrl(), QUrl("ws://foo.com/test")); + QCOMPARE(request.host(), QStringLiteral("foo.com")); + QCOMPARE(request.resourceName().length(), 5); + QCOMPARE(request.versions().length(), 1); + QCOMPARE(request.versions().at(0), QWebSocketProtocol::Version13); +} + +void tst_HandshakeRequest::tst_multipleVersions() +{ + QString header = QStringLiteral("GET /test HTTP/1.1\r\nHost: foo.com\r\n") + + QStringLiteral("Sec-WebSocket-Version: 4, 5, 6, 7, 8, 13\r\n") + + QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") + + QStringLiteral("Upgrade: websocket\r\n") + + QStringLiteral("Connection: Upgrade,keepalive\r\n\r\n"); + QByteArray data; + QTextStream textStream(&data); + QWebSocketHandshakeRequest request(80, false); + + textStream << header; + textStream.seek(0); + request.readHandshake(textStream); + + QVERIFY(request.isValid()); + QCOMPARE(request.port(), 80); + QVERIFY(!request.isSecure()); + QCOMPARE(request.extensions().length(), 0); + QCOMPARE(request.protocols().length(), 0); + QCOMPARE(request.headers().size(), 5); + QVERIFY(request.headers().contains(QStringLiteral("host"))); + QVERIFY(request.headers().contains(QStringLiteral("sec-websocket-version"))); + QVERIFY(request.headers().contains(QStringLiteral("sec-websocket-key"))); + QVERIFY(request.headers().contains(QStringLiteral("upgrade"))); + QVERIFY(request.headers().contains(QStringLiteral("connection"))); + QCOMPARE(request.key(), QStringLiteral("AVDFBDDFF")); + QCOMPARE(request.origin().length(), 0); + QCOMPARE(request.requestUrl(), QUrl("ws://foo.com/test")); + QCOMPARE(request.host(), QStringLiteral("foo.com")); + QCOMPARE(request.resourceName().length(), 5); + QCOMPARE(request.versions().length(), 6); + //should be 13 since the list is ordered in decreasing order + QCOMPARE(request.versions().at(0), QWebSocketProtocol::Version13); +} + +void tst_HandshakeRequest::tst_qtbug_39355() +{ + QString header = QStringLiteral("GET /ABC/DEF/ HTTP/1.1\r\nHost: localhost:1234\r\n") + + QStringLiteral("Sec-WebSocket-Version: 13\r\n") + + QStringLiteral("Sec-WebSocket-Key: 2Wg20829/4ziWlmsUAD8Dg==\r\n") + + QStringLiteral("Upgrade: websocket\r\n") + + QStringLiteral("Connection: Upgrade\r\n\r\n"); + QByteArray data; + QTextStream textStream(&data); + QWebSocketHandshakeRequest request(8080, false); + + textStream << header; + textStream.seek(0); + request.readHandshake(textStream); + + QVERIFY(request.isValid()); + QCOMPARE(request.port(), 1234); + QCOMPARE(request.host(), QStringLiteral("localhost")); +} + +QTEST_MAIN(tst_HandshakeRequest) + +#include "tst_handshakerequest.moc" diff --git a/tests/auto/websockets/handshakeresponse/handshakeresponse.pro b/tests/auto/websockets/handshakeresponse/handshakeresponse.pro new file mode 100644 index 0000000..4d7cd50 --- /dev/null +++ b/tests/auto/websockets/handshakeresponse/handshakeresponse.pro @@ -0,0 +1,14 @@ +CONFIG += console +CONFIG += testcase +CONFIG -= app_bundle + +TEMPLATE = app + +TARGET = tst_handshakeresponse + +QT = core testlib websockets websockets-private + +SOURCES += tst_handshakeresponse.cpp + +requires(contains(QT_CONFIG, private_tests)) +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/websockets/handshakeresponse/tst_handshakeresponse.cpp b/tests/auto/websockets/handshakeresponse/tst_handshakeresponse.cpp new file mode 100644 index 0000000..b5f103b --- /dev/null +++ b/tests/auto/websockets/handshakeresponse/tst_handshakeresponse.cpp @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Kurt Pattyn . +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include +#include +#include +#include + +#include "private/qwebsockethandshakerequest_p.h" +#include "private/qwebsockethandshakeresponse_p.h" +#include "private/qwebsocketprotocol_p.h" +#include "QtWebSockets/qwebsocketprotocol.h" + +QT_USE_NAMESPACE + +Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode) +Q_DECLARE_METATYPE(QWebSocketProtocol::OpCode) + +class tst_HandshakeResponse : public QObject +{ + Q_OBJECT + +public: + tst_HandshakeResponse(); + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + + void tst_date_response(); +}; + +tst_HandshakeResponse::tst_HandshakeResponse() +{} + +void tst_HandshakeResponse::initTestCase() +{ +} + +void tst_HandshakeResponse::cleanupTestCase() +{} + +void tst_HandshakeResponse::init() +{ + qRegisterMetaType("QWebSocketProtocol::OpCode"); + qRegisterMetaType("QWebSocketProtocol::CloseCode"); +} + +void tst_HandshakeResponse::cleanup() +{ +} + +void tst_HandshakeResponse::tst_date_response() +{ + QWebSocketHandshakeRequest request(80, false); + QString buffer; + QTextStream input(&buffer); + input << QStringLiteral("GET / HTTP/1.1\r\nHost: example.com\r\nSec-WebSocket-Version: 13\r\n") + + QStringLiteral("Sec-WebSocket-Key: AVDFBDDFF\r\n") + + QStringLiteral("Upgrade: websocket\r\n") + + QStringLiteral("Connection: Upgrade\r\n\r\n"); + request.readHandshake(input); + + QWebSocketHandshakeResponse response(request, "example.com", true, + QList() << QWebSocketProtocol::Version13, + QList(), + QList()); + QString data; + QTextStream output(&data); + output << response; + + QStringList list = data.split("\r\n"); + int index = list.indexOf(QRegExp("Date:.*")); + QVERIFY(index > -1); + QVERIFY(QLocale::c().toDateTime(list[index], "'Date:' ddd, dd MMM yyyy hh:mm:ss 'GMT'").isValid()); +} + +QTEST_MAIN(tst_HandshakeResponse) + +#include "tst_handshakeresponse.moc" diff --git a/tests/auto/websockets/qdefaultmaskgenerator/qdefaultmaskgenerator.pro b/tests/auto/websockets/qdefaultmaskgenerator/qdefaultmaskgenerator.pro new file mode 100644 index 0000000..3a951a7 --- /dev/null +++ b/tests/auto/websockets/qdefaultmaskgenerator/qdefaultmaskgenerator.pro @@ -0,0 +1,14 @@ +CONFIG += console +CONFIG += testcase +CONFIG -= app_bundle + +TEMPLATE = app + +TARGET = tst_defaultmaskgenerator + +QT = core testlib websockets websockets-private + +SOURCES += tst_defaultmaskgenerator.cpp + +requires(contains(QT_CONFIG, private_tests)) +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/websockets/qdefaultmaskgenerator/tst_defaultmaskgenerator.cpp b/tests/auto/websockets/qdefaultmaskgenerator/tst_defaultmaskgenerator.cpp new file mode 100644 index 0000000..f5fc5c4 --- /dev/null +++ b/tests/auto/websockets/qdefaultmaskgenerator/tst_defaultmaskgenerator.cpp @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Kurt Pattyn . +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include +#include +#include +#include +#include + +#include "private/qdefaultmaskgenerator_p.h" + +QT_USE_NAMESPACE + +class tst_QDefaultMaskGenerator : public QObject +{ + Q_OBJECT + +public: + tst_QDefaultMaskGenerator(); + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + + void tst_randomnessWithoutSeed(); + void tst_randomnessWithSeed(); + +private: +}; + + + +tst_QDefaultMaskGenerator::tst_QDefaultMaskGenerator() +{ +} + +void tst_QDefaultMaskGenerator::initTestCase() +{ +} + +void tst_QDefaultMaskGenerator::cleanupTestCase() +{ +} + +void tst_QDefaultMaskGenerator::init() +{ +} + +void tst_QDefaultMaskGenerator::cleanup() +{ +} + +void tst_QDefaultMaskGenerator::tst_randomnessWithoutSeed() +{ + //generate two series of data, and see if they differ + { + QDefaultMaskGenerator generator; + + QVector series1, series2; + for (int i = 0; i < 1000; ++i) + series1 << generator.nextMask(); + for (int i = 0; i < 1000; ++i) + series2 << generator.nextMask(); + + QVERIFY(series1 != series2); + } +} + +void tst_QDefaultMaskGenerator::tst_randomnessWithSeed() +{ + //generate two series of data, and see if they differ + //the generator is seeded + { + QDefaultMaskGenerator generator; + generator.seed(); + + QVector series1, series2; + for (int i = 0; i < 1000; ++i) + series1 << generator.nextMask(); + for (int i = 0; i < 1000; ++i) + series2 << generator.nextMask(); + + QVERIFY(series1 != series2); + } + //generates two series of data with 2 distinct generators + //both generators are seeded + { + QDefaultMaskGenerator generator1, generator2; + generator1.seed(); + generator2.seed(); + + QVector series1, series2; + for (int i = 0; i < 1000; ++i) { + series1 << generator1.nextMask(); + series2 << generator2.nextMask(); + } + + QVERIFY(series1 != series2); + } + //generates two series of data with 2 distinct generators + //only one of the two is seeded + { + QDefaultMaskGenerator generator1, generator2; + generator1.seed(); + + QVector series1, series2; + for (int i = 0; i < 1000; ++i) { + series1 << generator1.nextMask(); + series2 << generator2.nextMask(); + } + + QVERIFY(series1 != series2); + } +} + +QTEST_MAIN(tst_QDefaultMaskGenerator) + +#include "tst_defaultmaskgenerator.moc" diff --git a/tests/auto/websockets/qwebsocket/qwebsocket.pro b/tests/auto/websockets/qwebsocket/qwebsocket.pro new file mode 100644 index 0000000..0155d08 --- /dev/null +++ b/tests/auto/websockets/qwebsocket/qwebsocket.pro @@ -0,0 +1,13 @@ +CONFIG += console +CONFIG += testcase +CONFIG -= app_bundle + +QT = core testlib websockets + +TARGET = tst_qwebsocket + +TEMPLATE = app + +SOURCES += tst_qwebsocket.cpp + +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp b/tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp new file mode 100644 index 0000000..aca25d0 --- /dev/null +++ b/tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp @@ -0,0 +1,605 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Kurt Pattyn . +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include +#include +#include +#include + +QT_USE_NAMESPACE + +Q_DECLARE_METATYPE(QWebSocketProtocol::Version) + +class EchoServer : public QObject +{ + Q_OBJECT +public: + explicit EchoServer(QObject *parent = Q_NULLPTR); + ~EchoServer(); + + QHostAddress hostAddress() const { return m_pWebSocketServer->serverAddress(); } + quint16 port() const { return m_pWebSocketServer->serverPort(); } + +Q_SIGNALS: + void newConnection(QUrl requestUrl); + +private Q_SLOTS: + void onNewConnection(); + void processTextMessage(QString message); + void processBinaryMessage(QByteArray message); + void socketDisconnected(); + +private: + QWebSocketServer *m_pWebSocketServer; + QList m_clients; +}; + +EchoServer::EchoServer(QObject *parent) : + QObject(parent), + m_pWebSocketServer(new QWebSocketServer(QStringLiteral("Echo Server"), + QWebSocketServer::NonSecureMode, this)), + m_clients() +{ + if (m_pWebSocketServer->listen(QHostAddress(QStringLiteral("127.0.0.1")))) { + connect(m_pWebSocketServer, SIGNAL(newConnection()), + this, SLOT(onNewConnection())); + } +} + +EchoServer::~EchoServer() +{ + m_pWebSocketServer->close(); + qDeleteAll(m_clients.begin(), m_clients.end()); +} + +void EchoServer::onNewConnection() +{ + QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection(); + + Q_EMIT newConnection(pSocket->requestUrl()); + + connect(pSocket, SIGNAL(textMessageReceived(QString)), this, SLOT(processTextMessage(QString))); + connect(pSocket, SIGNAL(binaryMessageReceived(QByteArray)), this, SLOT(processBinaryMessage(QByteArray))); + connect(pSocket, SIGNAL(disconnected()), this, SLOT(socketDisconnected())); + + m_clients << pSocket; +} + +void EchoServer::processTextMessage(QString message) +{ + QWebSocket *pClient = qobject_cast(sender()); + if (pClient) { + pClient->sendTextMessage(message); + } +} + +void EchoServer::processBinaryMessage(QByteArray message) +{ + QWebSocket *pClient = qobject_cast(sender()); + if (pClient) { + pClient->sendBinaryMessage(message); + } +} + +void EchoServer::socketDisconnected() +{ + QWebSocket *pClient = qobject_cast(sender()); + if (pClient) { + m_clients.removeAll(pClient); + pClient->deleteLater(); + } +} + +class tst_QWebSocket : public QObject +{ + Q_OBJECT + +public: + tst_QWebSocket(); + +private Q_SLOTS: + void init(); + void initTestCase(); + void cleanupTestCase(); + void tst_initialisation_data(); + void tst_initialisation(); + void tst_settersAndGetters(); + void tst_invalidOpen_data(); + void tst_invalidOpen(); + void tst_invalidOrigin(); + void tst_sendTextMessage(); + void tst_sendBinaryMessage(); + void tst_errorString(); +#ifndef QT_NO_NETWORKPROXY + void tst_setProxy(); +#endif +}; + +tst_QWebSocket::tst_QWebSocket() +{ +} + +void tst_QWebSocket::init() +{ + qRegisterMetaType("QWebSocketProtocol::Version"); +} + +void tst_QWebSocket::initTestCase() +{ +} + +void tst_QWebSocket::cleanupTestCase() +{ +} + +void tst_QWebSocket::tst_initialisation_data() +{ + QTest::addColumn("origin"); + QTest::addColumn("expectedOrigin"); + QTest::addColumn("version"); + QTest::addColumn("expectedVersion"); + + QTest::newRow("Default origin and version") + << QString() << QString() + << QWebSocketProtocol::VersionUnknown << QWebSocketProtocol::VersionLatest; + QTest::newRow("Specific origin and default version") + << QStringLiteral("qt-project.org") << QStringLiteral("qt-project.org") + << QWebSocketProtocol::VersionUnknown << QWebSocketProtocol::VersionLatest; + QTest::newRow("Specific origin and specific version") + << QStringLiteral("qt-project.org") << QStringLiteral("qt-project.org") + << QWebSocketProtocol::Version7 << QWebSocketProtocol::Version7; +} + +void tst_QWebSocket::tst_initialisation() +{ + QFETCH(QString, origin); + QFETCH(QString, expectedOrigin); + QFETCH(QWebSocketProtocol::Version, version); + QFETCH(QWebSocketProtocol::Version, expectedVersion); + + QScopedPointer socket; + + if (origin.isEmpty() && (version == QWebSocketProtocol::VersionUnknown)) + socket.reset(new QWebSocket); + else if (!origin.isEmpty() && (version == QWebSocketProtocol::VersionUnknown)) + socket.reset(new QWebSocket(origin)); + else + socket.reset(new QWebSocket(origin, version)); + + QCOMPARE(socket->origin(), expectedOrigin); + QCOMPARE(socket->version(), expectedVersion); + QCOMPARE(socket->error(), QAbstractSocket::UnknownSocketError); + QVERIFY(socket->errorString().isEmpty()); + QVERIFY(!socket->isValid()); + QVERIFY(socket->localAddress().isNull()); + QCOMPARE(socket->localPort(), quint16(0)); + QCOMPARE(socket->pauseMode(), QAbstractSocket::PauseNever); + QVERIFY(socket->peerAddress().isNull()); + QCOMPARE(socket->peerPort(), quint16(0)); + QVERIFY(socket->peerName().isEmpty()); + QCOMPARE(socket->state(), QAbstractSocket::UnconnectedState); + QCOMPARE(socket->readBufferSize(), 0); + QVERIFY(socket->resourceName().isEmpty()); + QVERIFY(!socket->requestUrl().isValid()); + QCOMPARE(socket->closeCode(), QWebSocketProtocol::CloseCodeNormal); + QVERIFY(socket->closeReason().isEmpty()); + QVERIFY(socket->flush()); + QCOMPARE(socket->sendTextMessage(QStringLiteral("A text message")), 0); + QCOMPARE(socket->sendBinaryMessage(QByteArrayLiteral("A binary message")), 0); +} + +void tst_QWebSocket::tst_settersAndGetters() +{ + QWebSocket socket; + + socket.setPauseMode(QAbstractSocket::PauseNever); + QCOMPARE(socket.pauseMode(), QAbstractSocket::PauseNever); + socket.setPauseMode(QAbstractSocket::PauseOnSslErrors); + QCOMPARE(socket.pauseMode(), QAbstractSocket::PauseOnSslErrors); + + socket.setReadBufferSize(0); + QCOMPARE(socket.readBufferSize(), 0); + socket.setReadBufferSize(128); + QCOMPARE(socket.readBufferSize(), 128); + socket.setReadBufferSize(-1); + QCOMPARE(socket.readBufferSize(), -1); +} + +void tst_QWebSocket::tst_invalidOpen_data() +{ + QTest::addColumn("url"); + QTest::addColumn("expectedUrl"); + QTest::addColumn("expectedPeerName"); + QTest::addColumn("expectedResourceName"); + QTest::addColumn("stateAfterOpenCall"); + QTest::addColumn("disconnectedCount"); + QTest::addColumn("stateChangedCount"); + + QTest::newRow("Illegal local address") + << QStringLiteral("ws://127.0.0.1:1/") << QStringLiteral("ws://127.0.0.1:1/") + << QStringLiteral("127.0.0.1") + << QStringLiteral("/") << QAbstractSocket::ConnectingState + << 1 + << 2; //going from connecting to disconnected + QTest::newRow("URL containing new line in the hostname") + << QStringLiteral("ws://myhacky\r\nserver/") << QString() + << QString() + << QString() << QAbstractSocket::UnconnectedState + << 0 << 0; + QTest::newRow("URL containing new line in the resource name") + << QStringLiteral("ws://127.0.0.1:1/tricky\r\npath") << QString() + << QString() + << QString() + << QAbstractSocket::UnconnectedState + << 0 << 0; +} + +void tst_QWebSocket::tst_invalidOpen() +{ + QFETCH(QString, url); + QFETCH(QString, expectedUrl); + QFETCH(QString, expectedPeerName); + QFETCH(QString, expectedResourceName); + QFETCH(QAbstractSocket::SocketState, stateAfterOpenCall); + QFETCH(int, disconnectedCount); + QFETCH(int, stateChangedCount); + QWebSocket socket; + QSignalSpy errorSpy(&socket, SIGNAL(error(QAbstractSocket::SocketError))); + QSignalSpy aboutToCloseSpy(&socket, SIGNAL(aboutToClose())); + QSignalSpy connectedSpy(&socket, SIGNAL(connected())); + QSignalSpy disconnectedSpy(&socket, SIGNAL(disconnected())); + QSignalSpy stateChangedSpy(&socket, SIGNAL(stateChanged(QAbstractSocket::SocketState))); + QSignalSpy readChannelFinishedSpy(&socket, SIGNAL(readChannelFinished())); + QSignalSpy textFrameReceivedSpy(&socket, SIGNAL(textFrameReceived(QString,bool))); + QSignalSpy binaryFrameReceivedSpy(&socket, SIGNAL(binaryFrameReceived(QByteArray,bool))); + QSignalSpy textMessageReceivedSpy(&socket, SIGNAL(textMessageReceived(QString))); + QSignalSpy binaryMessageReceivedSpy(&socket, SIGNAL(binaryMessageReceived(QByteArray))); + QSignalSpy pongSpy(&socket, SIGNAL(pong(quint64,QByteArray))); + QSignalSpy bytesWrittenSpy(&socket, SIGNAL(bytesWritten(qint64))); + + socket.open(QUrl(url)); + + QVERIFY(socket.origin().isEmpty()); + QCOMPARE(socket.version(), QWebSocketProtocol::VersionLatest); + //at this point the socket is in a connecting state + //so, there should no error at this point + QCOMPARE(socket.error(), QAbstractSocket::UnknownSocketError); + QVERIFY(!socket.errorString().isEmpty()); + QVERIFY(!socket.isValid()); + QVERIFY(socket.localAddress().isNull()); + QCOMPARE(socket.localPort(), quint16(0)); + QCOMPARE(socket.pauseMode(), QAbstractSocket::PauseNever); + QVERIFY(socket.peerAddress().isNull()); + QCOMPARE(socket.peerPort(), quint16(0)); + QCOMPARE(socket.peerName(), expectedPeerName); + QCOMPARE(socket.state(), stateAfterOpenCall); + QCOMPARE(socket.readBufferSize(), 0); + QCOMPARE(socket.resourceName(), expectedResourceName); + QCOMPARE(socket.requestUrl().toString(), expectedUrl); + QCOMPARE(socket.closeCode(), QWebSocketProtocol::CloseCodeNormal); + QVERIFY(socket.closeReason().isEmpty()); + QCOMPARE(socket.sendTextMessage(QStringLiteral("A text message")), 0); + QCOMPARE(socket.sendBinaryMessage(QByteArrayLiteral("A text message")), 0); + + if (errorSpy.count() == 0) + QVERIFY(errorSpy.wait()); + QCOMPARE(errorSpy.count(), 1); + QList arguments = errorSpy.takeFirst(); + QAbstractSocket::SocketError socketError = + qvariant_cast(arguments.at(0)); + QCOMPARE(socketError, QAbstractSocket::ConnectionRefusedError); + QCOMPARE(aboutToCloseSpy.count(), 0); + QCOMPARE(connectedSpy.count(), 0); + QCOMPARE(disconnectedSpy.count(), disconnectedCount); + QCOMPARE(stateChangedSpy.count(), stateChangedCount); + if (stateChangedCount == 2) { + arguments = stateChangedSpy.takeFirst(); + QAbstractSocket::SocketState socketState = + qvariant_cast(arguments.at(0)); + arguments = stateChangedSpy.takeFirst(); + socketState = qvariant_cast(arguments.at(0)); + QCOMPARE(socketState, QAbstractSocket::UnconnectedState); + } + QCOMPARE(readChannelFinishedSpy.count(), 0); + QCOMPARE(textFrameReceivedSpy.count(), 0); + QCOMPARE(binaryFrameReceivedSpy.count(), 0); + QCOMPARE(textMessageReceivedSpy.count(), 0); + QCOMPARE(binaryMessageReceivedSpy.count(), 0); + QCOMPARE(pongSpy.count(), 0); + QCOMPARE(bytesWrittenSpy.count(), 0); +} + +void tst_QWebSocket::tst_invalidOrigin() +{ + QWebSocket socket(QStringLiteral("My server\r\nin the wild.")); + + QSignalSpy errorSpy(&socket, SIGNAL(error(QAbstractSocket::SocketError))); + QSignalSpy aboutToCloseSpy(&socket, SIGNAL(aboutToClose())); + QSignalSpy connectedSpy(&socket, SIGNAL(connected())); + QSignalSpy disconnectedSpy(&socket, SIGNAL(disconnected())); + QSignalSpy stateChangedSpy(&socket, SIGNAL(stateChanged(QAbstractSocket::SocketState))); + QSignalSpy readChannelFinishedSpy(&socket, SIGNAL(readChannelFinished())); + QSignalSpy textFrameReceivedSpy(&socket, SIGNAL(textFrameReceived(QString,bool))); + QSignalSpy binaryFrameReceivedSpy(&socket, SIGNAL(binaryFrameReceived(QByteArray,bool))); + QSignalSpy textMessageReceivedSpy(&socket, SIGNAL(textMessageReceived(QString))); + QSignalSpy binaryMessageReceivedSpy(&socket, SIGNAL(binaryMessageReceived(QByteArray))); + QSignalSpy pongSpy(&socket, SIGNAL(pong(quint64,QByteArray))); + QSignalSpy bytesWrittenSpy(&socket, SIGNAL(bytesWritten(qint64))); + + socket.open(QUrl(QStringLiteral("ws://127.0.0.1:1/"))); + + //at this point the socket is in a connecting state + //so, there should no error at this point + QCOMPARE(socket.error(), QAbstractSocket::UnknownSocketError); + QVERIFY(!socket.errorString().isEmpty()); + QVERIFY(!socket.isValid()); + QVERIFY(socket.localAddress().isNull()); + QCOMPARE(socket.localPort(), quint16(0)); + QCOMPARE(socket.pauseMode(), QAbstractSocket::PauseNever); + QVERIFY(socket.peerAddress().isNull()); + QCOMPARE(socket.peerPort(), quint16(0)); + QCOMPARE(socket.peerName(), QStringLiteral("127.0.0.1")); + QCOMPARE(socket.state(), QAbstractSocket::ConnectingState); + QCOMPARE(socket.readBufferSize(), 0); + QCOMPARE(socket.resourceName(), QStringLiteral("/")); + QCOMPARE(socket.requestUrl(), QUrl(QStringLiteral("ws://127.0.0.1:1/"))); + QCOMPARE(socket.closeCode(), QWebSocketProtocol::CloseCodeNormal); + + QVERIFY(errorSpy.wait()); + + QCOMPARE(errorSpy.count(), 1); + QList arguments = errorSpy.takeFirst(); + QAbstractSocket::SocketError socketError = + qvariant_cast(arguments.at(0)); + QCOMPARE(socketError, QAbstractSocket::ConnectionRefusedError); + QCOMPARE(aboutToCloseSpy.count(), 0); + QCOMPARE(connectedSpy.count(), 0); + QCOMPARE(disconnectedSpy.count(), 1); + QCOMPARE(stateChangedSpy.count(), 2); //connectingstate, unconnectedstate + arguments = stateChangedSpy.takeFirst(); + QAbstractSocket::SocketState socketState = + qvariant_cast(arguments.at(0)); + arguments = stateChangedSpy.takeFirst(); + socketState = qvariant_cast(arguments.at(0)); + QCOMPARE(socketState, QAbstractSocket::UnconnectedState); + QCOMPARE(readChannelFinishedSpy.count(), 0); + QCOMPARE(textFrameReceivedSpy.count(), 0); + QCOMPARE(binaryFrameReceivedSpy.count(), 0); + QCOMPARE(textMessageReceivedSpy.count(), 0); + QCOMPARE(binaryMessageReceivedSpy.count(), 0); + QCOMPARE(pongSpy.count(), 0); + QCOMPARE(bytesWrittenSpy.count(), 0); +} + +void tst_QWebSocket::tst_sendTextMessage() +{ + EchoServer echoServer; + + QWebSocket socket; + + //should return 0 because socket is not open yet + QCOMPARE(socket.sendTextMessage(QStringLiteral("1234")), 0); + + QSignalSpy socketConnectedSpy(&socket, SIGNAL(connected())); + QSignalSpy serverConnectedSpy(&echoServer, SIGNAL(newConnection(QUrl))); + QSignalSpy textMessageReceived(&socket, SIGNAL(textMessageReceived(QString))); + QSignalSpy textFrameReceived(&socket, SIGNAL(textFrameReceived(QString,bool))); + QSignalSpy binaryMessageReceived(&socket, SIGNAL(binaryMessageReceived(QByteArray))); + QSignalSpy binaryFrameReceived(&socket, SIGNAL(binaryFrameReceived(QByteArray,bool))); + QSignalSpy socketError(&socket, SIGNAL(error(QAbstractSocket::SocketError))); + + QUrl url = QUrl(QStringLiteral("ws://") + echoServer.hostAddress().toString() + + QStringLiteral(":") + QString::number(echoServer.port())); + url.setPath("/segment/with spaces"); + url.addQueryItem("queryitem", "with encoded characters"); + + socket.open(url); + + if (socketConnectedSpy.count() == 0) + QVERIFY(socketConnectedSpy.wait(500)); + QCOMPARE(socketError.count(), 0); + QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); + QCOMPARE(serverConnectedSpy.count(), 1); + QList arguments = serverConnectedSpy.takeFirst(); + QUrl urlConnected = arguments.at(0).toUrl(); + QCOMPARE(urlConnected, url); + + socket.sendTextMessage(QStringLiteral("Hello world!")); + + QVERIFY(textMessageReceived.wait(500)); + QCOMPARE(textMessageReceived.count(), 1); + QCOMPARE(binaryMessageReceived.count(), 0); + QCOMPARE(binaryFrameReceived.count(), 0); + arguments = textMessageReceived.takeFirst(); + QString messageReceived = arguments.at(0).toString(); + QCOMPARE(messageReceived, QStringLiteral("Hello world!")); + + QCOMPARE(textFrameReceived.count(), 1); + arguments = textFrameReceived.takeFirst(); + QString frameReceived = arguments.at(0).toString(); + bool isLastFrame = arguments.at(1).toBool(); + QCOMPARE(frameReceived, QStringLiteral("Hello world!")); + QVERIFY(isLastFrame); + + socket.close(); + + //QTBUG-36762: QWebSocket emits multiplied signals when socket was reopened + socketConnectedSpy.clear(); + textMessageReceived.clear(); + textFrameReceived.clear(); + + socket.open(QUrl(QStringLiteral("ws://") + echoServer.hostAddress().toString() + + QStringLiteral(":") + QString::number(echoServer.port()))); + + if (socketConnectedSpy.count() == 0) + QVERIFY(socketConnectedSpy.wait(500)); + QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); + + socket.sendTextMessage(QStringLiteral("Hello world!")); + + QVERIFY(textMessageReceived.wait(500)); + QCOMPARE(textMessageReceived.count(), 1); + QCOMPARE(binaryMessageReceived.count(), 0); + QCOMPARE(binaryFrameReceived.count(), 0); + arguments = textMessageReceived.takeFirst(); + messageReceived = arguments.at(0).toString(); + QCOMPARE(messageReceived, QStringLiteral("Hello world!")); + + QCOMPARE(textFrameReceived.count(), 1); + arguments = textFrameReceived.takeFirst(); + frameReceived = arguments.at(0).toString(); + isLastFrame = arguments.at(1).toBool(); + QCOMPARE(frameReceived, QStringLiteral("Hello world!")); + QVERIFY(isLastFrame); + + QString reason = QStringLiteral("going away"); + socket.close(QWebSocketProtocol::CloseCodeGoingAway, reason); + QCOMPARE(socket.closeCode(), QWebSocketProtocol::CloseCodeGoingAway); + QCOMPARE(socket.closeReason(), reason); +} + +void tst_QWebSocket::tst_sendBinaryMessage() +{ + EchoServer echoServer; + + QWebSocket socket; + + //should return 0 because socket is not open yet + QCOMPARE(socket.sendBinaryMessage(QByteArrayLiteral("1234")), 0); + + QSignalSpy socketConnectedSpy(&socket, SIGNAL(connected())); + QSignalSpy textMessageReceived(&socket, SIGNAL(textMessageReceived(QString))); + QSignalSpy textFrameReceived(&socket, SIGNAL(textFrameReceived(QString,bool))); + QSignalSpy binaryMessageReceived(&socket, SIGNAL(binaryMessageReceived(QByteArray))); + QSignalSpy binaryFrameReceived(&socket, SIGNAL(binaryFrameReceived(QByteArray,bool))); + + socket.open(QUrl(QStringLiteral("ws://") + echoServer.hostAddress().toString() + + QStringLiteral(":") + QString::number(echoServer.port()))); + + if (socketConnectedSpy.count() == 0) + QVERIFY(socketConnectedSpy.wait(500)); + QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); + + socket.sendBinaryMessage(QByteArrayLiteral("Hello world!")); + + QVERIFY(binaryMessageReceived.wait(500)); + QCOMPARE(textMessageReceived.count(), 0); + QCOMPARE(textFrameReceived.count(), 0); + QCOMPARE(binaryMessageReceived.count(), 1); + QList arguments = binaryMessageReceived.takeFirst(); + QByteArray messageReceived = arguments.at(0).toByteArray(); + QCOMPARE(messageReceived, QByteArrayLiteral("Hello world!")); + + QCOMPARE(binaryFrameReceived.count(), 1); + arguments = binaryFrameReceived.takeFirst(); + QByteArray frameReceived = arguments.at(0).toByteArray(); + bool isLastFrame = arguments.at(1).toBool(); + QCOMPARE(frameReceived, QByteArrayLiteral("Hello world!")); + QVERIFY(isLastFrame); + + socket.close(); + + //QTBUG-36762: QWebSocket emits multiple signals when socket is reopened + socketConnectedSpy.clear(); + binaryMessageReceived.clear(); + binaryFrameReceived.clear(); + + socket.open(QUrl(QStringLiteral("ws://") + echoServer.hostAddress().toString() + + QStringLiteral(":") + QString::number(echoServer.port()))); + + if (socketConnectedSpy.count() == 0) + QVERIFY(socketConnectedSpy.wait(500)); + QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); + + socket.sendBinaryMessage(QByteArrayLiteral("Hello world!")); + + QVERIFY(binaryMessageReceived.wait(500)); + QCOMPARE(textMessageReceived.count(), 0); + QCOMPARE(textFrameReceived.count(), 0); + QCOMPARE(binaryMessageReceived.count(), 1); + arguments = binaryMessageReceived.takeFirst(); + messageReceived = arguments.at(0).toByteArray(); + QCOMPARE(messageReceived, QByteArrayLiteral("Hello world!")); + + QCOMPARE(binaryFrameReceived.count(), 1); + arguments = binaryFrameReceived.takeFirst(); + frameReceived = arguments.at(0).toByteArray(); + isLastFrame = arguments.at(1).toBool(); + QCOMPARE(frameReceived, QByteArrayLiteral("Hello world!")); + QVERIFY(isLastFrame); +} + +void tst_QWebSocket::tst_errorString() +{ + //Check for QTBUG-37228: QWebSocket returns "Unknown Error" for known errors + QWebSocket socket; + + //check that the default error string is empty + QVERIFY(socket.errorString().isEmpty()); + + QSignalSpy errorSpy(&socket, SIGNAL(error(QAbstractSocket::SocketError))); + + socket.open(QUrl(QStringLiteral("ws://someserver.on.mars:9999"))); + + if (errorSpy.count() == 0) + errorSpy.wait(500); + QCOMPARE(errorSpy.count(), 1); + QList arguments = errorSpy.takeFirst(); + QAbstractSocket::SocketError socketError = + qvariant_cast(arguments.at(0)); + QCOMPARE(socketError, QAbstractSocket::HostNotFoundError); + QCOMPARE(socket.errorString(), QStringLiteral("Host not found")); +} + +#ifndef QT_NO_NETWORKPROXY +void tst_QWebSocket::tst_setProxy() +{ + // check if property assignment works as expected. + QWebSocket socket; + QCOMPARE(socket.proxy(), QNetworkProxy(QNetworkProxy::DefaultProxy)); + + QNetworkProxy proxy; + proxy.setPort(123); + socket.setProxy(proxy); + QCOMPARE(socket.proxy(), proxy); + + proxy.setPort(321); + QCOMPARE(socket.proxy().port(), quint16(123)); + socket.setProxy(proxy); + QCOMPARE(socket.proxy(), proxy); +} +#endif // QT_NO_NETWORKPROXY + +QTEST_MAIN(tst_QWebSocket) + +#include "tst_qwebsocket.moc" diff --git a/tests/auto/websockets/qwebsocketcorsauthenticator/qwebsocketcorsauthenticator.pro b/tests/auto/websockets/qwebsocketcorsauthenticator/qwebsocketcorsauthenticator.pro new file mode 100644 index 0000000..aa485fc --- /dev/null +++ b/tests/auto/websockets/qwebsocketcorsauthenticator/qwebsocketcorsauthenticator.pro @@ -0,0 +1,13 @@ +CONFIG += console +CONFIG += testcase +CONFIG -= app_bundle + +TEMPLATE = app + +TARGET = tst_qwebsocketcorsauthenticator + +QT = core testlib websockets + +SOURCES += tst_qwebsocketcorsauthenticator.cpp + +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/websockets/qwebsocketcorsauthenticator/tst_qwebsocketcorsauthenticator.cpp b/tests/auto/websockets/qwebsocketcorsauthenticator/tst_qwebsocketcorsauthenticator.cpp new file mode 100644 index 0000000..225adc8 --- /dev/null +++ b/tests/auto/websockets/qwebsocketcorsauthenticator/tst_qwebsocketcorsauthenticator.cpp @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Kurt Pattyn . +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include +#include +#include +#include + +#include "QtWebSockets/qwebsocketcorsauthenticator.h" + +QT_USE_NAMESPACE + +class tst_QWebSocketCorsAuthenticator : public QObject +{ + Q_OBJECT + +public: + tst_QWebSocketCorsAuthenticator(); + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + + void tst_initialization(); +}; + +tst_QWebSocketCorsAuthenticator::tst_QWebSocketCorsAuthenticator() +{} + +void tst_QWebSocketCorsAuthenticator::initTestCase() +{ +} + +void tst_QWebSocketCorsAuthenticator::cleanupTestCase() +{} + +void tst_QWebSocketCorsAuthenticator::init() +{ +} + +void tst_QWebSocketCorsAuthenticator::cleanup() +{ +} + +void tst_QWebSocketCorsAuthenticator::tst_initialization() +{ + { + QWebSocketCorsAuthenticator authenticator((QString())); + + QCOMPARE(authenticator.allowed(), true); + QCOMPARE(authenticator.origin(), QString()); + } + { + QWebSocketCorsAuthenticator authenticator(QStringLiteral("com.somesite")); + + QCOMPARE(authenticator.allowed(), true); + QCOMPARE(authenticator.origin(), QStringLiteral("com.somesite")); + + QWebSocketCorsAuthenticator other(authenticator); + QCOMPARE(other.origin(), authenticator.origin()); + QCOMPARE(other.allowed(), authenticator.allowed()); + + authenticator.setAllowed(false); + QVERIFY(!authenticator.allowed()); + QCOMPARE(other.allowed(), true); //make sure other is a real copy + + authenticator.setAllowed(true); + QVERIFY(authenticator.allowed()); + + authenticator.setAllowed(false); + other = authenticator; + QCOMPARE(other.origin(), authenticator.origin()); + QCOMPARE(other.allowed(), authenticator.allowed()); + } +} + +QTEST_MAIN(tst_QWebSocketCorsAuthenticator) + +#include "tst_qwebsocketcorsauthenticator.moc" + diff --git a/tests/auto/websockets/qwebsocketserver/qwebsocketserver.pro b/tests/auto/websockets/qwebsocketserver/qwebsocketserver.pro new file mode 100644 index 0000000..25216d3 --- /dev/null +++ b/tests/auto/websockets/qwebsocketserver/qwebsocketserver.pro @@ -0,0 +1,13 @@ +CONFIG += console +CONFIG += testcase +CONFIG -= app_bundle + +QT = core testlib websockets + +TARGET = tst_qwebsocketserver + +TEMPLATE = app + +SOURCES += tst_qwebsocketserver.cpp + +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/websockets/qwebsocketserver/tst_qwebsocketserver.cpp b/tests/auto/websockets/qwebsocketserver/tst_qwebsocketserver.cpp new file mode 100644 index 0000000..c2ba842 --- /dev/null +++ b/tests/auto/websockets/qwebsocketserver/tst_qwebsocketserver.cpp @@ -0,0 +1,390 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Kurt Pattyn . +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include + +QT_USE_NAMESPACE + +Q_DECLARE_METATYPE(QWebSocketProtocol::Version) +Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode) +Q_DECLARE_METATYPE(QWebSocketServer::SslMode) +Q_DECLARE_METATYPE(QWebSocketCorsAuthenticator *) +#ifndef QT_NO_SSL +Q_DECLARE_METATYPE(QSslError) +#endif + +class tst_QWebSocketServer : public QObject +{ + Q_OBJECT + +public: + tst_QWebSocketServer(); + +private Q_SLOTS: + void init(); + void initTestCase(); + void cleanupTestCase(); + void tst_initialisation(); + void tst_settersAndGetters(); + void tst_listening(); + void tst_connectivity(); + void tst_maxPendingConnections(); + void tst_serverDestroyedWhileSocketConnected(); +}; + +tst_QWebSocketServer::tst_QWebSocketServer() +{ +} + +void tst_QWebSocketServer::init() +{ + qRegisterMetaType("QWebSocketProtocol::Version"); + qRegisterMetaType("QWebSocketProtocol::CloseCode"); + qRegisterMetaType("QWebSocketServer::SslMode"); + qRegisterMetaType("QWebSocketCorsAuthenticator *"); +#ifndef QT_NO_SSL + qRegisterMetaType("QSslError"); +#endif +} + +void tst_QWebSocketServer::initTestCase() +{ +} + +void tst_QWebSocketServer::cleanupTestCase() +{ +} + +void tst_QWebSocketServer::tst_initialisation() +{ + { + QWebSocketServer server(QString(), QWebSocketServer::NonSecureMode); + + QVERIFY(server.serverName().isEmpty()); + QCOMPARE(server.secureMode(), QWebSocketServer::NonSecureMode); + QVERIFY(!server.isListening()); + QCOMPARE(server.maxPendingConnections(), 30); + QCOMPARE(server.serverPort(), quint16(0)); + QCOMPARE(server.serverAddress(), QHostAddress()); + QCOMPARE(server.socketDescriptor(), -1); + QVERIFY(!server.hasPendingConnections()); + QVERIFY(!server.nextPendingConnection()); + QCOMPARE(server.error(), QWebSocketProtocol::CloseCodeNormal); + QVERIFY(server.errorString().isEmpty()); + #ifndef QT_NO_NETWORKPROXY + QCOMPARE(server.proxy().type(), QNetworkProxy::DefaultProxy); + #endif + #ifndef QT_NO_SSL + QCOMPARE(server.sslConfiguration(), QSslConfiguration::defaultConfiguration()); + #endif + QCOMPARE(server.supportedVersions().count(), 1); + QCOMPARE(server.supportedVersions().at(0), QWebSocketProtocol::VersionLatest); + QCOMPARE(server.supportedVersions().at(0), QWebSocketProtocol::Version13); + + server.close(); + //closing a server should not affect any of the parameters + //certainly if the server was not opened before + + QVERIFY(server.serverName().isEmpty()); + QCOMPARE(server.secureMode(), QWebSocketServer::NonSecureMode); + QVERIFY(!server.isListening()); + QCOMPARE(server.maxPendingConnections(), 30); + QCOMPARE(server.serverPort(), quint16(0)); + QCOMPARE(server.serverAddress(), QHostAddress()); + QCOMPARE(server.socketDescriptor(), -1); + QVERIFY(!server.hasPendingConnections()); + QVERIFY(!server.nextPendingConnection()); + QCOMPARE(server.error(), QWebSocketProtocol::CloseCodeNormal); + QVERIFY(server.errorString().isEmpty()); + #ifndef QT_NO_NETWORKPROXY + QCOMPARE(server.proxy().type(), QNetworkProxy::DefaultProxy); + #endif + #ifndef QT_NO_SSL + QCOMPARE(server.sslConfiguration(), QSslConfiguration::defaultConfiguration()); + #endif + QCOMPARE(server.supportedVersions().count(), 1); + QCOMPARE(server.supportedVersions().at(0), QWebSocketProtocol::VersionLatest); + QCOMPARE(server.supportedVersions().at(0), QWebSocketProtocol::Version13); + QCOMPARE(server.serverUrl(), QUrl()); + } + + { +#ifndef QT_NO_SSL + QWebSocketServer sslServer(QString(), QWebSocketServer::SecureMode); + QCOMPARE(sslServer.secureMode(), QWebSocketServer::SecureMode); +#endif + } +} + +void tst_QWebSocketServer::tst_settersAndGetters() +{ + QWebSocketServer server(QString(), QWebSocketServer::NonSecureMode); + + server.setMaxPendingConnections(23); + QCOMPARE(server.maxPendingConnections(), 23); + server.setMaxPendingConnections(INT_MIN); + QCOMPARE(server.maxPendingConnections(), INT_MIN); + server.setMaxPendingConnections(INT_MAX); + QCOMPARE(server.maxPendingConnections(), INT_MAX); + + QVERIFY(!server.setSocketDescriptor(-2)); + QCOMPARE(server.socketDescriptor(), -1); + + server.setServerName(QStringLiteral("Qt WebSocketServer")); + QCOMPARE(server.serverName(), QStringLiteral("Qt WebSocketServer")); + +#ifndef QT_NO_NETWORKPROXY + QNetworkProxy proxy(QNetworkProxy::Socks5Proxy); + server.setProxy(proxy); + QCOMPARE(server.proxy(), proxy); +#endif +#ifndef QT_NO_SSL + //cannot set an ssl configuration on a non secure server + QSslConfiguration sslConfiguration = QSslConfiguration::defaultConfiguration(); + sslConfiguration.setPeerVerifyDepth(sslConfiguration.peerVerifyDepth() + 1); + server.setSslConfiguration(sslConfiguration); + QVERIFY(server.sslConfiguration() != sslConfiguration); + QCOMPARE(server.sslConfiguration(), QSslConfiguration::defaultConfiguration()); + + QWebSocketServer sslServer(QString(), QWebSocketServer::SecureMode); + sslServer.setSslConfiguration(sslConfiguration); + QCOMPARE(sslServer.sslConfiguration(), sslConfiguration); + QVERIFY(sslServer.sslConfiguration() != QSslConfiguration::defaultConfiguration()); +#endif +} + +void tst_QWebSocketServer::tst_listening() +{ + //These listening tests are not too extensive, as the implementation of QWebSocketServer + //relies on QTcpServer + + QWebSocketServer server(QString(), QWebSocketServer::NonSecureMode); + + QSignalSpy serverAcceptErrorSpy(&server, SIGNAL(acceptError(QAbstractSocket::SocketError))); + QSignalSpy serverConnectionSpy(&server, SIGNAL(newConnection())); + QSignalSpy serverErrorSpy(&server, + SIGNAL(serverError(QWebSocketProtocol::CloseCode))); + QSignalSpy corsAuthenticationSpy(&server, + SIGNAL(originAuthenticationRequired(QWebSocketCorsAuthenticator*))); + QSignalSpy serverClosedSpy(&server, SIGNAL(closed())); +#ifndef QT_NO_SSL + QSignalSpy peerVerifyErrorSpy(&server, SIGNAL(peerVerifyError(QSslError))); + QSignalSpy sslErrorsSpy(&server, SIGNAL(sslErrors(QList))); +#endif + + QVERIFY(server.listen()); //listen on all network interface, choose an appropriate port + QVERIFY(server.isListening()); + QCOMPARE(serverClosedSpy.count(), 0); + server.close(); + QVERIFY(serverClosedSpy.wait(1000)); + QVERIFY(!server.isListening()); + QCOMPARE(serverErrorSpy.count(), 0); + + QVERIFY(!server.listen(QHostAddress(QStringLiteral("1.2.3.4")), 0)); + QCOMPARE(server.error(), QWebSocketProtocol::CloseCodeAbnormalDisconnection); + QCOMPARE(server.errorString().toLatin1().constData(), "The address is not available"); + QVERIFY(!server.isListening()); + + QCOMPARE(serverAcceptErrorSpy.count(), 0); + QCOMPARE(serverConnectionSpy.count(), 0); + QCOMPARE(corsAuthenticationSpy.count(), 0); +#ifndef QT_NO_SSL + QCOMPARE(peerVerifyErrorSpy.count(), 0); + QCOMPARE(sslErrorsSpy.count(), 0); +#endif + QCOMPARE(serverErrorSpy.count(), 1); + QCOMPARE(serverClosedSpy.count(), 1); +} + +void tst_QWebSocketServer::tst_connectivity() +{ + QWebSocketServer server(QString(), QWebSocketServer::NonSecureMode); + QSignalSpy serverConnectionSpy(&server, SIGNAL(newConnection())); + QSignalSpy serverErrorSpy(&server, + SIGNAL(serverError(QWebSocketProtocol::CloseCode))); + QSignalSpy corsAuthenticationSpy(&server, + SIGNAL(originAuthenticationRequired(QWebSocketCorsAuthenticator*))); + QSignalSpy serverClosedSpy(&server, SIGNAL(closed())); +#ifndef QT_NO_SSL + QSignalSpy peerVerifyErrorSpy(&server, SIGNAL(peerVerifyError(QSslError))); + QSignalSpy sslErrorsSpy(&server, SIGNAL(sslErrors(QList))); +#endif + QWebSocket socket; + QSignalSpy socketConnectedSpy(&socket, SIGNAL(connected())); + + QVERIFY(server.listen()); + QCOMPARE(server.serverAddress(), QHostAddress(QHostAddress::Any)); + QCOMPARE(server.serverUrl(), QUrl(QStringLiteral("ws://") + QHostAddress(QHostAddress::LocalHost).toString() + + QStringLiteral(":").append(QString::number(server.serverPort())))); + + socket.open(server.serverUrl().toString()); + + if (socketConnectedSpy.count() == 0) + QVERIFY(socketConnectedSpy.wait()); + QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); + QCOMPARE(serverConnectionSpy.count(), 1); + QCOMPARE(corsAuthenticationSpy.count(), 1); + + QCOMPARE(serverClosedSpy.count(), 0); + + server.close(); + + QVERIFY(serverClosedSpy.wait()); + QCOMPARE(serverClosedSpy.count(), 1); +#ifndef QT_NO_SSL + QCOMPARE(peerVerifyErrorSpy.count(), 0); + QCOMPARE(sslErrorsSpy.count(), 0); +#endif + QCOMPARE(serverErrorSpy.count(), 0); +} + +void tst_QWebSocketServer::tst_maxPendingConnections() +{ + //tests if maximum connections are respected + //also checks if there are no side-effects like signals that are unexpectedly thrown + QWebSocketServer server(QString(), QWebSocketServer::NonSecureMode); + server.setMaxPendingConnections(2); + QSignalSpy serverConnectionSpy(&server, SIGNAL(newConnection())); + QSignalSpy serverErrorSpy(&server, + SIGNAL(serverError(QWebSocketProtocol::CloseCode))); + QSignalSpy corsAuthenticationSpy(&server, + SIGNAL(originAuthenticationRequired(QWebSocketCorsAuthenticator*))); + QSignalSpy serverClosedSpy(&server, SIGNAL(closed())); +#ifndef QT_NO_SSL + QSignalSpy peerVerifyErrorSpy(&server, SIGNAL(peerVerifyError(QSslError))); + QSignalSpy sslErrorsSpy(&server, SIGNAL(sslErrors(QList))); +#endif + QSignalSpy serverAcceptErrorSpy(&server, SIGNAL(acceptError(QAbstractSocket::SocketError))); + + QWebSocket socket1; + QWebSocket socket2; + QWebSocket socket3; + + QSignalSpy socket1ConnectedSpy(&socket1, SIGNAL(connected())); + QSignalSpy socket2ConnectedSpy(&socket2, SIGNAL(connected())); + QSignalSpy socket3ConnectedSpy(&socket3, SIGNAL(connected())); + + QVERIFY(server.listen()); + + socket1.open(server.serverUrl().toString()); + + if (socket1ConnectedSpy.count() == 0) + QVERIFY(socket1ConnectedSpy.wait()); + QCOMPARE(socket1.state(), QAbstractSocket::ConnectedState); + QCOMPARE(serverConnectionSpy.count(), 1); + QCOMPARE(corsAuthenticationSpy.count(), 1); + socket2.open(server.serverUrl().toString()); + if (socket2ConnectedSpy.count() == 0) + QVERIFY(socket2ConnectedSpy.wait()); + QCOMPARE(socket2.state(), QAbstractSocket::ConnectedState); + QCOMPARE(serverConnectionSpy.count(), 2); + QCOMPARE(corsAuthenticationSpy.count(), 2); + socket3.open(server.serverUrl().toString()); + if (socket3ConnectedSpy.count() == 0) + QVERIFY(!socket3ConnectedSpy.wait(250)); + QCOMPARE(socket3.state(), QAbstractSocket::UnconnectedState); + QCOMPARE(serverConnectionSpy.count(), 2); + QCOMPARE(corsAuthenticationSpy.count(), 2); + + QVERIFY(server.hasPendingConnections()); + QWebSocket *pSocket = server.nextPendingConnection(); + QVERIFY(pSocket); + delete pSocket; + QVERIFY(server.hasPendingConnections()); + pSocket = server.nextPendingConnection(); + QVERIFY(pSocket); + delete pSocket; + QVERIFY(!server.hasPendingConnections()); + QVERIFY(!server.nextPendingConnection()); + +//will resolve in another commit +#ifndef Q_OS_WIN + QCOMPARE(serverErrorSpy.count(), 1); + QCOMPARE(serverErrorSpy.at(0).at(0).value(), + QWebSocketProtocol::CloseCodeAbnormalDisconnection); +#endif + QCOMPARE(serverClosedSpy.count(), 0); + + server.close(); + + QVERIFY(serverClosedSpy.wait()); + QCOMPARE(serverClosedSpy.count(), 1); +#ifndef QT_NO_SSL + QCOMPARE(peerVerifyErrorSpy.count(), 0); + QCOMPARE(sslErrorsSpy.count(), 0); +#endif + QCOMPARE(serverAcceptErrorSpy.count(), 0); +} + +void tst_QWebSocketServer::tst_serverDestroyedWhileSocketConnected() +{ + QWebSocketServer * server = new QWebSocketServer(QString(), QWebSocketServer::NonSecureMode); + QSignalSpy serverConnectionSpy(server, SIGNAL(newConnection())); + QSignalSpy corsAuthenticationSpy(server, + SIGNAL(originAuthenticationRequired(QWebSocketCorsAuthenticator*))); + QSignalSpy serverClosedSpy(server, SIGNAL(closed())); + + QWebSocket socket; + QSignalSpy socketConnectedSpy(&socket, SIGNAL(connected())); + QSignalSpy socketDisconnectedSpy(&socket, SIGNAL(disconnected())); + + QVERIFY(server->listen()); + QCOMPARE(server->serverAddress(), QHostAddress(QHostAddress::Any)); + QCOMPARE(server->serverUrl(), QUrl(QStringLiteral("ws://") + QHostAddress(QHostAddress::LocalHost).toString() + + QStringLiteral(":").append(QString::number(server->serverPort())))); + + socket.open(server->serverUrl().toString()); + + if (socketConnectedSpy.count() == 0) + QVERIFY(socketConnectedSpy.wait()); + QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); + QCOMPARE(serverConnectionSpy.count(), 1); + QCOMPARE(corsAuthenticationSpy.count(), 1); + + QCOMPARE(serverClosedSpy.count(), 0); + + delete server; + + if (socketDisconnectedSpy.count() == 0) + QVERIFY(socketDisconnectedSpy.wait()); + QCOMPARE(socketDisconnectedSpy.count(), 1); +} + +QTEST_MAIN(tst_QWebSocketServer) + +#include "tst_qwebsocketserver.moc" diff --git a/tests/auto/websockets/websocketframe/tst_websocketframe.cpp b/tests/auto/websockets/websocketframe/tst_websocketframe.cpp new file mode 100644 index 0000000..5db82d5 --- /dev/null +++ b/tests/auto/websockets/websocketframe/tst_websocketframe.cpp @@ -0,0 +1,624 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Kurt Pattyn . +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include +#include +#include +#include + +#include "private/qwebsocketframe_p.h" +#include "private/qwebsocketprotocol_p.h" +#include "qwebsocketprotocol.h" + +QT_USE_NAMESPACE + +Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode) +Q_DECLARE_METATYPE(QWebSocketProtocol::OpCode) + +/*! + * \brief class FrameHelper is used to encode a single frame. + * + * \internal + */ +class FrameHelper +{ +public: + FrameHelper(); + + QByteArray wireRepresentation(); + + void setRsv1(int value) { m_rsv1 = value; } + void setRsv2(int value) { m_rsv2 = value; } + void setRsv3(int value) { m_rsv3 = value; } + void setMask(quint32 mask) { m_mask = mask; } + void setOpCode(QWebSocketProtocol::OpCode opCode) { m_opCode = opCode; } + void setPayload(const QByteArray &payload) { m_payload = payload; } + void setFinalFrame(bool isFinal) { m_isFinalFrame = isFinal; } + +private: + int m_rsv1; + int m_rsv2; + int m_rsv3; + quint32 m_mask; + QWebSocketProtocol::OpCode m_opCode; + QByteArray m_payload; + bool m_isFinalFrame; +}; + +FrameHelper::FrameHelper() : + m_rsv1(0), m_rsv2(0), m_rsv3(0), + m_mask(0), m_opCode(QWebSocketProtocol::OpCodeReserved3), + m_payload(), m_isFinalFrame(false) +{} + +QByteArray FrameHelper::wireRepresentation() +{ + quint8 byte = 0x00; + QByteArray wireRep; + quint64 payloadLength = m_payload.length(); + + //FIN, opcode + byte = static_cast((m_opCode & 0x0F) | (m_isFinalFrame ? 0x80 : 0x00)); //FIN, opcode + //RSV1-3 + byte |= static_cast(((m_rsv1 & 0x01) << 6) | ((m_rsv2 & 0x01) << 5) | + ((m_rsv3 & 0x01) << 4)); + wireRep.append(static_cast(byte)); + + byte = 0x00; + if (m_mask != 0) + { + byte |= 0x80; + } + if (payloadLength <= 125) + { + byte |= static_cast(payloadLength); + wireRep.append(static_cast(byte)); + } + else if (payloadLength <= 0xFFFFU) + { + byte |= 126; + wireRep.append(static_cast(byte)); + quint16 swapped = qToBigEndian(static_cast(payloadLength)); + wireRep.append(static_cast(static_cast(&swapped)), 2); + } + else + { + byte |= 127; + wireRep.append(static_cast(byte)); + quint64 swapped = qToBigEndian(payloadLength); + wireRep.append(static_cast(static_cast(&swapped)), 8); + } + //Write mask + if (m_mask != 0) + { + wireRep.append(static_cast(static_cast(&m_mask)), + sizeof(quint32)); + } + QByteArray tmpData = m_payload; + if (m_mask) + { + tmpData.detach(); + QWebSocketProtocol::mask(&tmpData, m_mask); + } + wireRep.append(tmpData); + return wireRep; +} + +class tst_WebSocketFrame : public QObject +{ + Q_OBJECT + +public: + tst_WebSocketFrame(); + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + + void tst_initialization(); + void tst_copyConstructorAndAssignment(); + + void tst_goodFrames_data(); + void tst_goodFrames(); + + void tst_invalidFrames_data(); + void tst_invalidFrames(); + + void tst_malformedFrames_data(); + void tst_malformedFrames(); +}; + +tst_WebSocketFrame::tst_WebSocketFrame() +{} + +void tst_WebSocketFrame::initTestCase() +{ +} + +void tst_WebSocketFrame::cleanupTestCase() +{} + +void tst_WebSocketFrame::init() +{ + qRegisterMetaType("QWebSocketProtocol::OpCode"); + qRegisterMetaType("QWebSocketProtocol::CloseCode"); +} + +void tst_WebSocketFrame::cleanup() +{ +} + +void tst_WebSocketFrame::tst_initialization() +{ + QWebSocketFrame frame; + QVERIFY(!frame.isValid()); + QCOMPARE(frame.payload().length(), 0); +} + +void tst_WebSocketFrame::tst_copyConstructorAndAssignment() +{ + FrameHelper frameHelper; + frameHelper.setRsv1(0); + frameHelper.setRsv2(0); + frameHelper.setRsv3(0); + frameHelper.setFinalFrame(true); + frameHelper.setMask(1234u); + frameHelper.setOpCode(QWebSocketProtocol::OpCodeBinary); + frameHelper.setPayload(QByteArrayLiteral("12345")); + + QByteArray payload = frameHelper.wireRepresentation(); + QBuffer buffer(&payload); + buffer.open(QIODevice::ReadOnly); + + QWebSocketFrame frame = QWebSocketFrame::readFrame(&buffer); + buffer.close(); + + { + QWebSocketFrame other(frame); + QCOMPARE(other.closeCode(), frame.closeCode()); + QCOMPARE(other.closeReason(), frame.closeReason()); + QCOMPARE(other.hasMask(), frame.hasMask()); + QCOMPARE(other.isContinuationFrame(), frame.isContinuationFrame()); + QCOMPARE(other.isControlFrame(), frame.isControlFrame()); + QCOMPARE(other.isDataFrame(), frame.isDataFrame()); + QCOMPARE(other.isFinalFrame(), frame.isFinalFrame()); + QCOMPARE(other.isValid(), frame.isValid()); + QCOMPARE(other.mask(), frame.mask()); + QCOMPARE(other.opCode(), frame.opCode()); + QCOMPARE(other.payload(), frame.payload()); + QCOMPARE(other.rsv1(), frame.rsv1()); + QCOMPARE(other.rsv2(), frame.rsv2()); + QCOMPARE(other.rsv3(), frame.rsv3()); + } + { + QWebSocketFrame other; + other = frame; + QCOMPARE(other.closeCode(), frame.closeCode()); + QCOMPARE(other.closeReason(), frame.closeReason()); + QCOMPARE(other.hasMask(), frame.hasMask()); + QCOMPARE(other.isContinuationFrame(), frame.isContinuationFrame()); + QCOMPARE(other.isControlFrame(), frame.isControlFrame()); + QCOMPARE(other.isDataFrame(), frame.isDataFrame()); + QCOMPARE(other.isFinalFrame(), frame.isFinalFrame()); + QCOMPARE(other.isValid(), frame.isValid()); + QCOMPARE(other.mask(), frame.mask()); + QCOMPARE(other.opCode(), frame.opCode()); + QCOMPARE(other.payload(), frame.payload()); + QCOMPARE(other.rsv1(), frame.rsv1()); + QCOMPARE(other.rsv2(), frame.rsv2()); + QCOMPARE(other.rsv3(), frame.rsv3()); + } +} + +void tst_WebSocketFrame::tst_goodFrames_data() +{ + QTest::addColumn("rsv1"); + QTest::addColumn("rsv2"); + QTest::addColumn("rsv3"); + QTest::addColumn("mask"); + QTest::addColumn("opCode"); + QTest::addColumn("isFinal"); + QTest::addColumn("payload"); + QTest::addColumn("isControlFrame"); + QTest::addColumn("isDataFrame"); + QTest::addColumn("isContinuationFrame"); + + QTest::newRow("Non masked final text frame with small payload") + << 0 << 0 << 0 + << 0U << QWebSocketProtocol::OpCodeText + << true << QStringLiteral("Hello world!").toUtf8() + << false << true << false; + QTest::newRow("Non masked final binary frame with small payload") + << 0 << 0 << 0 + << 0U << QWebSocketProtocol::OpCodeBinary + << true << QByteArrayLiteral("\x00\x01\x02\x03\x04") + << false << true << false; + QTest::newRow("Non masked final text frame with no payload") + << 0 << 0 << 0 + << 0U << QWebSocketProtocol::OpCodeText + << true << QByteArray() + << false << true << false; + QTest::newRow("Non masked final binary frame with no payload") + << 0 << 0 << 0 + << 0U << QWebSocketProtocol::OpCodeBinary + << true << QByteArray() + << false << true << false; + + QTest::newRow("Non masked final close frame with small payload") + << 0 << 0 << 0 + << 0U << QWebSocketProtocol::OpCodeClose + << true << QStringLiteral("Hello world!").toUtf8() + << true << false << false; + QTest::newRow("Non masked final close frame with no payload") + << 0 << 0 << 0 + << 0U << QWebSocketProtocol::OpCodeClose + << true << QByteArray() + << true << false << false; + QTest::newRow("Non masked final ping frame with small payload") + << 0 << 0 << 0 + << 0U << QWebSocketProtocol::OpCodePing + << true << QStringLiteral("Hello world!").toUtf8() + << true << false << false; + QTest::newRow("Non masked final pong frame with no payload") + << 0 << 0 << 0 + << 0U << QWebSocketProtocol::OpCodePong + << true << QByteArray() + << true << false << false; + + QTest::newRow("Non masked final continuation frame with small payload") + << 0 << 0 << 0 + << 0U << QWebSocketProtocol::OpCodeContinue + << true << QStringLiteral("Hello world!").toUtf8() + << false << true << true; + QTest::newRow("Non masked non-final continuation frame with small payload") + << 0 << 0 << 0 + << 0U << QWebSocketProtocol::OpCodeContinue + << false << QStringLiteral("Hello world!").toUtf8() + << false << true << true; +} + +void tst_WebSocketFrame::tst_goodFrames() +{ + QFETCH(int, rsv1); + QFETCH(int, rsv2); + QFETCH(int, rsv3); + QFETCH(quint32, mask); + QFETCH(QWebSocketProtocol::OpCode, opCode); + QFETCH(bool, isFinal); + QFETCH(QByteArray, payload); + QFETCH(bool, isControlFrame); + QFETCH(bool, isDataFrame); + QFETCH(bool, isContinuationFrame); + + FrameHelper helper; + helper.setRsv1(rsv1); + helper.setRsv2(rsv2); + helper.setRsv3(rsv3); + helper.setMask(mask); + helper.setOpCode(opCode); + helper.setFinalFrame(isFinal); + helper.setPayload(payload); + + QByteArray wireRepresentation = helper.wireRepresentation(); + QBuffer buffer; + buffer.setData(wireRepresentation); + buffer.open(QIODevice::ReadOnly); + QWebSocketFrame frame = QWebSocketFrame::readFrame(&buffer); + buffer.close(); + QVERIFY(frame.isValid()); + QCOMPARE(frame.rsv1(), rsv1); + QCOMPARE(frame.rsv2(), rsv2); + QCOMPARE(frame.rsv3(), rsv3); + QCOMPARE(frame.hasMask(), (mask != 0)); + QCOMPARE(frame.opCode(), opCode); + QCOMPARE(frame.isFinalFrame(), isFinal); + QCOMPARE(frame.isControlFrame(), isControlFrame); + QCOMPARE(frame.isDataFrame(), isDataFrame); + QCOMPARE(frame.isContinuationFrame(), isContinuationFrame); + QCOMPARE(frame.payload().length(), payload.length()); + QCOMPARE(frame.payload(), payload); +} + +void tst_WebSocketFrame::tst_invalidFrames_data() +{ + QTest::addColumn("rsv1"); + QTest::addColumn("rsv2"); + QTest::addColumn("rsv3"); + QTest::addColumn("mask"); + QTest::addColumn("opCode"); + QTest::addColumn("isFinal"); + QTest::addColumn("payload"); + QTest::addColumn("expectedError"); + + QTest::newRow("RSV1 != 0") + << 1 << 0 << 0 + << 0U << QWebSocketProtocol::OpCodeText + << true << QStringLiteral("Hello world!").toUtf8() + << QWebSocketProtocol::CloseCodeProtocolError; + QTest::newRow("RSV2 != 0") + << 0 << 1 << 0 + << 0U << QWebSocketProtocol::OpCodeText + << true << QStringLiteral("Hello world!").toUtf8() + << QWebSocketProtocol::CloseCodeProtocolError; + QTest::newRow("RSV3 != 0") + << 0 << 0 << 1 + << 0U << QWebSocketProtocol::OpCodeText + << true << QStringLiteral("Hello world!").toUtf8() + << QWebSocketProtocol::CloseCodeProtocolError; + QTest::newRow("RSV1 != 0 and RSV2 != 0") + << 1 << 1 << 0 + << 0U << QWebSocketProtocol::OpCodeText + << true << QStringLiteral("Hello world!").toUtf8() + << QWebSocketProtocol::CloseCodeProtocolError; + QTest::newRow("RSV1 != 0 and RSV3 != 0") + << 1 << 0 << 1 + << 0U << QWebSocketProtocol::OpCodeText + << true << QStringLiteral("Hello world!").toUtf8() + << QWebSocketProtocol::CloseCodeProtocolError; + QTest::newRow("RSV2 != 0 and RSV3 != 0") + << 0 << 1 << 1 + << 0U << QWebSocketProtocol::OpCodeText + << true << QStringLiteral("Hello world!").toUtf8() + << QWebSocketProtocol::CloseCodeProtocolError; + + QTest::newRow("Reserved OpCode 3") + << 0 << 0 << 0 + << 0U << QWebSocketProtocol::OpCodeReserved3 + << true << QStringLiteral("Hello world!").toUtf8() + << QWebSocketProtocol::CloseCodeProtocolError; + QTest::newRow("Reserved OpCode 4") + << 0 << 0 << 0 + << 0U << QWebSocketProtocol::OpCodeReserved4 + << true << QStringLiteral("Hello world!").toUtf8() + << QWebSocketProtocol::CloseCodeProtocolError; + QTest::newRow("Reserved OpCode 5") + << 0 << 0 << 0 + << 0U << QWebSocketProtocol::OpCodeReserved5 + << true << QStringLiteral("Hello world!").toUtf8() + << QWebSocketProtocol::CloseCodeProtocolError; + QTest::newRow("Reserved OpCode 6") + << 0 << 0 << 0 + << 0U << QWebSocketProtocol::OpCodeReserved6 + << true << QStringLiteral("Hello world!").toUtf8() + << QWebSocketProtocol::CloseCodeProtocolError; + QTest::newRow("Reserved OpCode 7") + << 0 << 0 << 0 + << 0U << QWebSocketProtocol::OpCodeReserved7 + << true << QStringLiteral("Hello world!").toUtf8() + << QWebSocketProtocol::CloseCodeProtocolError; + QTest::newRow("Reserved OpCode B") + << 0 << 0 << 0 + << 0U << QWebSocketProtocol::OpCodeReservedB + << true << QStringLiteral("Hello world!").toUtf8() + << QWebSocketProtocol::CloseCodeProtocolError; + QTest::newRow("Reserved OpCode C") + << 0 << 0 << 0 + << 0U << QWebSocketProtocol::OpCodeReservedC + << true << QStringLiteral("Hello world!").toUtf8() + << QWebSocketProtocol::CloseCodeProtocolError; + QTest::newRow("Reserved OpCode D") + << 0 << 0 << 0 + << 0U << QWebSocketProtocol::OpCodeReservedD + << true << QStringLiteral("Hello world!").toUtf8() + << QWebSocketProtocol::CloseCodeProtocolError; + QTest::newRow("Reserved OpCode E") + << 0 << 0 << 0 + << 0U << QWebSocketProtocol::OpCodeReservedE + << true << QStringLiteral("Hello world!").toUtf8() + << QWebSocketProtocol::CloseCodeProtocolError; + QTest::newRow("Reserved OpCode F") + << 0 << 0 << 0 + << 0U << QWebSocketProtocol::OpCodeReservedF + << true << QStringLiteral("Hello world!").toUtf8() + << QWebSocketProtocol::CloseCodeProtocolError; + + QTest::newRow("Close Frame with payload > 125 bytes") + << 0 << 0 << 0 + << 0U << QWebSocketProtocol::OpCodeClose + << true << QString(126, 'a').toUtf8() + << QWebSocketProtocol::CloseCodeProtocolError; + QTest::newRow("Non-final Close Frame") + << 0 << 0 << 0 + << 0U << QWebSocketProtocol::OpCodeClose + << false << QString(126, 'a').toUtf8() + << QWebSocketProtocol::CloseCodeProtocolError; + QTest::newRow("Ping Frame with payload > 125 bytes") + << 0 << 0 << 0 + << 0U << QWebSocketProtocol::OpCodePing + << true << QString(126, 'a').toUtf8() + << QWebSocketProtocol::CloseCodeProtocolError; + QTest::newRow("Non-final Ping Frame") + << 0 << 0 << 0 + << 0U << QWebSocketProtocol::OpCodePing + << false << QString(126, 'a').toUtf8() + << QWebSocketProtocol::CloseCodeProtocolError; + QTest::newRow("Pong Frame with payload > 125 bytes") + << 0 << 0 << 0 + << 0U << QWebSocketProtocol::OpCodePong + << true << QString(126, 'a').toUtf8() + << QWebSocketProtocol::CloseCodeProtocolError; + QTest::newRow("Non-final Pong Frame") + << 0 << 0 << 0 + << 0U << QWebSocketProtocol::OpCodePong + << false << QString(126, 'a').toUtf8() + << QWebSocketProtocol::CloseCodeProtocolError; +} + +void tst_WebSocketFrame::tst_invalidFrames() +{ + QFETCH(int, rsv1); + QFETCH(int, rsv2); + QFETCH(int, rsv3); + QFETCH(quint32, mask); + QFETCH(QWebSocketProtocol::OpCode, opCode); + QFETCH(bool, isFinal); + QFETCH(QByteArray, payload); + QFETCH(QWebSocketProtocol::CloseCode, expectedError); + + FrameHelper helper; + helper.setRsv1(rsv1); + helper.setRsv2(rsv2); + helper.setRsv3(rsv3); + helper.setMask(mask); + helper.setOpCode(opCode); + helper.setFinalFrame(isFinal); + helper.setPayload(payload); + + QByteArray wireRepresentation = helper.wireRepresentation(); + QBuffer buffer; + buffer.setData(wireRepresentation); + buffer.open(QIODevice::ReadOnly); + QWebSocketFrame frame = QWebSocketFrame::readFrame(&buffer); + buffer.close(); + + QVERIFY(!frame.isValid()); + QCOMPARE(frame.closeCode(), expectedError); +} + + +/* + * Incomplete or overly large frames + * Payload must be crafted manually + * + QTest::newRow("Frame Too Big") + << 0 << 0 << 0 + << 0U << QWebSocketProtocol::OpCodeText + << true << QString(MAX_FRAME_SIZE_IN_BYTES + 1, 'a').toUtf8() + << QWebSocketProtocol::CloseCodeTooMuchData; + + */ +void tst_WebSocketFrame::tst_malformedFrames_data() +{ + QTest::addColumn("payload"); + QTest::addColumn("expectedError"); + + //too little data + QTest::newRow("No data") << QByteArray() << QWebSocketProtocol::CloseCodeGoingAway; + FrameHelper helper; + helper.setRsv1(0); + helper.setRsv2(0); + helper.setRsv3(0); + helper.setMask(0U); + helper.setOpCode(QWebSocketProtocol::OpCodeText); + helper.setFinalFrame(true); + helper.setPayload(QString(10, 'a').toUtf8()); + QByteArray wireRep = helper.wireRepresentation(); + + //too little data + //header + payload should be 12 bytes for non-masked payloads < 126 bytes + for (int i = 1; i < 12; ++i) + { + QTest::newRow(QStringLiteral("Header too small - %1 byte(s)").arg(i).toLatin1().constData()) + << wireRep.left(i) + << QWebSocketProtocol::CloseCodeGoingAway; + } + //too much data + { + const char bigpayloadIndicator = char(127); + const quint64 payloadSize = MAX_FRAME_SIZE_IN_BYTES + 1; + uchar swapped[8] = {0}; + qToBigEndian(payloadSize, swapped); + QTest::newRow("Frame too big") + << wireRep.left(1).append(bigpayloadIndicator) + .append(reinterpret_cast(swapped), 8) + << QWebSocketProtocol::CloseCodeTooMuchData; + } + //invalid size field + { + const char bigpayloadIndicator = char(127); + quint64 payloadSize = quint64(1) << 63; + uchar swapped[8] = {0}; + qToBigEndian(payloadSize, swapped); + QTest::newRow("Highest bit of payload length is set") + << wireRep.left(1).append(bigpayloadIndicator) + .append(reinterpret_cast(swapped), 8) + << QWebSocketProtocol::CloseCodeProtocolError; + + payloadSize = 256; + qToBigEndian(payloadSize, swapped); + QTest::newRow("Overlong 64-bit size field; should be 16-bit") + << wireRep.left(1).append(bigpayloadIndicator) + .append(reinterpret_cast(swapped), 8) + << QWebSocketProtocol::CloseCodeProtocolError; + } + //overlong size field + { + const char largepayloadIndicator = char(126); + const quint16 payloadSize = 120; + uchar swapped[2] = {0}; + qToBigEndian(payloadSize, swapped); + QTest::newRow("Overlong 16-bit size field") + << wireRep.left(1).append(largepayloadIndicator) + .append(reinterpret_cast(swapped), 2) + << QWebSocketProtocol::CloseCodeProtocolError; + } + { + const char bigpayloadIndicator = char(127); + quint64 payloadSize = 120; + uchar swapped[8] = {0}; + qToBigEndian(payloadSize, swapped); + QTest::newRow("Overlong 64-bit size field; should be 7-bit") + << wireRep.left(1).append(bigpayloadIndicator) + .append(reinterpret_cast(swapped), 8) + << QWebSocketProtocol::CloseCodeProtocolError; + + payloadSize = 256; + qToBigEndian(payloadSize, swapped); + QTest::newRow("Overlong 64-bit size field; should be 16-bit") + << wireRep.left(1).append(bigpayloadIndicator) + .append(reinterpret_cast(swapped), 8) + << QWebSocketProtocol::CloseCodeProtocolError; + } +} + +void tst_WebSocketFrame::tst_malformedFrames() +{ + QFETCH(QByteArray, payload); + QFETCH(QWebSocketProtocol::CloseCode, expectedError); + + QBuffer buffer; + buffer.setData(payload); + buffer.open(QIODevice::ReadOnly); + QWebSocketFrame frame = QWebSocketFrame::readFrame(&buffer); + buffer.close(); + + QVERIFY(!frame.isValid()); + QCOMPARE(frame.closeCode(), expectedError); +} + +QTEST_MAIN(tst_WebSocketFrame) + +#include "tst_websocketframe.moc" + diff --git a/tests/auto/websockets/websocketframe/websocketframe.pro b/tests/auto/websockets/websocketframe/websocketframe.pro new file mode 100644 index 0000000..9682348 --- /dev/null +++ b/tests/auto/websockets/websocketframe/websocketframe.pro @@ -0,0 +1,14 @@ +CONFIG += console +CONFIG += testcase +CONFIG -= app_bundle + +TEMPLATE = app + +TARGET = tst_websocketframe + +QT = core testlib websockets websockets-private + +SOURCES += tst_websocketframe.cpp + +requires(contains(QT_CONFIG, private_tests)) +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/websockets/websocketprotocol/tst_websocketprotocol.cpp b/tests/auto/websockets/websocketprotocol/tst_websocketprotocol.cpp new file mode 100644 index 0000000..94816de --- /dev/null +++ b/tests/auto/websockets/websocketprotocol/tst_websocketprotocol.cpp @@ -0,0 +1,289 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Kurt Pattyn . +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include +#include + +#include + +#include "QtWebSockets/qwebsocketprotocol.h" +#include "private/qwebsocketprotocol_p.h" + +QT_USE_NAMESPACE + +Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode) +Q_DECLARE_METATYPE(QWebSocketProtocol::OpCode) +Q_DECLARE_METATYPE(QWebSocketProtocol::Version) + +class tst_WebSocketProtocol : public QObject +{ + Q_OBJECT + +public: + tst_WebSocketProtocol(); + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + + void tst_validMasks_data(); + void tst_validMasks(); + + void tst_opCodes_data(); + void tst_opCodes(); + + void tst_closeCodes_data(); + void tst_closeCodes(); + + void tst_versionFromString_data(); + void tst_versionFromString(); +}; + +tst_WebSocketProtocol::tst_WebSocketProtocol() +{} + +void tst_WebSocketProtocol::initTestCase() +{ +} + +void tst_WebSocketProtocol::cleanupTestCase() +{} + +void tst_WebSocketProtocol::init() +{ + qRegisterMetaType("QWebSocketProtocol::OpCode"); + qRegisterMetaType("QWebSocketProtocol::CloseCode"); +} + +void tst_WebSocketProtocol::cleanup() +{ +} + +void tst_WebSocketProtocol::tst_validMasks_data() +{ + QTest::addColumn("mask"); + QTest::addColumn("inputdata"); + QTest::addColumn("result"); + + QTest::newRow("Empty payload") << 0x12345678u << QString() << QByteArray(); + QTest::newRow("ASCII payload of 8 characters") + << 0x12345678u + << QStringLiteral("abcdefgh") + << QByteArrayLiteral("\x73\x56\x35\x1C\x77\x52\x31\x10"); + QTest::newRow("ASCII payload of 9 characters") + << 0x12345678u + << QStringLiteral("abcdefghi") + << QByteArrayLiteral("\x73\x56\x35\x1C\x77\x52\x31\x10\x7B"); + //MSVC doesn't like UTF-8 in source code; + //the following text is represented in the string below: ∫∂ƒ©øØ + QTest::newRow("UTF-8 payload") + << 0x12345678u + << QString::fromUtf8("\xE2\x88\xAB\xE2\x88\x82\xC6\x92\xC2\xA9\xC3\xB8\xC3\x98") + << QByteArrayLiteral("\x2D\x0B\x69\xD1\xEA\xEC"); +} + +void tst_WebSocketProtocol::tst_validMasks() +{ + QFETCH(quint32, mask); + QFETCH(QString, inputdata); + QFETCH(QByteArray, result); + + //put latin1 into an explicit array + //otherwise, the intermediate object is deleted and the data pointer becomes invalid + QByteArray latin1 = inputdata.toLatin1(); + char *data = latin1.data(); + + QWebSocketProtocol::mask(data, inputdata.size(), mask); + QCOMPARE(QByteArray::fromRawData(data, inputdata.size()), result); +} + +void tst_WebSocketProtocol::tst_opCodes_data() +{ + QTest::addColumn("opCode"); + QTest::addColumn("isReserved"); + + QTest::newRow("OpCodeBinary") << QWebSocketProtocol::OpCodeBinary << false; + QTest::newRow("OpCodeClose") << QWebSocketProtocol::OpCodeClose << false; + QTest::newRow("OpCodeContinue") << QWebSocketProtocol::OpCodeContinue << false; + QTest::newRow("OpCodePing") << QWebSocketProtocol::OpCodePing << false; + QTest::newRow("OpCodePong") << QWebSocketProtocol::OpCodePong << false; + QTest::newRow("OpCodeReserved3") << QWebSocketProtocol::OpCodeReserved3 << true; + QTest::newRow("OpCodeReserved4") << QWebSocketProtocol::OpCodeReserved4 << true; + QTest::newRow("OpCodeReserved5") << QWebSocketProtocol::OpCodeReserved5 << true; + QTest::newRow("OpCodeReserved6") << QWebSocketProtocol::OpCodeReserved6 << true; + QTest::newRow("OpCodeReserved7") << QWebSocketProtocol::OpCodeReserved7 << true; + QTest::newRow("OpCodeReserved8") << QWebSocketProtocol::OpCodeReservedB << true; + QTest::newRow("OpCodeReservedC") << QWebSocketProtocol::OpCodeReservedC << true; + QTest::newRow("OpCodeReservedD") << QWebSocketProtocol::OpCodeReservedD << true; + QTest::newRow("OpCodeReservedE") << QWebSocketProtocol::OpCodeReservedE << true; + QTest::newRow("OpCodeReservedF") << QWebSocketProtocol::OpCodeReservedF << true; + QTest::newRow("OpCodeText") << QWebSocketProtocol::OpCodeText << false; +} + +void tst_WebSocketProtocol::tst_opCodes() +{ + QFETCH(QWebSocketProtocol::OpCode, opCode); + QFETCH(bool, isReserved); + + bool result = QWebSocketProtocol::isOpCodeReserved(opCode); + + QCOMPARE(result, isReserved); +} + +void tst_WebSocketProtocol::tst_closeCodes_data() +{ + QTest::addColumn("closeCode"); + QTest::addColumn("isValid"); + + for (int i = 0; i < 1000; ++i) + { + QTest::newRow(QStringLiteral("Close code %1").arg(i).toLatin1().constData()) << i << false; + } + + for (int i = 1000; i < 1004; ++i) + { + QTest::newRow(QStringLiteral("Close code %1").arg(i).toLatin1().constData()) << i << true; + } + + QTest::newRow("Close code 1004") << 1004 << false; + QTest::newRow("Close code 1005") << 1005 << false; + QTest::newRow("Close code 1006") << 1006 << false; + + for (int i = 1007; i < 1012; ++i) + { + QTest::newRow(QStringLiteral("Close code %1").arg(i).toLatin1().constData()) << i << true; + } + + for (int i = 1013; i < 3000; ++i) + { + QTest::newRow(QStringLiteral("Close code %1").arg(i).toLatin1().constData()) << i << false; + } + + for (int i = 3000; i < 5000; ++i) + { + QTest::newRow(QStringLiteral("Close code %1").arg(i).toLatin1().constData()) << i << true; + } + + QTest::newRow("Close code 5000") << 1004 << false; + QTest::newRow("Close code 6000") << 1004 << false; + QTest::newRow("Close code 7000") << 1004 << false; +} + +void tst_WebSocketProtocol::tst_closeCodes() +{ + QFETCH(int, closeCode); + QFETCH(bool, isValid); + + bool result = QWebSocketProtocol::isCloseCodeValid(closeCode); + + QCOMPARE(result, isValid); +} + +void tst_WebSocketProtocol::tst_versionFromString_data() +{ + QTest::addColumn("version"); + QTest::addColumn("versionString"); + + //happy flow; good data + QTest::newRow("Version 0") + << QWebSocketProtocol::Version0 + << QStringLiteral("0"); + QTest::newRow("Version 4") + << QWebSocketProtocol::Version4 + << QStringLiteral("4"); + QTest::newRow("Version 5") + << QWebSocketProtocol::Version5 + << QStringLiteral("5"); + QTest::newRow("Version 6") + << QWebSocketProtocol::Version6 + << QStringLiteral("6"); + QTest::newRow("Version 7") + << QWebSocketProtocol::Version7 + << QStringLiteral("7"); + QTest::newRow("Version 8") + << QWebSocketProtocol::Version8 + << QStringLiteral("8"); + QTest::newRow("Version 13") + << QWebSocketProtocol::Version13 + << QStringLiteral("13"); + + //rainy flow; invalid data + QTest::newRow("Version -1") + << QWebSocketProtocol::VersionUnknown + << QStringLiteral("-1"); + QTest::newRow("Version 1") + << QWebSocketProtocol::VersionUnknown + << QStringLiteral("1"); + QTest::newRow("Version 2") + << QWebSocketProtocol::VersionUnknown + << QStringLiteral("2"); + QTest::newRow("Version 3") + << QWebSocketProtocol::VersionUnknown + << QStringLiteral("3"); + QTest::newRow("Version 9") + << QWebSocketProtocol::VersionUnknown + << QStringLiteral("9"); + QTest::newRow("Version 10") + << QWebSocketProtocol::VersionUnknown + << QStringLiteral("10"); + QTest::newRow("Version 11") + << QWebSocketProtocol::VersionUnknown + << QStringLiteral("11"); + QTest::newRow("Version 12") + << QWebSocketProtocol::VersionUnknown + << QStringLiteral("12"); + QTest::newRow("Version abcd") + << QWebSocketProtocol::VersionUnknown + << QStringLiteral("abcd"); + QTest::newRow("Version 1.6") + << QWebSocketProtocol::VersionUnknown + << QStringLiteral("1.6"); + QTest::newRow("Version empty") + << QWebSocketProtocol::VersionUnknown + << QString(); +} + +void tst_WebSocketProtocol::tst_versionFromString() +{ + QFETCH(QWebSocketProtocol::Version, version); + QFETCH(QString, versionString); + + QCOMPARE(QWebSocketProtocol::versionFromString(versionString), version); +} + +QTEST_MAIN(tst_WebSocketProtocol) + +#include "tst_websocketprotocol.moc" + diff --git a/tests/auto/websockets/websocketprotocol/websocketprotocol.pro b/tests/auto/websockets/websocketprotocol/websocketprotocol.pro new file mode 100644 index 0000000..c21bb64 --- /dev/null +++ b/tests/auto/websockets/websocketprotocol/websocketprotocol.pro @@ -0,0 +1,14 @@ +CONFIG += console +CONFIG += testcase +CONFIG -= app_bundle + +TEMPLATE = app + +TARGET = tst_websocketprotocol + +QT = core testlib websockets websockets-private + +SOURCES += tst_websocketprotocol.cpp + +requires(contains(QT_CONFIG, private_tests)) +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/websockets/websockets.pro b/tests/auto/websockets/websockets.pro new file mode 100644 index 0000000..4698cd0 --- /dev/null +++ b/tests/auto/websockets/websockets.pro @@ -0,0 +1,16 @@ +TEMPLATE = subdirs + +SUBDIRS = \ + qwebsocketcorsauthenticator + +contains(QT_CONFIG, private_tests): SUBDIRS += \ + websocketprotocol \ + dataprocessor \ + websocketframe \ + handshakerequest \ + handshakeresponse \ + qdefaultmaskgenerator + +SUBDIRS += \ + qwebsocket \ + qwebsocketserver -- cgit v1.2.1 From bd1f5e1651c7cdaa712feebe2573dd158c87bb07 Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Wed, 20 May 2015 14:37:58 +0200 Subject: Fix qmldir for qmlwebsockets_compat It is not supported to have both "import Qt.WebSockets 1.0" and "import QtWebSockets 1.0" in the same project. Task-number: QTBUG-46205 Change-Id: I71b824b091f4491b8ab5e1eae8290a51159b03e2 Reviewed-by: Alex Blasche --- tests/auto/auto.pro | 4 ++ tests/auto/qml/qml.pro | 3 ++ tests/auto/qml/qmlwebsockets/qmlwebsockets.pro | 9 ++++ tests/auto/qml/qmlwebsockets/tst_qmlwebsockets.cpp | 35 +++++++++++++++ tests/auto/qml/qmlwebsockets/tst_qmlwebsockets.qml | 52 ++++++++++++++++++++++ .../qmlwebsockets_compat/qmlwebsockets_compat.pro | 9 ++++ .../tst_qmlwebsockets_compat.cpp | 35 +++++++++++++++ .../tst_qmlwebsockets_compat.qml | 52 ++++++++++++++++++++++ 8 files changed, 199 insertions(+) create mode 100644 tests/auto/qml/qml.pro create mode 100644 tests/auto/qml/qmlwebsockets/qmlwebsockets.pro create mode 100644 tests/auto/qml/qmlwebsockets/tst_qmlwebsockets.cpp create mode 100644 tests/auto/qml/qmlwebsockets/tst_qmlwebsockets.qml create mode 100644 tests/auto/qml/qmlwebsockets_compat/qmlwebsockets_compat.pro create mode 100644 tests/auto/qml/qmlwebsockets_compat/tst_qmlwebsockets_compat.cpp create mode 100644 tests/auto/qml/qmlwebsockets_compat/tst_qmlwebsockets_compat.qml (limited to 'tests/auto') diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 634e44b..d83cc1f 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -1,3 +1,7 @@ TEMPLATE = subdirs SUBDIRS += websockets + +qtHaveModule(quick) { + SUBDIRS += qml +} diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro new file mode 100644 index 0000000..24941ad --- /dev/null +++ b/tests/auto/qml/qml.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs + +SUBDIRS += qmlwebsockets qmlwebsockets_compat diff --git a/tests/auto/qml/qmlwebsockets/qmlwebsockets.pro b/tests/auto/qml/qmlwebsockets/qmlwebsockets.pro new file mode 100644 index 0000000..9405f37 --- /dev/null +++ b/tests/auto/qml/qmlwebsockets/qmlwebsockets.pro @@ -0,0 +1,9 @@ +TEMPLATE = app +TARGET = tst_qmlwebsockets +CONFIG += qmltestcase +CONFIG += console +SOURCES += tst_qmlwebsockets.cpp + +importFiles.path = . +DEPLOYMENT += importFiles + diff --git a/tests/auto/qml/qmlwebsockets/tst_qmlwebsockets.cpp b/tests/auto/qml/qmlwebsockets/tst_qmlwebsockets.cpp new file mode 100644 index 0000000..c230bf5 --- /dev/null +++ b/tests/auto/qml/qmlwebsockets/tst_qmlwebsockets.cpp @@ -0,0 +1,35 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +QUICK_TEST_MAIN(qmlwebsockets) diff --git a/tests/auto/qml/qmlwebsockets/tst_qmlwebsockets.qml b/tests/auto/qml/qmlwebsockets/tst_qmlwebsockets.qml new file mode 100644 index 0000000..6018037 --- /dev/null +++ b/tests/auto/qml/qmlwebsockets/tst_qmlwebsockets.qml @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.5 +import QtWebSockets 1.0 + +Rectangle { + width: 360 + height: 360 + + function appendMessage(message) { + messageBox.text += "\n" + message + } + + WebSocketServer { + id: server + } + + WebSocket { + id: socket + } +} diff --git a/tests/auto/qml/qmlwebsockets_compat/qmlwebsockets_compat.pro b/tests/auto/qml/qmlwebsockets_compat/qmlwebsockets_compat.pro new file mode 100644 index 0000000..104e6de --- /dev/null +++ b/tests/auto/qml/qmlwebsockets_compat/qmlwebsockets_compat.pro @@ -0,0 +1,9 @@ +TEMPLATE = app +TARGET = tst_qmlwebsockets_compat +CONFIG += qmltestcase +CONFIG += console +SOURCES += tst_qmlwebsockets_compat.cpp + +importFiles.path = . +DEPLOYMENT += importFiles + diff --git a/tests/auto/qml/qmlwebsockets_compat/tst_qmlwebsockets_compat.cpp b/tests/auto/qml/qmlwebsockets_compat/tst_qmlwebsockets_compat.cpp new file mode 100644 index 0000000..0ce5bce --- /dev/null +++ b/tests/auto/qml/qmlwebsockets_compat/tst_qmlwebsockets_compat.cpp @@ -0,0 +1,35 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +QUICK_TEST_MAIN(qmlwebsockets_compat) diff --git a/tests/auto/qml/qmlwebsockets_compat/tst_qmlwebsockets_compat.qml b/tests/auto/qml/qmlwebsockets_compat/tst_qmlwebsockets_compat.qml new file mode 100644 index 0000000..fa2a992 --- /dev/null +++ b/tests/auto/qml/qmlwebsockets_compat/tst_qmlwebsockets_compat.qml @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.5 +import Qt.WebSockets 1.0 + +Rectangle { + width: 360 + height: 360 + + function appendMessage(message) { + messageBox.text += "\n" + message + } + + WebSocketServer { + id: server + } + + WebSocket { + id: socket + } +} -- cgit v1.2.1 From 083f25b2989f5736a7531d9a49d839a79784906a Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Wed, 20 May 2015 14:38:41 +0200 Subject: tests: enable cmake in auto tests Change-Id: Idbfbaa86675381110f35118baf16cac891976707 Reviewed-by: Alex Blasche --- tests/auto/auto.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests/auto') diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index d83cc1f..d96c4a5 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -1,6 +1,6 @@ TEMPLATE = subdirs -SUBDIRS += websockets +SUBDIRS += cmake websockets qtHaveModule(quick) { SUBDIRS += qml -- cgit v1.2.1