summaryrefslogtreecommitdiffstats
path: root/tests/auto/network
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/network')
-rw-r--r--tests/auto/network/access/access.pro7
-rw-r--r--tests/auto/network/access/hpack/hpack.pro6
-rw-r--r--tests/auto/network/access/hpack/tst_hpack.cpp852
-rw-r--r--tests/auto/network/access/http2/certs/fluke.cert75
-rw-r--r--tests/auto/network/access/http2/certs/fluke.key15
-rw-r--r--tests/auto/network/access/http2/http2.pro8
-rw-r--r--tests/auto/network/access/http2/http2srv.cpp695
-rw-r--r--tests/auto/network/access/http2/http2srv.h172
-rw-r--r--tests/auto/network/access/http2/tst_http2.cpp539
-rw-r--r--tests/auto/network/access/qftp/qftp.pro9
-rw-r--r--tests/auto/network/access/qftp/tst_qftp.cpp9
-rw-r--r--tests/auto/network/access/qhttpnetworkconnection/qhttpnetworkconnection.pro2
-rw-r--r--tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp182
-rw-r--r--tests/auto/network/access/qhttpnetworkreply/qhttpnetworkreply.pro2
-rw-r--r--tests/auto/network/access/qnetworkcookie/tst_qnetworkcookie.cpp27
-rw-r--r--tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp28
-rw-r--r--tests/auto/network/access/qnetworkreply/qnetworkreply.pro2
-rw-r--r--tests/auto/network/access/qnetworkreply/test/test.pro3
-rw-r--r--tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp84
-rw-r--r--tests/auto/network/access/qnetworkrequest/tst_qnetworkrequest.cpp27
-rw-r--r--tests/auto/network/kernel/kernel.pro3
-rw-r--r--tests/auto/network/kernel/qauthenticator/qauthenticator.pro2
-rw-r--r--tests/auto/network/kernel/qhostaddress/qhostaddress.pro8
-rw-r--r--tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp50
-rw-r--r--tests/auto/network/kernel/qhostinfo/qhostinfo.pro8
-rw-r--r--tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp8
-rw-r--r--tests/auto/network/kernel/qnetworkdatagram/qnetworkdatagram.pro5
-rw-r--r--tests/auto/network/kernel/qnetworkdatagram/tst_qnetworkdatagram.cpp146
-rw-r--r--tests/auto/network/socket/platformsocketengine/platformsocketengine.pri10
-rw-r--r--tests/auto/network/socket/platformsocketengine/platformsocketengine.pro2
-rw-r--r--tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp9
-rw-r--r--tests/auto/network/socket/qhttpsocketengine/qhttpsocketengine.pro2
-rw-r--r--tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp4
-rw-r--r--tests/auto/network/socket/qlocalsocket/test/test.pro8
-rw-r--r--tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp2
-rw-r--r--tests/auto/network/socket/qsctpsocket/qsctpsocket.pro6
-rw-r--r--tests/auto/network/socket/qsctpsocket/tst_qsctpsocket.cpp488
-rw-r--r--tests/auto/network/socket/qsocks5socketengine/qsocks5socketengine.pro2
-rw-r--r--tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp4
-rw-r--r--tests/auto/network/socket/qtcpserver/crashingServer/main.cpp8
-rw-r--r--tests/auto/network/socket/qtcpserver/test/test.pro11
-rw-r--r--tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp39
-rw-r--r--tests/auto/network/socket/qtcpsocket/qtcpsocket.pro4
-rw-r--r--tests/auto/network/socket/qtcpsocket/test/test.pro8
-rw-r--r--tests/auto/network/socket/qudpsocket/test/test.pro6
-rw-r--r--tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp121
-rw-r--r--tests/auto/network/socket/socket.pro8
-rw-r--r--tests/auto/network/ssl/qsslcertificate/qsslcertificate.pro2
-rw-r--r--tests/auto/network/ssl/qsslcipher/qsslcipher.pro2
-rw-r--r--tests/auto/network/ssl/qssldiffiehellmanparameters/qssldiffiehellmanparameters.pro8
-rw-r--r--tests/auto/network/ssl/qssldiffiehellmanparameters/tst_qssldiffiehellmanparameters.cpp163
-rw-r--r--tests/auto/network/ssl/qsslellipticcurve/qsslellipticcurve.pro2
-rw-r--r--tests/auto/network/ssl/qsslerror/qsslerror.pro2
-rw-r--r--tests/auto/network/ssl/qsslkey/qsslkey.pro4
-rw-r--r--tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp61
-rw-r--r--tests/auto/network/ssl/qsslsocket/qsslsocket.pro16
-rw-r--r--tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp397
-rw-r--r--tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/qsslsocket_onDemandCertificates_member.pro10
-rw-r--r--tests/auto/network/ssl/qsslsocket_onDemandCertificates_static/qsslsocket_onDemandCertificates_static.pro10
-rw-r--r--tests/auto/network/ssl/ssl.pro13
60 files changed, 3822 insertions, 584 deletions
diff --git a/tests/auto/network/access/access.pro b/tests/auto/network/access/access.pro
index bc76190e30..1d78cf253b 100644
--- a/tests/auto/network/access/access.pro
+++ b/tests/auto/network/access/access.pro
@@ -12,9 +12,12 @@ SUBDIRS=\
qftp \
qhttpnetworkreply \
qabstractnetworkcache \
+ hpack \
+ http2
-!contains(QT_CONFIG, private_tests): SUBDIRS -= \
+!qtConfig(private_tests): SUBDIRS -= \
qhttpnetworkconnection \
qhttpnetworkreply \
qftp \
-
+ hpack \
+ http2
diff --git a/tests/auto/network/access/hpack/hpack.pro b/tests/auto/network/access/hpack/hpack.pro
new file mode 100644
index 0000000000..3c8b8e7944
--- /dev/null
+++ b/tests/auto/network/access/hpack/hpack.pro
@@ -0,0 +1,6 @@
+QT += core core-private network network-private testlib
+CONFIG += testcase parallel_test c++14
+TEMPLATE = app
+TARGET = tst_hpack
+
+SOURCES += tst_hpack.cpp
diff --git a/tests/auto/network/access/hpack/tst_hpack.cpp b/tests/auto/network/access/hpack/tst_hpack.cpp
new file mode 100644
index 0000000000..bd337c9f5f
--- /dev/null
+++ b/tests/auto/network/access/hpack/tst_hpack.cpp
@@ -0,0 +1,852 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2014 Governikus GmbH & Co. KG.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+
+#include <QtNetwork/private/bitstreams_p.h>
+#include <QtNetwork/private/hpack_p.h>
+
+#include <QtCore/qbytearray.h>
+
+#include <cstdlib>
+#include <vector>
+#include <string>
+
+QT_USE_NAMESPACE
+
+using namespace HPack;
+
+class tst_Hpack: public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_Hpack();
+private Q_SLOTS:
+ void bitstreamConstruction();
+ void bitstreamWrite();
+ void bitstreamReadWrite();
+ void bitstreamCompression();
+ void bitstreamErrors();
+
+ void lookupTableConstructor();
+
+ void lookupTableStatic_data();
+ void lookupTableStatic();
+ void lookupTableDynamic();
+
+ void hpackEncodeRequest_data();
+ void hpackEncodeRequest();
+ void hpackDecodeRequest_data();
+ void hpackDecodeRequest();
+
+ void hpackEncodeResponse_data();
+ void hpackEncodeResponse();
+ void hpackDecodeResponse_data();
+ void hpackDecodeResponse();
+
+ // TODO: more-more-more tests needed!
+
+private:
+ void hpackEncodeRequest(bool withHuffman);
+ void hpackEncodeResponse(bool withHuffman);
+
+ HttpHeader header1;
+ std::vector<uchar> buffer1;
+ BitOStream request1;
+
+ HttpHeader header2;
+ std::vector<uchar> buffer2;
+ BitOStream request2;
+
+ HttpHeader header3;
+ std::vector<uchar> buffer3;
+ BitOStream request3;
+};
+
+using StreamError = BitIStream::Error;
+
+tst_Hpack::tst_Hpack()
+ : request1(buffer1),
+ request2(buffer2),
+ request3(buffer3)
+{
+}
+
+void tst_Hpack::bitstreamConstruction()
+{
+ const uchar bytes[] = {0xDE, 0xAD, 0xBE, 0xEF};
+ const int size = int(sizeof bytes);
+
+ // Default ctors:
+ std::vector<uchar> buffer;
+ {
+ const BitOStream out(buffer);
+ QVERIFY(out.bitLength() == 0);
+ QVERIFY(out.byteLength() == 0);
+
+ const BitIStream in;
+ QVERIFY(in.bitLength() == 0);
+ QVERIFY(in.streamOffset() == 0);
+ QVERIFY(in.error() == StreamError::NoError);
+ }
+
+ // Create istream with some data:
+ {
+ BitIStream in(bytes, bytes + size);
+ QVERIFY(in.bitLength() == size * 8);
+ QVERIFY(in.streamOffset() == 0);
+ QVERIFY(in.error() == StreamError::NoError);
+ // 'Read' some data back:
+ for (int i = 0; i < size; ++i) {
+ uchar bitPattern = 0;
+ const auto bitsRead = in.peekBits(i * 8, 8, &bitPattern);
+ QVERIFY(bitsRead == 8);
+ QVERIFY(bitPattern == bytes[i]);
+ }
+ }
+
+ // Copy ctors:
+ {
+ // Ostreams - copy is disabled.
+ // Istreams:
+ const BitIStream in1;
+ const BitIStream in2(in1);
+ QVERIFY(in2.bitLength() == in1.bitLength());
+ QVERIFY(in2.streamOffset() == in1.streamOffset());
+ QVERIFY(in2.error() == StreamError::NoError);
+
+ const BitIStream in3(bytes, bytes + size);
+ const BitIStream in4(in3);
+ QVERIFY(in4.bitLength() == in3.bitLength());
+ QVERIFY(in4.streamOffset() == in3.streamOffset());
+ QVERIFY(in4.error() == StreamError::NoError);
+ }
+}
+
+void tst_Hpack::bitstreamWrite()
+{
+ // Known representations,
+ // https://http2.github.io/http2-spec/compression.html.
+ // 5.1 Integer Representation
+
+ // Test bit/byte lengths of the
+ // resulting data:
+ std::vector<uchar> buffer;
+ BitOStream out(buffer);
+ out.write(3);
+ // 11, fits into 8-bit prefix:
+ QVERIFY(out.bitLength() == 8);
+ QVERIFY(out.byteLength() == 1);
+ QVERIFY(out.begin()[0] == 3);
+
+ out.clear();
+ QVERIFY(out.bitLength() == 0);
+ QVERIFY(out.byteLength() == 0);
+
+ // This number does not fit into 8-bit
+ // prefix we'll need 2 bytes:
+ out.write(256);
+ QVERIFY(out.byteLength() == 2);
+ QVERIFY(out.bitLength() == 16);
+ QVERIFY(out.begin()[0] == 0xff);
+ QVERIFY(out.begin()[1] == 1);
+
+ out.clear();
+
+ // See 5.2 String Literal Representation.
+
+ // We use Huffman code,
+ // char 'a' has a prefix code 00011 (5 bits)
+ out.write(QByteArray("aaa", 3), true);
+ QVERIFY(out.byteLength() == 3);
+ QVERIFY(out.bitLength() == 24);
+ // Now we must have in our stream:
+ // 10000010 | 00011000| 11000111
+ const uchar *encoded = out.begin();
+ QVERIFY(encoded[0] == 0x82);
+ QVERIFY(encoded[1] == 0x18);
+ QVERIFY(encoded[2] == 0xC7);
+ // TODO: add more tests ...
+}
+
+void tst_Hpack::bitstreamReadWrite()
+{
+ // We can write into the bit stream:
+ // 1) bit patterns
+ // 2) integers (see HPACK, 5.1)
+ // 3) string (see HPACK, 5.2)
+ std::vector<uchar> buffer;
+ BitOStream out(buffer);
+ out.writeBits(0xf, 3);
+ QVERIFY(out.byteLength() == 1);
+ QVERIFY(out.bitLength() == 3);
+
+ // Now, read it back:
+ {
+ BitIStream in(out.begin(), out.end());
+ uchar bitPattern = 0;
+ const auto bitsRead = in.peekBits(0, 3, &bitPattern);
+ // peekBits pack into the most significant byte/bit:
+ QVERIFY(bitsRead == 3);
+ QVERIFY((bitPattern >> 5) == 7);
+ }
+
+ const quint32 testInt = 133;
+ out.write(testInt);
+
+ // This integer does not fit into the current 5-bit prefix,
+ // so byteLength == 2.
+ QVERIFY(out.byteLength() == 2);
+ const auto bitLength = out.bitLength();
+ QVERIFY(bitLength > 3);
+
+ // Now, read it back:
+ {
+ BitIStream in(out.begin(), out.end());
+ in.skipBits(3); // Bit pattern
+ quint32 value = 0;
+ QVERIFY(in.read(&value));
+ QVERIFY(in.error() == StreamError::NoError);
+ QCOMPARE(value, testInt);
+ }
+
+ const QByteArray testString("ABCDE", 5);
+ out.write(testString, true); // Compressed
+ out.write(testString, false); // Non-compressed
+ QVERIFY(out.byteLength() > 2);
+ QVERIFY(out.bitLength() > bitLength);
+
+ // Now, read it back:
+ {
+ BitIStream in(out.begin(), out.end());
+ in.skipBits(bitLength); // Bit pattern and integer
+ QByteArray value;
+ // Read compressed string first ...
+ QVERIFY(in.read(&value));
+ QCOMPARE(value, testString);
+ QCOMPARE(in.error(), StreamError::NoError);
+ // Now non-compressed ...
+ QVERIFY(in.read(&value));
+ QCOMPARE(value, testString);
+ QCOMPARE(in.error(), StreamError::NoError);
+ }
+}
+
+void tst_Hpack::bitstreamCompression()
+{
+ // Similar to bitstreamReadWrite but
+ // writes/reads a lot of mixed strings/integers.
+ std::vector<std::string> strings;
+ std::vector<quint32> integers;
+ std::vector<bool> isA; // integer or string.
+ const std::string bytes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789()[]/*");
+ const unsigned nValues = 100000;
+
+ quint64 totalStringBytes = 0;
+ std::vector<uchar> buffer;
+ BitOStream out(buffer);
+ for (unsigned i = 0; i < nValues; ++i) {
+ const bool isString = std::rand() % 1000 > 500;
+ isA.push_back(isString);
+ if (!isString) {
+ integers.push_back(std::rand() % 1000);
+ out.write(integers.back());
+ } else {
+ const auto start = std::rand() % (bytes.length() / 2);
+ auto end = start * 2;
+ if (!end)
+ end = bytes.length() / 2;
+ strings.push_back(bytes.substr(start, end - start));
+ const auto &s = strings.back();
+ totalStringBytes += s.size();
+ QByteArray data(s.c_str(), int(s.size()));
+ const bool compressed(std::rand() % 1000 > 500);
+ out.write(data, compressed);
+ }
+ }
+
+ qDebug() << "Compressed(?) byte length:" << out.byteLength()
+ << "total string bytes:" << totalStringBytes;
+ qDebug() << "total integer bytes (for quint32):" << integers.size() * sizeof(quint32);
+
+ QVERIFY(out.byteLength() > 0);
+ QVERIFY(out.bitLength() > 0);
+
+ BitIStream in(out.begin(), out.end());
+
+ for (unsigned i = 0, iS = 0, iI = 0; i < nValues; ++i) {
+ if (isA[i]) {
+ QByteArray data;
+ QVERIFY(in.read(&data));
+ QCOMPARE(in.error(), StreamError::NoError);
+ QCOMPARE(data.toStdString(), strings[iS]);
+ ++iS;
+ } else {
+ quint32 value = 0;
+ QVERIFY(in.read(&value));
+ QCOMPARE(in.error(), StreamError::NoError);
+ QCOMPARE(value, integers[iI]);
+ ++iI;
+ }
+ }
+}
+
+void tst_Hpack::bitstreamErrors()
+{
+ {
+ BitIStream in;
+ quint32 val = 0;
+ QVERIFY(!in.read(&val));
+ QCOMPARE(in.error(), StreamError::NotEnoughData);
+ }
+ {
+ // Integer in a stream, that does not fit into quint32.
+ const uchar bytes[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ BitIStream in(bytes, bytes + sizeof bytes);
+ quint32 val = 0;
+ QVERIFY(!in.read(&val));
+ QCOMPARE(in.error(), StreamError::InvalidInteger);
+ }
+ {
+ const uchar byte = 0x82; // 1 - Huffman compressed, 2 - the (fake) byte length.
+ BitIStream in(&byte, &byte + 1);
+ QByteArray val;
+ QVERIFY(!in.read(&val));
+ QCOMPARE(in.error(), StreamError::NotEnoughData);
+ }
+}
+
+void tst_Hpack::lookupTableConstructor()
+{
+ {
+ FieldLookupTable nonIndexed(4096, false);
+ QVERIFY(nonIndexed.dynamicDataSize() == 0);
+ QVERIFY(nonIndexed.numberOfDynamicEntries() == 0);
+ QVERIFY(nonIndexed.numberOfStaticEntries() != 0);
+ QVERIFY(nonIndexed.numberOfStaticEntries() == nonIndexed.numberOfEntries());
+ // Now we add some fake field and verify what 'non-indexed' means ... no search
+ // by name.
+ QVERIFY(nonIndexed.prependField("custom-key", "custom-value"));
+ // 54: 10 + 12 in name/value pair above + 32 required by HPACK specs ...
+ QVERIFY(nonIndexed.dynamicDataSize() == 54);
+ QVERIFY(nonIndexed.numberOfDynamicEntries() == 1);
+ QCOMPARE(nonIndexed.numberOfEntries(), nonIndexed.numberOfStaticEntries() + 1);
+ // Should fail to find it (invalid index 0) - search is disabled.
+ QVERIFY(nonIndexed.indexOf("custom-key", "custom-value") == 0);
+ }
+ {
+ // "key" + "value" == 8 bytes, + 32 (HPACK's requirement) == 40.
+ // Let's ask for a max-size 32 so that entry does not fit:
+ FieldLookupTable nonIndexed(32, false);
+ QVERIFY(nonIndexed.prependField("key", "value"));
+ QVERIFY(nonIndexed.numberOfEntries() == nonIndexed.numberOfStaticEntries());
+ QVERIFY(nonIndexed.indexOf("key", "value") == 0);
+ }
+ {
+ FieldLookupTable indexed(4096, true);
+ QVERIFY(indexed.dynamicDataSize() == 0);
+ QVERIFY(indexed.numberOfDynamicEntries() == 0);
+ QVERIFY(indexed.numberOfStaticEntries() != 0);
+ QVERIFY(indexed.numberOfStaticEntries() == indexed.numberOfEntries());
+ QVERIFY(indexed.prependField("custom-key", "custom-value"));
+ QVERIFY(indexed.dynamicDataSize() == 54);
+ QVERIFY(indexed.numberOfDynamicEntries() == 1);
+ QVERIFY(indexed.numberOfEntries() == indexed.numberOfStaticEntries() + 1);
+ QVERIFY(indexed.indexOf("custom-key") == indexed.numberOfStaticEntries() + 1);
+ QVERIFY(indexed.indexOf("custom-key", "custom-value") == indexed.numberOfStaticEntries() + 1);
+ }
+}
+
+void tst_Hpack::lookupTableStatic_data()
+{
+ QTest::addColumn<QByteArray>("expectedName");
+ QTest::addColumn<QByteArray>("expectedValue");
+
+ // Some predefined fields to find
+ // (they are always defined/required by HPACK).
+ QTest::newRow(":authority|") << QByteArray(":authority") << QByteArray("");
+ QTest::newRow(":method|GET") << QByteArray(":method") << QByteArray("GET");
+ QTest::newRow(":method|POST") << QByteArray(":method") << QByteArray("POST");
+ QTest::newRow(":path|/") << QByteArray(":path") << QByteArray("/");
+ QTest::newRow(":path|/index.html") << QByteArray(":path") << QByteArray("/index.html");
+ QTest::newRow(":scheme|http") << QByteArray(":scheme") << QByteArray("http");
+ QTest::newRow(":scheme|https") << QByteArray(":scheme") << QByteArray("https");
+ QTest::newRow(":status|200") << QByteArray(":status") << QByteArray("200");
+ QTest::newRow(":status|204") << QByteArray(":status") << QByteArray("204");
+ QTest::newRow(":status|206") << QByteArray(":status") << QByteArray("206");
+ QTest::newRow(":status|304") << QByteArray(":status") << QByteArray("304");
+ QTest::newRow(":status|400") << QByteArray(":status") << QByteArray("400");
+ QTest::newRow(":status|404") << QByteArray(":status") << QByteArray("404");
+ QTest::newRow(":status|500") << QByteArray(":status") << QByteArray("500");
+}
+
+void tst_Hpack::lookupTableStatic()
+{
+ const FieldLookupTable table(0, false /*all static, no need in 'search index'*/);
+
+ QFETCH(QByteArray, expectedName);
+ QFETCH(QByteArray, expectedValue);
+
+ const quint32 index = table.indexOf(expectedName, expectedValue);
+ QVERIFY(index != 0);
+
+ QByteArray name, value;
+ QVERIFY(table.field(index, &name, &value));
+ QCOMPARE(name, expectedName);
+ QCOMPARE(value, expectedValue);
+}
+
+void tst_Hpack::lookupTableDynamic()
+{
+ // HPACK's table size:
+ // for every field -> size += field.name.length() + field.value.length() + 32.
+ // Let's set some size limit and try to fill table with enough entries to have several
+ // items evicted.
+ const quint32 tableSize = 8192;
+ const char stringData[] = "abcdefghijklmnopABCDEFGHIJKLMNOP0123456789()[]:";
+ const quint32 dataSize = sizeof stringData - 1;
+
+ FieldLookupTable table(tableSize, true);
+
+ std::vector<QByteArray> fieldsToFind;
+ quint32 evicted = 0;
+
+ while (true) {
+ // Strings are repeating way too often, I want to
+ // have at least some items really evicted and not found,
+ // therefore these weird dances with start/len.
+ const quint32 start = std::rand() % (dataSize - 10);
+ quint32 len = std::rand() % (dataSize - start);
+ if (!len)
+ len = 1;
+
+ const QByteArray val(stringData + start, len);
+ fieldsToFind.push_back(val);
+ const quint32 entriesBefore = table.numberOfDynamicEntries();
+ QVERIFY(table.prependField(val, val));
+ QVERIFY(table.indexOf(val));
+ QVERIFY(table.indexOf(val) == table.indexOf(val, val));
+ QByteArray fieldName, fieldValue;
+ table.field(table.indexOf(val), &fieldName, &fieldValue);
+
+ QVERIFY(val == fieldName);
+ QVERIFY(val == fieldValue);
+
+ if (table.numberOfDynamicEntries() <= entriesBefore) {
+ // We had to evict several items ...
+ evicted += entriesBefore - table.numberOfDynamicEntries() + 1;
+ if (evicted >= 200)
+ break;
+ }
+ }
+
+ QVERIFY(table.dynamicDataSize() <= tableSize);
+ QVERIFY(table.numberOfDynamicEntries() > 0);
+ QVERIFY(table.indexOf(fieldsToFind.back())); // We MUST have it in a table!
+
+ using size_type = std::vector<QByteArray>::size_type;
+ for (size_type i = 0, e = fieldsToFind.size(); i < e; ++i) {
+ const auto &val = fieldsToFind[i];
+ const quint32 index = table.indexOf(val);
+ if (!index) {
+ QVERIFY(i < size_type(evicted));
+ } else {
+ QVERIFY(index == table.indexOf(val, val));
+ QByteArray fieldName, fieldValue;
+ QVERIFY(table.field(index, &fieldName, &fieldValue));
+ QVERIFY(val == fieldName);
+ QVERIFY(val == fieldValue);
+ }
+ }
+
+ table.clearDynamicTable();
+
+ QVERIFY(table.numberOfDynamicEntries() == 0);
+ QVERIFY(table.dynamicDataSize() == 0);
+ QVERIFY(table.indexOf(fieldsToFind.back()) == 0);
+
+ QVERIFY(table.prependField("name1", "value1"));
+ QVERIFY(table.prependField("name2", "value2"));
+
+ QVERIFY(table.indexOf("name1") == table.numberOfStaticEntries() + 2);
+ QVERIFY(table.indexOf("name2", "value2") == table.numberOfStaticEntries() + 1);
+ QVERIFY(table.indexOf("name1", "value2") == 0);
+ QVERIFY(table.indexOf("name2", "value1") == 0);
+ QVERIFY(table.indexOf("name3") == 0);
+
+ QVERIFY(!table.indexIsValid(table.numberOfEntries() + 1));
+
+ QVERIFY(table.prependField("name1", "value1"));
+ QVERIFY(table.numberOfDynamicEntries() == 3);
+ table.evictEntry();
+ QVERIFY(table.indexOf("name1") != 0);
+ table.evictEntry();
+ QVERIFY(table.indexOf("name2") == 0);
+ QVERIFY(table.indexOf("name1") != 0);
+ table.evictEntry();
+ QVERIFY(table.dynamicDataSize() == 0);
+ QVERIFY(table.numberOfDynamicEntries() == 0);
+ QVERIFY(table.indexOf("name1") == 0);
+}
+
+void tst_Hpack::hpackEncodeRequest_data()
+{
+ QTest::addColumn<bool>("compression");
+ QTest::newRow("no-string-compression") << false;
+ QTest::newRow("with-string-compression") << true;
+}
+
+void tst_Hpack::hpackEncodeRequest(bool withHuffman)
+{
+ // This function uses examples from HPACK specs
+ // (see appendix).
+
+ Encoder encoder(4096, withHuffman);
+ // HPACK, C.3.1 First Request
+ /*
+ :method: GET
+ :scheme: http
+ :path: /
+ :authority: www.example.com
+
+ Hex dump of encoded data (without Huffman):
+
+ 8286 8441 0f77 7777 2e65 7861 6d70 6c65 | ...A.www.example
+ 2e63 6f6d
+
+ Hex dump of encoded data (with Huffman):
+
+ 8286 8441 8cf1 e3c2 e5f2 3a6b a0ab 90f4 ff
+ */
+ request1.clear();
+ header1 = {{":method", "GET"},
+ {":scheme", "http"},
+ {":path", "/"},
+ {":authority", "www.example.com"}};
+ QVERIFY(encoder.encodeRequest(request1, header1));
+ QVERIFY(encoder.dynamicTableSize() == 57);
+
+ // HPACK, C.3.2 Second Request
+ /*
+ Header list to encode:
+
+ :method: GET
+ :scheme: http
+ :path: /
+ :authority: www.example.com
+ cache-control: no-cache
+
+ Hex dump of encoded data (without Huffman):
+
+ 8286 84be 5808 6e6f 2d63 6163 6865
+
+ Hex dump of encoded data (with Huffman):
+
+ 8286 84be 5886 a8eb 1064 9cbf
+ */
+
+ request2.clear();
+ header2 = {{":method", "GET"},
+ {":scheme", "http"},
+ {":path", "/"},
+ {":authority", "www.example.com"},
+ {"cache-control", "no-cache"}};
+ encoder.encodeRequest(request2, header2);
+ QVERIFY(encoder.dynamicTableSize() == 110);
+
+ // HPACK, C.3.3 Third Request
+ /*
+ Header list to encode:
+
+ :method: GET
+ :scheme: https
+ :path: /index.html
+ :authority: www.example.com
+ custom-key: custom-value
+
+ Hex dump of encoded data (without Huffman):
+
+ 8287 85bf 400a 6375 7374 6f6d 2d6b 6579
+ 0c63 7573 746f 6d2d 7661 6c75 65
+
+ Hex dump of encoded data (with Huffman):
+
+ 8287 85bf 4088 25a8 49e9 5ba9 7d7f 8925
+ a849 e95b b8e8 b4bf
+ */
+ request3.clear();
+ header3 = {{":method", "GET"},
+ {":scheme", "https"},
+ {":path", "/index.html"},
+ {":authority", "www.example.com"},
+ {"custom-key", "custom-value"}};
+ encoder.encodeRequest(request3, header3);
+ QVERIFY(encoder.dynamicTableSize() == 164);
+}
+
+void tst_Hpack::hpackEncodeRequest()
+{
+ QFETCH(bool, compression);
+
+ hpackEncodeRequest(compression);
+
+ // See comments above about these hex dumps ...
+ const uchar bytes1NH[] = {0x82, 0x86, 0x84, 0x41,
+ 0x0f, 0x77, 0x77, 0x77,
+ 0x2e, 0x65, 0x78, 0x61,
+ 0x6d, 0x70, 0x6c, 0x65,
+ 0x2e, 0x63, 0x6f, 0x6d};
+
+ const uchar bytes1WH[] = {0x82, 0x86, 0x84, 0x41,
+ 0x8c, 0xf1, 0xe3, 0xc2,
+ 0xe5, 0xf2, 0x3a, 0x6b,
+ 0xa0, 0xab, 0x90, 0xf4,
+ 0xff};
+
+ const uchar *hexDump1 = compression ? bytes1WH : bytes1NH;
+ const quint64 byteLength1 = compression ? sizeof bytes1WH : sizeof bytes1NH;
+
+ QCOMPARE(request1.byteLength(), byteLength1);
+ QCOMPARE(request1.bitLength(), byteLength1 * 8);
+
+ for (quint32 i = 0, e = request1.byteLength(); i < e; ++i)
+ QCOMPARE(hexDump1[i], request1.begin()[i]);
+
+ const uchar bytes2NH[] = {0x82, 0x86, 0x84, 0xbe,
+ 0x58, 0x08, 0x6e, 0x6f,
+ 0x2d, 0x63, 0x61, 0x63,
+ 0x68, 0x65};
+
+ const uchar bytes2WH[] = {0x82, 0x86, 0x84, 0xbe,
+ 0x58, 0x86, 0xa8, 0xeb,
+ 0x10, 0x64, 0x9c, 0xbf};
+
+ const uchar *hexDump2 = compression ? bytes2WH : bytes2NH;
+ const auto byteLength2 = compression ? sizeof bytes2WH : sizeof bytes2NH;
+ QVERIFY(request2.byteLength() == byteLength2);
+ QVERIFY(request2.bitLength() == byteLength2 * 8);
+ for (quint32 i = 0, e = request2.byteLength(); i < e; ++i)
+ QCOMPARE(hexDump2[i], request2.begin()[i]);
+
+ const uchar bytes3NH[] = {0x82, 0x87, 0x85, 0xbf,
+ 0x40, 0x0a, 0x63, 0x75,
+ 0x73, 0x74, 0x6f, 0x6d,
+ 0x2d, 0x6b, 0x65, 0x79,
+ 0x0c, 0x63, 0x75, 0x73,
+ 0x74, 0x6f, 0x6d, 0x2d,
+ 0x76, 0x61, 0x6c, 0x75,
+ 0x65};
+ const uchar bytes3WH[] = {0x82, 0x87, 0x85, 0xbf,
+ 0x40, 0x88, 0x25, 0xa8,
+ 0x49, 0xe9, 0x5b, 0xa9,
+ 0x7d, 0x7f, 0x89, 0x25,
+ 0xa8, 0x49, 0xe9, 0x5b,
+ 0xb8, 0xe8, 0xb4, 0xbf};
+
+ const uchar *hexDump3 = compression ? bytes3WH : bytes3NH;
+ const quint64 byteLength3 = compression ? sizeof bytes3WH : sizeof bytes3NH;
+ QCOMPARE(request3.byteLength(), byteLength3);
+ QCOMPARE(request3.bitLength(), byteLength3 * 8);
+ for (quint32 i = 0, e = request3.byteLength(); i < e; ++i)
+ QCOMPARE(hexDump3[i], request3.begin()[i]);
+}
+
+void tst_Hpack::hpackDecodeRequest_data()
+{
+ QTest::addColumn<bool>("compression");
+ QTest::newRow("no-string-compression") << false;
+ QTest::newRow("with-string-compression") << true;
+}
+
+void tst_Hpack::hpackDecodeRequest()
+{
+ QFETCH(bool, compression);
+ hpackEncodeRequest(compression);
+
+ QVERIFY(request1.byteLength());
+ QVERIFY(request2.byteLength());
+ QVERIFY(request3.byteLength());
+
+ Decoder decoder(4096);
+ BitIStream inputStream1(request1.begin(), request1.end());
+ QVERIFY(decoder.decodeHeaderFields(inputStream1));
+ QCOMPARE(decoder.dynamicTableSize(), quint32(57));
+ {
+ const auto &decoded = decoder.decodedHeader();
+ QVERIFY(decoded == header1);
+ }
+
+ BitIStream inputStream2{request2.begin(), request2.end()};
+ QVERIFY(decoder.decodeHeaderFields(inputStream2));
+ QCOMPARE(decoder.dynamicTableSize(), quint32(110));
+ {
+ const auto &decoded = decoder.decodedHeader();
+ QVERIFY(decoded == header2);
+ }
+
+ BitIStream inputStream3(request3.begin(), request3.end());
+ QVERIFY(decoder.decodeHeaderFields(inputStream3));
+ QCOMPARE(decoder.dynamicTableSize(), quint32(164));
+ {
+ const auto &decoded = decoder.decodedHeader();
+ QVERIFY(decoded == header3);
+ }
+}
+
+void tst_Hpack::hpackEncodeResponse_data()
+{
+ hpackEncodeRequest_data();
+}
+
+void tst_Hpack::hpackEncodeResponse()
+{
+ QFETCH(bool, compression);
+
+ hpackEncodeResponse(compression);
+
+ // TODO: we can also test bytes - using hex dumps from HPACK's specs,
+ // for now only test a table behavior/expected sizes.
+}
+
+void tst_Hpack::hpackEncodeResponse(bool withCompression)
+{
+ Encoder encoder(256, withCompression); // 256 - this will result in entries evicted.
+
+ // HPACK, C.5.1 First Response
+ /*
+ Header list to encode:
+
+ :status: 302
+ cache-control: private
+ date: Mon, 21 Oct 2013 20:13:21 GMT
+ location: https://www.example.com
+ */
+ request1.clear();
+ header1 = {{":status", "302"},
+ {"cache-control", "private"},
+ {"date", "Mon, 21 Oct 2013 20:13:21 GMT"},
+ {"location", "https://www.example.com"}};
+
+ QVERIFY(encoder.encodeResponse(request1, header1));
+ QCOMPARE(encoder.dynamicTableSize(), quint32(222));
+
+ // HPACK, C.5.2 Second Response
+ /*
+
+
+ The (":status", "302") header field is evicted from the dynamic
+ table to free space to allow adding the (":status", "307") header field.
+
+ Header list to encode:
+
+ :status: 307
+ cache-control: private
+ date: Mon, 21 Oct 2013 20:13:21 GMT
+ location: https://www.example.com
+ */
+ request2.clear();
+ header2 = {{":status", "307"},
+ {"cache-control", "private"},
+ {"date", "Mon, 21 Oct 2013 20:13:21 GMT"},
+ {"location", "https://www.example.com"}};
+ QVERIFY(encoder.encodeResponse(request2, header2));
+ QCOMPARE(encoder.dynamicTableSize(), quint32(222));
+
+ // HPACK, C.5.3 Third Response
+ /*
+ Several header fields are evicted from the dynamic table
+ during the processing of this header list.
+
+ Header list to encode:
+
+ :status: 200
+ cache-control: private
+ date: Mon, 21 Oct 2013 20:13:22 GMT
+ location: https://www.example.com
+ content-encoding: gzip
+ set-cookie: foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1
+ */
+ request3.clear();
+ header3 = {{":status", "200"},
+ {"cache-control", "private"},
+ {"date", "Mon, 21 Oct 2013 20:13:22 GMT"},
+ {"location", "https://www.example.com"},
+ {"content-encoding", "gzip"},
+ {"set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"}};
+ QVERIFY(encoder.encodeResponse(request3, header3));
+ QCOMPARE(encoder.dynamicTableSize(), quint32(215));
+}
+
+void tst_Hpack::hpackDecodeResponse_data()
+{
+ hpackEncodeRequest_data();
+}
+
+void tst_Hpack::hpackDecodeResponse()
+{
+ QFETCH(bool, compression);
+
+ hpackEncodeResponse(compression);
+
+ QVERIFY(request1.byteLength());
+ Decoder decoder(256); // This size will result in entries evicted.
+ BitIStream inputStream1(request1.begin(), request1.end());
+ QVERIFY(decoder.decodeHeaderFields(inputStream1));
+ QCOMPARE(decoder.dynamicTableSize(), quint32(222));
+
+ {
+ const auto &decoded = decoder.decodedHeader();
+ QVERIFY(decoded == header1);
+ }
+
+ QVERIFY(request2.byteLength());
+ BitIStream inputStream2(request2.begin(), request2.end());
+ QVERIFY(decoder.decodeHeaderFields(inputStream2));
+ QCOMPARE(decoder.dynamicTableSize(), quint32(222));
+
+ {
+ const auto &decoded = decoder.decodedHeader();
+ QVERIFY(decoded == header2);
+ }
+
+ QVERIFY(request3.byteLength());
+ BitIStream inputStream3(request3.begin(), request3.end());
+ QVERIFY(decoder.decodeHeaderFields(inputStream3));
+ QCOMPARE(decoder.dynamicTableSize(), quint32(215));
+
+ {
+ const auto &decoded = decoder.decodedHeader();
+ QVERIFY(decoded == header3);
+ }
+}
+
+QTEST_MAIN(tst_Hpack)
+
+#include "tst_hpack.moc"
diff --git a/tests/auto/network/access/http2/certs/fluke.cert b/tests/auto/network/access/http2/certs/fluke.cert
new file mode 100644
index 0000000000..ace4e4f0eb
--- /dev/null
+++ b/tests/auto/network/access/http2/certs/fluke.cert
@@ -0,0 +1,75 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 0 (0x0)
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=NO, ST=Oslo, L=Nydalen, O=Nokia Corporation and/or its subsidiary(-ies), OU=Development, CN=fluke.troll.no/emailAddress=ahanssen@trolltech.com
+ Validity
+ Not Before: Dec 4 01:10:32 2007 GMT
+ Not After : Apr 21 01:10:32 2035 GMT
+ Subject: C=NO, ST=Oslo, O=Nokia Corporation and/or its subsidiary(-ies), OU=Development, CN=fluke.troll.no
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (1024 bit)
+ Modulus (1024 bit):
+ 00:a7:c8:a0:4a:c4:19:05:1b:66:ba:32:e2:d2:f1:
+ 1c:6f:17:82:e4:39:2e:01:51:90:db:04:34:32:11:
+ 21:c2:0d:6f:59:d8:53:90:54:3f:83:8f:a9:d3:b3:
+ d5:ee:1a:9b:80:ae:c3:25:c9:5e:a5:af:4b:60:05:
+ aa:a0:d1:91:01:1f:ca:04:83:e3:58:1c:99:32:45:
+ 84:70:72:58:03:98:4a:63:8b:41:f5:08:49:d2:91:
+ 02:60:6b:e4:64:fe:dd:a0:aa:74:08:e9:34:4c:91:
+ 5f:12:3d:37:4d:54:2c:ad:7f:5b:98:60:36:02:8c:
+ 3b:f6:45:f3:27:6a:9b:94:9d
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ Netscape Comment:
+ OpenSSL Generated Certificate
+ X509v3 Subject Key Identifier:
+ 21:85:04:3D:23:01:66:E5:F7:9F:1A:84:24:8A:AF:0A:79:F4:E5:AC
+ X509v3 Authority Key Identifier:
+ DirName:/C=NO/ST=Oslo/L=Nydalen/O=Nokia Corporation and/or its subsidiary(-ies)/OU=Development/CN=fluke.troll.no/emailAddress=ahanssen@trolltech.com
+ serial:8E:A8:B4:E8:91:B7:54:2E
+
+ Signature Algorithm: sha1WithRSAEncryption
+ 6d:57:5f:d1:05:43:f0:62:05:ec:2a:71:a5:dc:19:08:f2:c4:
+ a6:bd:bb:25:d9:ca:89:01:0e:e4:cf:1f:c1:8c:c8:24:18:35:
+ 53:59:7b:c0:43:b4:32:e6:98:b2:a6:ef:15:05:0b:48:5f:e1:
+ a0:0c:97:a9:a1:77:d8:35:18:30:bc:a9:8f:d3:b7:54:c7:f1:
+ a9:9e:5d:e6:19:bf:f6:3c:5b:2b:d8:e4:3e:62:18:88:8b:d3:
+ 24:e1:40:9b:0c:e6:29:16:62:ab:ea:05:24:70:36:aa:55:93:
+ ef:02:81:1b:23:10:a2:04:eb:56:95:75:fc:f8:94:b1:5d:42:
+ c5:3f:36:44:85:5d:3a:2e:90:46:8a:a2:b9:6f:87:ae:0c:15:
+ 40:19:31:90:fc:3b:25:bb:ae:f1:66:13:0d:85:90:d9:49:34:
+ 8f:f2:5d:f9:7a:db:4d:5d:27:f6:76:9d:35:8c:06:a6:4c:a3:
+ b1:b2:b6:6f:1d:d7:a3:00:fd:72:eb:9e:ea:44:a1:af:21:34:
+ 7d:c7:42:e2:49:91:19:8b:c0:ad:ba:82:80:a8:71:70:f4:35:
+ 31:91:63:84:20:95:e9:60:af:64:8b:cc:ff:3d:8a:76:74:3d:
+ c8:55:6d:e4:8e:c3:2b:1c:e8:42:18:ae:9f:e6:6b:9c:34:06:
+ ec:6a:f2:c3
+-----BEGIN CERTIFICATE-----
+MIIEEzCCAvugAwIBAgIBADANBgkqhkiG9w0BAQUFADCBnDELMAkGA1UEBhMCTk8x
+DTALBgNVBAgTBE9zbG8xEDAOBgNVBAcTB055ZGFsZW4xFjAUBgNVBAoTDVRyb2xs
+dGVjaCBBU0ExFDASBgNVBAsTC0RldmVsb3BtZW50MRcwFQYDVQQDEw5mbHVrZS50
+cm9sbC5ubzElMCMGCSqGSIb3DQEJARYWYWhhbnNzZW5AdHJvbGx0ZWNoLmNvbTAe
+Fw0wNzEyMDQwMTEwMzJaFw0zNTA0MjEwMTEwMzJaMGMxCzAJBgNVBAYTAk5PMQ0w
+CwYDVQQIEwRPc2xvMRYwFAYDVQQKEw1Ucm9sbHRlY2ggQVNBMRQwEgYDVQQLEwtE
+ZXZlbG9wbWVudDEXMBUGA1UEAxMOZmx1a2UudHJvbGwubm8wgZ8wDQYJKoZIhvcN
+AQEBBQADgY0AMIGJAoGBAKfIoErEGQUbZroy4tLxHG8XguQ5LgFRkNsENDIRIcIN
+b1nYU5BUP4OPqdOz1e4am4CuwyXJXqWvS2AFqqDRkQEfygSD41gcmTJFhHByWAOY
+SmOLQfUISdKRAmBr5GT+3aCqdAjpNEyRXxI9N01ULK1/W5hgNgKMO/ZF8ydqm5Sd
+AgMBAAGjggEaMIIBFjAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NM
+IEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUIYUEPSMBZuX3nxqEJIqv
+Cnn05awwgbsGA1UdIwSBszCBsKGBoqSBnzCBnDELMAkGA1UEBhMCTk8xDTALBgNV
+BAgTBE9zbG8xEDAOBgNVBAcTB055ZGFsZW4xFjAUBgNVBAoTDVRyb2xsdGVjaCBB
+U0ExFDASBgNVBAsTC0RldmVsb3BtZW50MRcwFQYDVQQDEw5mbHVrZS50cm9sbC5u
+bzElMCMGCSqGSIb3DQEJARYWYWhhbnNzZW5AdHJvbGx0ZWNoLmNvbYIJAI6otOiR
+t1QuMA0GCSqGSIb3DQEBBQUAA4IBAQBtV1/RBUPwYgXsKnGl3BkI8sSmvbsl2cqJ
+AQ7kzx/BjMgkGDVTWXvAQ7Qy5piypu8VBQtIX+GgDJepoXfYNRgwvKmP07dUx/Gp
+nl3mGb/2PFsr2OQ+YhiIi9Mk4UCbDOYpFmKr6gUkcDaqVZPvAoEbIxCiBOtWlXX8
++JSxXULFPzZEhV06LpBGiqK5b4euDBVAGTGQ/Dslu67xZhMNhZDZSTSP8l35ettN
+XSf2dp01jAamTKOxsrZvHdejAP1y657qRKGvITR9x0LiSZEZi8CtuoKAqHFw9DUx
+kWOEIJXpYK9ki8z/PYp2dD3IVW3kjsMrHOhCGK6f5mucNAbsavLD
+-----END CERTIFICATE-----
diff --git a/tests/auto/network/access/http2/certs/fluke.key b/tests/auto/network/access/http2/certs/fluke.key
new file mode 100644
index 0000000000..9d1664d609
--- /dev/null
+++ b/tests/auto/network/access/http2/certs/fluke.key
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQCnyKBKxBkFG2a6MuLS8RxvF4LkOS4BUZDbBDQyESHCDW9Z2FOQ
+VD+Dj6nTs9XuGpuArsMlyV6lr0tgBaqg0ZEBH8oEg+NYHJkyRYRwclgDmEpji0H1
+CEnSkQJga+Rk/t2gqnQI6TRMkV8SPTdNVCytf1uYYDYCjDv2RfMnapuUnQIDAQAB
+AoGANFzLkanTeSGNFM0uttBipFT9F4a00dqHz6JnO7zXAT26I5r8sU1pqQBb6uLz
+/+Qz5Zwk8RUAQcsMRgJetuPQUb0JZjF6Duv24hNazqXBCu7AZzUenjafwmKC/8ri
+KpX3fTwqzfzi//FKGgbXQ80yykSSliDL3kn/drATxsLCgQECQQDXhEFWLJ0vVZ1s
+1Ekf+3NITE+DR16X+LQ4W6vyEHAjTbaNWtcTKdAWLA2l6N4WAAPYSi6awm+zMxx4
+VomVTsjdAkEAx0z+e7natLeFcrrq8pbU+wa6SAP1VfhQWKitxL1e7u/QO90NCpxE
+oQYKzMkmmpOOFjQwEMAy1dvFMbm4LHlewQJAC/ksDBaUcQHHqjktCtrUb8rVjAyW
+A8lscckeB2fEYyG5J6dJVaY4ClNOOs5yMDS2Afk1F6H/xKvtQ/5CzInA/QJATDub
+K+BPU8jO9q+gpuIi3VIZdupssVGmCgObVCHLakG4uO04y9IyPhV9lA9tALtoIf4c
+VIvv5fWGXBrZ48kZAQJBAJmVCdzQxd9LZI5vxijUCj5EI4e+x5DRqVUvyP8KCZrC
+AiNyoDP85T+hBZaSXK3aYGpVwelyj3bvo1GrTNwNWLw=
+-----END RSA PRIVATE KEY-----
diff --git a/tests/auto/network/access/http2/http2.pro b/tests/auto/network/access/http2/http2.pro
new file mode 100644
index 0000000000..e130f30784
--- /dev/null
+++ b/tests/auto/network/access/http2/http2.pro
@@ -0,0 +1,8 @@
+QT += core core-private network network-private testlib
+
+CONFIG += testcase parallel_test c++11
+TARGET = tst_http2
+HEADERS += http2srv.h
+SOURCES += tst_http2.cpp http2srv.cpp
+
+DEFINES += SRCDIR=\\\"$$PWD/\\\"
diff --git a/tests/auto/network/access/http2/http2srv.cpp b/tests/auto/network/access/http2/http2srv.cpp
new file mode 100644
index 0000000000..9d68b5c798
--- /dev/null
+++ b/tests/auto/network/access/http2/http2srv.cpp
@@ -0,0 +1,695 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+
+#include <QtNetwork/private/http2protocol_p.h>
+#include <QtNetwork/private/bitstreams_p.h>
+
+#include "http2srv.h"
+
+#ifndef QT_NO_SSL
+#include <QtNetwork/qsslconfiguration.h>
+#include <QtNetwork/qsslsocket.h>
+#include <QtNetwork/qsslkey.h>
+#endif
+
+#include <QtNetwork/qtcpsocket.h>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qfile.h>
+
+#include <cstdlib>
+#include <cstring>
+#include <limits>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Http2;
+using namespace HPack;
+
+namespace
+{
+
+inline bool is_valid_client_stream(quint32 streamID)
+{
+ // A valid client stream ID is an odd integer number in the range [1, INT_MAX].
+ return (streamID & 0x1) && streamID <= std::numeric_limits<qint32>::max();
+}
+
+void fill_push_header(const HttpHeader &originalRequest, HttpHeader &promisedRequest)
+{
+ for (const auto &field : originalRequest) {
+ if (field.name == QByteArray(":authority") ||
+ field.name == QByteArray(":scheme")) {
+ promisedRequest.push_back(field);
+ }
+ }
+}
+
+}
+
+Http2Server::Http2Server(bool h2c, const Http2Settings &ss, const Http2Settings &cs)
+ : serverSettings(ss),
+ clearTextHTTP2(h2c)
+{
+ for (const auto &s : cs)
+ expectedClientSettings[quint16(s.identifier)] = s.value;
+
+ responseBody = "<html>\n"
+ "<head>\n"
+ "<title>Sample \"Hello, World\" Application</title>\n"
+ "</head>\n"
+ "<body bgcolor=white>\n"
+ "<table border=\"0\" cellpadding=\"10\">\n"
+ "<tr>\n"
+ "<td>\n"
+ "<img src=\"images/springsource.png\">\n"
+ "</td>\n"
+ "<td>\n"
+ "<h1>Sample \"Hello, World\" Application</h1>\n"
+ "</td>\n"
+ "</tr>\n"
+ "</table>\n"
+ "<p>This is the home page for the HelloWorld Web application. </p>\n"
+ "</body>\n"
+ "</html>";
+}
+
+Http2Server::~Http2Server()
+{
+}
+
+void Http2Server::enablePushPromise(bool pushEnabled, const QByteArray &path)
+{
+ pushPromiseEnabled = pushEnabled;
+ pushPath = path;
+}
+
+void Http2Server::setResponseBody(const QByteArray &body)
+{
+ responseBody = body;
+}
+
+void Http2Server::startServer()
+{
+#ifdef QT_NO_SSL
+ // Let the test fail with timeout.
+ if (!clearTextHTTP2)
+ return;
+#endif
+ if (listen())
+ emit serverStarted(serverPort());
+}
+
+void Http2Server::sendServerSettings()
+{
+ Q_ASSERT(socket);
+
+ if (!serverSettings.size())
+ return;
+
+ writer.start(FrameType::SETTINGS, FrameFlag::EMPTY, connectionStreamID);
+ for (const auto &s : serverSettings) {
+ writer.append(s.identifier);
+ writer.append(s.value);
+ if (s.identifier == Settings::INITIAL_WINDOW_SIZE_ID)
+ streamRecvWindowSize = s.value;
+ }
+ writer.write(*socket);
+ // Now, let's update our peer on a session recv window size:
+ const quint32 updatedSize = 10 * streamRecvWindowSize;
+ if (sessionRecvWindowSize < updatedSize) {
+ const quint32 delta = updatedSize - sessionRecvWindowSize;
+ sessionRecvWindowSize = updatedSize;
+ sessionCurrRecvWindow = updatedSize;
+ sendWINDOW_UPDATE(connectionStreamID, delta);
+ }
+
+ waitingClientAck = true;
+ settingsSent = true;
+}
+
+void Http2Server::sendGOAWAY(quint32 streamID, quint32 error, quint32 lastStreamID)
+{
+ Q_ASSERT(socket);
+
+ writer.start(FrameType::GOAWAY, FrameFlag::EMPTY, streamID);
+ writer.append(lastStreamID);
+ writer.append(error);
+ writer.write(*socket);
+}
+
+void Http2Server::sendRST_STREAM(quint32 streamID, quint32 error)
+{
+ Q_ASSERT(socket);
+
+ writer.start(FrameType::RST_STREAM, FrameFlag::EMPTY, streamID);
+ writer.append(error);
+ writer.write(*socket);
+}
+
+void Http2Server::sendDATA(quint32 streamID, quint32 windowSize)
+{
+ Q_ASSERT(socket);
+
+ const auto it = suspendedStreams.find(streamID);
+ Q_ASSERT(it != suspendedStreams.end());
+
+ const quint32 offset = it->second;
+ Q_ASSERT(offset < quint32(responseBody.size()));
+
+ const quint32 bytes = std::min<quint32>(windowSize, responseBody.size() - offset);
+ const quint32 frameSizeLimit(clientSetting(Settings::MAX_FRAME_SIZE_ID, Http2::maxFrameSize));
+ const uchar *src = reinterpret_cast<const uchar *>(responseBody.constData() + offset);
+ const bool last = offset + bytes == quint32(responseBody.size());
+
+ writer.start(FrameType::DATA, FrameFlag::EMPTY, streamID);
+ writer.writeDATA(*socket, frameSizeLimit, src, bytes);
+
+ if (last) {
+ writer.start(FrameType::DATA, FrameFlag::END_STREAM, streamID);
+ writer.setPayloadSize(0);
+ writer.write(*socket);
+ suspendedStreams.erase(it);
+ activeRequests.erase(streamID);
+
+ Q_ASSERT(closedStreams.find(streamID) == closedStreams.end());
+ closedStreams.insert(streamID);
+ } else {
+ it->second += bytes;
+ }
+}
+
+void Http2Server::sendWINDOW_UPDATE(quint32 streamID, quint32 delta)
+{
+ Q_ASSERT(socket);
+
+ writer.start(FrameType::WINDOW_UPDATE, FrameFlag::EMPTY, streamID);
+ writer.append(delta);
+ writer.write(*socket);
+}
+
+void Http2Server::incomingConnection(qintptr socketDescriptor)
+{
+ if (clearTextHTTP2) {
+ socket.reset(new QTcpSocket);
+ const bool set = socket->setSocketDescriptor(socketDescriptor);
+ Q_ASSERT(set);
+ // Stop listening:
+ close();
+ QMetaObject::invokeMethod(this, "connectionEstablished",
+ Qt::QueuedConnection);
+ } else {
+#ifndef QT_NO_SSL
+ socket.reset(new QSslSocket);
+ QSslSocket *sslSocket = static_cast<QSslSocket *>(socket.data());
+ // Add HTTP2 as supported protocol:
+ auto conf = QSslConfiguration::defaultConfiguration();
+ auto protos = conf.allowedNextProtocols();
+ protos.prepend(QSslConfiguration::ALPNProtocolHTTP2);
+ conf.setAllowedNextProtocols(protos);
+ sslSocket->setSslConfiguration(conf);
+ // SSL-related setup ...
+ sslSocket->setPeerVerifyMode(QSslSocket::VerifyNone);
+ sslSocket->setProtocol(QSsl::TlsV1_2OrLater);
+ connect(sslSocket, SIGNAL(sslErrors(QList<QSslError>)),
+ this, SLOT(ignoreErrorSlot()));
+ QFile file(SRCDIR "certs/fluke.key");
+ file.open(QIODevice::ReadOnly);
+ QSslKey key(file.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
+ sslSocket->setPrivateKey(key);
+ auto localCert = QSslCertificate::fromPath(SRCDIR "certs/fluke.cert");
+ sslSocket->setLocalCertificateChain(localCert);
+ sslSocket->setSocketDescriptor(socketDescriptor, QAbstractSocket::ConnectedState);
+ // Stop listening.
+ close();
+ // Start SSL handshake and ALPN:
+ connect(sslSocket, SIGNAL(encrypted()), this, SLOT(connectionEstablished()));
+ sslSocket->startServerEncryption();
+#else
+ Q_UNREACHABLE();
+#endif
+ }
+}
+
+quint32 Http2Server::clientSetting(Http2::Settings identifier, quint32 defaultValue)
+{
+ const auto it = expectedClientSettings.find(quint16(identifier));
+ if (it != expectedClientSettings.end())
+ return it->second;
+ return defaultValue;
+}
+
+void Http2Server::connectionEstablished()
+{
+ using namespace Http2;
+
+ connect(socket.data(), SIGNAL(readyRead()),
+ this, SLOT(readReady()));
+
+ waitingClientPreface = true;
+ waitingClientAck = false;
+ waitingClientSettings = false;
+ settingsSent = false;
+ // We immediately send our settings so that our client
+ // can use flow control correctly.
+ sendServerSettings();
+
+ if (socket->bytesAvailable())
+ readReady();
+}
+
+void Http2Server::ignoreErrorSlot()
+{
+#ifndef QT_NO_SSL
+ static_cast<QSslSocket *>(socket.data())->ignoreSslErrors();
+#endif
+}
+
+// Now HTTP2 "server" part:
+/*
+This code is overly simplified but it tests the basic HTTP2 expected behavior:
+1. CONNECTION PREFACE
+2. SETTINGS
+3. sends our own settings (to modify the flow control)
+4. collects and reports requests
+5. if asked - sends responds to those requests
+6. does some very basic error handling
+7. tests frames validity/stream logic at the very basic level.
+*/
+
+void Http2Server::readReady()
+{
+ if (connectionError)
+ return;
+
+ if (waitingClientPreface) {
+ handleConnectionPreface();
+ } else {
+ const auto status = reader.read(*socket);
+ switch (status) {
+ case FrameStatus::incompleteFrame:
+ break;
+ case FrameStatus::goodFrame:
+ handleIncomingFrame();
+ break;
+ default:
+ connectionError = true;
+ sendGOAWAY(connectionStreamID, PROTOCOL_ERROR, connectionStreamID);
+ }
+ }
+
+ if (socket->bytesAvailable())
+ QMetaObject::invokeMethod(this, "readReady", Qt::QueuedConnection);
+}
+
+void Http2Server::handleConnectionPreface()
+{
+ Q_ASSERT(waitingClientPreface);
+
+ if (socket->bytesAvailable() < clientPrefaceLength)
+ return; // Wait for more data ...
+
+ char buf[clientPrefaceLength] = {};
+ socket->read(buf, clientPrefaceLength);
+ if (std::memcmp(buf, Http2clientPreface, clientPrefaceLength)) {
+ sendGOAWAY(connectionStreamID, PROTOCOL_ERROR, connectionStreamID);
+ emit clientPrefaceError();
+ connectionError = true;
+ return;
+ }
+
+ waitingClientPreface = false;
+ waitingClientSettings = true;
+}
+
+void Http2Server::handleIncomingFrame()
+{
+ // Frames that our implementation can send include:
+ // 1. SETTINGS (happens only during connection preface,
+ // handled already by this point)
+ // 2. SETTIGNS with ACK should be sent only as a response
+ // to a server's SETTINGS
+ // 3. HEADERS
+ // 4. CONTINUATION
+ // 5. DATA
+ // 6. PING
+ // 7. RST_STREAM
+ // 8. GOAWAY
+
+ inboundFrame = std::move(reader.inboundFrame());
+
+ if (continuedRequest.size()) {
+ if (inboundFrame.type() != FrameType::CONTINUATION ||
+ inboundFrame.streamID() != continuedRequest.front().streamID()) {
+ sendGOAWAY(connectionStreamID, PROTOCOL_ERROR, connectionStreamID);
+ emit invalidFrame();
+ connectionError = true;
+ return;
+ }
+ }
+
+ switch (inboundFrame.type()) {
+ case FrameType::SETTINGS:
+ handleSETTINGS();
+ break;
+ case FrameType::HEADERS:
+ case FrameType::CONTINUATION:
+ continuedRequest.push_back(std::move(inboundFrame));
+ processRequest();
+ break;
+ case FrameType::DATA:
+ handleDATA();
+ break;
+ case FrameType::RST_STREAM:
+ // TODO: this is not tested for now.
+ break;
+ case FrameType::PING:
+ // TODO: this is not tested for now.
+ break;
+ case FrameType::GOAWAY:
+ // TODO: this is not tested for now.
+ break;
+ case FrameType::WINDOW_UPDATE:
+ handleWINDOW_UPDATE();
+ break;
+ default:;
+ }
+}
+
+void Http2Server::handleSETTINGS()
+{
+ // SETTINGS is either a part of the connection preface,
+ // or a SETTINGS ACK.
+ Q_ASSERT(inboundFrame.type() == FrameType::SETTINGS);
+
+ if (inboundFrame.flags().testFlag(FrameFlag::ACK)) {
+ if (!waitingClientAck || inboundFrame.dataSize()) {
+ emit invalidFrame();
+ connectionError = true;
+ waitingClientAck = false;
+ return;
+ }
+
+ waitingClientAck = false;
+ emit serverSettingsAcked();
+ return;
+ }
+
+ // QHttp2ProtocolHandler always sends some settings,
+ // and the size is a multiple of 6.
+ if (!inboundFrame.dataSize() || inboundFrame.dataSize() % 6) {
+ sendGOAWAY(connectionStreamID, FRAME_SIZE_ERROR, connectionStreamID);
+ emit clientPrefaceError();
+ connectionError = true;
+ return;
+ }
+
+ const uchar *src = inboundFrame.dataBegin();
+ const uchar *end = src + inboundFrame.dataSize();
+
+ const auto notFound = expectedClientSettings.end();
+
+ while (src != end) {
+ const auto id = qFromBigEndian<quint16>(src);
+ const auto value = qFromBigEndian<quint32>(src + 2);
+ if (expectedClientSettings.find(id) == notFound ||
+ expectedClientSettings[id] != value) {
+ emit clientPrefaceError();
+ connectionError = true;
+ return;
+ }
+
+ src += 6;
+ }
+
+ // Send SETTINGS ACK:
+ writer.start(FrameType::SETTINGS, FrameFlag::ACK, connectionStreamID);
+ writer.write(*socket);
+ waitingClientSettings = false;
+ emit clientPrefaceOK();
+}
+
+void Http2Server::handleDATA()
+{
+ Q_ASSERT(inboundFrame.type() == FrameType::DATA);
+
+ const auto streamID = inboundFrame.streamID();
+
+ if (!is_valid_client_stream(streamID) ||
+ closedStreams.find(streamID) != closedStreams.end()) {
+ emit invalidFrame();
+ connectionError = true;
+ sendGOAWAY(connectionStreamID, PROTOCOL_ERROR, connectionStreamID);
+ return;
+ }
+
+ const auto payloadSize = inboundFrame.payloadSize();
+ if (sessionCurrRecvWindow < payloadSize) {
+ // Client does not respect our session window size!
+ emit invalidRequest(streamID);
+ connectionError = true;
+ sendGOAWAY(connectionStreamID, FLOW_CONTROL_ERROR, connectionStreamID);
+ return;
+ }
+
+ auto it = streamWindows.find(streamID);
+ if (it == streamWindows.end())
+ it = streamWindows.insert(std::make_pair(streamID, streamRecvWindowSize)).first;
+
+
+ if (it->second < payloadSize) {
+ emit invalidRequest(streamID);
+ connectionError = true;
+ sendGOAWAY(connectionStreamID, FLOW_CONTROL_ERROR, connectionStreamID);
+ return;
+ }
+
+ it->second -= payloadSize;
+ if (it->second < streamRecvWindowSize / 2) {
+ sendWINDOW_UPDATE(streamID, streamRecvWindowSize / 2);
+ it->second += streamRecvWindowSize / 2;
+ }
+
+ sessionCurrRecvWindow -= payloadSize;
+
+ if (sessionCurrRecvWindow < sessionRecvWindowSize / 2) {
+ // This is some quite naive and trivial logic on when to update.
+
+ sendWINDOW_UPDATE(connectionStreamID, sessionRecvWindowSize / 2);
+ sessionCurrRecvWindow += sessionRecvWindowSize / 2;
+ }
+
+ if (inboundFrame.flags().testFlag(FrameFlag::END_STREAM)) {
+ closedStreams.insert(streamID); // Enter "half-closed remote" state.
+ streamWindows.erase(it);
+ emit receivedData(streamID);
+ }
+}
+
+void Http2Server::handleWINDOW_UPDATE()
+{
+ const auto streamID = inboundFrame.streamID();
+ if (!streamID) // We ignore this for now to keep things simple.
+ return;
+
+ if (streamID && suspendedStreams.find(streamID) == suspendedStreams.end()) {
+ if (closedStreams.find(streamID) == closedStreams.end()) {
+ sendRST_STREAM(streamID, PROTOCOL_ERROR);
+ emit invalidFrame();
+ connectionError = true;
+ }
+
+ return;
+ }
+
+ const quint32 delta = qFromBigEndian<quint32>(inboundFrame.dataBegin());
+ if (!delta || delta > quint32(std::numeric_limits<qint32>::max())) {
+ sendRST_STREAM(streamID, PROTOCOL_ERROR);
+ emit invalidFrame();
+ connectionError = true;
+ return;
+ }
+
+ emit windowUpdate(streamID);
+ sendDATA(streamID, delta);
+}
+
+void Http2Server::sendResponse(quint32 streamID, bool emptyBody)
+{
+ Q_ASSERT(activeRequests.find(streamID) != activeRequests.end());
+
+ const quint32 maxFrameSize(clientSetting(Settings::MAX_FRAME_SIZE_ID,
+ Http2::maxFrameSize));
+
+ if (pushPromiseEnabled) {
+ // A real server supporting PUSH_PROMISE will probably first send
+ // PUSH_PROMISE and then a normal response (to a real request),
+ // so that a client parsing this response and discovering another
+ // resource it needs, will _already_ have this additional resource
+ // in PUSH_PROMISE.
+ lastPromisedStream += 2;
+
+ writer.start(FrameType::PUSH_PROMISE, FrameFlag::END_HEADERS, streamID);
+ writer.append(lastPromisedStream);
+
+ HttpHeader pushHeader;
+ fill_push_header(activeRequests[streamID], pushHeader);
+ pushHeader.push_back(HeaderField(":method", "GET"));
+ pushHeader.push_back(HeaderField(":path", pushPath));
+
+ // Now interesting part, let's make it into 'stream':
+ activeRequests[lastPromisedStream] = pushHeader;
+
+ HPack::BitOStream ostream(writer.outboundFrame().buffer);
+ const bool result = encoder.encodeRequest(ostream, pushHeader);
+ Q_ASSERT(result);
+
+ // Well, it's not HEADERS, it's PUSH_PROMISE with ... HEADERS block.
+ // Should work.
+ writer.writeHEADERS(*socket, maxFrameSize);
+ qDebug() << "server sent a PUSH_PROMISE on" << lastPromisedStream;
+
+ if (responseBody.isEmpty())
+ responseBody = QByteArray("I PROMISE (AND PUSH) YOU ...");
+
+ // Now we send this promised data as a normal response on our reserved
+ // stream (disabling PUSH_PROMISE for the moment to avoid recursion):
+ pushPromiseEnabled = false;
+ sendResponse(lastPromisedStream, false);
+ pushPromiseEnabled = true;
+ // Now we'll continue with _normal_ response.
+ }
+
+ writer.start(FrameType::HEADERS, FrameFlag::END_HEADERS, streamID);
+ if (emptyBody)
+ writer.addFlag(FrameFlag::END_STREAM);
+
+ HttpHeader header = {{":status", "200"}};
+ if (!emptyBody) {
+ header.push_back(HPack::HeaderField("content-length",
+ QString("%1").arg(responseBody.size()).toLatin1()));
+ }
+
+ HPack::BitOStream ostream(writer.outboundFrame().buffer);
+ const bool result = encoder.encodeResponse(ostream, header);
+ Q_ASSERT(result);
+
+ writer.writeHEADERS(*socket, maxFrameSize);
+
+ if (!emptyBody) {
+ Q_ASSERT(suspendedStreams.find(streamID) == suspendedStreams.end());
+
+ const quint32 windowSize = clientSetting(Settings::INITIAL_WINDOW_SIZE_ID,
+ Http2::defaultSessionWindowSize);
+ // Suspend to immediately resume it.
+ suspendedStreams[streamID] = 0; // start sending from offset 0
+ sendDATA(streamID, windowSize);
+ } else {
+ activeRequests.erase(streamID);
+ closedStreams.insert(streamID);
+ }
+}
+
+void Http2Server::processRequest()
+{
+ Q_ASSERT(continuedRequest.size());
+
+ if (!continuedRequest.back().flags().testFlag(FrameFlag::END_HEADERS))
+ return;
+
+ // We test here:
+ // 1. stream is 'idle'.
+ // 2. has priority set and dependency (it's 0x0 at the moment).
+ // 3. header can be decompressed.
+ const auto &headersFrame = continuedRequest.front();
+ const auto streamID = headersFrame.streamID();
+ if (!is_valid_client_stream(streamID)) {
+ emit invalidRequest(streamID);
+ connectionError = true;
+ sendGOAWAY(connectionStreamID, PROTOCOL_ERROR, connectionStreamID);
+ return;
+ }
+
+ if (closedStreams.find(streamID) != closedStreams.end()) {
+ emit invalidFrame();
+ connectionError = true;
+ sendGOAWAY(connectionStreamID, PROTOCOL_ERROR, connectionStreamID);
+ return;
+ }
+
+ quint32 dep = 0;
+ uchar w = 0;
+ if (!headersFrame.priority(&dep, &w)) {
+ emit invalidFrame();
+ sendRST_STREAM(streamID, PROTOCOL_ERROR);
+ return;
+ }
+
+ // Assemble headers ...
+ quint32 totalSize = 0;
+ for (const auto &frame : continuedRequest) {
+ if (std::numeric_limits<quint32>::max() - frame.dataSize() < totalSize) {
+ // Resulted in overflow ...
+ emit invalidFrame();
+ connectionError = true;
+ sendGOAWAY(connectionStreamID, PROTOCOL_ERROR, connectionStreamID);
+ return;
+ }
+ totalSize += frame.dataSize();
+ }
+
+ std::vector<uchar> hpackBlock(totalSize);
+ auto dst = hpackBlock.begin();
+ for (const auto &frame : continuedRequest) {
+ if (!frame.dataSize())
+ continue;
+ std::copy(frame.dataBegin(), frame.dataBegin() + frame.dataSize(), dst);
+ dst += frame.dataSize();
+ }
+
+ HPack::BitIStream inputStream{&hpackBlock[0], &hpackBlock[0] + hpackBlock.size()};
+
+ if (!decoder.decodeHeaderFields(inputStream)) {
+ emit decompressionFailed(streamID);
+ sendRST_STREAM(streamID, COMPRESSION_ERROR);
+ closedStreams.insert(streamID);
+ return;
+ }
+
+ // Actually, if needed, we can do a comparison here.
+ activeRequests[streamID] = decoder.decodedHeader();
+ if (headersFrame.flags().testFlag(FrameFlag::END_STREAM))
+ emit receivedRequest(streamID);
+ // else - we're waiting for incoming DATA frames ...
+ continuedRequest.clear();
+}
+
+QT_END_NAMESPACE
diff --git a/tests/auto/network/access/http2/http2srv.h b/tests/auto/network/access/http2/http2srv.h
new file mode 100644
index 0000000000..15a4f212c9
--- /dev/null
+++ b/tests/auto/network/access/http2/http2srv.h
@@ -0,0 +1,172 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef HTTP2SRV_H
+#define HTTP2SRV_H
+
+#include <QtNetwork/private/http2protocol_p.h>
+#include <QtNetwork/private/http2frames_p.h>
+#include <QtNetwork/private/hpack_p.h>
+
+#include <QtNetwork/qabstractsocket.h>
+#include <QtCore/qscopedpointer.h>
+#include <QtNetwork/qtcpserver.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qglobal.h>
+
+#include <vector>
+#include <map>
+#include <set>
+
+QT_BEGIN_NAMESPACE
+
+struct Http2Setting
+{
+ Http2::Settings identifier;
+ quint32 value = 0;
+
+ Http2Setting(Http2::Settings ident, quint32 v)
+ : identifier(ident),
+ value(v)
+ {}
+};
+
+using Http2Settings = std::vector<Http2Setting>;
+
+class Http2Server : public QTcpServer
+{
+ Q_OBJECT
+public:
+ Http2Server(bool clearText, const Http2Settings &serverSettings,
+ const Http2Settings &clientSettings);
+
+ ~Http2Server();
+
+ // To be called before server started:
+ void enablePushPromise(bool enabled, const QByteArray &path = QByteArray());
+ void setResponseBody(const QByteArray &body);
+
+ // Invokables, since we can call them from the main thread,
+ // but server (can) work on its own thread.
+ Q_INVOKABLE void startServer();
+ Q_INVOKABLE void sendServerSettings();
+ Q_INVOKABLE void sendGOAWAY(quint32 streamID, quint32 error,
+ quint32 lastStreamID);
+ Q_INVOKABLE void sendRST_STREAM(quint32 streamID, quint32 error);
+ Q_INVOKABLE void sendDATA(quint32 streamID, quint32 windowSize);
+ Q_INVOKABLE void sendWINDOW_UPDATE(quint32 streamID, quint32 delta);
+
+ Q_INVOKABLE void handleConnectionPreface();
+ Q_INVOKABLE void handleIncomingFrame();
+ Q_INVOKABLE void handleSETTINGS();
+ Q_INVOKABLE void handleDATA();
+ Q_INVOKABLE void handleWINDOW_UPDATE();
+
+ Q_INVOKABLE void sendResponse(quint32 streamID, bool emptyBody);
+
+private:
+ void processRequest();
+
+Q_SIGNALS:
+ void serverStarted(quint16 port);
+ // Error/success notifications:
+ void clientPrefaceOK();
+ void clientPrefaceError();
+ void serverSettingsAcked();
+ void invalidFrame();
+ void invalidRequest(quint32 streamID);
+ void decompressionFailed(quint32 streamID);
+ void receivedRequest(quint32 streamID);
+ void receivedData(quint32 streamID);
+ void windowUpdate(quint32 streamID);
+
+private slots:
+ void connectionEstablished();
+ void readReady();
+
+private:
+ void incomingConnection(qintptr socketDescriptor) Q_DECL_OVERRIDE;
+
+ quint32 clientSetting(Http2::Settings identifier, quint32 defaultValue);
+
+ QScopedPointer<QAbstractSocket> socket;
+
+ // Connection preface:
+ bool waitingClientPreface = false;
+ bool waitingClientSettings = false;
+ bool settingsSent = false;
+ bool waitingClientAck = false;
+
+ Http2Settings serverSettings;
+ std::map<quint16, quint32> expectedClientSettings;
+
+ bool connectionError = false;
+
+ Http2::FrameReader reader;
+ Http2::Frame inboundFrame;
+ Http2::FrameWriter writer;
+
+ using FrameSequence = std::vector<Http2::Frame>;
+ FrameSequence continuedRequest;
+
+ std::map<quint32, quint32> streamWindows;
+
+ HPack::Decoder decoder{HPack::FieldLookupTable::DefaultSize};
+ HPack::Encoder encoder{HPack::FieldLookupTable::DefaultSize, true};
+
+ using Http2Requests = std::map<quint32, HPack::HttpHeader>;
+ Http2Requests activeRequests;
+ // 'remote half-closed' streams to keep
+ // track of streams with END_STREAM set:
+ std::set<quint32> closedStreams;
+ // streamID + offset in response body to send.
+ std::map<quint32, quint32> suspendedStreams;
+
+ // We potentially reset this once (see sendServerSettings)
+ // and do not change later:
+ quint32 sessionRecvWindowSize = Http2::defaultSessionWindowSize;
+ // This changes in the range [0, sessionRecvWindowSize]
+ // while handling DATA frames:
+ quint32 sessionCurrRecvWindow = sessionRecvWindowSize;
+ // This we potentially update only once (sendServerSettings).
+ quint32 streamRecvWindowSize = Http2::defaultSessionWindowSize;
+
+ QByteArray responseBody;
+ bool clearTextHTTP2 = false;
+ bool pushPromiseEnabled = false;
+ quint32 lastPromisedStream = 0;
+ QByteArray pushPath;
+
+protected slots:
+ void ignoreErrorSlot();
+};
+
+QT_END_NAMESPACE
+
+#endif
+
diff --git a/tests/auto/network/access/http2/tst_http2.cpp b/tests/auto/network/access/http2/tst_http2.cpp
new file mode 100644
index 0000000000..771ddb01be
--- /dev/null
+++ b/tests/auto/network/access/http2/tst_http2.cpp
@@ -0,0 +1,539 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+
+#include "http2srv.h"
+
+#include <QtNetwork/qnetworkaccessmanager.h>
+#include <QtNetwork/qnetworkrequest.h>
+#include <QtNetwork/qnetworkreply.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qthread.h>
+#include <QtCore/qurl.h>
+
+#ifndef QT_NO_SSL
+#ifndef QT_NO_OPENSSL
+#include <QtNetwork/private/qsslsocket_openssl_symbols_p.h>
+#endif // NO_OPENSSL
+#endif // NO_SSL
+
+#include <cstdlib>
+#include <string>
+
+// At the moment our HTTP/2 imlpementation requires ALPN and this means OpenSSL.
+#if !defined(QT_NO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(OPENSSL_NO_TLSEXT)
+const bool clearTextHTTP2 = false;
+#else
+const bool clearTextHTTP2 = true;
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class tst_Http2 : public QObject
+{
+ Q_OBJECT
+public:
+ tst_Http2();
+ ~tst_Http2();
+private slots:
+ // Tests:
+ void singleRequest();
+ void multipleRequests();
+ void flowControlClientSide();
+ void flowControlServerSide();
+ void pushPromise();
+
+protected slots:
+ // Slots to listen to our in-process server:
+ void serverStarted(quint16 port);
+ void clientPrefaceOK();
+ void clientPrefaceError();
+ void serverSettingsAcked();
+ void invalidFrame();
+ void invalidRequest(quint32 streamID);
+ void decompressionFailed(quint32 streamID);
+ void receivedRequest(quint32 streamID);
+ void receivedData(quint32 streamID);
+ void windowUpdated(quint32 streamID);
+ void replyFinished();
+
+private:
+ void clearHTTP2State();
+ // Run event for 'ms' milliseconds.
+ // The default value '5000' is enough for
+ // small payload.
+ void runEventLoop(int ms = 5000);
+ void stopEventLoop();
+ Http2Server *newServer(const Http2Settings &serverSettings,
+ const Http2Settings &clientSettings = defaultClientSettings);
+ // Send a get or post request, depending on a payload (empty or not).
+ void sendRequest(int streamNumber,
+ QNetworkRequest::Priority priority = QNetworkRequest::NormalPriority,
+ const QByteArray &payload = QByteArray());
+
+ quint16 serverPort = 0;
+ QThread *workerThread = nullptr;
+ QNetworkAccessManager manager;
+
+ QEventLoop eventLoop;
+ QTimer timer;
+
+ int nRequests = 0;
+ int nSentRequests = 0;
+
+ int windowUpdates = 0;
+ bool prefaceOK = false;
+ bool serverGotSettingsACK = false;
+
+ static const Http2Settings defaultServerSettings;
+ static const Http2Settings defaultClientSettings;
+};
+
+const Http2Settings tst_Http2::defaultServerSettings{{Http2::Settings::MAX_CONCURRENT_STREAMS_ID, 100}};
+const Http2Settings tst_Http2::defaultClientSettings{{Http2::Settings::MAX_FRAME_SIZE_ID, quint32(Http2::maxFrameSize)},
+ {Http2::Settings::ENABLE_PUSH_ID, quint32(0)}};
+
+namespace {
+
+// Our server lives/works on a different thread so we invoke its 'deleteLater'
+// instead of simple 'delete'.
+struct ServerDeleter
+{
+ static void cleanup(Http2Server *srv)
+ {
+ if (srv)
+ QMetaObject::invokeMethod(srv, "deleteLater", Qt::QueuedConnection);
+ }
+};
+
+using ServerPtr = QScopedPointer<Http2Server, ServerDeleter>;
+
+struct EnvVarGuard
+{
+ EnvVarGuard(const char *name, const QByteArray &value)
+ : varName(name),
+ prevValue(qgetenv(name))
+ {
+ Q_ASSERT(name);
+ qputenv(name, value);
+ }
+ ~EnvVarGuard()
+ {
+ if (prevValue.size())
+ qputenv(varName.c_str(), prevValue);
+ else
+ qunsetenv(varName.c_str());
+ }
+
+ const std::string varName;
+ const QByteArray prevValue;
+};
+
+} // unnamed namespace
+
+tst_Http2::tst_Http2()
+ : workerThread(new QThread)
+{
+ workerThread->start();
+
+ timer.setInterval(10000);
+ timer.setSingleShot(true);
+
+ connect(&timer, SIGNAL(timeout()), &eventLoop, SLOT(quit()));
+}
+
+tst_Http2::~tst_Http2()
+{
+ workerThread->quit();
+ workerThread->wait(5000);
+
+ if (workerThread->isFinished()) {
+ delete workerThread;
+ } else {
+ connect(workerThread, &QThread::finished,
+ workerThread, &QThread::deleteLater);
+ }
+}
+
+void tst_Http2::singleRequest()
+{
+ clearHTTP2State();
+
+ serverPort = 0;
+ nRequests = 1;
+
+ ServerPtr srv(newServer(defaultServerSettings));
+
+ QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection);
+ runEventLoop();
+
+ QVERIFY(serverPort != 0);
+
+ const QString urlAsString(clearTextHTTP2 ? QString("http://127.0.0.1:%1/index.html")
+ : QString("https://127.0.0.1:%1/index.html"));
+ const QUrl url(urlAsString.arg(serverPort));
+
+ QNetworkRequest request(url);
+ request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, QVariant(true));
+
+ auto reply = manager.get(request);
+ connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished);
+ // Since we're using self-signed certificates,
+ // ignore SSL errors:
+ reply->ignoreSslErrors();
+
+ runEventLoop();
+
+ QVERIFY(nRequests == 0);
+ QVERIFY(prefaceOK);
+ QVERIFY(serverGotSettingsACK);
+
+ QCOMPARE(reply->error(), QNetworkReply::NoError);
+ QVERIFY(reply->isFinished());
+}
+
+void tst_Http2::multipleRequests()
+{
+ clearHTTP2State();
+
+ serverPort = 0;
+ nRequests = 10;
+
+ ServerPtr srv(newServer(defaultServerSettings));
+
+ QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection);
+
+ runEventLoop();
+ QVERIFY(serverPort != 0);
+
+ // Just to make the order a bit more interesting
+ // we'll index this randomly:
+ QNetworkRequest::Priority priorities[] = {QNetworkRequest::HighPriority,
+ QNetworkRequest::NormalPriority,
+ QNetworkRequest::LowPriority};
+
+ for (int i = 0; i < nRequests; ++i)
+ sendRequest(i, priorities[std::rand() % 3]);
+
+ runEventLoop();
+
+ QVERIFY(nRequests == 0);
+ QVERIFY(prefaceOK);
+ QVERIFY(serverGotSettingsACK);
+}
+
+void tst_Http2::flowControlClientSide()
+{
+ // Create a server but impose limits:
+ // 1. Small MAX frame size, so we test CONTINUATION frames.
+ // 2. Small client windows so server responses cause client streams
+ // to suspend and server sends WINDOW_UPDATE frames.
+ // 3. Few concurrent streams, to test protocol handler can resume
+ // suspended requests.
+ using namespace Http2;
+
+ clearHTTP2State();
+
+ serverPort = 0;
+ nRequests = 10;
+ windowUpdates = 0;
+
+ const Http2Settings serverSettings = {{Settings::MAX_CONCURRENT_STREAMS_ID, 3}};
+
+ ServerPtr srv(newServer(serverSettings));
+
+ const QByteArray respond(int(Http2::defaultSessionWindowSize * 50), 'x');
+ srv->setResponseBody(respond);
+
+ QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection);
+
+ runEventLoop();
+ QVERIFY(serverPort != 0);
+
+ for (int i = 0; i < nRequests; ++i)
+ sendRequest(i);
+
+ runEventLoop(120000);
+
+ QVERIFY(nRequests == 0);
+ QVERIFY(prefaceOK);
+ QVERIFY(serverGotSettingsACK);
+ QVERIFY(windowUpdates > 0);
+}
+
+void tst_Http2::flowControlServerSide()
+{
+ // Quite aggressive test:
+ // low MAX_FRAME_SIZE forces a lot of small DATA frames,
+ // payload size exceedes stream/session RECV window sizes
+ // so that our implementation should deal with WINDOW_UPDATE
+ // on a session/stream level correctly + resume/suspend streams
+ // to let all replies finish without any error.
+ using namespace Http2;
+
+ clearHTTP2State();
+
+ serverPort = 0;
+ nRequests = 30;
+
+ const Http2Settings serverSettings = {{Settings::MAX_CONCURRENT_STREAMS_ID, 7}};
+
+ ServerPtr srv(newServer(serverSettings));
+
+ const QByteArray payload(int(Http2::defaultSessionWindowSize * 500), 'x');
+
+ QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection);
+
+ runEventLoop();
+ QVERIFY(serverPort != 0);
+
+ for (int i = 0; i < nRequests; ++i)
+ sendRequest(i, QNetworkRequest::NormalPriority, payload);
+
+ runEventLoop(120000);
+
+ QVERIFY(nRequests == 0);
+ QVERIFY(prefaceOK);
+ QVERIFY(serverGotSettingsACK);
+}
+
+void tst_Http2::pushPromise()
+{
+ // We will first send some request, the server should reply and also emulate
+ // PUSH_PROMISE sending us another response as promised.
+ using namespace Http2;
+
+ clearHTTP2State();
+
+ serverPort = 0;
+ nRequests = 1;
+
+ const EnvVarGuard env("QT_HTTP2_ENABLE_PUSH_PROMISE", "1");
+ const Http2Settings clientSettings{{Settings::MAX_FRAME_SIZE_ID, quint32(Http2::maxFrameSize)},
+ {Settings::ENABLE_PUSH_ID, quint32(1)}};
+
+ ServerPtr srv(newServer(defaultServerSettings, clientSettings));
+ srv->enablePushPromise(true, QByteArray("/script.js"));
+
+ QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection);
+ runEventLoop();
+
+ QVERIFY(serverPort != 0);
+
+ const QString urlAsString((clearTextHTTP2 ? QString("http://127.0.0.1:%1/")
+ : QString("https://127.0.0.1:%1/")).arg(serverPort));
+ const QUrl requestUrl(urlAsString + "index.html");
+
+ QNetworkRequest request(requestUrl);
+ request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, QVariant(true));
+
+ auto reply = manager.get(request);
+ connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished);
+ // Since we're using self-signed certificates, ignore SSL errors:
+ reply->ignoreSslErrors();
+
+ runEventLoop();
+
+ QVERIFY(nRequests == 0);
+ QVERIFY(prefaceOK);
+ QVERIFY(serverGotSettingsACK);
+
+ QCOMPARE(reply->error(), QNetworkReply::NoError);
+ QVERIFY(reply->isFinished());
+
+ // Now, the most interesting part!
+ nSentRequests = 0;
+ nRequests = 1;
+ // Create an additional request (let's say, we parsed reply and realized we
+ // need another resource):
+
+ const QUrl promisedUrl(urlAsString + "script.js");
+ QNetworkRequest promisedRequest(promisedUrl);
+ promisedRequest.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, QVariant(true));
+ reply = manager.get(promisedRequest);
+ connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished);
+ reply->ignoreSslErrors();
+
+ runEventLoop();
+
+ // Let's check that NO request was actually made:
+ QCOMPARE(nSentRequests, 0);
+ // Decreased by replyFinished():
+ QCOMPARE(nRequests, 0);
+ QCOMPARE(reply->error(), QNetworkReply::NoError);
+ QVERIFY(reply->isFinished());
+}
+
+void tst_Http2::serverStarted(quint16 port)
+{
+ serverPort = port;
+ stopEventLoop();
+}
+
+void tst_Http2::clearHTTP2State()
+{
+ windowUpdates = 0;
+ prefaceOK = false;
+ serverGotSettingsACK = false;
+}
+
+void tst_Http2::runEventLoop(int ms)
+{
+ timer.setInterval(ms);
+ timer.start();
+ eventLoop.exec();
+}
+
+void tst_Http2::stopEventLoop()
+{
+ timer.stop();
+ eventLoop.quit();
+}
+
+Http2Server *tst_Http2::newServer(const Http2Settings &serverSettings,
+ const Http2Settings &clientSettings)
+{
+ using namespace Http2;
+ auto srv = new Http2Server(clearTextHTTP2, serverSettings, clientSettings);
+
+ using Srv = Http2Server;
+ using Cl = tst_Http2;
+
+ connect(srv, &Srv::serverStarted, this, &Cl::serverStarted);
+ connect(srv, &Srv::clientPrefaceOK, this, &Cl::clientPrefaceOK);
+ connect(srv, &Srv::clientPrefaceError, this, &Cl::clientPrefaceError);
+ connect(srv, &Srv::serverSettingsAcked, this, &Cl::serverSettingsAcked);
+ connect(srv, &Srv::invalidFrame, this, &Cl::invalidFrame);
+ connect(srv, &Srv::invalidRequest, this, &Cl::invalidRequest);
+ connect(srv, &Srv::receivedRequest, this, &Cl::receivedRequest);
+ connect(srv, &Srv::receivedData, this, &Cl::receivedData);
+ connect(srv, &Srv::windowUpdate, this, &Cl::windowUpdated);
+
+ srv->moveToThread(workerThread);
+
+ return srv;
+}
+
+void tst_Http2::sendRequest(int streamNumber,
+ QNetworkRequest::Priority priority,
+ const QByteArray &payload)
+{
+ static const QString urlAsString(clearTextHTTP2 ? "http://127.0.0.1:%1/stream%2.html"
+ : "https://127.0.0.1:%1/stream%2.html");
+
+ const QUrl url(urlAsString.arg(serverPort).arg(streamNumber));
+ QNetworkRequest request(url);
+ request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, QVariant(true));
+ request.setPriority(priority);
+
+ QNetworkReply *reply = nullptr;
+ if (payload.size())
+ reply = manager.post(request, payload);
+ else
+ reply = manager.get(request);
+
+ reply->ignoreSslErrors();
+ connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished);
+}
+
+void tst_Http2::clientPrefaceOK()
+{
+ prefaceOK = true;
+}
+
+void tst_Http2::clientPrefaceError()
+{
+ prefaceOK = false;
+}
+
+void tst_Http2::serverSettingsAcked()
+{
+ serverGotSettingsACK = true;
+}
+
+void tst_Http2::invalidFrame()
+{
+}
+
+void tst_Http2::invalidRequest(quint32 streamID)
+{
+ Q_UNUSED(streamID)
+}
+
+void tst_Http2::decompressionFailed(quint32 streamID)
+{
+ Q_UNUSED(streamID)
+}
+
+void tst_Http2::receivedRequest(quint32 streamID)
+{
+ ++nSentRequests;
+ qDebug() << " server got a request on stream" << streamID;
+ Http2Server *srv = qobject_cast<Http2Server *>(sender());
+ Q_ASSERT(srv);
+ QMetaObject::invokeMethod(srv, "sendResponse", Qt::QueuedConnection,
+ Q_ARG(quint32, streamID),
+ Q_ARG(bool, false /*non-empty body*/));
+}
+
+void tst_Http2::receivedData(quint32 streamID)
+{
+ qDebug() << " server got a 'POST' request on stream" << streamID;
+ Http2Server *srv = qobject_cast<Http2Server *>(sender());
+ Q_ASSERT(srv);
+ QMetaObject::invokeMethod(srv, "sendResponse", Qt::QueuedConnection,
+ Q_ARG(quint32, streamID),
+ Q_ARG(bool, true /*HEADERS only*/));
+}
+
+void tst_Http2::windowUpdated(quint32 streamID)
+{
+ Q_UNUSED(streamID)
+
+ ++windowUpdates;
+}
+
+void tst_Http2::replyFinished()
+{
+ QVERIFY(nRequests);
+
+ if (const auto reply = qobject_cast<QNetworkReply *>(sender()))
+ QCOMPARE(reply->error(), QNetworkReply::NoError);
+
+ --nRequests;
+ if (!nRequests)
+ stopEventLoop();
+}
+
+QT_END_NAMESPACE
+
+QTEST_MAIN(tst_Http2)
+
+#include "tst_http2.moc"
diff --git a/tests/auto/network/access/qftp/qftp.pro b/tests/auto/network/access/qftp/qftp.pro
index 4294f27e74..1959c1acac 100644
--- a/tests/auto/network/access/qftp/qftp.pro
+++ b/tests/auto/network/access/qftp/qftp.pro
@@ -2,12 +2,5 @@ CONFIG += testcase
TARGET = tst_qftp
SOURCES += tst_qftp.cpp
-requires(contains(QT_CONFIG,private_tests))
+requires(qtConfig(private_tests))
QT = core network network-private testlib
-
-wince {
- addFiles.files = rfc3252.txt
- addFiles.path = .
- DEPLOYMENT += addFiles
-}
-
diff --git a/tests/auto/network/access/qftp/tst_qftp.cpp b/tests/auto/network/access/qftp/tst_qftp.cpp
index edeb471401..a13fa86405 100644
--- a/tests/auto/network/access/qftp/tst_qftp.cpp
+++ b/tests/auto/network/access/qftp/tst_qftp.cpp
@@ -276,14 +276,9 @@ void tst_QFtp::init()
inFileDirExistsFunction = false;
-#if !defined(Q_OS_WINCE)
srand(time(0));
uniqueExtension = QString::number((quintptr)this) + QString::number(rand())
+ QString::number((qulonglong)time(0));
-#else
- srand(0);
- uniqueExtension = QString::number((quintptr)this) + QString::number(rand()) + QLatin1Char('0');
-#endif
}
void tst_QFtp::cleanup()
@@ -1353,11 +1348,7 @@ void tst_QFtp::abort_data()
QTest::newRow( "get_fluke02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("qtest/rfc3252") << QByteArray();
// Qt/CE test environment has too little memory for this test
-#if !defined(Q_OS_WINCE)
QByteArray bigData( 10*1024*1024, 0 );
-#else
- QByteArray bigData( 1*1024*1024, 0 );
-#endif
bigData.fill( 'B' );
QTest::newRow( "put_fluke01" ) << QtNetworkSettings::serverName() << (uint)21 << QString("qtest/upload/abort_put") << bigData;
}
diff --git a/tests/auto/network/access/qhttpnetworkconnection/qhttpnetworkconnection.pro b/tests/auto/network/access/qhttpnetworkconnection/qhttpnetworkconnection.pro
index bd20fd33dd..d32b651b86 100644
--- a/tests/auto/network/access/qhttpnetworkconnection/qhttpnetworkconnection.pro
+++ b/tests/auto/network/access/qhttpnetworkconnection/qhttpnetworkconnection.pro
@@ -1,6 +1,6 @@
CONFIG += testcase
TARGET = tst_qhttpnetworkconnection
SOURCES += tst_qhttpnetworkconnection.cpp
-requires(contains(QT_CONFIG,private_tests))
+requires(qtConfig(private_tests))
QT = core-private network-private testlib
diff --git a/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp b/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp
index ef742aaa9a..84766f5484 100644
--- a/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp
+++ b/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp
@@ -151,14 +151,7 @@ void tst_QHttpNetworkConnection::head()
QHttpNetworkRequest request(protocol + host + path, QHttpNetworkRequest::Head);
QHttpNetworkReply *reply = connection.sendRequest(request);
- QTime stopWatch;
- stopWatch.start();
- do {
- QCoreApplication::instance()->processEvents();
- if (stopWatch.elapsed() >= 30000)
- break;
- } while (!reply->isFinished());
-
+ QTRY_VERIFY_WITH_TIMEOUT(reply->isFinished(), 30000);
QCOMPARE(reply->statusCode(), statusCode);
QCOMPARE(reply->reasonPhrase(), statusString);
// only check it if it is set and expected
@@ -208,15 +201,7 @@ void tst_QHttpNetworkConnection::get()
QHttpNetworkRequest request(protocol + host + path);
QHttpNetworkReply *reply = connection.sendRequest(request);
- QTime stopWatch;
- stopWatch.start();
- forever {
- QCoreApplication::instance()->processEvents();
- if (reply->bytesAvailable())
- break;
- if (stopWatch.elapsed() >= 30000)
- break;
- }
+ QTRY_VERIFY_WITH_TIMEOUT(reply->bytesAvailable(), 30000);
QCOMPARE(reply->statusCode(), statusCode);
QCOMPARE(reply->reasonPhrase(), statusString);
@@ -224,17 +209,8 @@ void tst_QHttpNetworkConnection::get()
if (reply->contentLength() != -1 && contentLength != -1)
QCOMPARE(reply->contentLength(), qint64(contentLength));
- stopWatch.start();
- QByteArray ba;
- do {
- QCoreApplication::instance()->processEvents();
- while (reply->bytesAvailable())
- ba += reply->readAny();
- if (stopWatch.elapsed() >= 30000)
- break;
- } while (!reply->isFinished());
-
- QVERIFY(reply->isFinished());
+ QTRY_VERIFY_WITH_TIMEOUT(reply->isFinished(), 30000);
+ QByteArray ba = reply->readAll();
//do not require server generated error pages to be a fixed size
if (downloadSize != -1)
QCOMPARE(ba.size(), downloadSize);
@@ -303,13 +279,7 @@ void tst_QHttpNetworkConnection::put()
connect(reply, SIGNAL(finishedWithError(QNetworkReply::NetworkError,QString)),
SLOT(finishedWithError(QNetworkReply::NetworkError,QString)));
- QTime stopWatch;
- stopWatch.start();
- do {
- QCoreApplication::instance()->processEvents();
- if (stopWatch.elapsed() >= 30000)
- break;
- } while (!reply->isFinished() && !finishedCalled && !finishedWithErrorCalled);
+ QTRY_VERIFY_WITH_TIMEOUT(reply->isFinished() || finishedCalled || finishedWithErrorCalled, 30000);
if (reply->isFinished()) {
QByteArray ba;
@@ -385,16 +355,7 @@ void tst_QHttpNetworkConnection::post()
QHttpNetworkReply *reply = connection.sendRequest(request);
- QTime stopWatch;
- stopWatch.start();
- forever {
- QCoreApplication::instance()->processEvents();
- if (reply->bytesAvailable())
- break;
- if (stopWatch.elapsed() >= 30000)
- break;
- }
-
+ QTRY_VERIFY_WITH_TIMEOUT(reply->bytesAvailable(), 30000);
QCOMPARE(reply->statusCode(), statusCode);
QCOMPARE(reply->reasonPhrase(), statusString);
@@ -411,17 +372,8 @@ void tst_QHttpNetworkConnection::post()
}
}
- stopWatch.start();
- QByteArray ba;
- do {
- QCoreApplication::instance()->processEvents();
- while (reply->bytesAvailable())
- ba += reply->readAny();
- if (stopWatch.elapsed() >= 30000)
- break;
- } while (!reply->isFinished());
-
- QVERIFY(reply->isFinished());
+ QTRY_VERIFY_WITH_TIMEOUT(reply->isFinished(), 30000);
+ QByteArray ba = reply->readAll();
//don't require fixed size for generated error pages
if (downloadSize != -1)
QCOMPARE(ba.size(), downloadSize);
@@ -536,17 +488,7 @@ void tst_QHttpNetworkConnection::get401()
connect(reply, SIGNAL(finishedWithError(QNetworkReply::NetworkError,QString)),
SLOT(finishedWithError(QNetworkReply::NetworkError,QString)));
- QTime stopWatch;
- stopWatch.start();
- forever {
- QCoreApplication::instance()->processEvents();
- if (finishedCalled)
- break;
- if (finishedWithErrorCalled)
- break;
- if (stopWatch.elapsed() >= 30000)
- break;
- }
+ QTRY_VERIFY_WITH_TIMEOUT(finishedCalled || finishedWithErrorCalled, 30000);
QCOMPARE(reply->statusCode(), statusCode);
delete reply;
}
@@ -595,16 +537,8 @@ void tst_QHttpNetworkConnection::compression()
if (!autoCompress)
request.setHeaderField("Accept-Encoding", contentCoding.toLatin1());
QHttpNetworkReply *reply = connection.sendRequest(request);
- QTime stopWatch;
- stopWatch.start();
- forever {
- QCoreApplication::instance()->processEvents();
- if (reply->bytesAvailable())
- break;
- if (stopWatch.elapsed() >= 30000)
- break;
- }
+ QTRY_VERIFY_WITH_TIMEOUT(reply->bytesAvailable(), 30000);
QCOMPARE(reply->statusCode(), statusCode);
QCOMPARE(reply->reasonPhrase(), statusString);
bool isLengthOk = (reply->contentLength() == qint64(contentLength)
@@ -613,17 +547,8 @@ void tst_QHttpNetworkConnection::compression()
QVERIFY(isLengthOk);
- stopWatch.start();
- QByteArray ba;
- do {
- QCoreApplication::instance()->processEvents();
- while (reply->bytesAvailable())
- ba += reply->readAny();
- if (stopWatch.elapsed() >= 30000)
- break;
- } while (!reply->isFinished());
-
- QVERIFY(reply->isFinished());
+ QTRY_VERIFY_WITH_TIMEOUT(reply->isFinished(), 30000);
+ QByteArray ba = reply->readAll();
QCOMPARE(ba.size(), downloadSize);
delete reply;
@@ -694,17 +619,7 @@ void tst_QHttpNetworkConnection::ignoresslerror()
connect(reply, SIGNAL(finished()), SLOT(finishedReply()));
- QTime stopWatch;
- stopWatch.start();
- forever {
- QCoreApplication::instance()->processEvents();
- if (reply->bytesAvailable())
- break;
- if (statusCode == 100 && finishedWithErrorCalled)
- break;
- if (stopWatch.elapsed() >= 30000)
- break;
- }
+ QTRY_VERIFY_WITH_TIMEOUT(reply->bytesAvailable() || (statusCode == 100 && finishedWithErrorCalled), 30000);
QCOMPARE(reply->statusCode(), statusCode);
delete reply;
}
@@ -746,15 +661,7 @@ void tst_QHttpNetworkConnection::nossl()
connect(reply, SIGNAL(finishedWithError(QNetworkReply::NetworkError,QString)),
SLOT(finishedWithError(QNetworkReply::NetworkError,QString)));
- QTime stopWatch;
- stopWatch.start();
- forever {
- QCoreApplication::instance()->processEvents();
- if (finishedWithErrorCalled)
- break;
- if (stopWatch.elapsed() >= 30000)
- break;
- }
+ QTRY_VERIFY_WITH_TIMEOUT(finishedWithErrorCalled, 30000);
QCOMPARE(netErrorCode, networkError);
delete reply;
}
@@ -774,6 +681,15 @@ void tst_QHttpNetworkConnection::getMultiple_data()
QTest::newRow("1 connection, pipelining allowed, 100 requests") << quint16(1) << true << 100;
}
+static bool allRepliesFinished(const QList<QHttpNetworkReply*> *_replies)
+{
+ const QList<QHttpNetworkReply*> &replies = *_replies;
+ for (int i = 0; i < replies.length(); i++)
+ if (!replies.at(i)->isFinished())
+ return false;
+ return true;
+}
+
void tst_QHttpNetworkConnection::getMultiple()
{
QFETCH(quint16, connectionCount);
@@ -797,27 +713,7 @@ void tst_QHttpNetworkConnection::getMultiple()
replies.append(reply);
}
- QTime stopWatch;
- stopWatch.start();
- int finishedCount = 0;
- do {
- QCoreApplication::instance()->processEvents();
- if (stopWatch.elapsed() >= 60000)
- break;
-
- finishedCount = 0;
- for (int i = 0; i < replies.length(); i++)
- if (replies.at(i)->isFinished())
- finishedCount++;
-
- } while (finishedCount != replies.length());
-
- // redundant
- for (int i = 0; i < replies.length(); i++)
- QVERIFY(replies.at(i)->isFinished());
-
- qDebug() << "===" << stopWatch.elapsed() << "msec ===";
-
+ QTRY_VERIFY_WITH_TIMEOUT(allRepliesFinished(&replies), 60000);
qDeleteAll(requests);
qDeleteAll(replies);
}
@@ -854,24 +750,10 @@ void tst_QHttpNetworkConnection::getMultipleWithPipeliningAndMultiplePriorities(
replies.append(reply);
}
- QTime stopWatch;
- stopWatch.start();
- int finishedCount = 0;
- do {
- QCoreApplication::instance()->processEvents();
- if (stopWatch.elapsed() >= 60000)
- break;
-
- finishedCount = 0;
- for (int i = 0; i < replies.length(); i++)
- if (replies.at(i)->isFinished())
- finishedCount++;
-
- } while (finishedCount != replies.length());
+ QTRY_VERIFY_WITH_TIMEOUT(allRepliesFinished(&replies), 60000);
int pipelinedCount = 0;
for (int i = 0; i < replies.length(); i++) {
- QVERIFY(replies.at(i)->isFinished());
QVERIFY (!(replies.at(i)->request().isPipeliningAllowed() == false
&& replies.at(i)->isPipeliningUsed()));
@@ -885,8 +767,6 @@ void tst_QHttpNetworkConnection::getMultipleWithPipeliningAndMultiplePriorities(
// requests had been pipelined)
QVERIFY(pipelinedCount >= requestCount / 2);
- qDebug() << "===" << stopWatch.elapsed() << "msec ===";
-
qDeleteAll(requests);
qDeleteAll(replies);
}
@@ -1062,17 +942,7 @@ void tst_QHttpNetworkConnection::getAndThenDeleteObject()
QHttpNetworkReply *reply = connection->sendRequest(request);
reply->setDownstreamLimited(true);
- QTime stopWatch;
- stopWatch.start();
- forever {
- QCoreApplication::instance()->processEvents();
- if (reply->bytesAvailable())
- break;
- if (stopWatch.elapsed() >= 30000)
- break;
- }
-
- QVERIFY(reply->bytesAvailable());
+ QTRY_VERIFY_WITH_TIMEOUT(reply->bytesAvailable(), 30000);
QCOMPARE(reply->statusCode() ,200);
QVERIFY(!reply->isFinished()); // must not be finished
diff --git a/tests/auto/network/access/qhttpnetworkreply/qhttpnetworkreply.pro b/tests/auto/network/access/qhttpnetworkreply/qhttpnetworkreply.pro
index 1810a38f6e..31570e6f01 100644
--- a/tests/auto/network/access/qhttpnetworkreply/qhttpnetworkreply.pro
+++ b/tests/auto/network/access/qhttpnetworkreply/qhttpnetworkreply.pro
@@ -1,6 +1,6 @@
CONFIG += testcase
TARGET = tst_qhttpnetworkreply
SOURCES += tst_qhttpnetworkreply.cpp
-requires(contains(QT_CONFIG,private_tests))
+requires(qtConfig(private_tests))
QT = core-private network-private testlib
diff --git a/tests/auto/network/access/qnetworkcookie/tst_qnetworkcookie.cpp b/tests/auto/network/access/qnetworkcookie/tst_qnetworkcookie.cpp
index 0424fc47ed..96c4917473 100644
--- a/tests/auto/network/access/qnetworkcookie/tst_qnetworkcookie.cpp
+++ b/tests/auto/network/access/qnetworkcookie/tst_qnetworkcookie.cpp
@@ -46,33 +46,6 @@ private slots:
void parseMultipleCookies();
};
-QT_BEGIN_NAMESPACE
-
-namespace QTest {
- template<>
- char *toString(const QNetworkCookie &cookie)
- {
- return qstrdup(cookie.toRawForm());
- }
-
- template<>
- char *toString(const QList<QNetworkCookie> &list)
- {
- QByteArray result = "QList(";
- bool first = true;
- foreach (QNetworkCookie cookie, list) {
- if (!first)
- result += ", ";
- first = false;
- result += "QNetworkCookie(" + cookie.toRawForm() + ')';
- }
- result.append(')');
- return qstrdup(result.constData());
- }
-}
-
-QT_END_NAMESPACE
-
void tst_QNetworkCookie::getterSetter()
{
QNetworkCookie cookie;
diff --git a/tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp b/tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp
index 849e2d8662..a0459021be 100644
--- a/tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp
+++ b/tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp
@@ -55,34 +55,6 @@ private slots:
void rfc6265();
};
-QT_BEGIN_NAMESPACE
-
-namespace QTest {
- template<>
- char *toString(const QNetworkCookie &cookie)
- {
- return qstrdup(cookie.toRawForm());
- }
-
- template<>
- char *toString(const QList<QNetworkCookie> &list)
- {
- QByteArray result = "QList(";
- bool first = true;
- foreach (QNetworkCookie cookie, list) {
- if (!first)
- result += ", ";
- first = false;
- result += "QNetworkCookie(" + cookie.toRawForm() + ')';
- }
-
- result.append(')');
- return qstrdup(result.constData());
- }
-}
-
-QT_END_NAMESPACE
-
class MyCookieJar: public QNetworkCookieJar
{
public:
diff --git a/tests/auto/network/access/qnetworkreply/qnetworkreply.pro b/tests/auto/network/access/qnetworkreply/qnetworkreply.pro
index bd10c77252..d3a92436ac 100644
--- a/tests/auto/network/access/qnetworkreply/qnetworkreply.pro
+++ b/tests/auto/network/access/qnetworkreply/qnetworkreply.pro
@@ -1,5 +1,5 @@
TEMPLATE = subdirs
-!winrt:!wince: SUBDIRS += echo
+!winrt:SUBDIRS += echo
test.depends += $$SUBDIRS
SUBDIRS += test
diff --git a/tests/auto/network/access/qnetworkreply/test/test.pro b/tests/auto/network/access/qnetworkreply/test/test.pro
index 772bb55990..45a5734305 100644
--- a/tests/auto/network/access/qnetworkreply/test/test.pro
+++ b/tests/auto/network/access/qnetworkreply/test/test.pro
@@ -5,12 +5,13 @@ SOURCES += ../tst_qnetworkreply.cpp
TARGET = ../tst_qnetworkreply
QT = core-private network-private testlib
+QT_FOR_CONFIG += gui-private
RESOURCES += ../qnetworkreply.qrc
TESTDATA += ../empty ../rfc3252.txt ../resource ../bigfile ../*.jpg ../certs \
../index.html ../smb-file.txt
-contains(QT_CONFIG,xcb): CONFIG+=insignificant_test # unstable, QTBUG-21102
+qtConfig(xcb): CONFIG+=insignificant_test # unstable, QTBUG-21102
win32:CONFIG += insignificant_test # QTBUG-24226
!winrt: TEST_HELPER_INSTALLS = ../echo/echo
diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
index b75b6d5df0..649278d48b 100644
--- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
+++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
@@ -205,6 +205,7 @@ private Q_SLOTS:
void invalidProtocol();
void getFromData_data();
void getFromData();
+ void getFromFile_data();
void getFromFile();
void getFromFileSpecial_data();
void getFromFileSpecial();
@@ -489,45 +490,6 @@ private:
bool tst_QNetworkReply::seedCreated = false;
-QT_BEGIN_NAMESPACE
-
-namespace QTest {
- template<>
- char *toString(const QNetworkReply::NetworkError& code)
- {
- const QMetaObject *mo = &QNetworkReply::staticMetaObject;
- int index = mo->indexOfEnumerator("NetworkError");
- if (index == -1)
- return qstrdup("");
-
- QMetaEnum qme = mo->enumerator(index);
- return qstrdup(qme.valueToKey(code));
- }
-
- template<>
- char *toString(const QNetworkCookie &cookie)
- {
- return qstrdup(cookie.toRawForm());
- }
-
- template<>
- char *toString(const QList<QNetworkCookie> &list)
- {
- QByteArray result = "QList(";
- bool first = true;
- foreach (QNetworkCookie cookie, list) {
- if (!first)
- result += ", ";
- first = false;
- result += "QNetworkCookie(" + cookie.toRawForm() + ')';
- }
- result.append(')');
- return qstrdup(result.constData());
- }
-}
-
-QT_END_NAMESPACE
-
#define RUN_REQUEST(call) \
do { \
QString errorMsg = call; \
@@ -650,8 +612,10 @@ private slots:
#endif
void slotError(QAbstractSocket::SocketError err)
{
- Q_ASSERT(!client.isNull());
- qDebug() << "slotError" << err << client->errorString();
+ if (client.isNull())
+ qDebug() << "slotError" << err;
+ else
+ qDebug() << "slotError" << err << client->errorString();
}
public slots:
@@ -1674,14 +1638,26 @@ void tst_QNetworkReply::getFromData()
QCOMPARE(reply->readAll(), expected);
}
+void tst_QNetworkReply::getFromFile_data()
+{
+ QTest::addColumn<bool>("backgroundAttribute");
+
+ QTest::newRow("no-background-attribute") << false;
+ QTest::newRow("background-attribute") << true;
+}
+
void tst_QNetworkReply::getFromFile()
{
+ QFETCH(bool, backgroundAttribute);
+
// create the file:
QTemporaryFile file(QDir::currentPath() + "/temp-XXXXXX");
file.setAutoRemove(true);
QVERIFY2(file.open(), qPrintable(file.errorString()));
QNetworkRequest request(QUrl::fromLocalFile(file.fileName()));
+ if (backgroundAttribute)
+ request.setAttribute(QNetworkRequest::BackgroundRequestAttribute, QVariant::fromValue(true));
QNetworkReplyPtr reply;
static const char fileData[] = "This is some data that is in the file.\r\n";
@@ -1691,6 +1667,7 @@ void tst_QNetworkReply::getFromFile()
QCOMPARE(file.size(), qint64(data.size()));
RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply));
+ QVERIFY(waitForFinish(reply) != Timeout);
QCOMPARE(reply->url(), request.url());
QCOMPARE(reply->error(), QNetworkReply::NoError);
@@ -4319,9 +4296,6 @@ void tst_QNetworkReply::ioPutToFileFromProcess()
QSKIP("No qprocess support", SkipAll);
#else
-#if defined(Q_OS_WINCE)
- QSKIP("Currently no stdin/out supported for Windows CE");
-#else
#ifdef Q_OS_WIN
if (qstrcmp(QTest::currentDataTag(), "small") == 0)
QSKIP("When passing a CR-LF-LF sequence through Windows stdio, it gets converted, "
@@ -4355,7 +4329,6 @@ void tst_QNetworkReply::ioPutToFileFromProcess()
QCOMPARE(file.size(), qint64(data.size()));
QByteArray contents = file.readAll();
QCOMPARE(contents, data);
-#endif
#endif // QT_NO_PROCESS
}
@@ -6328,17 +6301,7 @@ void tst_QNetworkReply::getAndThenDeleteObject()
reply->setReadBufferSize(1);
reply->setParent((QObject*)0); // must be 0 because else it is the manager
- QTime stopWatch;
- stopWatch.start();
- forever {
- QCoreApplication::instance()->processEvents();
- if (reply->bytesAvailable())
- break;
- if (stopWatch.elapsed() >= 30000)
- break;
- }
-
- QVERIFY(reply->bytesAvailable());
+ QTRY_VERIFY_WITH_TIMEOUT(reply->bytesAvailable(), 30000);
QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200);
QVERIFY(!reply->isFinished()); // must not be finished
@@ -6561,12 +6524,7 @@ void tst_QNetworkReply::getFromHttpIntoBuffer2()
QFETCH(bool, useDownloadBuffer);
// On my Linux Desktop the results are already visible with 128 kB, however we use this to have good results.
-#if defined(Q_OS_WINCE_WM)
- // Show some mercy to non-desktop platform/s
- enum {UploadSize = 4*1024*1024}; // 4 MB
-#else
enum {UploadSize = 32*1024*1024}; // 32 MB
-#endif
GetFromHttpIntoBuffer2Server server(UploadSize, true, false);
@@ -7892,10 +7850,6 @@ void tst_QNetworkReply::backgroundRequestInterruption()
QNetworkSessionPrivate::setUsagePolicies(*const_cast<QNetworkSession *>(session.data()), original);
QVERIFY(reply->isFinished());
-#ifdef Q_OS_OSX
- if (QSysInfo::MacintoshVersion == QSysInfo::MV_10_8)
- QEXPECT_FAIL("ftp, bg, nobg", "See QTBUG-32435", Abort);
-#endif
QCOMPARE(reply->error(), error);
#endif
}
diff --git a/tests/auto/network/access/qnetworkrequest/tst_qnetworkrequest.cpp b/tests/auto/network/access/qnetworkrequest/tst_qnetworkrequest.cpp
index a14aaf3cb1..bc9144e40e 100644
--- a/tests/auto/network/access/qnetworkrequest/tst_qnetworkrequest.cpp
+++ b/tests/auto/network/access/qnetworkrequest/tst_qnetworkrequest.cpp
@@ -56,33 +56,6 @@ private slots:
void removeHeader();
};
-QT_BEGIN_NAMESPACE
-
-namespace QTest {
- template<>
- char *toString(const QNetworkCookie &cookie)
- {
- return qstrdup(cookie.toRawForm());
- }
-
- template<>
- char *toString(const QList<QNetworkCookie> &list)
- {
- QByteArray result = "QList(";
- bool first = true;
- foreach (QNetworkCookie cookie, list) {
- if (!first)
- result += ", ";
- first = false;
- result += "QNetworkCookie(" + cookie.toRawForm() + ')';
- }
- result.append(')');
- return qstrdup(result.constData());
- }
-}
-
-QT_END_NAMESPACE
-
void tst_QNetworkRequest::ctor_data()
{
QTest::addColumn<QUrl>("url");
diff --git a/tests/auto/network/kernel/kernel.pro b/tests/auto/network/kernel/kernel.pro
index bb13c7dd7d..42df80dfa1 100644
--- a/tests/auto/network/kernel/kernel.pro
+++ b/tests/auto/network/kernel/kernel.pro
@@ -7,6 +7,7 @@ SUBDIRS=\
qauthenticator \
qnetworkproxy \
qnetworkinterface \
+ qnetworkdatagram \
qnetworkaddressentry \
qhostaddress \
@@ -17,7 +18,7 @@ winrt: SUBDIRS -= \
osx: SUBDIRS -= \ # QTBUG-41847
qhostinfo \
-!contains(QT_CONFIG, private_tests): SUBDIRS -= \
+!qtConfig(private_tests): SUBDIRS -= \
qauthenticator \
qhostinfo \
diff --git a/tests/auto/network/kernel/qauthenticator/qauthenticator.pro b/tests/auto/network/kernel/qauthenticator/qauthenticator.pro
index 5e4759b690..5038eea9af 100644
--- a/tests/auto/network/kernel/qauthenticator/qauthenticator.pro
+++ b/tests/auto/network/kernel/qauthenticator/qauthenticator.pro
@@ -1,6 +1,6 @@
CONFIG += testcase
TARGET = tst_qauthenticator
-requires(contains(QT_CONFIG,private_tests))
+requires(qtConfig(private_tests))
QT = core network-private testlib
SOURCES += tst_qauthenticator.cpp
DEFINES += SRCDIR=\\\"$$PWD/\\\"
diff --git a/tests/auto/network/kernel/qhostaddress/qhostaddress.pro b/tests/auto/network/kernel/qhostaddress/qhostaddress.pro
index 19d74dfd9b..a79fa2f59d 100644
--- a/tests/auto/network/kernel/qhostaddress/qhostaddress.pro
+++ b/tests/auto/network/kernel/qhostaddress/qhostaddress.pro
@@ -5,10 +5,4 @@ SOURCES += tst_qhostaddress.cpp
QT = core network testlib
-win32: {
-wince {
- LIBS += -lws2
-} else {
- LIBS += -lws2_32
-}
-}
+win32:LIBS += -lws2_32
diff --git a/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp b/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp
index 4fb97fe1f2..419c781aab 100644
--- a/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp
+++ b/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp
@@ -62,6 +62,8 @@ private slots:
void specialAddresses();
void compare_data();
void compare();
+ void isEqual_data();
+ void isEqual();
void assignment();
void scopeId();
void hashKey();
@@ -291,6 +293,7 @@ void tst_QHostAddress::compare_data()
QTest::newRow("5") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::Broadcast) << false;
QTest::newRow("6") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::LocalHostIPv6) << false;
QTest::newRow("7") << QHostAddress() << QHostAddress(QHostAddress::LocalHostIPv6) << false;
+ QTest::newRow("any4-any6") << QHostAddress(QHostAddress::AnyIPv4) << QHostAddress(QHostAddress::AnyIPv6) << false;
Q_IPV6ADDR localhostv4mapped = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 127, 0, 0, 1 } };
QTest::newRow("v4-v4mapped") << QHostAddress(QHostAddress::LocalHost) << QHostAddress("::ffff:127.0.0.1") << false;
@@ -309,6 +312,53 @@ void tst_QHostAddress::compare()
QCOMPARE(qHash(first), qHash(second));
}
+void tst_QHostAddress::isEqual_data()
+{
+ QTest::addColumn<QHostAddress>("first");
+ QTest::addColumn<QHostAddress>("second");
+ QTest::addColumn<int>("flags");
+ QTest::addColumn<bool>("result");
+
+ // QHostAddress::StrictConversion is already tested in compare()
+ QTest::newRow("localhost4to6-local") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::LocalHostIPv6) << (int)QHostAddress::ConvertLocalHost << true;
+ QTest::newRow("localhost4to6-compat") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::LocalHostIPv6) << (int)QHostAddress::ConvertV4CompatToIPv4 << false;
+ QTest::newRow("localhost4to6-mapped") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::LocalHostIPv6) << (int)QHostAddress::ConvertV4MappedToIPv4 << false;
+ QTest::newRow("localhost4to6-unspec") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::LocalHostIPv6) << (int)QHostAddress::ConvertUnspecifiedAddress << false;
+ QTest::newRow("0.0.0.1-::1-local") << QHostAddress("0.0.0.1") << QHostAddress(QHostAddress::LocalHostIPv6) << (int)QHostAddress::ConvertLocalHost << false;
+ QTest::newRow("v4-v4compat-local") << QHostAddress("192.168.1.1") << QHostAddress("::192.168.1.1") << (int)QHostAddress::ConvertLocalHost << false;
+ QTest::newRow("v4-v4mapped-local") << QHostAddress("192.168.1.1") << QHostAddress("::ffff:192.168.1.1") << (int)QHostAddress::ConvertLocalHost << false;
+ QTest::newRow("0.0.0.1-::1-unspec") << QHostAddress("0.0.0.1") << QHostAddress(QHostAddress::LocalHostIPv6) << (int)QHostAddress::ConvertUnspecifiedAddress << false;
+ QTest::newRow("v4-v4compat-unspec") << QHostAddress("192.168.1.1") << QHostAddress("::192.168.1.1") << (int)QHostAddress::ConvertUnspecifiedAddress << false;
+ QTest::newRow("v4-v4mapped-unspec") << QHostAddress("192.168.1.1") << QHostAddress("::ffff:192.168.1.1") << (int)QHostAddress::ConvertUnspecifiedAddress << false;
+ QTest::newRow("0.0.0.1-::1-compat") << QHostAddress("0.0.0.1") << QHostAddress(QHostAddress::LocalHostIPv6) << (int)QHostAddress::ConvertV4CompatToIPv4 << false;
+ QTest::newRow("v4-v4compat-compat") << QHostAddress("192.168.1.1") << QHostAddress("::192.168.1.1") << (int)QHostAddress::ConvertV4CompatToIPv4 << true;
+ QTest::newRow("v4-v4mapped-compat") << QHostAddress("192.168.1.1") << QHostAddress("::ffff:192.168.1.1") << (int)QHostAddress::ConvertV4CompatToIPv4 << false;
+ QTest::newRow("0.0.0.1-::1-mapped") << QHostAddress("0.0.0.1") << QHostAddress(QHostAddress::LocalHostIPv6) << (int)QHostAddress::ConvertV4MappedToIPv4 << false;
+ QTest::newRow("v4-v4compat-mapped") << QHostAddress("192.168.1.1") << QHostAddress("::192.168.1.1") << (int)QHostAddress::ConvertV4MappedToIPv4 << false;
+ QTest::newRow("v4-v4mapped-mapped") << QHostAddress("192.168.1.1") << QHostAddress("::FFFF:192.168.1.1") << (int)QHostAddress::ConvertV4MappedToIPv4 << true;
+ QTest::newRow("undef-any-local") << QHostAddress() << QHostAddress(QHostAddress::Any) << (int)QHostAddress::ConvertLocalHost << false;
+ QTest::newRow("undef-any-unspec") << QHostAddress() << QHostAddress(QHostAddress::Any) << (int)QHostAddress::ConvertUnspecifiedAddress << false;
+ QTest::newRow("anyv6-anyv4-compat") << QHostAddress(QHostAddress::AnyIPv6) << QHostAddress(QHostAddress::AnyIPv4) << (int)QHostAddress::ConvertV4CompatToIPv4 << true;
+ QTest::newRow("anyv6-anyv4-mapped") << QHostAddress(QHostAddress::AnyIPv6) << QHostAddress(QHostAddress::AnyIPv4) << (int)QHostAddress::ConvertV4MappedToIPv4 << false;
+ QTest::newRow("anyv6-anyv4-unspec") << QHostAddress(QHostAddress::AnyIPv6) << QHostAddress(QHostAddress::AnyIPv4) << (int)QHostAddress::ConvertUnspecifiedAddress << true;
+ QTest::newRow("any-anyv4-unspec") << QHostAddress(QHostAddress::Any) << QHostAddress(QHostAddress::AnyIPv4) << (int)QHostAddress::ConvertUnspecifiedAddress << true;
+ QTest::newRow("any-anyv6-unspec") << QHostAddress(QHostAddress::Any) << QHostAddress(QHostAddress::AnyIPv6) << (int)QHostAddress::ConvertUnspecifiedAddress << true;
+ QTest::newRow("anyv6-anyv4-local") << QHostAddress(QHostAddress::AnyIPv6) << QHostAddress(QHostAddress::AnyIPv4) << (int)QHostAddress::ConvertLocalHost << false;
+ QTest::newRow("any-anyv4-local") << QHostAddress(QHostAddress::Any) << QHostAddress(QHostAddress::AnyIPv4) << (int)QHostAddress::ConvertLocalHost << false;
+ QTest::newRow("any-anyv6-local") << QHostAddress(QHostAddress::Any) << QHostAddress(QHostAddress::AnyIPv6) << (int)QHostAddress::ConvertLocalHost << false;
+}
+
+void tst_QHostAddress::isEqual()
+{
+ QFETCH(QHostAddress, first);
+ QFETCH(QHostAddress, second);
+ QFETCH(int, flags);
+ QFETCH(bool, result);
+
+ QCOMPARE(first.isEqual(second, QHostAddress::ConversionModeFlag(flags)), result);
+ QCOMPARE(second.isEqual(first, QHostAddress::ConversionModeFlag(flags)), result);
+}
+
void tst_QHostAddress::assignment()
{
QHostAddress address;
diff --git a/tests/auto/network/kernel/qhostinfo/qhostinfo.pro b/tests/auto/network/kernel/qhostinfo/qhostinfo.pro
index 12858c97ee..67a37faeb5 100644
--- a/tests/auto/network/kernel/qhostinfo/qhostinfo.pro
+++ b/tests/auto/network/kernel/qhostinfo/qhostinfo.pro
@@ -3,14 +3,10 @@ TARGET = tst_qhostinfo
SOURCES += tst_qhostinfo.cpp
-requires(contains(QT_CONFIG,private_tests))
+requires(qtConfig(private_tests))
QT = core-private network-private testlib
-wince {
- LIBS += ws2.lib
-} else {
- win32:LIBS += -lws2_32
-}
+win32:LIBS += -lws2_32
# needed for getaddrinfo with official MinGW
mingw:DEFINES += _WIN32_WINNT=0x0501
diff --git a/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp b/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp
index 13d4442ada..f6d9b71aa2 100644
--- a/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp
+++ b/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp
@@ -66,11 +66,7 @@
#include "private/qhostinfo_p.h"
#if !defined(QT_NO_GETADDRINFO)
-# if !defined(Q_OS_WINCE)
# include <sys/types.h>
-# else
-# include <types.h>
-# endif
# if defined(Q_OS_UNIX)
# include <sys/socket.h>
# endif
@@ -399,11 +395,7 @@ protected:
void tst_QHostInfo::threadSafety()
{
const int nattempts = 5;
-#if defined(Q_OS_WINCE)
- const int runs = 10;
-#else
const int runs = 100;
-#endif
LookupThread thr[nattempts];
for (int j = 0; j < runs; ++j) {
for (int i = 0; i < nattempts; ++i)
diff --git a/tests/auto/network/kernel/qnetworkdatagram/qnetworkdatagram.pro b/tests/auto/network/kernel/qnetworkdatagram/qnetworkdatagram.pro
new file mode 100644
index 0000000000..a2fe44060e
--- /dev/null
+++ b/tests/auto/network/kernel/qnetworkdatagram/qnetworkdatagram.pro
@@ -0,0 +1,5 @@
+CONFIG += testcase console
+CONFIG -= app_bundle
+TARGET = tst_qnetworkdatagram
+SOURCES += tst_qnetworkdatagram.cpp
+QT = core network testlib
diff --git a/tests/auto/network/kernel/qnetworkdatagram/tst_qnetworkdatagram.cpp b/tests/auto/network/kernel/qnetworkdatagram/tst_qnetworkdatagram.cpp
new file mode 100644
index 0000000000..3295580432
--- /dev/null
+++ b/tests/auto/network/kernel/qnetworkdatagram/tst_qnetworkdatagram.cpp
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Intel Corporation.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QNetworkDatagram>
+#include <QtTest>
+#include <QCoreApplication>
+
+class tst_QNetworkDatagram : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QNetworkDatagram();
+
+private Q_SLOTS:
+ void getSetCheck();
+ void makeReply_data();
+ void makeReply();
+};
+
+tst_QNetworkDatagram::tst_QNetworkDatagram()
+{
+}
+
+void tst_QNetworkDatagram::getSetCheck()
+{
+ QNetworkDatagram dg;
+
+ QVERIFY(dg.isNull());
+ QVERIFY(!dg.isValid());
+ QCOMPARE(dg.senderAddress(), QHostAddress());
+ QCOMPARE(dg.destinationAddress(), QHostAddress());
+ QCOMPARE(dg.senderPort(), -1);
+ QCOMPARE(dg.destinationPort(), -1);
+ QCOMPARE(dg.hopLimit(), -1);
+ QCOMPARE(dg.interfaceIndex(), 0U);
+
+ dg.setHopLimit(1);
+ QCOMPARE(dg.hopLimit(), 1);
+ dg.setHopLimit(255);
+ QCOMPARE(dg.hopLimit(), 255);
+
+ dg.setInterfaceIndex(1);
+ QCOMPARE(dg.interfaceIndex(), 1U);
+ dg.setInterfaceIndex(1234567U);
+ QCOMPARE(dg.interfaceIndex(), 1234567U);
+
+ dg.setSender(QHostAddress::Any, 12345);
+ QCOMPARE(dg.senderAddress(), QHostAddress(QHostAddress::Any));
+ QCOMPARE(dg.senderPort(), 12345);
+ dg.setSender(QHostAddress::LocalHost);
+ QCOMPARE(dg.senderAddress(), QHostAddress(QHostAddress::LocalHost));
+ QCOMPARE(dg.senderPort(), 0);
+
+ dg.setDestination(QHostAddress::LocalHostIPv6, 12345);
+ QCOMPARE(dg.destinationAddress(), QHostAddress(QHostAddress::LocalHostIPv6));
+ QCOMPARE(dg.destinationPort(), 12345);
+ dg.setDestination(QHostAddress::Broadcast, 137);
+ QCOMPARE(dg.destinationAddress(), QHostAddress(QHostAddress::Broadcast));
+ QCOMPARE(dg.destinationPort(), 137);
+}
+
+void tst_QNetworkDatagram::makeReply_data()
+{
+ qRegisterMetaType<QNetworkDatagram>();
+ QTest::addColumn<QNetworkDatagram>("dgram");
+ QTest::addColumn<QString>("localAddress");
+
+ QNetworkDatagram dgram("some data", QHostAddress("192.0.2.1"), 10001);
+ dgram.setHopLimit(64);
+ dgram.setSender(QHostAddress::LocalHost, 12345);
+ QTest::newRow("ipv4") << dgram << "192.0.2.1";
+
+ dgram.setDestination(QHostAddress("224.0.0.1"), 10002);
+ QTest::newRow("ipv4-multicast") << dgram << QString();
+
+ dgram.setSender(QHostAddress::LocalHostIPv6, 12346);
+ dgram.setDestination(QHostAddress("2001:db8::1"), 12347);
+ QTest::newRow("ipv6") << dgram << "2001:db8::1";
+
+ dgram.setSender(QHostAddress("fe80::1%1"), 10003);
+ dgram.setDestination(QHostAddress("fe80::2%1"), 10004);
+ dgram.setInterfaceIndex(1);
+ QTest::newRow("ipv6-linklocal") << dgram << "fe80::2%1";
+
+ dgram.setDestination(QHostAddress("ff02::1%1"), 10005);
+ QTest::newRow("ipv6-multicast") << dgram << QString();
+}
+
+void tst_QNetworkDatagram::makeReply()
+{
+ QFETCH(QNetworkDatagram, dgram);
+ QFETCH(QString, localAddress);
+
+ {
+ QNetworkDatagram reply = dgram.makeReply("World");
+ QCOMPARE(reply.data(), QByteArray("World"));
+ QCOMPARE(reply.senderAddress(), QHostAddress(localAddress));
+ QCOMPARE(reply.senderPort(), localAddress.isEmpty() ? -1 : dgram.destinationPort());
+ QCOMPARE(reply.destinationAddress(), dgram.senderAddress());
+ QCOMPARE(reply.destinationPort(), dgram.senderPort());
+ QCOMPARE(reply.interfaceIndex(), dgram.interfaceIndex());
+ QCOMPARE(reply.hopLimit(), -1);
+ }
+
+ QNetworkDatagram copy = dgram;
+ copy.setData(copy.data());
+ {
+ QNetworkDatagram reply = qMove(copy).makeReply("World");
+ QCOMPARE(reply.data(), QByteArray("World"));
+ QCOMPARE(reply.senderAddress(), QHostAddress(localAddress));
+ QCOMPARE(reply.senderPort(), localAddress.isEmpty() ? -1 : dgram.destinationPort());
+ QCOMPARE(reply.destinationAddress(), dgram.senderAddress());
+ QCOMPARE(reply.destinationPort(), dgram.senderPort());
+ QCOMPARE(reply.interfaceIndex(), dgram.interfaceIndex());
+ QCOMPARE(reply.hopLimit(), -1);
+ }
+}
+
+QTEST_MAIN(tst_QNetworkDatagram)
+#include "tst_qnetworkdatagram.moc"
diff --git a/tests/auto/network/socket/platformsocketengine/platformsocketengine.pri b/tests/auto/network/socket/platformsocketengine/platformsocketengine.pri
index a3b4e89450..46c722deba 100644
--- a/tests/auto/network/socket/platformsocketengine/platformsocketengine.pri
+++ b/tests/auto/network/socket/platformsocketengine/platformsocketengine.pri
@@ -4,15 +4,9 @@ QNETWORK_SRC = $$QT_SOURCE_TREE/src/network
INCLUDEPATH += $$QNETWORK_SRC
-win32 {
- wince {
- LIBS += -lws2
- } else {
- LIBS += -lws2_32
- }
-}
+win32:LIBS += -lws2_32
-unix:contains(QT_CONFIG, reduce_exports) {
+unix:qtConfig(reduce_exports) {
SOURCES += $$QNETWORK_SRC/socket/qnativesocketengine_unix.cpp
SOURCES += $$QNETWORK_SRC/socket/qnativesocketengine.cpp
SOURCES += $$QNETWORK_SRC/socket/qabstractsocketengine.cpp
diff --git a/tests/auto/network/socket/platformsocketengine/platformsocketengine.pro b/tests/auto/network/socket/platformsocketengine/platformsocketengine.pro
index eee762037d..ab96bb444e 100644
--- a/tests/auto/network/socket/platformsocketengine/platformsocketengine.pro
+++ b/tests/auto/network/socket/platformsocketengine/platformsocketengine.pro
@@ -4,7 +4,7 @@ SOURCES += tst_platformsocketengine.cpp
include(../platformsocketengine/platformsocketengine.pri)
-requires(contains(QT_CONFIG,private_tests))
+requires(qtConfig(private_tests))
MOC_DIR=tmp
diff --git a/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp b/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp
index b3ecd884cd..43b5422635 100644
--- a/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp
+++ b/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp
@@ -495,9 +495,6 @@ void tst_PlatformSocketEngine::readWriteBufferSize()
qint64 bufferSize = device.receiveBufferSize();
QVERIFY(bufferSize != -1);
device.setReceiveBufferSize(bufferSize + 1);
-#if defined(Q_OS_WINCE)
- QEXPECT_FAIL(0, "Not supported by default on WinCE", Continue);
-#endif
QVERIFY(device.receiveBufferSize() > bufferSize);
bufferSize = device.sendBufferSize();
@@ -607,8 +604,8 @@ void tst_PlatformSocketEngine::invalidSend()
PLATFORMSOCKETENGINE socket;
QVERIFY(socket.initialize(QAbstractSocket::TcpSocket));
- QTest::ignoreMessage(QtWarningMsg, PLATFORMSOCKETENGINESTRING "::writeDatagram() was"
- " called by a socket other than QAbstractSocket::UdpSocket");
+ QTest::ignoreMessage(QtWarningMsg, PLATFORMSOCKETENGINESTRING "::writeDatagram() was called"
+ " not in QAbstractSocket::BoundState or QAbstractSocket::ConnectedState");
QCOMPARE(socket.writeDatagram("hei", 3, QIpPacketHeader(QHostAddress::LocalHost, 143)),
(qlonglong) -1);
}
@@ -650,7 +647,7 @@ void tst_PlatformSocketEngine::receiveUrgentData()
QByteArray response;
// Native OOB data test doesn't work on HP-UX or WinCE
-#if !defined(Q_OS_HPUX) && !defined(Q_OS_WINCE)
+#if !defined(Q_OS_HPUX)
// The server sends an urgent message
msg = 'Q';
QCOMPARE(int(::send(socketDescriptor, &msg, sizeof(msg), MSG_OOB)), 1);
diff --git a/tests/auto/network/socket/qhttpsocketengine/qhttpsocketengine.pro b/tests/auto/network/socket/qhttpsocketengine/qhttpsocketengine.pro
index 12ce576e23..56a4fb8aee 100644
--- a/tests/auto/network/socket/qhttpsocketengine/qhttpsocketengine.pro
+++ b/tests/auto/network/socket/qhttpsocketengine/qhttpsocketengine.pro
@@ -7,6 +7,6 @@ include(../platformsocketengine/platformsocketengine.pri)
MOC_DIR=tmp
-requires(contains(QT_CONFIG,private_tests))
+requires(qtConfig(private_tests))
QT = core-private network-private testlib
diff --git a/tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp b/tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp
index 7237542e5c..68f3ea059b 100644
--- a/tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp
+++ b/tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp
@@ -626,11 +626,7 @@ void tst_QHttpSocketEngine::downloadBigFile()
QTime stopWatch;
stopWatch.start();
-#if defined(Q_OS_WINCE)
- QTestEventLoop::instance().enterLoop(240);
-#else
QTestEventLoop::instance().enterLoop(60);
-#endif
if (QTestEventLoop::instance().timeout())
QFAIL("Network operation timed out");
diff --git a/tests/auto/network/socket/qlocalsocket/test/test.pro b/tests/auto/network/socket/qlocalsocket/test/test.pro
index 6a5df7f9b6..ab9ed90b1d 100644
--- a/tests/auto/network/socket/qlocalsocket/test/test.pro
+++ b/tests/auto/network/socket/qlocalsocket/test/test.pro
@@ -2,13 +2,7 @@ CONFIG += testcase
DEFINES += QLOCALSERVER_DEBUG
DEFINES += QLOCALSOCKET_DEBUG
-
-wince* {
- DEFINES += QT_LOCALSOCKET_TCP
- DEFINES += SRCDIR=\\\"../\\\"
-} else {
- DEFINES += SRCDIR=\\\"$$PWD/../\\\"
-}
+DEFINES += SRCDIR=\\\"$$PWD/../\\\"
QT = core network testlib
diff --git a/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp b/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp
index 17d7697f94..8cc06a77ba 100644
--- a/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp
+++ b/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp
@@ -868,10 +868,8 @@ void tst_QLocalSocket::threadedConnection_data()
QTest::newRow("1 client") << 1;
QTest::newRow("2 clients") << 2;
QTest::newRow("5 clients") << 5;
-#ifndef Q_OS_WINCE
QTest::newRow("10 clients") << 10;
QTest::newRow("20 clients") << 20;
-#endif
}
void tst_QLocalSocket::threadedConnection()
diff --git a/tests/auto/network/socket/qsctpsocket/qsctpsocket.pro b/tests/auto/network/socket/qsctpsocket/qsctpsocket.pro
new file mode 100644
index 0000000000..49a40ce9b5
--- /dev/null
+++ b/tests/auto/network/socket/qsctpsocket/qsctpsocket.pro
@@ -0,0 +1,6 @@
+CONFIG += testcase
+TARGET = tst_qsctpsocket
+QT = core network testlib
+
+SOURCES += tst_qsctpsocket.cpp
+
diff --git a/tests/auto/network/socket/qsctpsocket/tst_qsctpsocket.cpp b/tests/auto/network/socket/qsctpsocket/tst_qsctpsocket.cpp
new file mode 100644
index 0000000000..cf15e60531
--- /dev/null
+++ b/tests/auto/network/socket/qsctpsocket/tst_qsctpsocket.cpp
@@ -0,0 +1,488 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com>
+** 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 <QtTest/QtTest>
+#include <QDebug>
+#include <QEventLoop>
+#include <QByteArray>
+#include <QString>
+#include <QHostAddress>
+#include <QHostInfo>
+#include <QNetworkInterface>
+#include <QTime>
+
+#include <QSctpSocket>
+#include <QSctpServer>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/sctp.h>
+
+#define SOCKET int
+#define INVALID_SOCKET -1
+
+class tst_QSctpSocket : public QObject
+{
+ Q_OBJECT
+
+public:
+ static void enterLoop(int secs)
+ {
+ ++loopLevel;
+ QTestEventLoop::instance().enterLoop(secs);
+ --loopLevel;
+ }
+ static void exitLoop()
+ {
+ // Safe exit - if we aren't in an event loop, don't
+ // exit one.
+ if (loopLevel > 0)
+ QTestEventLoop::instance().exitLoop();
+ }
+ static bool timeout()
+ {
+ return QTestEventLoop::instance().timeout();
+ }
+
+private slots:
+ void constructing();
+ void bind_data();
+ void bind();
+ void setInvalidSocketDescriptor();
+ void setSocketDescriptor();
+ void socketDescriptor();
+ void hostNotFound();
+ void connecting();
+ void readAndWrite();
+ void loop_data();
+ void loop();
+ void loopInTCPMode_data();
+ void loopInTCPMode();
+ void readDatagramAfterClose();
+ void clientSendDataOnDelayedDisconnect();
+
+protected slots:
+ void exitLoopSlot();
+
+private:
+ static int loopLevel;
+};
+
+int tst_QSctpSocket::loopLevel = 0;
+
+//----------------------------------------------------------------------------------
+void tst_QSctpSocket::constructing()
+{
+ QSctpSocket socket;
+
+ // Check the initial state of the QSctpSocket.
+ QCOMPARE(socket.state(), QAbstractSocket::UnconnectedState);
+ QVERIFY(socket.isSequential());
+ QVERIFY(!socket.isOpen());
+ QVERIFY(!socket.isValid());
+ QCOMPARE(socket.socketType(), QAbstractSocket::SctpSocket);
+ QCOMPARE(socket.maximumChannelCount(), 0);
+ QCOMPARE(socket.readChannelCount(), 0);
+ QCOMPARE(socket.writeChannelCount(), 0);
+
+ char c;
+ QCOMPARE(socket.getChar(&c), false);
+ QCOMPARE(socket.bytesAvailable(), Q_INT64_C(0));
+ QCOMPARE(socket.canReadLine(), false);
+ QCOMPARE(socket.readLine(), QByteArray());
+ QCOMPARE(socket.socketDescriptor(), qintptr(-1));
+ QCOMPARE(int(socket.localPort()), 0);
+ QVERIFY(socket.localAddress() == QHostAddress());
+ QCOMPARE(int(socket.peerPort()), 0);
+ QVERIFY(socket.peerAddress() == QHostAddress());
+ QCOMPARE(socket.error(), QAbstractSocket::UnknownSocketError);
+ QCOMPARE(socket.errorString(), QString("Unknown error"));
+}
+
+//----------------------------------------------------------------------------------
+void tst_QSctpSocket::bind_data()
+{
+ QTest::addColumn<QString>("stringAddr");
+ QTest::addColumn<bool>("successExpected");
+ QTest::addColumn<QString>("stringExpectedLocalAddress");
+
+ // iterate all interfaces, add all addresses on them as test data
+ QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
+ for (const QNetworkInterface &interface : interfaces) {
+ if (!interface.isValid())
+ continue;
+
+ for (const QNetworkAddressEntry &entry : interface.addressEntries()) {
+ if (entry.ip().isInSubnet(QHostAddress::parseSubnet("fe80::/10"))
+ || entry.ip().isInSubnet(QHostAddress::parseSubnet("169.254/16")))
+ continue; // link-local bind will fail, at least on Linux, so skip it.
+
+ QString ip(entry.ip().toString());
+ QTest::newRow(ip.toLatin1().constData()) << ip << true << ip;
+ }
+ }
+
+ // additionally, try bind to known-bad addresses, and make sure this doesn't work
+ // these ranges are guaranteed to be reserved for 'documentation purposes',
+ // and thus, should be unused in the real world. Not that I'm assuming the
+ // world is full of competent administrators, or anything.
+ QStringList knownBad;
+ knownBad << "198.51.100.1";
+ knownBad << "2001:0DB8::1";
+ foreach (const QString &badAddress, knownBad) {
+ QTest::newRow(badAddress.toLatin1().constData()) << badAddress << false << QString();
+ }
+}
+
+// Testing bind function
+void tst_QSctpSocket::bind()
+{
+ QFETCH(QString, stringAddr);
+ QFETCH(bool, successExpected);
+ QFETCH(QString, stringExpectedLocalAddress);
+
+ QHostAddress addr(stringAddr);
+ QHostAddress expectedLocalAddress(stringExpectedLocalAddress);
+
+ QSctpSocket socket;
+ qDebug() << "Binding " << addr;
+
+ if (successExpected)
+ QVERIFY2(socket.bind(addr), qPrintable(socket.errorString()));
+ else
+ QVERIFY(!socket.bind(addr));
+
+ QCOMPARE(socket.localAddress(), expectedLocalAddress);
+}
+
+//----------------------------------------------------------------------------------
+void tst_QSctpSocket::setInvalidSocketDescriptor()
+{
+ QSctpSocket socket;
+ QCOMPARE(socket.socketDescriptor(), qintptr(INVALID_SOCKET));
+ QVERIFY(!socket.setSocketDescriptor(-5, QAbstractSocket::UnconnectedState));
+ QCOMPARE(socket.socketDescriptor(), qintptr(INVALID_SOCKET));
+
+ QCOMPARE(socket.error(), QAbstractSocket::UnsupportedSocketOperationError);
+}
+
+//----------------------------------------------------------------------------------
+void tst_QSctpSocket::setSocketDescriptor()
+{
+ QSctpServer server;
+
+ server.setMaximumChannelCount(16);
+ QVERIFY(server.listen());
+
+ SOCKET sock = ::socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP);
+
+ QVERIFY(sock != INVALID_SOCKET);
+ QSctpSocket socket;
+ QVERIFY(socket.setSocketDescriptor(sock, QAbstractSocket::UnconnectedState));
+ QCOMPARE(socket.socketDescriptor(), qintptr(sock));
+ QCOMPARE(socket.readChannelCount(), 0);
+ QCOMPARE(socket.writeChannelCount(), 0);
+
+ socket.connectToHost(QHostAddress::LocalHost, server.serverPort());
+ QVERIFY(socket.waitForConnected(3000));
+ QVERIFY(server.waitForNewConnection(3000));
+
+ QCOMPARE(socket.readChannelCount(), server.maximumChannelCount());
+ QVERIFY(socket.writeChannelCount() <= server.maximumChannelCount());
+
+ QSctpSocket *acceptedSocket = server.nextPendingDatagramConnection();
+ QVERIFY(acceptedSocket);
+ QCOMPARE(acceptedSocket->readChannelCount(), socket.writeChannelCount());
+ QCOMPARE(acceptedSocket->writeChannelCount(), socket.readChannelCount());
+}
+
+//----------------------------------------------------------------------------------
+void tst_QSctpSocket::socketDescriptor()
+{
+ QSctpSocket socket;
+
+ QSctpServer server;
+
+ QVERIFY(server.listen());
+
+ QCOMPARE(socket.socketDescriptor(), qintptr(INVALID_SOCKET));
+ socket.connectToHost(QHostAddress::LocalHost, server.serverPort());
+ QVERIFY(server.waitForNewConnection(3000));
+ if (socket.state() != QAbstractSocket::ConnectedState) {
+ QVERIFY((socket.state() == QAbstractSocket::HostLookupState
+ && socket.socketDescriptor() == INVALID_SOCKET)
+ || socket.state() == QAbstractSocket::ConnectingState);
+ QVERIFY(socket.waitForConnected(3000));
+ QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
+ }
+ QVERIFY(socket.socketDescriptor() != INVALID_SOCKET);
+}
+
+//----------------------------------------------------------------------------------
+void tst_QSctpSocket::hostNotFound()
+{
+ QSctpSocket socket;
+
+ socket.connectToHost("nosuchserver.qt-project.org", 80);
+ QVERIFY(!socket.waitForConnected(3000));
+ QCOMPARE(socket.state(), QTcpSocket::UnconnectedState);
+ QCOMPARE(socket.error(), QAbstractSocket::HostNotFoundError);
+}
+
+// Testing connect function
+void tst_QSctpSocket::connecting()
+{
+ QSctpServer server;
+
+ QVERIFY(server.listen());
+
+ QSctpSocket socket;
+ socket.connectToHost(QHostAddress::LocalHost, server.serverPort());
+ QVERIFY(socket.waitForConnected(3000));
+
+ QVERIFY(server.waitForNewConnection(3000));
+ QSctpSocket *acceptedSocket = server.nextPendingDatagramConnection();
+ QVERIFY(acceptedSocket);
+
+ QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
+ QCOMPARE(acceptedSocket->state(), QAbstractSocket::ConnectedState);
+ QCOMPARE(socket.readChannelCount(), acceptedSocket->readChannelCount());
+ QCOMPARE(socket.writeChannelCount(),acceptedSocket->writeChannelCount());
+}
+
+// Testing read/write functions
+void tst_QSctpSocket::readAndWrite()
+{
+ QSctpServer server;
+
+ QVERIFY(server.listen());
+
+ QSctpSocket socket;
+ socket.connectToHost(QHostAddress::LocalHost, server.serverPort());
+ QVERIFY(socket.waitForConnected(3000));
+
+ QVERIFY(server.waitForNewConnection(3000));
+ QSctpSocket *acceptedSocket = server.nextPendingDatagramConnection();
+ QVERIFY(acceptedSocket);
+
+ QByteArray ba(1000, 1);
+ QVERIFY(acceptedSocket->writeDatagram(ba));
+ QVERIFY(acceptedSocket->waitForBytesWritten(3000));
+
+ QVERIFY(socket.waitForReadyRead(3000));
+ QNetworkDatagram datagram = socket.readDatagram();
+ QVERIFY(datagram.isValid());
+ QCOMPARE(datagram.data(), ba);
+
+ QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
+ QCOMPARE(socket.error(), QAbstractSocket::UnknownSocketError);
+ QCOMPARE(socket.errorString(), QString("Unknown error"));
+ QCOMPARE(acceptedSocket->state(), QAbstractSocket::ConnectedState);
+ QCOMPARE(acceptedSocket->error(), QAbstractSocket::UnknownSocketError);
+ QCOMPARE(acceptedSocket->errorString(), QString("Unknown error"));
+}
+
+//----------------------------------------------------------------------------------
+void tst_QSctpSocket::loop_data()
+{
+ QTest::addColumn<QByteArray>("peterDatagram");
+ QTest::addColumn<QByteArray>("paulDatagram");
+ QTest::addColumn<int>("peterChannel");
+ QTest::addColumn<int>("paulChannel");
+
+ QTest::newRow("\"Almond!\" | \"Joy!\"") << QByteArray("Almond!") << QByteArray("Joy!") << 0 << 0;
+ QTest::newRow("\"A\" | \"B\"") << QByteArray("A") << QByteArray("B") << 1 << 1;
+ QTest::newRow("\"AB\" | \"B\"") << QByteArray("AB") << QByteArray("B") << 0 << 1;
+ QTest::newRow("\"AB\" | \"BB\"") << QByteArray("AB") << QByteArray("BB") << 1 << 0;
+ QTest::newRow("\"A\\0B\" | \"B\\0B\"") << QByteArray::fromRawData("A\0B", 3) << QByteArray::fromRawData("B\0B", 3) << 0 << 1;
+ QTest::newRow("BigDatagram") << QByteArray(600, '@') << QByteArray(600, '@') << 1 << 0;
+}
+
+void tst_QSctpSocket::loop()
+{
+ QFETCH(QByteArray, peterDatagram);
+ QFETCH(QByteArray, paulDatagram);
+ QFETCH(int, peterChannel);
+ QFETCH(int, paulChannel);
+
+ QSctpServer server;
+
+ server.setMaximumChannelCount(10);
+ QVERIFY(server.listen());
+
+ QSctpSocket peter;
+ peter.setMaximumChannelCount(10);
+ peter.connectToHost(QHostAddress::LocalHost, server.serverPort());
+ QVERIFY(peter.waitForConnected(3000));
+
+ QVERIFY(server.waitForNewConnection(3000));
+ QSctpSocket *paul = server.nextPendingDatagramConnection();
+ QVERIFY(paul);
+
+ peter.setCurrentWriteChannel(peterChannel);
+ QVERIFY(peter.writeDatagram(peterDatagram));
+ paul->setCurrentWriteChannel(paulChannel);
+ QVERIFY(paul->writeDatagram(paulDatagram));
+ QVERIFY(peter.flush());
+ QVERIFY(paul->flush());
+
+ peter.setCurrentReadChannel(paulChannel);
+ QVERIFY(peter.waitForReadyRead(3000));
+ QCOMPARE(peter.bytesAvailable(), paulDatagram.size());
+ QCOMPARE(peter.readDatagram().data(), paulDatagram);
+
+ paul->setCurrentReadChannel(peterChannel);
+ QVERIFY(paul->waitForReadyRead(3000));
+ QCOMPARE(paul->bytesAvailable(), peterDatagram.size());
+ QCOMPARE(paul->readDatagram().data(), peterDatagram);
+}
+
+//----------------------------------------------------------------------------------
+void tst_QSctpSocket::loopInTCPMode_data()
+{
+ QTest::addColumn<QByteArray>("peterDatagram");
+ QTest::addColumn<QByteArray>("paulDatagram");
+
+ QTest::newRow("\"Almond!\" | \"Joy!\"") << QByteArray("Almond!") << QByteArray("Joy!");
+ QTest::newRow("\"A\" | \"B\"") << QByteArray("A") << QByteArray("B");
+ QTest::newRow("\"AB\" | \"B\"") << QByteArray("AB") << QByteArray("B");
+ QTest::newRow("\"AB\" | \"BB\"") << QByteArray("AB") << QByteArray("BB");
+ QTest::newRow("\"A\\0B\" | \"B\\0B\"") << QByteArray::fromRawData("A\0B", 3) << QByteArray::fromRawData("B\0B", 3);
+ QTest::newRow("BigDatagram") << QByteArray(600, '@') << QByteArray(600, '@');
+}
+
+void tst_QSctpSocket::loopInTCPMode()
+{
+ QFETCH(QByteArray, peterDatagram);
+ QFETCH(QByteArray, paulDatagram);
+
+ QSctpServer server;
+
+ server.setMaximumChannelCount(-1);
+ QVERIFY(server.listen());
+
+ QSctpSocket peter;
+ peter.setMaximumChannelCount(-1);
+ peter.connectToHost(QHostAddress::LocalHost, server.serverPort());
+ QVERIFY(peter.waitForConnected(3000));
+ QVERIFY(server.waitForNewConnection(3000));
+
+ QTcpSocket *paul = server.nextPendingConnection();
+ QVERIFY(paul);
+
+ QCOMPARE(peter.write(peterDatagram), qint64(peterDatagram.size()));
+ QCOMPARE(paul->write(paulDatagram), qint64(paulDatagram.size()));
+ QVERIFY(peter.flush());
+ QVERIFY(paul->flush());
+
+ QVERIFY(peter.waitForReadyRead(3000));
+ QVERIFY(paul->waitForReadyRead(3000));
+
+ QCOMPARE(peter.bytesAvailable(), paulDatagram.size());
+ QByteArray peterBuffer = peter.readAll();
+
+ QCOMPARE(paul->bytesAvailable(), peterDatagram.size());
+ QByteArray paulBuffer = paul->readAll();
+
+ QCOMPARE(peterBuffer, paulDatagram);
+ QCOMPARE(paulBuffer, peterDatagram);
+}
+
+//----------------------------------------------------------------------------------
+void tst_QSctpSocket::exitLoopSlot()
+{
+ exitLoop();
+}
+
+//----------------------------------------------------------------------------------
+void tst_QSctpSocket::readDatagramAfterClose()
+{
+ QSctpServer server;
+
+ QVERIFY(server.listen());
+
+ QSctpSocket socket;
+ socket.connectToHost(QHostAddress::LocalHost, server.serverPort());
+ QVERIFY(socket.waitForConnected(3000));
+ QVERIFY(server.waitForNewConnection(3000));
+
+ QSctpSocket *acceptedSocket = server.nextPendingDatagramConnection();
+ QVERIFY(acceptedSocket);
+
+ connect(&socket, &QIODevice::readyRead, this, &tst_QSctpSocket::exitLoopSlot);
+
+ QByteArray ba(1000, 1);
+ QVERIFY(acceptedSocket->writeDatagram(ba));
+
+ enterLoop(10);
+ if (timeout())
+ QFAIL("Network operation timed out");
+
+ QCOMPARE(socket.bytesAvailable(), ba.size());
+ socket.close();
+ QVERIFY(!socket.readDatagram().isValid());
+}
+
+// Test buffered socket properly send data on delayed disconnect
+void tst_QSctpSocket::clientSendDataOnDelayedDisconnect()
+{
+ QSctpServer server;
+
+ QVERIFY(server.listen());
+
+ // Connect to server, write data and close socket
+ QSctpSocket socket;
+ socket.connectToHost(QHostAddress::LocalHost, server.serverPort());
+ QVERIFY(socket.waitForConnected(3000));
+
+ QByteArray sendData("GET /\r\n");
+ sendData = sendData.repeated(1000);
+ QVERIFY(socket.writeDatagram(sendData));
+ socket.close();
+ QCOMPARE(socket.state(), QAbstractSocket::ClosingState);
+ QVERIFY(socket.waitForDisconnected(3000));
+
+ QVERIFY(server.waitForNewConnection(3000));
+ QSctpSocket *acceptedSocket = server.nextPendingDatagramConnection();
+ QVERIFY(acceptedSocket);
+
+ QVERIFY(acceptedSocket->waitForReadyRead(3000));
+ QNetworkDatagram datagram = acceptedSocket->readDatagram();
+ QVERIFY(datagram.isValid());
+ QCOMPARE(datagram.data(), sendData);
+}
+
+QTEST_MAIN(tst_QSctpSocket)
+
+#include "tst_qsctpsocket.moc"
diff --git a/tests/auto/network/socket/qsocks5socketengine/qsocks5socketengine.pro b/tests/auto/network/socket/qsocks5socketengine/qsocks5socketengine.pro
index f3c24e19fd..71ceafa133 100644
--- a/tests/auto/network/socket/qsocks5socketengine/qsocks5socketengine.pro
+++ b/tests/auto/network/socket/qsocks5socketengine/qsocks5socketengine.pro
@@ -10,4 +10,4 @@ MOC_DIR=tmp
QT = core-private network-private testlib
-requires(contains(QT_CONFIG,private_tests))
+requires(qtConfig(private_tests))
diff --git a/tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp b/tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp
index b4955df107..c945d77cda 100644
--- a/tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp
+++ b/tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp
@@ -785,11 +785,7 @@ void tst_QSocks5SocketEngine::downloadBigFile()
QTime stopWatch;
stopWatch.start();
-#if !defined(Q_OS_WINCE)
QTestEventLoop::instance().enterLoop(60);
-#else
- QTestEventLoop::instance().enterLoop(180);
-#endif
if (QTestEventLoop::instance().timeout())
QFAIL("Network operation timed out");
diff --git a/tests/auto/network/socket/qtcpserver/crashingServer/main.cpp b/tests/auto/network/socket/qtcpserver/crashingServer/main.cpp
index fdf1c48adf..1a8e7920d3 100644
--- a/tests/auto/network/socket/qtcpserver/crashingServer/main.cpp
+++ b/tests/auto/network/socket/qtcpserver/crashingServer/main.cpp
@@ -47,16 +47,8 @@ int main(int argc, char *argv[])
return 1;
}
-#if defined(Q_OS_WINCE)
- QFile file(QLatin1String("/test_signal.txt"));
- file.open(QIODevice::WriteOnly);
- file.write("Listening\n");
- file.flush();
- file.close();
-#else
printf("Listening\n");
fflush(stdout);
-#endif
server.waitForNewConnection(5000);
qFatal("Crash");
diff --git a/tests/auto/network/socket/qtcpserver/test/test.pro b/tests/auto/network/socket/qtcpserver/test/test.pro
index f0abfbc085..4491523383 100644
--- a/tests/auto/network/socket/qtcpserver/test/test.pro
+++ b/tests/auto/network/socket/qtcpserver/test/test.pro
@@ -1,16 +1,7 @@
CONFIG += testcase
SOURCES += ../tst_qtcpserver.cpp
-win32: {
-wince {
- LIBS += -lws2
- crashApp.files = ../crashingServer/crashingServer.exe
- crashApp.path = crashingServer
- DEPLOYMENT += crashApp
-} else {
- LIBS += -lws2_32
-}
-}
+win32:LIBS += -lws2_32
TARGET = ../tst_qtcpserver
diff --git a/tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp b/tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp
index 30aab3bf34..5a0baf73b5 100644
--- a/tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp
+++ b/tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp
@@ -106,6 +106,8 @@ private slots:
void eagainBlockingAccept();
+ void canAccessPendingConnectionsWhileNotListening();
+
private:
#ifndef QT_NO_BEARERMANAGEMENT
QNetworkSession *networkSession;
@@ -467,11 +469,7 @@ void tst_QTcpServer::waitForConnectionTest()
ThreadConnector connector(findLocalIpSocket.localAddress(), server.serverPort());
connector.start();
-#if defined(Q_OS_WINCE)
- QVERIFY(server.waitForNewConnection(9000, &timeout));
-#else
QVERIFY(server.waitForNewConnection(3000, &timeout));
-#endif
QVERIFY(!timeout);
}
@@ -562,21 +560,6 @@ void tst_QTcpServer::addressReusable()
QSKIP("No proxy support");
#endif // QT_NO_NETWORKPROXY
}
-#if defined(Q_OS_WINCE)
- QString signalName = QString::fromLatin1("/test_signal.txt");
- QFile::remove(signalName);
- // The crashingServer process will crash once it gets a connection.
- QProcess process;
- QString processExe = crashingServerDir + "/crashingServer";
- process.start(processExe);
- QVERIFY2(process.waitForStarted(), qPrintable(
- QString::fromLatin1("Could not start %1: %2").arg(processExe, process.errorString())));
- int waitCount = 5;
- while (waitCount-- && !QFile::exists(signalName))
- QTest::qWait(1000);
- QVERIFY(QFile::exists(signalName));
- QFile::remove(signalName);
-#else
// The crashingServer process will crash once it gets a connection.
QProcess process;
QString processExe = crashingServerDir + "/crashingServer";
@@ -584,7 +567,6 @@ void tst_QTcpServer::addressReusable()
QVERIFY2(process.waitForStarted(), qPrintable(
QString::fromLatin1("Could not start %1: %2").arg(processExe, process.errorString())));
QVERIFY(process.waitForReadyRead(5000));
-#endif
QTcpSocket socket;
socket.connectToHost(QHostAddress::LocalHost, 49199);
@@ -990,5 +972,22 @@ void tst_QTcpServer::eagainBlockingAccept()
server.close();
}
+class NonListeningTcpServer : public QTcpServer
+{
+public:
+ void addSocketFromOutside(QTcpSocket* s)
+ {
+ addPendingConnection(s);
+ }
+};
+
+void tst_QTcpServer::canAccessPendingConnectionsWhileNotListening()
+{
+ NonListeningTcpServer server;
+ QTcpSocket socket;
+ server.addSocketFromOutside(&socket);
+ QCOMPARE(&socket, server.nextPendingConnection());
+}
+
QTEST_MAIN(tst_QTcpServer)
#include "tst_qtcpserver.moc"
diff --git a/tests/auto/network/socket/qtcpsocket/qtcpsocket.pro b/tests/auto/network/socket/qtcpsocket/qtcpsocket.pro
index fe6042b8a7..1183b23556 100644
--- a/tests/auto/network/socket/qtcpsocket/qtcpsocket.pro
+++ b/tests/auto/network/socket/qtcpsocket/qtcpsocket.pro
@@ -1,6 +1,6 @@
TEMPLATE = subdirs
SUBDIRS = test
-!wince:!vxworks: SUBDIRS += stressTest
+!vxworks: SUBDIRS += stressTest
-requires(contains(QT_CONFIG,private_tests))
+requires(qtConfig(private_tests))
diff --git a/tests/auto/network/socket/qtcpsocket/test/test.pro b/tests/auto/network/socket/qtcpsocket/test/test.pro
index 3e64b87b53..337e75b372 100644
--- a/tests/auto/network/socket/qtcpsocket/test/test.pro
+++ b/tests/auto/network/socket/qtcpsocket/test/test.pro
@@ -2,13 +2,7 @@ CONFIG += testcase
QT = core-private network-private testlib
SOURCES += ../tst_qtcpsocket.cpp
-win32: {
-wince {
- LIBS += -lws2
-} else {
- LIBS += -lws2_32
-}
-}
+win32:LIBS += -lws2_32
TARGET = tst_qtcpsocket
diff --git a/tests/auto/network/socket/qudpsocket/test/test.pro b/tests/auto/network/socket/qudpsocket/test/test.pro
index e4812416dc..73486a2bc3 100644
--- a/tests/auto/network/socket/qudpsocket/test/test.pro
+++ b/tests/auto/network/socket/qudpsocket/test/test.pro
@@ -15,10 +15,4 @@ win32 {
DESTDIR = ../
}
-wince* {
- addApp.files = ../clientserver/clientserver.exe
- addApp.path = clientserver
- DEPLOYMENT += addApp
-}
-
TARGET = tst_qudpsocket
diff --git a/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp b/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp
index ba49e8b041..aa01384350 100644
--- a/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp
+++ b/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp
@@ -39,6 +39,7 @@
#include <qhostinfo.h>
#include <qtcpsocket.h>
#include <qmap.h>
+#include <qnetworkdatagram.h>
#include <QNetworkProxy>
#include <QNetworkInterface>
@@ -114,6 +115,7 @@ protected slots:
void async_readDatagramSlot();
private:
+ QList<QHostAddress> allAddresses;
#ifndef QT_NO_BEARERMANAGEMENT
QNetworkConfigurationManager *netConfMan;
QNetworkConfiguration networkConfiguration;
@@ -173,6 +175,7 @@ void tst_QUdpSocket::initTestCase()
{
if (!QtNetworkSettings::verifyTestNetworkSettings())
QSKIP("No network test server available");
+ allAddresses = QNetworkInterface::allAddresses();
}
void tst_QUdpSocket::init()
@@ -252,6 +255,11 @@ void tst_QUdpSocket::unconnectedServerAndClientTest()
int(strlen(message[i])));
buf[strlen(message[i])] = '\0';
QCOMPARE(QByteArray(buf), QByteArray(message[i]));
+ QCOMPARE(port, clientSocket.localPort());
+ if (host.toIPv4Address()) // in case the sender is IPv4 mapped in IPv6
+ QCOMPARE(host.toIPv4Address(), makeNonAny(clientSocket.localAddress()).toIPv4Address());
+ else
+ QCOMPARE(host, makeNonAny(clientSocket.localAddress()));
}
}
@@ -325,14 +333,32 @@ void tst_QUdpSocket::broadcasting()
QVERIFY(serverSocket.hasPendingDatagrams());
do {
- QByteArray arr; arr.resize(serverSocket.pendingDatagramSize() + 1);
- QHostAddress host;
- quint16 port;
const int messageLength = int(strlen(message[i]));
- QCOMPARE((int) serverSocket.readDatagram(arr.data(), arr.size() - 1, &host, &port),
- messageLength);
+ QNetworkDatagram dgram = serverSocket.receiveDatagram();
+ QVERIFY(dgram.isValid());
+ QByteArray arr = dgram.data();
+
+ QCOMPARE(arr.length(), messageLength);
arr.resize(messageLength);
QCOMPARE(arr, QByteArray(message[i]));
+
+ if (dgram.senderAddress().toIPv4Address()) // in case it's a v6-mapped address
+ QVERIFY2(allAddresses.contains(QHostAddress(dgram.senderAddress().toIPv4Address())),
+ dgram.senderAddress().toString().toLatin1());
+ else if (!dgram.senderAddress().isNull())
+ QVERIFY2(allAddresses.contains(dgram.senderAddress()),
+ dgram.senderAddress().toString().toLatin1());
+ QCOMPARE(dgram.senderPort(), int(broadcastSocket.localPort()));
+ if (!dgram.destinationAddress().isNull()) {
+ QVERIFY2(dgram.destinationAddress() == QHostAddress::Broadcast
+ || broadcastAddresses.contains(dgram.destinationAddress()),
+ dgram.destinationAddress().toString().toLatin1());
+ QCOMPARE(dgram.destinationPort(), int(serverSocket.localPort()));
+ }
+
+ int ttl = dgram.hopLimit();
+ if (ttl != -1)
+ QVERIFY(ttl != 0);
} while (serverSocket.hasPendingDatagrams());
}
}
@@ -435,13 +461,8 @@ void tst_QUdpSocket::ipv6Loop()
char peterBuffer[16*1024];
char paulBuffer[16*1024];
-#if !defined(Q_OS_WINCE)
- QVERIFY2(peter.waitForReadyRead(5000), QtNetworkSettings::msgSocketError(peter).constData());
- QVERIFY2(paul.waitForReadyRead(5000), QtNetworkSettings::msgSocketError(paul).constData());
-#else
- QVERIFY(peter.waitForReadyRead(15000));
- QVERIFY(paul.waitForReadyRead(15000));
-#endif
+ QVERIFY(peter.waitForReadyRead(5000));
+ QVERIFY(paul.waitForReadyRead(5000));
if (success) {
QCOMPARE(peter.readDatagram(peterBuffer, sizeof(peterBuffer)), qint64(paulMessage.length()));
QCOMPARE(paul.readDatagram(paulBuffer, sizeof(peterBuffer)), qint64(peterMessage.length()));
@@ -938,9 +959,6 @@ void tst_QUdpSocket::outOfProcessConnectedClientServerTest()
#ifdef QT_NO_PROCESS
QSKIP("No qprocess support", SkipAll);
#else
-#if defined(Q_OS_WINCE)
- QSKIP("This test depends on reading data from QProcess (not supported on Qt/WinCE).");
-#endif
QProcess serverProcess;
serverProcess.start(QLatin1String("clientserver/clientserver server 1 1"),
QIODevice::ReadWrite | QIODevice::Text);
@@ -1002,9 +1020,6 @@ void tst_QUdpSocket::outOfProcessUnconnectedClientServerTest()
#ifdef QT_NO_PROCESS
QSKIP("No qprocess support", SkipAll);
#else
-#if defined(Q_OS_WINCE)
- QSKIP("This test depends on reading data from QProcess (not supported on Qt/WinCE).");
-#endif
QProcess serverProcess;
serverProcess.start(QLatin1String("clientserver/clientserver server 1 1"),
QIODevice::ReadWrite | QIODevice::Text);
@@ -1081,7 +1096,7 @@ void tst_QUdpSocket::zeroLengthDatagram()
#ifdef FORCE_SESSION
sender.setProperty("_q_networksession", QVariant::fromValue(networkSession));
#endif
- QCOMPARE(sender.writeDatagram(QByteArray(), QHostAddress::LocalHost, receiver.localPort()), qint64(0));
+ QCOMPARE(sender.writeDatagram(QNetworkDatagram(QByteArray(), QHostAddress::LocalHost, receiver.localPort())), qint64(0));
QVERIFY2(receiver.waitForReadyRead(1000), QtNetworkSettings::msgSocketError(receiver).constData());
QVERIFY(receiver.hasPendingDatagrams());
@@ -1366,10 +1381,20 @@ void tst_QUdpSocket::multicast()
QVERIFY(receiver.hasPendingDatagrams());
QList<QByteArray> receivedDatagrams;
while (receiver.hasPendingDatagrams()) {
- QByteArray datagram;
- datagram.resize(receiver.pendingDatagramSize());
- receiver.readDatagram(datagram.data(), datagram.size(), 0, 0);
- receivedDatagrams << datagram;
+ QNetworkDatagram dgram = receiver.receiveDatagram();
+ receivedDatagrams << dgram.data();
+
+ QVERIFY2(allAddresses.contains(dgram.senderAddress()),
+ dgram.senderAddress().toString().toLatin1());
+ QCOMPARE(dgram.senderPort(), int(sender.localPort()));
+ if (!dgram.destinationAddress().isNull()) {
+ QCOMPARE(dgram.destinationAddress(), groupAddress);
+ QCOMPARE(dgram.destinationPort(), int(receiver.localPort()));
+ }
+
+ int ttl = dgram.hopLimit();
+ if (ttl != -1)
+ QVERIFY(ttl != 0);
}
QCOMPARE(receivedDatagrams, datagrams);
@@ -1464,7 +1489,8 @@ void tst_QUdpSocket::linkLocalIPv6()
quint16 port = 0;
foreach (const QHostAddress& addr, addresses) {
QUdpSocket *s = new QUdpSocket;
- QVERIFY2(s->bind(addr, port), qPrintable(s->errorString()));
+ QVERIFY2(s->bind(addr, port), addr.toString().toLatin1()
+ + '/' + QByteArray::number(port) + ": " + qPrintable(s->errorString()));
port = s->localPort(); //bind same port, different networks
sockets << s;
}
@@ -1474,24 +1500,25 @@ void tst_QUdpSocket::linkLocalIPv6()
QSignalSpy neutralReadSpy(&neutral, SIGNAL(readyRead()));
QByteArray testData("hello");
- QByteArray receiveBuffer("xxxxx");
foreach (QUdpSocket *s, sockets) {
QSignalSpy spy(s, SIGNAL(readyRead()));
neutralReadSpy.clear();
QVERIFY(s->writeDatagram(testData, s->localAddress(), neutral.localPort()));
QTRY_VERIFY(neutralReadSpy.count() > 0); //note may need to accept a firewall prompt
- QHostAddress from;
- quint16 fromPort;
- QCOMPARE((int)neutral.readDatagram(receiveBuffer.data(), receiveBuffer.length(), &from, &fromPort), testData.length());
- QCOMPARE(from, s->localAddress());
- QCOMPARE(fromPort, s->localPort());
- QCOMPARE(receiveBuffer, testData);
-
- QVERIFY(neutral.writeDatagram(testData, s->localAddress(), s->localPort()));
+
+ QNetworkDatagram dgram = neutral.receiveDatagram(testData.length() * 2);
+ QVERIFY(dgram.isValid());
+ QCOMPARE(dgram.senderAddress(), s->localAddress());
+ QCOMPARE(dgram.senderPort(), int(s->localPort()));
+ QCOMPARE(dgram.data().length(), testData.length());
+ QCOMPARE(dgram.data(), testData);
+
+ QVERIFY(neutral.writeDatagram(dgram.makeReply(testData)));
QTRY_VERIFY(spy.count() > 0); //note may need to accept a firewall prompt
- QCOMPARE((int)s->readDatagram(receiveBuffer.data(), receiveBuffer.length(), &from, &fromPort), testData.length());
- QCOMPARE(receiveBuffer, testData);
+
+ dgram = s->receiveDatagram(testData.length() * 2);
+ QCOMPARE(dgram.data(), testData);
//sockets bound to other interfaces shouldn't have received anything
foreach (QUdpSocket *s2, sockets) {
@@ -1546,21 +1573,23 @@ void tst_QUdpSocket::linkLocalIPv4()
QVERIFY(neutral.bind(QHostAddress(QHostAddress::AnyIPv4)));
QByteArray testData("hello");
- QByteArray receiveBuffer("xxxxx");
foreach (QUdpSocket *s, sockets) {
QVERIFY(s->writeDatagram(testData, s->localAddress(), neutral.localPort()));
QVERIFY2(neutral.waitForReadyRead(10000), QtNetworkSettings::msgSocketError(neutral).constData());
- QHostAddress from;
- quint16 fromPort;
- QCOMPARE((int)neutral.readDatagram(receiveBuffer.data(), receiveBuffer.length(), &from, &fromPort), testData.length());
- QCOMPARE(from, s->localAddress());
- QCOMPARE(fromPort, s->localPort());
- QCOMPARE(receiveBuffer, testData);
-
- QVERIFY(neutral.writeDatagram(testData, s->localAddress(), s->localPort()));
+
QVERIFY2(s->waitForReadyRead(10000), QtNetworkSettings::msgSocketError(*s).constData());
- QCOMPARE((int)s->readDatagram(receiveBuffer.data(), receiveBuffer.length(), &from, &fromPort), testData.length());
- QCOMPARE(receiveBuffer, testData);
+ QNetworkDatagram dgram = neutral.receiveDatagram(testData.length() * 2);
+ QVERIFY(dgram.isValid());
+ QCOMPARE(dgram.senderAddress(), s->localAddress());
+ QCOMPARE(dgram.senderPort(), int(s->localPort()));
+ QCOMPARE(dgram.data().length(), testData.length());
+ QCOMPARE(dgram.data(), testData);
+
+ QVERIFY(neutral.writeDatagram(dgram.makeReply(testData)));
+
+ dgram = s->receiveDatagram(testData.length() * 2);
+ QVERIFY(dgram.isValid());
+ QCOMPARE(dgram.data(), testData);
//sockets bound to other interfaces shouldn't have received anything
foreach (QUdpSocket *s2, sockets) {
diff --git a/tests/auto/network/socket/socket.pro b/tests/auto/network/socket/socket.pro
index 436ebe5c7f..06fe356a5a 100644
--- a/tests/auto/network/socket/socket.pro
+++ b/tests/auto/network/socket/socket.pro
@@ -1,4 +1,6 @@
TEMPLATE=subdirs
+QT_FOR_CONFIG += network
+
SUBDIRS=\
qhttpsocketengine \
qudpsocket \
@@ -8,13 +10,17 @@ SUBDIRS=\
qsocks5socketengine \
qabstractsocket \
platformsocketengine \
+ qsctpsocket \
-!contains(QT_CONFIG, private_tests): SUBDIRS -= \
+!qtConfig(private_tests): SUBDIRS -= \
platformsocketengine \
qtcpsocket \
qhttpsocketengine \
qsocks5socketengine \
+!qtConfig(sctp): SUBDIRS -= \
+ qsctpsocket \
+
winrt: SUBDIRS -= \
qhttpsocketengine \
qsocks5socketengine \
diff --git a/tests/auto/network/ssl/qsslcertificate/qsslcertificate.pro b/tests/auto/network/ssl/qsslcertificate/qsslcertificate.pro
index 87a210c051..7c1cd5b66b 100644
--- a/tests/auto/network/ssl/qsslcertificate/qsslcertificate.pro
+++ b/tests/auto/network/ssl/qsslcertificate/qsslcertificate.pro
@@ -1,7 +1,7 @@
CONFIG += testcase
SOURCES += tst_qsslcertificate.cpp
-!wince:win32:LIBS += -lws2_32
+win32:LIBS += -lws2_32
QT = core network testlib
TARGET = tst_qsslcertificate
diff --git a/tests/auto/network/ssl/qsslcipher/qsslcipher.pro b/tests/auto/network/ssl/qsslcipher/qsslcipher.pro
index 4cb2dfebab..81ef2d8d9a 100644
--- a/tests/auto/network/ssl/qsslcipher/qsslcipher.pro
+++ b/tests/auto/network/ssl/qsslcipher/qsslcipher.pro
@@ -1,7 +1,7 @@
CONFIG += testcase
SOURCES += tst_qsslcipher.cpp
-win32:!wince: LIBS += -lws2_32
+win32:LIBS += -lws2_32
QT = core network testlib
TARGET = tst_qsslcipher
diff --git a/tests/auto/network/ssl/qssldiffiehellmanparameters/qssldiffiehellmanparameters.pro b/tests/auto/network/ssl/qssldiffiehellmanparameters/qssldiffiehellmanparameters.pro
new file mode 100644
index 0000000000..b8053f9eb3
--- /dev/null
+++ b/tests/auto/network/ssl/qssldiffiehellmanparameters/qssldiffiehellmanparameters.pro
@@ -0,0 +1,8 @@
+CONFIG += testcase
+CONFIG += parallel_test
+
+SOURCES += tst_qssldiffiehellmanparameters.cpp
+!wince*:win32:LIBS += -lws2_32
+QT = core network testlib
+
+TARGET = tst_qssldiffiehellmanparameters
diff --git a/tests/auto/network/ssl/qssldiffiehellmanparameters/tst_qssldiffiehellmanparameters.cpp b/tests/auto/network/ssl/qssldiffiehellmanparameters/tst_qssldiffiehellmanparameters.cpp
new file mode 100644
index 0000000000..f3b9003fbb
--- /dev/null
+++ b/tests/auto/network/ssl/qssldiffiehellmanparameters/tst_qssldiffiehellmanparameters.cpp
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QSslDiffieHellmanParameters>
+#include <QSslSocket>
+#include <QByteArray>
+
+class tst_QSslDiffieHellmanParameters : public QObject
+{
+ Q_OBJECT
+
+#ifndef QT_NO_SSL
+private Q_SLOTS:
+ void constructionEmpty();
+ void constructionDefault();
+ void constructionDER();
+ void constructionPEM();
+ void unsafe512Bits();
+ void unsafeNonPrime();
+#endif
+};
+
+#ifndef QT_NO_SSL
+
+void tst_QSslDiffieHellmanParameters::constructionEmpty()
+{
+ QSslDiffieHellmanParameters dh;
+
+ QCOMPARE(dh.isEmpty(), true);
+ QCOMPARE(dh.isValid(), true);
+ QCOMPARE(dh.error(), QSslDiffieHellmanParameters::NoError);
+}
+
+void tst_QSslDiffieHellmanParameters::constructionDefault()
+{
+ QSslDiffieHellmanParameters dh = QSslDiffieHellmanParameters::defaultParameters();
+
+#ifndef QT_NO_OPENSSL
+ QCOMPARE(dh.isValid(), true);
+ QCOMPARE(dh.error(), QSslDiffieHellmanParameters::NoError);
+#endif
+}
+
+void tst_QSslDiffieHellmanParameters::constructionDER()
+{
+ // Uniquely generated with 'openssl dhparam -outform DER -out out.der -check -2 4096'
+ const auto dh = QSslDiffieHellmanParameters::fromEncoded(QByteArray::fromBase64(QByteArrayLiteral(
+ "MIICCAKCAgEAsbQYx57ZlyEyWF8jD5WYEswGR2aTVFsHqP3026SdyTwcjY+YlMOae0EagK"
+ "jDA0UlPcih1kguQOvOVgyc5gI3YbBb4pCNEdy048xITlsdqG7qC3+2VvFR3vfixEbQQll9"
+ "2cGIIneD/36p7KJcDnBNUwwWj/VJKhTwelTfKTj2T39si9xGMkqZiQuCaXRk6vSKZ4ZDPk"
+ "jiq5Ti1kHVFbL9SMWRa8zplPtDMrVfhSyw10njgD4qKd1UoUPdmhEPhRZlHaZ/cAHNSHMj"
+ "uhDakeMpN+XP2/sl5IpPZ3/vVOk9PhBDFO1NYzKx/b7RQgZCUmXoglKYpfBiz8OheoI0hK"
+ "V0fU/OCtHjRrP4hE9vIHA2aE+gaQZiYCciGcR9BjHQ7Y8K9qHyTX8UIz2G4ZKzQZK9G+pA"
+ "K0xD+1H3qZ/MaUhzNDQOwwihnTjjXzTjfIGqYDdbouAhw+tX51CsGonI0cL3s3QMa3CwGH"
+ "mw+AH2b/Z68dTSy0sC3CYn9cNbrctqyeHwQrsx9FfpOz+Z6sk2WsPgqgSp/pDVVgm5oSfO"
+ "2mN7WAWgUlf9TQuj1HIRCTI+PbBq2vYvn+YResMRo+8ng1QptKAAgQoVVGNRYxZ9iAZlvO"
+ "52DcHKlsqDuafQ1XVGmzVIrKtBi2gfLtPqY4v6g6v26l8gbzK67PpWstllHiPb4VMCAQI="
+ )), QSsl::Der);
+
+#ifndef QT_NO_OPENSSL
+ QCOMPARE(dh.isValid(), true);
+ QCOMPARE(dh.error(), QSslDiffieHellmanParameters::NoError);
+#endif
+}
+
+void tst_QSslDiffieHellmanParameters::constructionPEM()
+{
+ // Uniquely generated with 'openssl dhparam -outform PEM -out out.pem -check -2 4096'
+ const auto dh = QSslDiffieHellmanParameters::fromEncoded(QByteArrayLiteral(
+ "-----BEGIN DH PARAMETERS-----\n"
+ "MIICCAKCAgEA9QTdqhQkbGuhWzBsW5X475AjjrITpg1BHX5+mp1sstUd84Lshq1T\n"
+ "+S2QQQtdl25EPoUblpyyLAf8krFSH4YwR7jjLWklA8paDOwRYod0zLmVZ1Wx6og3\n"
+ "PRc8P+SCs+6gKTXfv//bJJhiJXnM73lDFsGHbSqN+msf20ei/zy5Rwey2t8dPjLC\n"
+ "Q+qkb/avlovi2t2rsUWcxMT1875TQ4HuApayqw3R3lTQe9u05b9rTrinmT7AE4mm\n"
+ "xGqO9FZJdXYE2sOKwwJkpM48KFyV90uJANmqJnQrkgdukaGTHwxZxgAyO6ur/RWC\n"
+ "kzf9STFT6IY4Qy05q+oZVJfh8xPHszKmmC8nWaLfiHMYBnL5fv+1kh/aU11Kz9TG\n"
+ "iDXwQ+tzhKAutQPUwe3IGQUYQMZPwZI4vegdU88/7YPXuWt7b/0Il5+2ma5FbtG2\n"
+ "u02PMi+J3JZsYi/tEUv1tJBVHGH0kDpgcyOm8rvkCtNbNkETzfwUPoEgA0oPMhVt\n"
+ "sFGub1av+jLRyFNGNBJcqXAO+Tq2zXG00DxbGY+aooJ50qU/Lh5gfnCEMDXlMM9P\n"
+ "T8JVpWaaNLCC+0Z5txsfYp+FO8mOttIPIF6F8FtmTnm/jhNntvqKvsU+NHylIYzr\n"
+ "o42EpiWwS7ktPPUS2GtG+IUdy8rvdO1xJ5kNxs7ZlygY4W1htOhbUusCAQI=\n"
+ "-----END DH PARAMETERS-----\n"
+ ), QSsl::Pem);
+
+#ifndef QT_NO_OPENSSL
+ QCOMPARE(dh.isValid(), true);
+ QCOMPARE(dh.error(), QSslDiffieHellmanParameters::NoError);
+#endif
+}
+
+void tst_QSslDiffieHellmanParameters::unsafe512Bits()
+{
+ // Uniquely generated with 'openssl dhparam -outform PEM -out out.pem -check -2 512'
+ const auto dh = QSslDiffieHellmanParameters::fromEncoded(QByteArrayLiteral(
+ "-----BEGIN DH PARAMETERS-----\n"
+ "MEYCQQCf8goDn56akiliAtEL1ZG7VH+9wfLxsv8/B1emTUG+rMKB1yaVAU7HaAiM\n"
+ "Gtmo2bAWUqBczUTOTzqmWTm28P6bAgEC\n"
+ "-----END DH PARAMETERS-----\n"
+ ), QSsl::Pem);
+
+#ifndef QT_NO_OPENSSL
+ QCOMPARE(dh.isValid(), false);
+ QCOMPARE(dh.error(), QSslDiffieHellmanParameters::UnsafeParametersError);
+#endif
+}
+
+void tst_QSslDiffieHellmanParameters::unsafeNonPrime()
+{
+ // Uniquely generated with 'openssl dhparam -outform DER -out out.der -check -2 1024'
+ // and then modified by hand to make P not be a prime number.
+ const auto dh = QSslDiffieHellmanParameters::fromEncoded(QByteArray::fromBase64(QByteArrayLiteral(
+ "MIGHAoGBALLcOLg+ow8TMnbCUeNjwys6wUTIH9mn4ZSeIbD6qvCsJgg4cUxXwJQmPY"
+ "Xl15AsKXgkXWh0n+/N6tjH0sSRJnzDvN2H3KxFLKkvxmBYrDOJMdCuMgZD50aOsVyd"
+ "vholAW9zilkoYkB6sqwxY1Z2dbpTWajCsUAWZQ0AIP4Y5nesAgEC"
+ )), QSsl::Der);
+
+#ifndef QT_NO_OPENSSL
+ QCOMPARE(dh.isValid(), false);
+ QCOMPARE(dh.error(), QSslDiffieHellmanParameters::UnsafeParametersError);
+#endif
+}
+
+#endif // QT_NO_SSL
+
+QTEST_MAIN(tst_QSslDiffieHellmanParameters)
+#include "tst_qssldiffiehellmanparameters.moc"
diff --git a/tests/auto/network/ssl/qsslellipticcurve/qsslellipticcurve.pro b/tests/auto/network/ssl/qsslellipticcurve/qsslellipticcurve.pro
index e67b64b2b7..a180086c5e 100644
--- a/tests/auto/network/ssl/qsslellipticcurve/qsslellipticcurve.pro
+++ b/tests/auto/network/ssl/qsslellipticcurve/qsslellipticcurve.pro
@@ -1,7 +1,7 @@
CONFIG += testcase
SOURCES += tst_qsslellipticcurve.cpp
-win32:!wince: LIBS += -lws2_32
+win32:LIBS += -lws2_32
QT = core network testlib
TARGET = tst_qsslellipticcurve
diff --git a/tests/auto/network/ssl/qsslerror/qsslerror.pro b/tests/auto/network/ssl/qsslerror/qsslerror.pro
index 7737aae3f1..117fd4ac27 100644
--- a/tests/auto/network/ssl/qsslerror/qsslerror.pro
+++ b/tests/auto/network/ssl/qsslerror/qsslerror.pro
@@ -1,7 +1,7 @@
CONFIG += testcase
SOURCES += tst_qsslerror.cpp
-win32:!wince: LIBS += -lws2_32
+win32:LIBS += -lws2_32
QT = core network testlib
TARGET = tst_qsslerror
diff --git a/tests/auto/network/ssl/qsslkey/qsslkey.pro b/tests/auto/network/ssl/qsslkey/qsslkey.pro
index 7eb04793f3..8c3877631a 100644
--- a/tests/auto/network/ssl/qsslkey/qsslkey.pro
+++ b/tests/auto/network/ssl/qsslkey/qsslkey.pro
@@ -1,9 +1,9 @@
CONFIG += testcase
SOURCES += tst_qsslkey.cpp
-win32:!wince: LIBS += -lws2_32
+win32:LIBS += -lws2_32
QT = core network testlib
-contains(QT_CONFIG, private_tests) {
+qtConfig(private_tests) {
QT += core-private network-private
}
diff --git a/tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp b/tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp
index 8afc71a216..0112af4ed7 100644
--- a/tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp
+++ b/tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp
@@ -34,9 +34,14 @@
#include <QtNetwork/qhostaddress.h>
#include <QtNetwork/qnetworkproxy.h>
-#if !defined(QT_NO_SSL) && defined(QT_BUILD_INTERNAL)
-#include "private/qsslkey_p.h"
-#define TEST_CRYPTO
+#ifdef QT_BUILD_INTERNAL
+ #ifndef QT_NO_SSL
+ #include "private/qsslkey_p.h"
+ #define TEST_CRYPTO
+ #endif
+ #ifndef QT_NO_OPENSSL
+ #include "private/qsslsocket_openssl_symbols_p.h"
+ #endif
#endif
class tst_QSslKey : public QObject
@@ -58,7 +63,7 @@ class tst_QSslKey : public QObject
QList<KeyInfo> keyInfoList;
- void createPlainTestRows();
+ void createPlainTestRows(bool filter = false, QSsl::EncodingFormat format = QSsl::EncodingFormat::Pem);
public slots:
void initTestCase();
@@ -69,6 +74,10 @@ private slots:
void emptyConstructor();
void constructor_data();
void constructor();
+#ifndef QT_NO_OPENSSL
+ void constructorHandle_data();
+ void constructorHandle();
+#endif
void copyAndAssign_data();
void copyAndAssign();
void equalsOperator();
@@ -142,7 +151,7 @@ Q_DECLARE_METATYPE(QSsl::KeyAlgorithm)
Q_DECLARE_METATYPE(QSsl::KeyType)
Q_DECLARE_METATYPE(QSsl::EncodingFormat)
-void tst_QSslKey::createPlainTestRows()
+void tst_QSslKey::createPlainTestRows(bool filter, QSsl::EncodingFormat format)
{
QTest::addColumn<QString>("absFilePath");
QTest::addColumn<QSsl::KeyAlgorithm>("algorithm");
@@ -150,6 +159,9 @@ void tst_QSslKey::createPlainTestRows()
QTest::addColumn<int>("length");
QTest::addColumn<QSsl::EncodingFormat>("format");
foreach (KeyInfo keyInfo, keyInfoList) {
+ if (filter && keyInfo.format != format)
+ continue;
+
QTest::newRow(keyInfo.fileInfo.fileName().toLatin1())
<< keyInfo.fileInfo.absoluteFilePath() << keyInfo.algorithm << keyInfo.type
<< keyInfo.length << keyInfo.format;
@@ -176,6 +188,45 @@ void tst_QSslKey::constructor()
QVERIFY(!key.isNull());
}
+#ifndef QT_NO_OPENSSL
+
+void tst_QSslKey::constructorHandle_data()
+{
+ createPlainTestRows(true);
+}
+
+void tst_QSslKey::constructorHandle()
+{
+#ifndef QT_BUILD_INTERNAL
+ QSKIP("This test requires -developer-build.");
+#else
+ if (!QSslSocket::supportsSsl())
+ return;
+
+ QFETCH(QString, absFilePath);
+ QFETCH(QSsl::KeyAlgorithm, algorithm);
+ QFETCH(QSsl::KeyType, type);
+ QFETCH(int, length);
+
+ QByteArray pem = readFile(absFilePath);
+ auto func = (type == QSsl::KeyType::PublicKey
+ ? q_PEM_read_bio_PUBKEY
+ : q_PEM_read_bio_PrivateKey);
+
+ BIO* bio = q_BIO_new(q_BIO_s_mem());
+ q_BIO_write(bio, pem.constData(), pem.length());
+ QSslKey key(func(bio, nullptr, nullptr, nullptr), type);
+ q_BIO_free(bio);
+
+ QVERIFY(!key.isNull());
+ QCOMPARE(key.algorithm(), algorithm);
+ QCOMPARE(key.type(), type);
+ QCOMPARE(key.length(), length);
+#endif
+}
+
+#endif
+
void tst_QSslKey::copyAndAssign_data()
{
createPlainTestRows();
diff --git a/tests/auto/network/ssl/qsslsocket/qsslsocket.pro b/tests/auto/network/ssl/qsslsocket/qsslsocket.pro
index de2be8e126..5c92ca833a 100644
--- a/tests/auto/network/ssl/qsslsocket/qsslsocket.pro
+++ b/tests/auto/network/ssl/qsslsocket/qsslsocket.pro
@@ -1,7 +1,7 @@
CONFIG += testcase
SOURCES += tst_qsslsocket.cpp
-win32:!wince: LIBS += -lws2_32
+win32:LIBS += -lws2_32
QT = core core-private network-private testlib
TARGET = tst_qsslsocket
@@ -15,19 +15,11 @@ win32 {
}
# OpenSSL support
-contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) {
+qtConfig(openssl)|qtConfig(openssl-linked) {
# Add optional SSL libs
LIBS += $$OPENSSL_LIBS
}
-wince* {
- DEFINES += SRCDIR=\\\"./\\\"
+DEFINES += SRCDIR=\\\"$$PWD/\\\"
- certFiles.files = certs ssl.tar.gz
- certFiles.path = .
- DEPLOYMENT += certFiles
-} else {
- DEFINES += SRCDIR=\\\"$$PWD/\\\"
-}
-
-requires(contains(QT_CONFIG,private_tests))
+requires(qtConfig(private_tests))
diff --git a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp
index 00c3a41d88..4eb26d17fe 100644
--- a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp
+++ b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp
@@ -57,7 +57,7 @@
#include "private/qsslconfiguration_p.h"
Q_DECLARE_METATYPE(QSslSocket::SslMode)
-typedef QList<QSslError::SslError> SslErrorList;
+typedef QVector<QSslError::SslError> SslErrorList;
Q_DECLARE_METATYPE(SslErrorList)
Q_DECLARE_METATYPE(QSslError)
Q_DECLARE_METATYPE(QSslKey)
@@ -220,6 +220,10 @@ private slots:
void qtbug18498_peek();
void qtbug18498_peek2();
void dhServer();
+#ifndef QT_NO_OPENSSL
+ void dhServerCustomParamsNull();
+ void dhServerCustomParams();
+#endif
void ecdhServer();
void verifyClientCertificate_data();
void verifyClientCertificate();
@@ -230,6 +234,8 @@ private slots:
void simplePskConnect();
void ephemeralServerKey_data();
void ephemeralServerKey();
+ void allowedProtocolNegotiation();
+ void pskServer();
#endif
void setEmptyDefaultConfiguration(); // this test should be last
@@ -381,14 +387,14 @@ void tst_QSslSocket::cleanup()
#ifndef QT_NO_SSL
QSslSocketPtr tst_QSslSocket::newSocket()
{
- QSslSocket *socket = new QSslSocket;
+ const auto socket = QSslSocketPtr::create();
proxyAuthCalled = 0;
- connect(socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
+ connect(socket.data(), SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
Qt::DirectConnection);
- return QSslSocketPtr(socket);
+ return socket;
}
#endif
@@ -628,7 +634,8 @@ void tst_QSslSocket::sslErrors()
// check the SSL errors contain HostNameMismatch and an error due to
// the certificate being self-signed
SslErrorList sslErrors;
- foreach (const QSslError &err, socket->sslErrors())
+ const auto socketSslErrors = socket->sslErrors();
+ for (const QSslError &err : socketSslErrors)
sslErrors << err.error();
qSort(sslErrors);
QVERIFY(sslErrors.contains(QSslError::HostNameMismatch));
@@ -637,7 +644,8 @@ void tst_QSslSocket::sslErrors()
// check the same errors were emitted by sslErrors
QVERIFY(!sslErrorsSpy.isEmpty());
SslErrorList emittedErrors;
- foreach (const QSslError &err, qvariant_cast<QList<QSslError> >(sslErrorsSpy.first().first()))
+ const auto sslErrorsSpyErrors = qvariant_cast<QList<QSslError> >(qAsConst(sslErrorsSpy).first().first());
+ for (const QSslError &err : sslErrorsSpyErrors)
emittedErrors << err.error();
qSort(emittedErrors);
QCOMPARE(sslErrors, emittedErrors);
@@ -646,7 +654,7 @@ void tst_QSslSocket::sslErrors()
QVERIFY(!peerVerifyErrorSpy.isEmpty());
SslErrorList peerErrors;
const QList<QVariantList> &peerVerifyList = peerVerifyErrorSpy;
- foreach (const QVariantList &args, peerVerifyList)
+ for (const QVariantList &args : peerVerifyList)
peerErrors << qvariant_cast<QSslError>(args.first()).error();
qSort(peerErrors);
QCOMPARE(sslErrors, peerErrors);
@@ -1160,7 +1168,9 @@ void tst_QSslSocket::protocolServerSide_data()
#if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT)
QTest::newRow("ssl2-ssl2") << QSsl::SslV2 << QSsl::SslV2 << false; // no idea why it does not work, but we don't care about SSL 2
#endif
+#if !defined(OPENSSL_NO_SSL3)
QTest::newRow("ssl3-ssl3") << QSsl::SslV3 << QSsl::SslV3 << true;
+#endif
QTest::newRow("tls1.0-tls1.0") << QSsl::TlsV1_0 << QSsl::TlsV1_0 << true;
QTest::newRow("tls1ssl3-tls1ssl3") << QSsl::TlsV1SslV3 << QSsl::TlsV1SslV3 << true;
QTest::newRow("any-any") << QSsl::AnyProtocol << QSsl::AnyProtocol << true;
@@ -1174,23 +1184,27 @@ void tst_QSslSocket::protocolServerSide_data()
QTest::newRow("ssl2-any") << QSsl::SslV2 << QSsl::AnyProtocol << false; // no idea why it does not work, but we don't care about SSL 2
#endif
-#if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT)
+#if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT) && !defined(OPENSSL_NO_SSL3)
QTest::newRow("ssl3-ssl2") << QSsl::SslV3 << QSsl::SslV2 << false;
#endif
+#if !defined(OPENSSL_NO_SSL3)
QTest::newRow("ssl3-tls1.0") << QSsl::SslV3 << QSsl::TlsV1_0 << false;
QTest::newRow("ssl3-tls1ssl3") << QSsl::SslV3 << QSsl::TlsV1SslV3 << true;
QTest::newRow("ssl3-secure") << QSsl::SslV3 << QSsl::SecureProtocols << false;
-#if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT)
+#endif
+#if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT) && !defined(OPENSSL_NO_SSL3)
QTest::newRow("ssl3-any") << QSsl::SslV3 << QSsl::AnyProtocol << false; // we won't set a SNI header here because we connect to a
// numerical IP, so OpenSSL will send a SSL 2 handshake
-#else
+#elif !defined(OPENSSL_NO_SSL3)
QTest::newRow("ssl3-any") << QSsl::SslV3 << QSsl::AnyProtocol << true;
#endif
#if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT)
QTest::newRow("tls1.0-ssl2") << QSsl::TlsV1_0 << QSsl::SslV2 << false;
#endif
+#if !defined(OPENSSL_NO_SSL3)
QTest::newRow("tls1.0-ssl3") << QSsl::TlsV1_0 << QSsl::SslV3 << false;
+#endif
QTest::newRow("tls1-tls1ssl3") << QSsl::TlsV1_0 << QSsl::TlsV1SslV3 << true;
QTest::newRow("tls1.0-secure") << QSsl::TlsV1_0 << QSsl::SecureProtocols << true;
#if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT)
@@ -1203,7 +1217,9 @@ void tst_QSslSocket::protocolServerSide_data()
#if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT)
QTest::newRow("tls1ssl3-ssl2") << QSsl::TlsV1SslV3 << QSsl::SslV2 << false;
#endif
+#if !defined(OPENSSL_NO_SSL3)
QTest::newRow("tls1ssl3-ssl3") << QSsl::TlsV1SslV3 << QSsl::SslV3 << true;
+#endif
QTest::newRow("tls1ssl3-tls1.0") << QSsl::TlsV1SslV3 << QSsl::TlsV1_0 << true;
QTest::newRow("tls1ssl3-secure") << QSsl::TlsV1SslV3 << QSsl::SecureProtocols << true;
QTest::newRow("tls1ssl3-any") << QSsl::TlsV1SslV3 << QSsl::AnyProtocol << true;
@@ -1211,7 +1227,9 @@ void tst_QSslSocket::protocolServerSide_data()
#if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT)
QTest::newRow("secure-ssl2") << QSsl::SecureProtocols << QSsl::SslV2 << false;
#endif
+#if !defined(OPENSSL_NO_SSL3)
QTest::newRow("secure-ssl3") << QSsl::SecureProtocols << QSsl::SslV3 << false;
+#endif
QTest::newRow("secure-tls1.0") << QSsl::SecureProtocols << QSsl::TlsV1_0 << true;
QTest::newRow("secure-tls1ssl3") << QSsl::SecureProtocols << QSsl::TlsV1SslV3 << true;
QTest::newRow("secure-any") << QSsl::SecureProtocols << QSsl::AnyProtocol << true;
@@ -1219,7 +1237,9 @@ void tst_QSslSocket::protocolServerSide_data()
#if !defined(OPENSSL_NO_SSL2) && !defined(QT_SECURETRANSPORT)
QTest::newRow("any-ssl2") << QSsl::AnyProtocol << QSsl::SslV2 << false; // no idea why it does not work, but we don't care about SSL 2
#endif
+#if !defined(OPENSSL_NO_SSL3)
QTest::newRow("any-ssl3") << QSsl::AnyProtocol << QSsl::SslV3 << true;
+#endif
QTest::newRow("any-tls1.0") << QSsl::AnyProtocol << QSsl::TlsV1_0 << true;
QTest::newRow("any-tls1ssl3") << QSsl::AnyProtocol << QSsl::TlsV1SslV3 << true;
QTest::newRow("any-secure") << QSsl::AnyProtocol << QSsl::SecureProtocols << true;
@@ -1244,8 +1264,8 @@ void tst_QSslSocket::protocolServerSide()
QEventLoop loop;
QTimer::singleShot(5000, &loop, SLOT(quit()));
- QSslSocketPtr client(new QSslSocket);
- socket = client.data();
+ QSslSocket client;
+ socket = &client;
QFETCH(QSsl::SslProtocol, clientProtocol);
socket->setProtocol(clientProtocol);
// upon SSL wrong version error, error will be triggered, not sslErrors
@@ -1253,14 +1273,14 @@ void tst_QSslSocket::protocolServerSide()
connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot()));
connect(socket, SIGNAL(encrypted()), &loop, SLOT(quit()));
- client->connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort());
+ client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort());
loop.exec();
QFETCH(bool, works);
QAbstractSocket::SocketState expectedState = (works) ? QAbstractSocket::ConnectedState : QAbstractSocket::UnconnectedState;
- QCOMPARE(int(client->state()), int(expectedState));
- QCOMPARE(client->isEncrypted(), works);
+ QCOMPARE(int(client.state()), int(expectedState));
+ QCOMPARE(client.isEncrypted(), works);
}
#ifndef QT_NO_OPENSSL
@@ -1285,8 +1305,8 @@ void tst_QSslSocket::serverCipherPreferences()
QEventLoop loop;
QTimer::singleShot(5000, &loop, SLOT(quit()));
- QSslSocketPtr client(new QSslSocket);
- socket = client.data();
+ QSslSocket client;
+ socket = &client;
socket->setCiphers("AES256-SHA:AES128-SHA");
// upon SSL wrong version error, error will be triggered, not sslErrors
@@ -1294,12 +1314,12 @@ void tst_QSslSocket::serverCipherPreferences()
connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot()));
connect(socket, SIGNAL(encrypted()), &loop, SLOT(quit()));
- client->connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort());
+ client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort());
loop.exec();
- QVERIFY(client->isEncrypted());
- QCOMPARE(client->sessionCipher().name(), QString("AES128-SHA"));
+ QVERIFY(client.isEncrypted());
+ QCOMPARE(client.sessionCipher().name(), QString("AES128-SHA"));
}
{
@@ -1314,8 +1334,8 @@ void tst_QSslSocket::serverCipherPreferences()
QEventLoop loop;
QTimer::singleShot(5000, &loop, SLOT(quit()));
- QSslSocketPtr client(new QSslSocket);
- socket = client.data();
+ QSslSocket client;
+ socket = &client;
socket->setCiphers("AES256-SHA:AES128-SHA");
// upon SSL wrong version error, error will be triggered, not sslErrors
@@ -1323,12 +1343,12 @@ void tst_QSslSocket::serverCipherPreferences()
connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot()));
connect(socket, SIGNAL(encrypted()), &loop, SLOT(quit()));
- client->connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort());
+ client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort());
loop.exec();
- QVERIFY(client->isEncrypted());
- QCOMPARE(client->sessionCipher().name(), QString("AES256-SHA"));
+ QVERIFY(client.isEncrypted());
+ QCOMPARE(client.sessionCipher().name(), QString("AES256-SHA"));
}
}
@@ -1419,21 +1439,21 @@ void tst_QSslSocket::setSocketDescriptor()
QEventLoop loop;
QTimer::singleShot(5000, &loop, SLOT(quit()));
- QSslSocketPtr client(new QSslSocket);
- socket = client.data();;
+ QSslSocket client;
+ socket = &client;
connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot()));
connect(socket, SIGNAL(encrypted()), &loop, SLOT(quit()));
- client->connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort());
+ client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort());
loop.exec();
- QCOMPARE(client->state(), QAbstractSocket::ConnectedState);
- QVERIFY(client->isEncrypted());
- QVERIFY(!client->peerAddress().isNull());
- QVERIFY(client->peerPort() != 0);
- QVERIFY(!client->localAddress().isNull());
- QVERIFY(client->localPort() != 0);
+ QCOMPARE(client.state(), QAbstractSocket::ConnectedState);
+ QVERIFY(client.isEncrypted());
+ QVERIFY(!client.peerAddress().isNull());
+ QVERIFY(client.peerPort() != 0);
+ QVERIFY(!client.localAddress().isNull());
+ QVERIFY(client.localPort() != 0);
}
void tst_QSslSocket::setSslConfiguration_data()
@@ -2846,10 +2866,37 @@ void tst_QSslSocket::qtbug18498_peek2()
void tst_QSslSocket::dhServer()
{
- if (!QSslSocket::supportsSsl()) {
- qWarning("SSL not supported, skipping test");
+ if (!QSslSocket::supportsSsl())
+ QSKIP("No SSL support");
+
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
return;
- }
+
+ SslServer server;
+ server.ciphers = QLatin1String("DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA");
+ QVERIFY(server.listen());
+
+ QEventLoop loop;
+ QTimer::singleShot(5000, &loop, SLOT(quit()));
+
+ QSslSocket client;
+ socket = &client;
+ connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), &loop, SLOT(quit()));
+ connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot()));
+ connect(socket, SIGNAL(encrypted()), &loop, SLOT(quit()));
+
+ client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort());
+
+ loop.exec();
+ QCOMPARE(client.state(), QAbstractSocket::ConnectedState);
+}
+
+#ifndef QT_NO_OPENSSL
+void tst_QSslSocket::dhServerCustomParamsNull()
+{
+ if (!QSslSocket::supportsSsl())
+ QSKIP("No SSL support");
QFETCH_GLOBAL(bool, setProxy);
if (setProxy)
@@ -2857,22 +2904,74 @@ void tst_QSslSocket::dhServer()
SslServer server;
server.ciphers = QLatin1String("DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA");
+
+ QSslConfiguration cfg = server.config;
+ cfg.setDiffieHellmanParameters(QSslDiffieHellmanParameters());
+ server.config = cfg;
+
QVERIFY(server.listen());
QEventLoop loop;
QTimer::singleShot(5000, &loop, SLOT(quit()));
- QSslSocketPtr client(new QSslSocket);
- socket = client.data();
+ QSslSocket client;
+ socket = &client;
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), &loop, SLOT(quit()));
connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot()));
connect(socket, SIGNAL(encrypted()), &loop, SLOT(quit()));
- client->connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort());
+ client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort());
loop.exec();
- QCOMPARE(client->state(), QAbstractSocket::ConnectedState);
+
+ QVERIFY(client.state() != QAbstractSocket::ConnectedState);
}
+#endif // QT_NO_OPENSSL
+
+#ifndef QT_NO_OPENSSL
+void tst_QSslSocket::dhServerCustomParams()
+{
+ if (!QSslSocket::supportsSsl())
+ QSKIP("No SSL support");
+
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ return;
+
+ SslServer server;
+ server.ciphers = QLatin1String("DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA");
+
+ QSslConfiguration cfg = server.config;
+
+ // Custom 2048-bit DH parameters generated with 'openssl dhparam -outform DER -out out.der -check -2 2048'
+ const auto dh = QSslDiffieHellmanParameters::fromEncoded(QByteArray::fromBase64(QByteArrayLiteral(
+ "MIIBCAKCAQEAvVA7b8keTfjFutCtTJmP/pnQfw/prKa+GMed/pBWjrC4N1YwnI8h/A861d9WE/VWY7XMTjvjX3/0"
+ "aaU8wEe0EXNpFdlTH+ZMQctQTSJOyQH0RCTwJfDGPCPT9L+c9GKwEKWORH38Earip986HJc0w3UbnfIwXUdsWHiXi"
+ "Z6r3cpyBmTKlsXTFiDVAOUXSiO8d/zOb6zHZbDfyB/VbtZRmnA7TXVn9oMzC0g9+FXHdrV4K+XfdvNZdCegvoAZiy"
+ "R6ZQgNG9aZ36/AQekhg060hp55f9HDPgXqYeNeXBiferjUtU7S9b3s83XhOJAr01/0Tf5dENwCfg2gK36TM8cC4wI"
+ "BAg==")), QSsl::Der);
+ cfg.setDiffieHellmanParameters(dh);
+
+ server.config = cfg;
+
+ QVERIFY(server.listen());
+
+ QEventLoop loop;
+ QTimer::singleShot(5000, &loop, SLOT(quit()));
+
+ QSslSocket client;
+ socket = &client;
+ connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), &loop, SLOT(quit()));
+ connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot()));
+ connect(socket, SIGNAL(encrypted()), &loop, SLOT(quit()));
+
+ client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort());
+
+ loop.exec();
+
+ QVERIFY(client.state() == QAbstractSocket::ConnectedState);
+}
+#endif // QT_NO_OPENSSL
void tst_QSslSocket::ecdhServer()
{
@@ -2892,16 +2991,16 @@ void tst_QSslSocket::ecdhServer()
QEventLoop loop;
QTimer::singleShot(5000, &loop, SLOT(quit()));
- QSslSocketPtr client(new QSslSocket);
- socket = client.data();
+ QSslSocket client;
+ socket = &client;
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), &loop, SLOT(quit()));
connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot()));
connect(socket, SIGNAL(encrypted()), &loop, SLOT(quit()));
- client->connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort());
+ client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort());
loop.exec();
- QCOMPARE(client->state(), QAbstractSocket::ConnectedState);
+ QCOMPARE(client.state(), QAbstractSocket::ConnectedState);
}
void tst_QSslSocket::verifyClientCertificate_data()
@@ -3003,16 +3102,16 @@ void tst_QSslSocket::verifyClientCertificate()
QFETCH(QList<QSslCertificate>, clientCerts);
QFETCH(QSslKey, clientKey);
- QSslSocketPtr client(new QSslSocket);
- client->setLocalCertificateChain(clientCerts);
- client->setPrivateKey(clientKey);
- socket = client.data();
+ QSslSocket client;
+ client.setLocalCertificateChain(clientCerts);
+ client.setPrivateKey(clientKey);
+ socket = &client;
connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot()));
connect(socket, SIGNAL(disconnected()), &loop, SLOT(quit()));
connect(socket, SIGNAL(encrypted()), &loop, SLOT(quit()));
- client->connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort());
+ client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort());
loop.exec();
@@ -3034,8 +3133,8 @@ void tst_QSslSocket::verifyClientCertificate()
}
// check client socket
- QCOMPARE(int(client->state()), int(expectedState));
- QCOMPARE(client->isEncrypted(), works);
+ QCOMPARE(int(client.state()), int(expectedState));
+ QCOMPARE(client.isEncrypted(), works);
}
void tst_QSslSocket::readBufferMaxSize()
@@ -3126,8 +3225,12 @@ class PskProvider : public QObject
Q_OBJECT
public:
+ bool m_server;
+ QByteArray m_identity;
+ QByteArray m_psk;
+
explicit PskProvider(QObject *parent = 0)
- : QObject(parent)
+ : QObject(parent), m_server(false)
{
}
@@ -3146,7 +3249,11 @@ public slots:
{
QVERIFY(authenticator);
QCOMPARE(authenticator->identityHint(), PSK_SERVER_IDENTITY_HINT);
- QVERIFY(authenticator->maximumIdentityLength() > 0);
+ if (m_server)
+ QCOMPARE(authenticator->maximumIdentityLength(), 0);
+ else
+ QVERIFY(authenticator->maximumIdentityLength() > 0);
+
QVERIFY(authenticator->maximumPreSharedKeyLength() > 0);
if (!m_identity.isEmpty()) {
@@ -3159,12 +3266,61 @@ public slots:
QCOMPARE(authenticator->preSharedKey(), m_psk);
}
}
-
-private:
- QByteArray m_identity;
- QByteArray m_psk;
};
+class PskServer : public QTcpServer
+{
+ Q_OBJECT
+public:
+ PskServer()
+ : socket(0),
+ config(QSslConfiguration::defaultConfiguration()),
+ ignoreSslErrors(true),
+ peerVerifyMode(QSslSocket::AutoVerifyPeer),
+ protocol(QSsl::TlsV1_0),
+ m_pskProvider()
+ {
+ m_pskProvider.m_server = true;
+ }
+ QSslSocket *socket;
+ QSslConfiguration config;
+ bool ignoreSslErrors;
+ QSslSocket::PeerVerifyMode peerVerifyMode;
+ QSsl::SslProtocol protocol;
+ QString ciphers;
+ PskProvider m_pskProvider;
+
+protected:
+ void incomingConnection(qintptr socketDescriptor)
+ {
+ socket = new QSslSocket(this);
+ socket->setSslConfiguration(config);
+ socket->setPeerVerifyMode(peerVerifyMode);
+ socket->setProtocol(protocol);
+ if (ignoreSslErrors)
+ connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot()));
+
+ if (!ciphers.isEmpty()) {
+ socket->setCiphers(ciphers);
+ }
+
+ QVERIFY(socket->setSocketDescriptor(socketDescriptor, QAbstractSocket::ConnectedState));
+ QVERIFY(!socket->peerAddress().isNull());
+ QVERIFY(socket->peerPort() != 0);
+ QVERIFY(!socket->localAddress().isNull());
+ QVERIFY(socket->localPort() != 0);
+
+ connect(socket, &QSslSocket::preSharedKeyAuthenticationRequired, &m_pskProvider, &PskProvider::providePsk);
+
+ socket->startServerEncryption();
+ }
+
+protected slots:
+ void ignoreErrorSlot()
+ {
+ socket->ignoreSslErrors();
+ }
+};
void tst_QSslSocket::simplePskConnect_data()
{
QTest::addColumn<PskConnectTestType>("pskTestType");
@@ -3188,7 +3344,7 @@ void tst_QSslSocket::simplePskConnect()
bool pskCipherFound = false;
const QList<QSslCipher> supportedCiphers = QSslSocket::supportedCiphers();
- foreach (const QSslCipher &cipher, supportedCiphers) {
+ for (const QSslCipher &cipher : supportedCiphers) {
if (cipher.name() == PSK_CIPHER_WITHOUT_AUTH) {
pskCipherFound = true;
break;
@@ -3466,6 +3622,129 @@ void tst_QSslSocket::ephemeralServerKey()
QCOMPARE(client->sslConfiguration().ephemeralServerKey().isNull(), emptyKey);
}
+void tst_QSslSocket::allowedProtocolNegotiation()
+{
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(OPENSSL_NO_TLSEXT)
+
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ return;
+
+ const QByteArray expectedNegotiated("cool-protocol");
+ QList<QByteArray> serverProtos;
+ serverProtos << expectedNegotiated << "not-so-cool-protocol";
+ QList<QByteArray> clientProtos;
+ clientProtos << "uber-cool-protocol" << expectedNegotiated << "not-so-cool-protocol";
+
+
+ SslServer server;
+ server.config.setAllowedNextProtocols(serverProtos);
+ QVERIFY(server.listen());
+
+ QSslSocket clientSocket;
+ auto configuration = clientSocket.sslConfiguration();
+ configuration.setAllowedNextProtocols(clientProtos);
+ clientSocket.setSslConfiguration(configuration);
+
+ clientSocket.connectToHostEncrypted("127.0.0.1", server.serverPort());
+ clientSocket.ignoreSslErrors();
+
+ QEventLoop loop;
+ QTimer::singleShot(5000, &loop, SLOT(quit()));
+ connect(&clientSocket, SIGNAL(encrypted()), &loop, SLOT(quit()));
+ loop.exec();
+
+ QVERIFY(server.socket->sslConfiguration().nextNegotiatedProtocol() ==
+ clientSocket.sslConfiguration().nextNegotiatedProtocol());
+ QVERIFY(server.socket->sslConfiguration().nextNegotiatedProtocol() == expectedNegotiated);
+
+#endif // OPENSSL_VERSION_NUMBER
+}
+
+void tst_QSslSocket::pskServer()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (!QSslSocket::supportsSsl() || setProxy)
+ return;
+
+ QSslSocket socket;
+ this->socket = &socket;
+
+ QSignalSpy connectedSpy(&socket, SIGNAL(connected()));
+ QVERIFY(connectedSpy.isValid());
+
+ QSignalSpy disconnectedSpy(&socket, SIGNAL(disconnected()));
+ QVERIFY(disconnectedSpy.isValid());
+
+ QSignalSpy connectionEncryptedSpy(&socket, SIGNAL(encrypted()));
+ QVERIFY(connectionEncryptedSpy.isValid());
+
+ QSignalSpy pskAuthenticationRequiredSpy(&socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)));
+ QVERIFY(pskAuthenticationRequiredSpy.isValid());
+
+ connect(&socket, SIGNAL(connected()), this, SLOT(exitLoop()));
+ connect(&socket, SIGNAL(disconnected()), this, SLOT(exitLoop()));
+ connect(&socket, SIGNAL(modeChanged(QSslSocket::SslMode)), this, SLOT(exitLoop()));
+ connect(&socket, SIGNAL(encrypted()), this, SLOT(exitLoop()));
+ connect(&socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(exitLoop()));
+ connect(&socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(exitLoop()));
+ connect(&socket, SIGNAL(peerVerifyError(QSslError)), this, SLOT(exitLoop()));
+ connect(&socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(exitLoop()));
+
+ // force a PSK cipher w/o auth
+ socket.setCiphers(PSK_CIPHER_WITHOUT_AUTH);
+
+ PskProvider provider;
+ provider.setIdentity(PSK_CLIENT_IDENTITY);
+ provider.setPreSharedKey(PSK_CLIENT_PRESHAREDKEY);
+ connect(&socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), &provider, SLOT(providePsk(QSslPreSharedKeyAuthenticator*)));
+ socket.setPeerVerifyMode(QSslSocket::VerifyNone);
+
+ PskServer server;
+ server.m_pskProvider.setIdentity(provider.m_identity);
+ server.m_pskProvider.setPreSharedKey(provider.m_psk);
+ server.config.setPreSharedKeyIdentityHint(PSK_SERVER_IDENTITY_HINT);
+ QVERIFY(server.listen());
+
+ // Start connecting
+ socket.connectToHost(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort());
+ enterLoop(5);
+
+ // Entered connected state
+ QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
+ QCOMPARE(socket.mode(), QSslSocket::UnencryptedMode);
+ QVERIFY(!socket.isEncrypted());
+ QCOMPARE(connectedSpy.count(), 1);
+ QCOMPARE(disconnectedSpy.count(), 0);
+
+ // Enter encrypted mode
+ socket.startClientEncryption();
+ QCOMPARE(socket.mode(), QSslSocket::SslClientMode);
+ QVERIFY(!socket.isEncrypted());
+ QCOMPARE(connectionEncryptedSpy.count(), 0);
+
+ // Start handshake.
+ enterLoop(10);
+
+ // We must get the PSK signal in all cases
+ QCOMPARE(pskAuthenticationRequiredSpy.count(), 1);
+
+ QCOMPARE(connectionEncryptedSpy.count(), 1);
+ QVERIFY(socket.isEncrypted());
+ QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
+
+ // check writing
+ socket.write("Hello from Qt TLS/PSK!");
+ QVERIFY(socket.waitForBytesWritten());
+
+ // disconnect
+ socket.disconnectFromHost();
+ enterLoop(10);
+
+ QCOMPARE(socket.state(), QAbstractSocket::UnconnectedState);
+ QCOMPARE(disconnectedSpy.count(), 1);
+}
+
#endif // QT_NO_OPENSSL
#endif // QT_NO_SSL
diff --git a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/qsslsocket_onDemandCertificates_member.pro b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/qsslsocket_onDemandCertificates_member.pro
index ae911e43ed..c862b3d3ae 100644
--- a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/qsslsocket_onDemandCertificates_member.pro
+++ b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/qsslsocket_onDemandCertificates_member.pro
@@ -2,7 +2,7 @@ CONFIG += testcase
testcase.timeout = 300 # this test is slow
SOURCES += tst_qsslsocket_onDemandCertificates_member.cpp
-win32:!wince: LIBS += -lws2_32
+win32:LIBS += -lws2_32
QT = core core-private network-private testlib
TARGET = tst_qsslsocket_onDemandCertificates_member
@@ -15,10 +15,6 @@ win32 {
}
}
-wince* {
- DEFINES += SRCDIR=\\\"./\\\"
-} else {
- DEFINES += SRCDIR=\\\"$$PWD/\\\"
-}
+DEFINES += SRCDIR=\\\"$$PWD/\\\"
-requires(contains(QT_CONFIG,private_tests))
+requires(qtConfig(private_tests))
diff --git a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_static/qsslsocket_onDemandCertificates_static.pro b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_static/qsslsocket_onDemandCertificates_static.pro
index 25e5a5d5c7..c27a58fcd2 100644
--- a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_static/qsslsocket_onDemandCertificates_static.pro
+++ b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_static/qsslsocket_onDemandCertificates_static.pro
@@ -1,7 +1,7 @@
CONFIG += testcase
SOURCES += tst_qsslsocket_onDemandCertificates_static.cpp
-win32:!wince: LIBS += -lws2_32
+win32:LIBS += -lws2_32
QT = core core-private network-private testlib
TARGET = tst_qsslsocket_onDemandCertificates_static
@@ -14,10 +14,6 @@ win32 {
}
}
-wince* {
- DEFINES += SRCDIR=\\\"./\\\"
-} else {
- DEFINES += SRCDIR=\\\"$$PWD/\\\"
-}
+DEFINES += SRCDIR=\\\"$$PWD/\\\"
-requires(contains(QT_CONFIG,private_tests))
+requires(qtConfig(private_tests))
diff --git a/tests/auto/network/ssl/ssl.pro b/tests/auto/network/ssl/ssl.pro
index 25d79ebfe8..175f361071 100644
--- a/tests/auto/network/ssl/ssl.pro
+++ b/tests/auto/network/ssl/ssl.pro
@@ -1,4 +1,6 @@
TEMPLATE=subdirs
+QT_FOR_CONFIG += network
+
SUBDIRS=\
qsslcertificate \
qsslcipher \
@@ -6,8 +8,8 @@ SUBDIRS=\
qsslerror \
qsslkey \
-contains(QT_CONFIG, ssl) | contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) {
- contains(QT_CONFIG, private_tests) {
+qtConfig(ssl) {
+ qtConfig(private_tests) {
SUBDIRS += \
qsslsocket \
qsslsocket_onDemandCertificates_member \
@@ -19,8 +21,9 @@ winrt: SUBDIRS -= \
qsslsocket_onDemandCertificates_member \
qsslsocket_onDemandCertificates_static \
-contains(QT_CONFIG, ssl) | contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) {
- contains(QT_CONFIG, private_tests) {
- SUBDIRS += qasn1element
+qtConfig(ssl) {
+ qtConfig(private_tests) {
+ SUBDIRS += qasn1element \
+ qssldiffiehellmanparameters
}
}