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 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 --- .gitignore | 1 - .../qml/qmlwebsocketclient/main.qml | 2 +- .../qml/qmlwebsocketserver/main.qml | 2 +- src/imports/qmlwebsockets_compat/qmldir | 2 +- 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 ++++++++++++++++++++++ 12 files changed, 202 insertions(+), 4 deletions(-) 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 diff --git a/.gitignore b/.gitignore index 218d86e..78433a4 100644 --- a/.gitignore +++ b/.gitignore @@ -56,4 +56,3 @@ include tests/auto/cmake/build lib/ mkspecs/ -qml/ diff --git a/examples/websockets/qmlwebsocketclient/qml/qmlwebsocketclient/main.qml b/examples/websockets/qmlwebsocketclient/qml/qmlwebsocketclient/main.qml index 6d2749c..35d64e0 100644 --- a/examples/websockets/qmlwebsocketclient/qml/qmlwebsocketclient/main.qml +++ b/examples/websockets/qmlwebsocketclient/qml/qmlwebsocketclient/main.qml @@ -31,7 +31,7 @@ ** ****************************************************************************/ import QtQuick 2.0 -import Qt.WebSockets 1.0 +import QtWebSockets 1.0 Rectangle { width: 360 diff --git a/examples/websockets/qmlwebsocketserver/qml/qmlwebsocketserver/main.qml b/examples/websockets/qmlwebsocketserver/qml/qmlwebsocketserver/main.qml index 6c3433f..c0178ba 100644 --- a/examples/websockets/qmlwebsocketserver/qml/qmlwebsocketserver/main.qml +++ b/examples/websockets/qmlwebsocketserver/qml/qmlwebsocketserver/main.qml @@ -32,7 +32,7 @@ ****************************************************************************/ import QtQuick 2.0 -import Qt.WebSockets 1.0 +import QtWebSockets 1.0 Rectangle { width: 360 diff --git a/src/imports/qmlwebsockets_compat/qmldir b/src/imports/qmlwebsockets_compat/qmldir index 8541103..eca44f0 100644 --- a/src/imports/qmlwebsockets_compat/qmldir +++ b/src/imports/qmlwebsockets_compat/qmldir @@ -1,4 +1,4 @@ module Qt.WebSockets -plugin ../../QtWebSockets/declarative_qmlwebsockets +plugin declarative_qmlwebsockets ../../QtWebSockets/ classname QtWebSocketsDeclarativeModule typeinfo ../../QtWebSockets/plugins.qmltypes 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 88dd8bc7e0365d0b0846b97d60c74370452f13b3 Mon Sep 17 00:00:00 2001 From: Sze Howe Koh Date: Fri, 22 May 2015 07:47:53 +0800 Subject: Doc: Document the changes to the QML import statement The changes happened in 759b6b12489b68fcbd755398ff9337acefb035a0 [ChangeLog][QML] The import statement has changed from "import Qt.WebSockets 1.0" to "import QtWebSockets 1.0". The old statement is still supported, but it cannot be mixed with the new statement within the same project. Change-Id: I95d75e4a87133c452d2ea43c42593415de882c9b Reviewed-by: Liang Qi Reviewed-by: Alex Blasche --- src/websockets/doc/src/qtwebsockets-module.qdoc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/websockets/doc/src/qtwebsockets-module.qdoc b/src/websockets/doc/src/qtwebsockets-module.qdoc index acbe2ac..6c717f4 100644 --- a/src/websockets/doc/src/qtwebsockets-module.qdoc +++ b/src/websockets/doc/src/qtwebsockets-module.qdoc @@ -58,4 +58,9 @@ \code import QtWebSockets 1.0 \endcode + + \note Prior to Qt 5.5, the import statement was \c{import Qt.WebSockets 1.0} + (notice the dot between \c Qt and \c WebSockets). The old statement is still + supported for backwards compatibility, but it cannot be mixed with the new + statement within the same project. */ -- cgit v1.2.1 From 311f231f8b308b10e1b355ae366505c8ffadf86f Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Fri, 22 May 2015 08:22:35 +0200 Subject: Correct the default port of secure hand shake request Task-number: QTBUG-46055 Change-Id: Iefdec32f778d39520802eabb25f4db37f80fdf76 Reviewed-by: Oswald Buddenhagen Reviewed-by: Luca Niccoli Reviewed-by: Alex Blasche --- src/websockets/qwebsocket_p.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/websockets/qwebsocket_p.cpp b/src/websockets/qwebsocket_p.cpp index c7a2d00..174214c 100644 --- a/src/websockets/qwebsocket_p.cpp +++ b/src/websockets/qwebsocket_p.cpp @@ -1038,6 +1038,10 @@ void QWebSocketPrivate::processStateChanged(QAbstractSocket::SocketState socketS Q_ASSERT(m_pSocket); Q_Q(QWebSocket); QAbstractSocket::SocketState webSocketState = this->state(); + int port = 80; + if (m_requestUrl.scheme() == QStringLiteral("wss")) + port = 443; + switch (socketState) { case QAbstractSocket::ConnectedState: if (webSocketState == QAbstractSocket::ConnectingState) { @@ -1046,7 +1050,7 @@ void QWebSocketPrivate::processStateChanged(QAbstractSocket::SocketState socketS createHandShakeRequest(m_resourceName, m_requestUrl.host() % QStringLiteral(":") - % QString::number(m_requestUrl.port(80)), + % QString::number(m_requestUrl.port(port)), origin(), QString(), QString(), -- 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(-) 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 From 79e84ac39d17264d24c732a4e9693f4b5b57b3ac Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Mon, 25 May 2015 15:19:26 +0200 Subject: Update plugins.qmltypes for QtWebSockets and Qt.WebSockets Change-Id: I7cacbce1625015636e92b2fd5f2ade694a97a5c9 Reviewed-by: Sze Howe Koh Reviewed-by: Alex Blasche --- src/imports/qmlwebsockets/plugins.qmltypes | 5 +- src/imports/qmlwebsockets_compat/plugins.qmltypes | 97 +++++++++++++++++++++++ src/imports/qmlwebsockets_compat/qmldir | 2 +- 3 files changed, 101 insertions(+), 3 deletions(-) create mode 100644 src/imports/qmlwebsockets_compat/plugins.qmltypes diff --git a/src/imports/qmlwebsockets/plugins.qmltypes b/src/imports/qmlwebsockets/plugins.qmltypes index 5b8d1f9..5df4b5c 100644 --- a/src/imports/qmlwebsockets/plugins.qmltypes +++ b/src/imports/qmlwebsockets/plugins.qmltypes @@ -1,4 +1,4 @@ -import QtQuick.tooling 1.1 +import QtQuick.tooling 1.2 // This file describes the plugin-supplied types contained in the library. // It is used for QML tooling purposes only. @@ -7,6 +7,7 @@ import QtQuick.tooling 1.1 // 'qmlplugindump -notrelocatable QtWebSockets 1.0' Module { + dependencies: [] Component { name: "QQmlWebSocket" prototype: "QObject" @@ -51,7 +52,7 @@ Module { Component { name: "QQmlWebSocketServer" prototype: "QObject" - exports: ["Qt.WebSockets/WebSocketServer 1.0"] + exports: ["QtWebSockets/WebSocketServer 1.0"] exportMetaObjectRevisions: [0] Property { name: "url"; type: "QUrl"; isReadonly: true } Property { name: "host"; type: "string" } diff --git a/src/imports/qmlwebsockets_compat/plugins.qmltypes b/src/imports/qmlwebsockets_compat/plugins.qmltypes new file mode 100644 index 0000000..ff8d976 --- /dev/null +++ b/src/imports/qmlwebsockets_compat/plugins.qmltypes @@ -0,0 +1,97 @@ +import QtQuick.tooling 1.2 + +// This file describes the plugin-supplied types contained in the library. +// It is used for QML tooling purposes only. +// +// This file was auto-generated by: +// 'qmlplugindump -notrelocatable Qt.WebSockets 1.0' + +Module { + dependencies: [] + Component { + name: "QQmlWebSocket" + prototype: "QObject" + exports: ["Qt.WebSockets/WebSocket 1.0"] + exportMetaObjectRevisions: [0] + Enum { + name: "Status" + values: { + "Connecting": 0, + "Open": 1, + "Closing": 2, + "Closed": 3, + "Error": 4 + } + } + Property { name: "url"; type: "QUrl" } + Property { name: "status"; type: "Status"; isReadonly: true } + Property { name: "errorString"; type: "string"; isReadonly: true } + Property { name: "active"; type: "bool" } + Signal { + name: "textMessageReceived" + Parameter { name: "message"; type: "string" } + } + Signal { + name: "statusChanged" + Parameter { name: "status"; type: "Status" } + } + Signal { + name: "activeChanged" + Parameter { name: "isActive"; type: "bool" } + } + Signal { + name: "errorStringChanged" + Parameter { name: "errorString"; type: "string" } + } + Method { + name: "sendTextMessage" + type: "qlonglong" + Parameter { name: "message"; type: "string" } + } + } + Component { + name: "QQmlWebSocketServer" + prototype: "QObject" + exports: ["Qt.WebSockets/WebSocketServer 1.0"] + exportMetaObjectRevisions: [0] + Property { name: "url"; type: "QUrl"; isReadonly: true } + Property { name: "host"; type: "string" } + Property { name: "port"; type: "ushort" } + Property { name: "name"; type: "string" } + Property { name: "errorString"; type: "string"; isReadonly: true } + Property { name: "listen"; type: "bool" } + Property { name: "accept"; type: "bool" } + Signal { + name: "clientConnected" + Parameter { name: "webSocket"; type: "QQmlWebSocket"; isPointer: true } + } + Signal { + name: "errorStringChanged" + Parameter { name: "errorString"; type: "string" } + } + Signal { + name: "urlChanged" + Parameter { name: "url"; type: "QUrl" } + } + Signal { + name: "portChanged" + Parameter { name: "port"; type: "ushort" } + } + Signal { + name: "nameChanged" + Parameter { name: "name"; type: "string" } + } + Signal { + name: "hostChanged" + Parameter { name: "host"; type: "string" } + } + Signal { + name: "listenChanged" + Parameter { name: "listen"; type: "bool" } + } + Signal { + name: "acceptChanged" + Parameter { name: "accept"; type: "bool" } + } + } +} diff --git a/src/imports/qmlwebsockets_compat/qmldir b/src/imports/qmlwebsockets_compat/qmldir index eca44f0..a4310d9 100644 --- a/src/imports/qmlwebsockets_compat/qmldir +++ b/src/imports/qmlwebsockets_compat/qmldir @@ -1,4 +1,4 @@ module Qt.WebSockets plugin declarative_qmlwebsockets ../../QtWebSockets/ classname QtWebSocketsDeclarativeModule -typeinfo ../../QtWebSockets/plugins.qmltypes +typeinfo plugins.qmltypes -- cgit v1.2.1 From 5edfb3c7ee338c0b562f33a8c4315454bfc18886 Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Fri, 22 May 2015 14:07:34 +0200 Subject: QWebSocketServer: handle new connection after invalid one Manually tested with sslechoserver and sslechoclient in examples, invalid connection from "telnet localhost 1234". Task-number: QTBUG-44866 Change-Id: I19c29c7c5f57eef4f9ae069e105fd1db346fb5c5 Reviewed-by: Luca Niccoli Reviewed-by: Alex Blasche --- src/websockets/qwebsocketserver_p.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/websockets/qwebsocketserver_p.cpp b/src/websockets/qwebsocketserver_p.cpp index 73ca9d7..bc23674 100644 --- a/src/websockets/qwebsocketserver_p.cpp +++ b/src/websockets/qwebsocketserver_p.cpp @@ -370,13 +370,15 @@ void QWebSocketServerPrivate::setError(QWebSocketProtocol::CloseCode code, const */ void QWebSocketServerPrivate::onNewConnection() { - QTcpSocket *pTcpSocket = m_pTcpServer->nextPendingConnection(); - //use a queued connection because a QSslSocket - //needs the event loop to process incoming data - //if not queued, data is incomplete when handshakeReceived is called - QObjectPrivate::connect(pTcpSocket, &QTcpSocket::readyRead, - this, &QWebSocketServerPrivate::handshakeReceived, - Qt::QueuedConnection); + while (m_pTcpServer->hasPendingConnections()) { + QTcpSocket *pTcpSocket = m_pTcpServer->nextPendingConnection(); + //use a queued connection because a QSslSocket + //needs the event loop to process incoming data + //if not queued, data is incomplete when handshakeReceived is called + QObjectPrivate::connect(pTcpSocket, &QTcpSocket::readyRead, + this, &QWebSocketServerPrivate::handshakeReceived, + Qt::QueuedConnection); + } } /*! -- cgit v1.2.1 From 150db98da8695f74601b1776742e8284602207fe Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Tue, 17 Feb 2015 10:57:02 +0100 Subject: Doc: Add documentation on how to test with Autobahn|Testsuite Change-Id: Ia18acdc3c54e2bb48209406d2a6f9e156b67324c Reviewed-by: Liang Qi Reviewed-by: Venugopal Shivashankar --- src/websockets/doc/qtwebsockets.qdocconf | 3 +- src/websockets/doc/src/index.qdoc | 20 ++++++++++- tests/doc/README | 58 ++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 tests/doc/README diff --git a/src/websockets/doc/qtwebsockets.qdocconf b/src/websockets/doc/qtwebsockets.qdocconf index 2e1e15b..8ce18ec 100644 --- a/src/websockets/doc/qtwebsockets.qdocconf +++ b/src/websockets/doc/qtwebsockets.qdocconf @@ -44,7 +44,8 @@ headerdirs += .. \ sourcedirs += .. \ src \ - ../../imports + ../../imports \ + ../../../tests/doc exampledirs += ../../../examples/websockets \ diff --git a/src/websockets/doc/src/index.qdoc b/src/websockets/doc/src/index.qdoc index 0d28036..344a859 100644 --- a/src/websockets/doc/src/index.qdoc +++ b/src/websockets/doc/src/index.qdoc @@ -57,7 +57,7 @@ QT += websockets \endcode - \section1 Reference documentation + \section1 Reference Documentation \list \li \l{Qt WebSockets C++ Classes}{C++ Classes} \li \l{Qt WebSockets QML Types}{QML Types} @@ -67,4 +67,22 @@ The module provides the following \l{Qt WebSockets Examples}{Examples} as a guide to using the API. + + \section1 Conformance + \list + \li \l {Testing Qt WebSockets} + \endlist +*/ + +/*! + \page qtwebsockets-testing.html + \title Testing Qt WebSockets + + \l {http://autobahn.ws/testsuite/}{Autobahn|Testsuite}, a standard test + suite for WebSocket Protocol (RFC 6455), can be used for testing the + conformance of Qt WebSockets. Refer to Autobahn|Testsuite + \l {http://autobahn.ws/testsuite/installation.html}{installation documentation} + to set up the test suite. + + \include README testsuite */ diff --git a/tests/doc/README b/tests/doc/README new file mode 100644 index 0000000..da9b2b5 --- /dev/null +++ b/tests/doc/README @@ -0,0 +1,58 @@ +This directory contains autotests and manual tests for the Qt WebSockets +module. + +In addition, Autobahn|Testsuite, a standard test suite for WebSocket +Protocol (RFC 6455), can be used for testing the conformance of Qt +WebSockets. + +http://autobahn.ws/testsuite/ + +Refer to Autobahn|Testsuite installation documentation at +http://autobahn.ws/testsuite/installation.html + +//! [testsuite] +\section1 Testing Qt WebSockets with Autobahn|Testsuite + + +\section2 wstest - fuzzingserver mode + +\code + cd your_build_dir/tests/manual/compliance + qmake your_src_dir/tests/manual/compliance/compliance.pro + make + + cd ~ + wstest -m fuzzingserver +\endcode + +Then, in another terminal: + +\code + cd your_build_dir/tests/manual/compliance + ./tst_compliance +\endcode + +Test results will be generated under ~/reports/clients directory. +Point your browser to ~/reports/clients/index.html. + + +\section2 wstest - fuzzingclient mode + +\code + cd your_build_dir/examples/websockets/echoserver + qmake your_src_dir/examples/websockets/echoserver/echoserver.pro + make + + ./echoserver -p 9001 +\endcode + +Then, in another terminal: + +\code + cd ~ + wstest -m fuzzingclient +\endcode + +Test results will be generated under ~/reports/servers directory. +Point your browser to ~/reports/servers/index.html. +//! [testsuite] -- cgit v1.2.1 From 0e3d20ddcfcb520fba3cab53fe39e1493a8348f9 Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Wed, 3 Jun 2015 10:30:51 +0200 Subject: 5.5.0 changelog Change-Id: Ia9541416b13519389e5a2061a8ef978046570286 Reviewed-by: Oswald Buddenhagen Reviewed-by: Luca Niccoli Reviewed-by: Liang Qi --- dist/changes-5.5.0 | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 dist/changes-5.5.0 diff --git a/dist/changes-5.5.0 b/dist/changes-5.5.0 new file mode 100644 index 0000000..b32634b --- /dev/null +++ b/dist/changes-5.5.0 @@ -0,0 +1,49 @@ +Qt 5.5 introduces many new features and improvements as well as bugfixes +over the 5.4.x series. For more details, refer to the online documentation +included in this distribution. The documentation is also available online: + + http://doc.qt.io/qt-5/index.html + +The Qt version 5.5 series is binary compatible with the 5.4.x series. +Applications compiled for 5.4 will continue to run with 5.5. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + + https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* QML * +**************************************************************************** + + - The import statement has changed from "import Qt.WebSockets 1.0" to + "import QtWebSockets 1.0". The old statement is still supported, but it + cannot be mixed with the new statement within the same project. + +**************************************************************************** +* QtWebSockets * +**************************************************************************** + + - QWebSocket: + * [QTBUG-41285] Fixed QWebSocket's handling of query parameters with + encoded characters + * [QTBUG-42298] Added masking of ping from client side based on RFC 6455, + Section 5.1. + * [QTBUG-44893] Fixed spurious error signals on first connection + * [QTBUG-44889] Fixed handling of url paths with encoded characters + * [QTBUG-46055] Corrected the default port of secure hand shake request + + - QWebSocketServer: + * [QTBUG-44866] Avoid hanging after an invalid SSL request + * [QTBUG-45331] Fixed a crash when destroying the QWebSocketServer + +**************************************************************************** +* Platform Specific Changes * +**************************************************************************** + +WinRT +----- + - [QTBUG-44491] Fixed the build for WinRT/ARM -- cgit v1.2.1 From 8c2c5938b79f64e869a82f742da063e281171e1d Mon Sep 17 00:00:00 2001 From: Venugopal Shivashankar Date: Thu, 28 May 2015 22:36:56 +0200 Subject: Doc: Added an overview page and updated the qdocconf Task-number: QTBUG-41044 Change-Id: I074573e814de63e009744a11054365fb2f25bdb9 Reviewed-by: Liang Qi --- .../images/websockets-pictorial-representation.jpg | Bin 0 -> 39914 bytes src/websockets/doc/qtwebsockets.qdocconf | 3 +- src/websockets/doc/src/index.qdoc | 9 +- src/websockets/doc/src/overview.qdoc | 112 +++++++++++++++++++++ 4 files changed, 118 insertions(+), 6 deletions(-) create mode 100644 src/websockets/doc/images/websockets-pictorial-representation.jpg create mode 100644 src/websockets/doc/src/overview.qdoc diff --git a/src/websockets/doc/images/websockets-pictorial-representation.jpg b/src/websockets/doc/images/websockets-pictorial-representation.jpg new file mode 100644 index 0000000..5308fdd Binary files /dev/null and b/src/websockets/doc/images/websockets-pictorial-representation.jpg differ diff --git a/src/websockets/doc/qtwebsockets.qdocconf b/src/websockets/doc/qtwebsockets.qdocconf index 8ce18ec..002898c 100644 --- a/src/websockets/doc/qtwebsockets.qdocconf +++ b/src/websockets/doc/qtwebsockets.qdocconf @@ -53,7 +53,8 @@ exampledirs += ../../../examples/websock examples.fileextensions += "*.html" -imagedirs += ../../../examples/websockets/doc/images +imagedirs += ../../../examples/websockets/doc/images \ + images manifestmeta.thumbnail.names += "QtWebSockets/*" diff --git a/src/websockets/doc/src/index.qdoc b/src/websockets/doc/src/index.qdoc index 344a859..e0f219c 100644 --- a/src/websockets/doc/src/index.qdoc +++ b/src/websockets/doc/src/index.qdoc @@ -37,11 +37,9 @@ the solution for applications that struggle to get real-time data feeds with less network latency and minimum data exchange. - The Qt WebSockets module implements the WebSocket protocol as specified in - \l {http://tools.ietf.org/html/rfc6455} {RFC 6455}. It provides C++ and QML - interfaces that enable Qt applications to act as a server that can process - WebSocket-based requests, or a client that can consume data received from - the server, or both. + The Qt WebSockets module provides C++ and QML interfaces that enable + Qt applications to act as a server that can process WebSocket requests, + or a client that can consume data received from the server, or both. To use this module in your application, use the following include statement: @@ -59,6 +57,7 @@ \section1 Reference Documentation \list + \li \l{Qt WebSockets Overview}{Overview} \li \l{Qt WebSockets C++ Classes}{C++ Classes} \li \l{Qt WebSockets QML Types}{QML Types} \endlist diff --git a/src/websockets/doc/src/overview.qdoc b/src/websockets/doc/src/overview.qdoc new file mode 100644 index 0000000..df080c1 --- /dev/null +++ b/src/websockets/doc/src/overview.qdoc @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! +\page websockets-overview.html +\title Qt WebSockets Overview +\brief Provides insight into the WebSocket protocol and the Qt WebSockets module. + +Qt WebSockets enables you to build WebSocket-aware applications. It +provides an implementation for the WebSocket protocol, which is offered by IETF +(Internet Engineering Task Force) as a better alternative for bidirectional +communication using the existing web infrastructure. + +Historically, web applications that needed bidirectional communication or +push notifications had to use one of the HTTP-based solutions available. These +solutions employed different techniques such as polling, long-polling, and +streaming, to overcome the limitations of HTTP protocol, which is not designed +for such use cases. As a result, high network latency, unnecessary data +exchange, and stale or old data. The WebSocket offering by IETF helps to +overcome these problems to a large extent. + +\section1 How does it Work? + +\image websockets-pictorial-representation.jpg + +As you can see in the pictorial representation, WebSocket-based solution +consists of a client-side and server-side. The native client-side support for +WebSocket is available on most of the popular web browsers such as Google +Chrome, Internet Explorer, Safari, and so on. The server-side support for +WebSocket makes it a complete solution, enabling bidirectional communication. +Any browser with native WebSocket support should let you run a simple HTML and +JavaScript-based client application using the HTML5 WebSocket API. + +A WebSocket connection begins with a initial HTTP-compatible handshake, +which ensures backwards compatibility so that the WebSocket connections can +share the default HTTP (80) and HTTPS (443) ports. On successful handshake, +the connection is open for data exchange, until one of the two entities end +the connection. + +The WebSocket protocol uses \c ws: and \c wss: URL schemes to represent +unsecure and secure WebSocket requests, respectively. During the initial +handshake, if a proxy server is detected, the protocol tries to set up a tunnel +by issuing an \c{HTTP CONNECT} statement to the proxy. The tunnel approach to +handle proxies is used irrespective of the request type, although it is proved +to work better with TLS (Transport Layer Security) in secure connections. + +\section1 Typical Use Cases + +WebSocket suits best for scenarios where, +\list + \li data presented must be up-to-date, + \li low network latency and minimal data exchange is crucial. +\endlist + +A few example applications where we struggle to achieve these using the +traditional approach are, instant messaging, online gaming, online stock +trading, and so on. + +\section1 Role of Qt WebSockets + +The Qt WebSockets module provides APIs to develop WebSocket-based server and +client applications. An example of where these APIs can be used is a server +application that provides stock data, and a client application that registers +for push notification when there is a change in price of a few stocks. + +The module provides both C++ and QML versions of the API, so you can choose +the alternative that suits your need. + +\section2 Qt WebSockets with Qt Cloud Services + +The client application usually depends on an external service for data. Most of +these service providers do not support WebSocket yet, so you end up developing +a WebSocket-aware server application to bridge the gap. You can choose to run +the server on an enterprise WebSocket gateway service such as Qt Cloud +Services, avoiding the hassle of maintaining the necessary infrastructure +required to host such a service. + +The Qt Cloud Services provides a Managed Application Runtime (MAR) backend, +which enables deploying and running an instance of server application on the +cloud. The server instance running on MAR gets a WebSocket URL, which can be +used by the client applications to connect and receive data. + +\section2 Related Information +\list +\li \l {http://tools.ietf.org/html/rfc6455}{WebSocket RFC 6455} +\li \l {https://qtcloudservices.com}{Qt Cloud Services} +\endlist +*/ -- cgit v1.2.1 From 086f3722777ee61f3c019ca064d4a844cf0f6fe4 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 29 Jun 2015 10:48:23 +0200 Subject: Bump version Change-Id: Ie226303b4a1059c22fa5752adcb621fcc05a53e8 --- .qmake.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.qmake.conf b/.qmake.conf index 76fcbdf..2ea3e52 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -3,4 +3,4 @@ load(qt_build_config) CONFIG += qt_example_installs CONFIG += warning_clean -MODULE_VERSION = 5.5.0 +MODULE_VERSION = 5.5.1 -- cgit v1.2.1