diff options
Diffstat (limited to 'tests/auto/network')
294 files changed, 16159 insertions, 6441 deletions
diff --git a/tests/auto/network/.prev_CMakeLists.txt b/tests/auto/network/.prev_CMakeLists.txt deleted file mode 100644 index aafbe7abff..0000000000 --- a/tests/auto/network/.prev_CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -# Generated from network.pro. - -add_subdirectory(selftest) -add_subdirectory(access) -add_subdirectory(kernel) -add_subdirectory(ssl) -add_subdirectory(socket) diff --git a/tests/auto/network/CMakeLists.txt b/tests/auto/network/CMakeLists.txt index c8bb0cf799..9b15208f71 100644 --- a/tests/auto/network/CMakeLists.txt +++ b/tests/auto/network/CMakeLists.txt @@ -1,5 +1,6 @@ -# Generated from network.pro. -# special case begin +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + # SSL library include path is not propagated with private tests which results in # test not being able to find the ssl header when they are not in the standard # include paths @@ -12,9 +13,8 @@ if (QT_FEATURE_private_tests) include_directories($<TARGET_PROPERTY:WrapOpenSSLHeaders::WrapOpenSSLHeaders,INTERFACE_INCLUDE_DIRECTORIES>) endif() endif() -# special case end -# add_subdirectory(selftest) # special case not ported +# add_subdirectory(selftest) # TODO: not ported add_subdirectory(access) add_subdirectory(kernel) add_subdirectory(ssl) diff --git a/tests/auto/network/access/CMakeLists.txt b/tests/auto/network/access/CMakeLists.txt index d225eb1299..ed99aa8746 100644 --- a/tests/auto/network/access/CMakeLists.txt +++ b/tests/auto/network/access/CMakeLists.txt @@ -1,6 +1,10 @@ -# Generated from access.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause -add_subdirectory(qnetworkdiskcache) +add_subdirectory(qhttpheaders) +if(QT_FEATURE_networkdiskcache) + add_subdirectory(qnetworkdiskcache) +endif() add_subdirectory(qnetworkcookiejar) add_subdirectory(qnetworkaccessmanager) add_subdirectory(qnetworkcookie) @@ -8,7 +12,16 @@ add_subdirectory(qnetworkrequest) add_subdirectory(qnetworkreply) add_subdirectory(qnetworkcachemetadata) add_subdirectory(qabstractnetworkcache) +if(QT_FEATURE_http) + add_subdirectory(qnetworkreply_local) + add_subdirectory(qformdatabuilder) + add_subdirectory(qnetworkrequestfactory) + add_subdirectory(qrestaccessmanager) +endif() if(QT_FEATURE_private_tests) + add_subdirectory(qhttp2connection) + add_subdirectory(qhttpheaderparser) + add_subdirectory(qhttpheadershelper) add_subdirectory(qhttpnetworkconnection) add_subdirectory(qhttpnetworkreply) add_subdirectory(hpack) diff --git a/tests/auto/network/access/access.pro b/tests/auto/network/access/access.pro deleted file mode 100644 index 45d7b0cda5..0000000000 --- a/tests/auto/network/access/access.pro +++ /dev/null @@ -1,26 +0,0 @@ -TEMPLATE=subdirs -QT_FOR_CONFIG += network - -SUBDIRS=\ - qnetworkdiskcache \ - qnetworkcookiejar \ - qnetworkaccessmanager \ - qnetworkcookie \ - qnetworkrequest \ - qhttpnetworkconnection \ - qnetworkreply \ - qnetworkcachemetadata \ - qhttpnetworkreply \ - qabstractnetworkcache \ - hpack \ - http2 \ - hsts \ - qdecompresshelper - -!qtConfig(private_tests): SUBDIRS -= \ - qhttpnetworkconnection \ - qhttpnetworkreply \ - hpack \ - http2 \ - hsts \ - qdecompresshelper diff --git a/tests/auto/network/access/hpack/CMakeLists.txt b/tests/auto/network/access/hpack/CMakeLists.txt index 08ff2a6798..32cd4b2f06 100644 --- a/tests/auto/network/access/hpack/CMakeLists.txt +++ b/tests/auto/network/access/hpack/CMakeLists.txt @@ -1,17 +1,21 @@ -# Generated from hpack.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_hpack Test: ##################################################################### -qt_add_test(tst_hpack +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_hpack LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_hpack SOURCES tst_hpack.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::Network Qt::NetworkPrivate ) - -#### Keys ignored in scope 1:.:.:hpack.pro:<TRUE>: -# TEMPLATE = "app" diff --git a/tests/auto/network/access/hpack/hpack.pro b/tests/auto/network/access/hpack/hpack.pro deleted file mode 100644 index 2823ae4d0c..0000000000 --- a/tests/auto/network/access/hpack/hpack.pro +++ /dev/null @@ -1,6 +0,0 @@ -QT = core core-private network network-private testlib -CONFIG += testcase parallel_test c++11 -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 index d5e359db57..e6b43eaed4 100644 --- a/tests/auto/network/access/hpack/tst_hpack.cpp +++ b/tests/auto/network/access/hpack/tst_hpack.cpp @@ -1,33 +1,9 @@ -/**************************************************************************** -** -** 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> +// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2014 Governikus GmbH & Co. KG. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QTest> +#include <QRandomGenerator> #include <QtNetwork/private/bitstreams_p.h> #include <QtNetwork/private/hpack_p.h> diff --git a/tests/auto/network/access/hsts/CMakeLists.txt b/tests/auto/network/access/hsts/CMakeLists.txt index 323fb84bc7..821a034940 100644 --- a/tests/auto/network/access/hsts/CMakeLists.txt +++ b/tests/auto/network/access/hsts/CMakeLists.txt @@ -1,17 +1,23 @@ -# Generated from hsts.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qhsts Test: ##################################################################### -qt_add_test(tst_qhsts +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qhsts LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qhsts SOURCES tst_qhsts.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::Network Qt::NetworkPrivate ) -#### Keys ignored in scope 1:.:.:hsts.pro:<TRUE>: # TEMPLATE = "app" diff --git a/tests/auto/network/access/hsts/hsts.pro b/tests/auto/network/access/hsts/hsts.pro deleted file mode 100644 index dad6638364..0000000000 --- a/tests/auto/network/access/hsts/hsts.pro +++ /dev/null @@ -1,6 +0,0 @@ -QT = core core-private network network-private testlib -CONFIG += testcase parallel_test c++11 -TEMPLATE = app -TARGET = tst_qhsts - -SOURCES += tst_qhsts.cpp diff --git a/tests/auto/network/access/hsts/tst_qhsts.cpp b/tests/auto/network/access/hsts/tst_qhsts.cpp index b81ea31c03..4e9a5cc53f 100644 --- a/tests/auto/network/access/hsts/tst_qhsts.cpp +++ b/tests/auto/network/access/hsts/tst_qhsts.cpp @@ -1,32 +1,7 @@ -/**************************************************************************** -** -** 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> +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QTest> #include <QtCore/qdatetime.h> #include <QtCore/qdir.h> @@ -34,6 +9,7 @@ #include <QtCore/qpair.h> #include <QtCore/qurl.h> +#include <QtNetwork/qhttpheaders.h> #include <QtNetwork/private/qhstsstore_p.h> #include <QtNetwork/private/qhsts_p.h> @@ -214,104 +190,108 @@ void tst_QHsts::testPolicyExpiration() void tst_QHsts::testSTSHeaderParser() { QHstsHeaderParser parser; - using Header = QPair<QByteArray, QByteArray>; - using Headers = QList<Header>; QVERIFY(!parser.includeSubDomains()); QVERIFY(!parser.expirationDate().isValid()); - Headers list; - QVERIFY(!parser.parse(list)); + QHttpHeaders headers; + QVERIFY(!parser.parse(headers)); QVERIFY(!parser.includeSubDomains()); QVERIFY(!parser.expirationDate().isValid()); - list << Header("Strict-Transport-security", "200"); - QVERIFY(!parser.parse(list)); + headers.append("Strict-Transport-security", "200"); + QVERIFY(!parser.parse(headers)); QVERIFY(!parser.includeSubDomains()); QVERIFY(!parser.expirationDate().isValid()); // This header is missing REQUIRED max-age directive, so we'll ignore it: - list << Header("Strict-Transport-Security", "includeSubDomains"); - QVERIFY(!parser.parse(list)); + headers.append("Strict-Transport-Security", "includeSubDomains"); + QVERIFY(!parser.parse(headers)); QVERIFY(!parser.includeSubDomains()); QVERIFY(!parser.expirationDate().isValid()); - list.pop_back(); - list << Header("Strict-Transport-Security", "includeSubDomains;max-age=1000"); - QVERIFY(parser.parse(list)); + headers.removeAt(headers.size() - 1); + headers.append("Strict-Transport-Security", "includeSubDomains;max-age=1000"); + QVERIFY(parser.parse(headers)); + QVERIFY(parser.expirationDate() > QDateTime::currentDateTimeUtc()); + QVERIFY(parser.includeSubDomains()); + + headers.removeAt(headers.size() - 1); + headers.append("strict-transport-security", "includeSubDomains;max-age=1000"); + QVERIFY(parser.parse(headers)); QVERIFY(parser.expirationDate() > QDateTime::currentDateTimeUtc()); QVERIFY(parser.includeSubDomains()); - list.pop_back(); + headers.removeAt(headers.size() - 1); // Invalid (includeSubDomains twice): - list << Header("Strict-Transport-Security", "max-age = 1000 ; includeSubDomains;includeSubDomains"); - QVERIFY(!parser.parse(list)); + headers.append("Strict-Transport-Security", "max-age = 1000 ; includeSubDomains;includeSubDomains"); + QVERIFY(!parser.parse(headers)); QVERIFY(!parser.includeSubDomains()); QVERIFY(!parser.expirationDate().isValid()); - list.pop_back(); + headers.removeAt(headers.size() - 1); // Invalid (weird number of seconds): - list << Header("Strict-Transport-Security", "max-age=-1000 ; includeSubDomains"); - QVERIFY(!parser.parse(list)); + headers.append("Strict-Transport-Security", "max-age=-1000 ; includeSubDomains"); + QVERIFY(!parser.parse(headers)); QVERIFY(!parser.includeSubDomains()); QVERIFY(!parser.expirationDate().isValid()); - list.pop_back(); + headers.removeAt(headers.size() - 1); // Note, directives are case-insensitive + we should ignore unknown directive. - list << Header("Strict-Transport-Security", ";max-age=1000 ;includesubdomains;;" + headers.append("Strict-Transport-Security", ";max-age=1000 ;includesubdomains;;" "nowsomeunknownheader=\"somevaluewithescapes\\;\""); - QVERIFY(parser.parse(list)); + QVERIFY(parser.parse(headers)); QVERIFY(parser.includeSubDomains()); QVERIFY(parser.expirationDate().isValid()); - list.pop_back(); + headers.removeAt(headers.size() - 1); // Check that we know how to unescape max-age: - list << Header("Strict-Transport-Security", "max-age=\"1000\""); - QVERIFY(parser.parse(list)); + headers.append("Strict-Transport-Security", "max-age=\"1000\""); + QVERIFY(parser.parse(headers)); QVERIFY(!parser.includeSubDomains()); QVERIFY(parser.expirationDate().isValid()); - list.pop_back(); + headers.removeAt(headers.size() - 1); // The only STS header, with invalid syntax though, to be ignored: - list << Header("Strict-Transport-Security", "max-age; max-age=15768000"); - QVERIFY(!parser.parse(list)); + headers.append("Strict-Transport-Security", "max-age; max-age=15768000"); + QVERIFY(!parser.parse(headers)); QVERIFY(!parser.includeSubDomains()); QVERIFY(!parser.expirationDate().isValid()); // Now we check that our parse chosses the first valid STS header and ignores // others: - list.clear(); - list << Header("Strict-Transport-Security", "includeSubdomains; max-age=\"hehehe\";"); - list << Header("Strict-Transport-Security", "max-age=10101"); - QVERIFY(parser.parse(list)); + headers.clear(); + headers.append("Strict-Transport-Security", "includeSubdomains; max-age=\"hehehe\";"); + headers.append("Strict-Transport-Security", "max-age=10101"); + QVERIFY(parser.parse(headers)); QVERIFY(!parser.includeSubDomains()); QVERIFY(parser.expirationDate().isValid()); - list.clear(); - list << Header("Strict-Transport-Security", "max-age=0"); - QVERIFY(parser.parse(list)); + headers.clear(); + headers.append("Strict-Transport-Security", "max-age=0"); + QVERIFY(parser.parse(headers)); QVERIFY(!parser.includeSubDomains()); QVERIFY(parser.expirationDate() <= QDateTime::currentDateTimeUtc()); // Parsing is case-insensitive: - list.pop_back(); - list << Header("Strict-Transport-Security", "Max-aGE=1000; InclUdesUbdomains"); - QVERIFY(parser.parse(list)); + headers.removeAt(headers.size() - 1); + headers.append("Strict-Transport-Security", "Max-aGE=1000; InclUdesUbdomains"); + QVERIFY(parser.parse(headers)); QVERIFY(parser.includeSubDomains()); QVERIFY(parser.expirationDate().isValid()); // Grammar of STS header is quite permissive, let's check we can parse // some weird but valid header: - list.pop_back(); - list << Header("Strict-Transport-Security", ";;; max-age = 17; ; ; ; ;;; ;;" + headers.removeAt(headers.size() - 1); + headers.append("Strict-Transport-Security", ";;; max-age = 17; ; ; ; ;;; ;;" ";;; ; includeSubdomains ;;thisIsUnknownDirective;;;;"); - QVERIFY(parser.parse(list)); + QVERIFY(parser.parse(headers)); QVERIFY(parser.includeSubDomains()); QVERIFY(parser.expirationDate().isValid()); - list.pop_back(); - list << Header("Strict-Transport-Security", "max-age=1000; includeSubDomains bogon"); - QVERIFY(!parser.parse(list)); + headers.removeAt(headers.size() - 1); + headers.append("Strict-Transport-Security", "max-age=1000; includeSubDomains bogon"); + QVERIFY(!parser.parse(headers)); QVERIFY(!parser.includeSubDomains()); QVERIFY(!parser.expirationDate().isValid()); } diff --git a/tests/auto/network/access/http2/BLACKLIST b/tests/auto/network/access/http2/BLACKLIST new file mode 100644 index 0000000000..3de8d6d448 --- /dev/null +++ b/tests/auto/network/access/http2/BLACKLIST @@ -0,0 +1,2 @@ +[duplicateRequestsWithAborts] +qnx ci # QTBUG-119616 diff --git a/tests/auto/network/access/http2/CMakeLists.txt b/tests/auto/network/access/http2/CMakeLists.txt index ed5f7c8275..7ea559940b 100644 --- a/tests/auto/network/access/http2/CMakeLists.txt +++ b/tests/auto/network/access/http2/CMakeLists.txt @@ -1,20 +1,24 @@ -# Generated from http2.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_http2 Test: ##################################################################### -qt_add_test(tst_http2 +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_http2 LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_http2 SOURCES - ../../../../shared/emulationdetector.h http2srv.cpp http2srv.h tst_http2.cpp - DEFINES - SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/\\\" - INCLUDE_DIRECTORIES - ../../../../shared - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::Network Qt::NetworkPrivate + Qt::TestPrivate + BUNDLE_ANDROID_OPENSSL_LIBS ) diff --git a/tests/auto/network/access/http2/certs/fluke.cert b/tests/auto/network/access/http2/certs/fluke.cert index ace4e4f0eb..4cc4d9a5ea 100644 --- a/tests/auto/network/access/http2/certs/fluke.cert +++ b/tests/auto/network/access/http2/certs/fluke.cert @@ -1,75 +1,34 @@ -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 +MIIF6zCCA9OgAwIBAgIUfo9amJtJGWqWE6f+SkAO85zkGr4wDQYJKoZIhvcNAQEL +BQAwgYMxCzAJBgNVBAYTAk5PMQ0wCwYDVQQIDARPc2xvMQ0wCwYDVQQHDARPc2xv +MRcwFQYDVQQKDA5UaGUgUXQgQ29tcGFueTEMMAoGA1UECwwDUiZEMRIwEAYDVQQD +DAlIMiBUZXN0ZXIxGzAZBgkqhkiG9w0BCQEWDG1pbmltaUBxdC5pbzAgFw0yMDEw +MjYxMjAxMzFaGA8yMTIwMTAwMjEyMDEzMVowgYMxCzAJBgNVBAYTAk5PMQ0wCwYD +VQQIDARPc2xvMQ0wCwYDVQQHDARPc2xvMRcwFQYDVQQKDA5UaGUgUXQgQ29tcGFu +eTEMMAoGA1UECwwDUiZEMRIwEAYDVQQDDAlIMiBUZXN0ZXIxGzAZBgkqhkiG9w0B +CQEWDG1pbmltaUBxdC5pbzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +AOiUp5+E4blouKH7q+rVNR8NoYX2XkBW+q+rpy1zu5ssRSzbqxAjDx9dkht7Qlnf +VlDT00JvpOWdeuPon5915edQRsY4Unl6mKH29ra3OtUa1/yCJXsGVJTKCj7k4Bxb +5mZzb/fTlZntMLdTIBMfUbw62FKir1WjKIcJ9fCoG8JaGeKVO4Rh5p0ezd4UUUId +r1BXl5Nqdqy2vTMsEDnjOsD3egkv8I2SKN4O6n/C3wWYpMOWYZkGoZiKz7rJs/i/ +ez7bsV7JlwdzTlhpJzkcOSVFBP6JlEOxTNNxZ1wtKy7PtZGmsSSATq2e6+bw38Ae +Op0XnzzqcGjtDDofBmT7OFzZWjS9VZS6+DOOe2QHWle1nCHcHyH4ku6IRlsr9xkR +NAIlOfnvHHxqJUenoeaZ4oQDjCBKS1KXygJO/tL7BLTQVn/xK1EmPvKNnjzWk4tR +PnibUhhs5635qpOU/YPqFBh1JjVruZbsWcDAhRcew0uxONXOa9E+4lttQ9ySYa1A +LvWqJuAX7gu2BsBMLyqfm811YnA7CIFMyO+HlqmkLFfv5L/xIRAXR7l26YGO0VwX +CGjMfz4NVPMMke4nB7qa9NkpXQBQKMms3Qzd5JW0Hy9Ruj5O8GPcFZmV0twjd1uJ +PD/cAjkWLaXjdNsJ16QWc2nghQRS6HYqKRX6j+CXOxupAgMBAAGjUzBRMB0GA1Ud +DgQWBBRSCOU58j9NJZkMamt623qyCrhN3TAfBgNVHSMEGDAWgBRSCOU58j9NJZkM +amt623qyCrhN3TAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQCq +q4jxsWeNDv5Nq14hJtF9HB+ZL64zcZtRjJP1YgNs0QppKICmjPOL2nIMGmI/jKrs +0eGAL/9XXNVHPxm1OPOncvimMMmU6emZfpMdEtTfKP43+Pg9HgKRjLoQp406vGeQ +8ki/mbBhrItVPgEm3tu2AFA02XTYi+YxCI9kRZLGkM3FbgtOuTLPl0Z9y+kiPc9F +uCSC03anBEqv+vDSI8+wODymQ/IJ3Jyz1lxIRDfp4qAekmy0jU2c91VOHHEmOmqq +kqygGFRdwbe99m9yP63r6q0b5K3X2UnJ6bns0hmTwThYwpVPXLU8jdaTddbMukN2 +/Ef96Tsw8nWOEOPMySHOTIPgwyZRp26b0kA9EmhLwOP401SxXVQCmSRmtwNagmtg +jJKmZoYBN+//D45ibK8z6Q0oOm9P+Whf/uUXehcRxBxyV3xz7k0wKGQbHj/ddwcy +IUoIN4lrAlib+lK170kTKN352PDmrpo2gmIzPEsfurKAIMSelDl6H+kih16BtZ8y +Nz6fh9Soqrg3OSAware8pxV7k51crBMoPLN78KoRV8MFCK4K7Fddq4rRISq6hiXq +r1nsjoEPuKM9huprmZVZe9t5YcDa2I+wb3IiE3uwpZbAdaLDyQ5n6F/qpsiIkZXn +gtcF7oqpG5oYrwCcZ53y/ezUgUg7PlSz2XwAGvQtgg== -----END CERTIFICATE----- diff --git a/tests/auto/network/access/http2/certs/fluke.key b/tests/auto/network/access/http2/certs/fluke.key index 9d1664d609..337ce541a6 100644 --- a/tests/auto/network/access/http2/certs/fluke.key +++ b/tests/auto/network/access/http2/certs/fluke.key @@ -1,15 +1,52 @@ ------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----- +-----BEGIN PRIVATE KEY----- +MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQDolKefhOG5aLih ++6vq1TUfDaGF9l5AVvqvq6ctc7ubLEUs26sQIw8fXZIbe0JZ31ZQ09NCb6TlnXrj +6J+fdeXnUEbGOFJ5epih9va2tzrVGtf8giV7BlSUygo+5OAcW+Zmc2/305WZ7TC3 +UyATH1G8OthSoq9VoyiHCfXwqBvCWhnilTuEYeadHs3eFFFCHa9QV5eTanastr0z +LBA54zrA93oJL/CNkijeDup/wt8FmKTDlmGZBqGYis+6ybP4v3s+27FeyZcHc05Y +aSc5HDklRQT+iZRDsUzTcWdcLSsuz7WRprEkgE6tnuvm8N/AHjqdF5886nBo7Qw6 +HwZk+zhc2Vo0vVWUuvgzjntkB1pXtZwh3B8h+JLuiEZbK/cZETQCJTn57xx8aiVH +p6HmmeKEA4wgSktSl8oCTv7S+wS00FZ/8StRJj7yjZ481pOLUT54m1IYbOet+aqT +lP2D6hQYdSY1a7mW7FnAwIUXHsNLsTjVzmvRPuJbbUPckmGtQC71qibgF+4LtgbA +TC8qn5vNdWJwOwiBTMjvh5appCxX7+S/8SEQF0e5dumBjtFcFwhozH8+DVTzDJHu +Jwe6mvTZKV0AUCjJrN0M3eSVtB8vUbo+TvBj3BWZldLcI3dbiTw/3AI5Fi2l43Tb +CdekFnNp4IUEUuh2KikV+o/glzsbqQIDAQABAoICAFw1q6tr5I48vY7DF+rXsuLn +5ZUWE1IQ6fzB4lr72nJv/9EEGnMgYzt9PpMUsD6vdCpBgS2C0+6RHArFzJtNA+RM +iHLIG7K7702veyr/xBx/MwiSlMeMv/XpkFxVI6E6skMGG2s3AMXxKvJTy5CpRx+I +eQFyLG+Ya1X2lgJes/q+/CpAHkOjCOpcLySQC5NZ74q734V7nSdmn+Zs3tYEh+O/ +eiuwTP/j5b38Te5vVTqDxTciJPmljmXLCwa0N100lWlbcpvw8qbqiTI2Jm3XCbUE +AzHjW9vmrF3cRS1fXxKFGShw3SRqlkbxjfeWoi8qDPUBS4m8LOr8qG9Wo5Nfon0z +zLP4bci3zHDvVcaaZrrsUBs/yZbg+Dgka1DmX7ekmeccr2yTdKDFgPupYUyxVbTl +a9ZLJysjFD7rgBv1ZclHonLp6Vbm+ZoTqvteo4ikAy6L9RtBWJ23XEK34PkP/+c5 +2vWZaOrnjSeBHbFce8cdJSxqWpP+eSCI5I9XbDrYFIsQ/gqKgtzDKy2ihJ2Y8STL +yO4hyFPFjxc+Gg4/P2PpmT5CY2ty44M0BWs+JGW96CJPrrplf2lmQUQJj5LZY66X +Z/4C9L7ZYtKZ+bs5SvU46yWugAvQZX22Xm9xLXWyVXRdx3bj+3M3fDnF9di/zdbh +CgLx7oWPNrXc7FCajnn9AoIBAQD5FMYwRpw9NWT9WDxQwx+cSI4Icbd88ByTW63S +LzeRwZA0J9/SfwO+aBRupzc9GkGXCiZcGMw3AGsCtig8yFlw8E5KnzN7KlftDMnM +9NUxxzlR8VwKyLnZfG7sDTl057ZlUujnqhmt/F8F7dIy7FVO1dE/8nngA+FYTCOG +UZdGjwyBDlDM0JJdUWGY3xslutcpCDN5mzSTKjy9drMvImAshRawxRF6WBpn7vr2 +nC6vciqfx1Mzx1vyk0Jm0ilaydDdLMADjt/iL4Nkr0BEs4k+UzQiKDwp8gu7abQ1 +eBfxd9Iar4htQa2I1Ewl6P01G/q+ZYwgHhJ9RVn4AxQXefILAoIBAQDvCouORdQX +C8wsyp7MwXlF/3NQeNN5/+B2mhbxrBOf7PmMCXLnkRWcjwJtzypWFqJ0sqai/2+0 +bqbMcjX5maT8stT2shl3zXe/Ejt2e3TBYpc1tyuses8Kb5BMU8hu6tTd3G2CMXpD +dT6DVemJZCTtwj9aBNIxSizvlgMolJnCpzhPnlfHSI6E+g3m/LTTo3HwbjMSw/Uq +irgjOpI2wSBB6LZPSgjvfcYPRyWUk16L4A5uSX0cADnovDFLa5/h0wJvN/OoCSQg +rLCXG5E18EyL5Wc58BCY1ZvxmjG3lQtgPxYu2Jwc36R/y/JKlxW5suER5ZNpbbD4 +uOyTt2VxMQ2bAoIBAQC5+MzRFqdo/AjfL5Y5JrbfVTzXCTDa09xCGd16ZU60QTWN ++4ed/r+o1sUKqUcRFB2MzEM/2DQBjQpZB/CbEWvWa1XJWXxypXbowveZU+QqOnmN +uQvj8WLyA3o+PNF9e9QvauwCrHpn8VpxbtPWuaYoKnUFreFZZQxHhPGxRBIS2JOZ +eDrT8ZaWnkCkh1AZp5smQ71LOprSlmKrg4jd1GjCVMxQR5N5KXbtyv0OTCZ/UFqK +2aRBsMPyJgkaBChkZPLRcKwc+/wlQRx1fHQb14DNTApMxoXFO7eOwqmOkpAt9iyl +SBIwoS0UUI5ab88+bBmXNvKcuFdNuQ4nowTJUn9pAoIBADMNkILBXSvS5DeIyuO2 +Sp1tkoZUV+5NfPY3sMDK3KIibaW/+t+EOBZo4L7tKQCb8vRzl21mmsfxfgRaPDbj +3r3tv9g0b4YLxxBy52pFscj/soXRai17SS7UZwA2QK+XzgDYbDcLNC6mIsTQG4Gx +dsWk3/zs3KuUSQaehmwrWK+fIUK38c1pLK8v7LoxrLkqxlHwZ04RthHw8KTthH7X +Pnl1J0LF8CSeOyfWLSuPUfkT0GEzptnNHpEbaHfQM6R6eaGhVJPF6AZme4y6YYgg +m2ihhSt1n0XVEWpHYWjxFy3mK2mz75unFC4LM+NEY2p2zuUQoCw7NjnY3QYrfCnx +rRMCggEAXeXsMSLFjjyuoL7iKbAxo52HD/P0fBoy58LyRcwfNVr0lvYan4pYEx+o +KijIh9K16PqXZXKMA9v003B+ulmF8bJ7SddCZ5NGvnFhUTDe4DdTKgp2RuwQ3Bsc +3skPIDbhVETyOLCtys34USHrq8U/0DlGY3eLRfxw9GnbKxSBGa/KEu/qQLPNUo50 +7xHZDg7GKeC3kqNJeqKM9rkp0VzIGkEnaD9127LeNDmERDfftxJzFoC/THvUBLfU +6Sus2ZYwRE8VFvKC30Q45t/c54X3IuhYvAuiCuTmyfE4ruyzyOwKzhUkeeLq1APX +g0veFbyfzlJ0q8qzD/iffqqIa2ZSmQ== +-----END PRIVATE KEY----- diff --git a/tests/auto/network/access/http2/http2.pro b/tests/auto/network/access/http2/http2.pro deleted file mode 100644 index 646ea117f7..0000000000 --- a/tests/auto/network/access/http2/http2.pro +++ /dev/null @@ -1,9 +0,0 @@ -QT = core core-private network network-private testlib - -CONFIG += testcase parallel_test c++11 -TARGET = tst_http2 -INCLUDEPATH += ../../../../shared/ -HEADERS += http2srv.h ../../../../shared/emulationdetector.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 index 9513744476..b52ea5527b 100644 --- a/tests/auto/network/access/http2/http2srv.cpp +++ b/tests/auto/network/access/http2/http2srv.cpp @@ -1,32 +1,7 @@ -/**************************************************************************** -** -** 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> +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QTest> #include <QtNetwork/private/http2protocol_p.h> #include <QtNetwork/private/bitstreams_p.h> @@ -109,6 +84,12 @@ Http2Server::~Http2Server() { } +void Http2Server::setInformationalStatusCode(int code) +{ + if (code == 100 || (102 <= code && code <= 199)) + informationalStatusCode = code; +} + void Http2Server::enablePushPromise(bool pushEnabled, const QByteArray &path) { pushPromiseEnabled = pushEnabled; @@ -125,6 +106,28 @@ void Http2Server::setContentEncoding(const QByteArray &encoding) contentEncoding = encoding; } +void Http2Server::setAuthenticationHeader(const QByteArray &authentication) +{ + authenticationHeader = authentication; +} + +void Http2Server::setAuthenticationRequired(bool enable) +{ + Q_ASSERT(!enable || authenticationHeader.isEmpty()); + authenticationRequired = enable; +} + +void Http2Server::setRedirect(const QByteArray &url, int count) +{ + redirectUrl = url; + redirectCount = count; +} + +void Http2Server::setSendTrailingHEADERS(bool enable) +{ + sendTrailingHEADERS = enable; +} + void Http2Server::emulateGOAWAY(int timeout) { Q_ASSERT(timeout >= 0); @@ -143,6 +146,17 @@ bool Http2Server::isClearText() const return connectionType == H2Type::h2c || connectionType == H2Type::h2cDirect; } +QByteArray Http2Server::requestAuthorizationHeader() +{ + const auto isAuthHeader = [](const HeaderField &field) { + return field.name == "authorization"; + }; + const auto requestHeaders = decoder.decodedHeader(); + const auto authentication = + std::find_if(requestHeaders.cbegin(), requestHeaders.cend(), isAuthHeader); + return authentication == requestHeaders.cend() ? QByteArray() : authentication->value; +} + void Http2Server::startServer() { if (listen()) { @@ -251,9 +265,20 @@ void Http2Server::sendDATA(quint32 streamID, quint32 windowSize) return; if (last) { - writer.start(FrameType::DATA, FrameFlag::END_STREAM, streamID); - writer.setPayloadSize(0); - writer.write(*socket); + if (sendTrailingHEADERS) { + writer.start(FrameType::HEADERS, + FrameFlag::PRIORITY | FrameFlag::END_HEADERS | FrameFlag::END_STREAM, streamID); + const quint32 maxFrameSize(clientSetting(Settings::MAX_FRAME_SIZE_ID, + Http2::maxPayloadSize)); + // 5 bytes for PRIORITY data: + writer.append(quint32(0)); // streamID 0 (32-bit) + writer.append(quint8(0)); // + weight 0 (8-bit) + writer.writeHEADERS(*socket, maxFrameSize); + } else { + writer.start(FrameType::DATA, FrameFlag::END_STREAM, streamID); + writer.setPayloadSize(0); + writer.write(*socket); + } suspendedStreams.erase(it); activeRequests.erase(streamID); @@ -302,11 +327,12 @@ void Http2Server::incomingConnection(qintptr socketDescriptor) sslSocket->setProtocol(QSsl::TlsV1_2OrLater); connect(sslSocket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot())); - QFile file(SRCDIR "certs/fluke.key"); - file.open(QIODevice::ReadOnly); + QFile file(QT_TESTCASE_SOURCEDIR "/certs/fluke.key"); + if (!file.open(QIODevice::ReadOnly)) + qFatal("Cannot open certificate file %s", qPrintable(file.fileName())); QSslKey key(file.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey); sslSocket->setPrivateKey(key); - auto localCert = QSslCertificate::fromPath(SRCDIR "certs/fluke.cert"); + auto localCert = QSslCertificate::fromPath(QT_TESTCASE_SOURCEDIR "/certs/fluke.cert"); sslSocket->setLocalCertificateChain(localCert); sslSocket->setSocketDescriptor(socketDescriptor, QAbstractSocket::ConnectedState); // Stop listening. @@ -364,16 +390,12 @@ bool Http2Server::verifyProtocolUpgradeRequest() bool settingsOk = false; QHttpNetworkReplyPrivate *firstRequestReader = protocolUpgradeHandler->d_func(); + const auto headers = firstRequestReader->headers(); // That's how we append them, that's what I expect to find: - for (const auto &header : firstRequestReader->fields) { - if (header.first == "Connection") - connectionOk = header.second.contains("Upgrade, HTTP2-Settings"); - else if (header.first == "Upgrade") - upgradeOk = header.second.contains("h2c"); - else if (header.first == "HTTP2-Settings") - settingsOk = true; - } + connectionOk = headers.combinedValue(QHttpHeaders::WellKnownHeader::Connection).contains("Upgrade, HTTP2-Settings"); + upgradeOk = headers.combinedValue(QHttpHeaders::WellKnownHeader::Upgrade).contains("h2c"); + settingsOk = headers.contains("HTTP2-Settings"); return connectionOk && upgradeOk && settingsOk; } @@ -737,10 +759,15 @@ void Http2Server::handleDATA() } if (inboundFrame.flags().testFlag(FrameFlag::END_STREAM)) { - closedStreams.insert(streamID); // Enter "half-closed remote" state. - streamWindows.erase(it); + if (responseBody.isEmpty()) { + closedStreams.insert(streamID); // Enter "half-closed remote" state. + streamWindows.erase(it); + } emit receivedData(streamID); } + emit receivedDATAFrame(streamID, + QByteArray(reinterpret_cast<const char *>(inboundFrame.dataBegin()), + inboundFrame.dataSize())); } void Http2Server::handleWINDOW_UPDATE() @@ -817,10 +844,32 @@ void Http2Server::sendResponse(quint32 streamID, bool emptyBody) // Now we'll continue with _normal_ response. } + // Create a header with an informational status code and some random header + // fields. The setter ensures that the value is 100 or is between 102 and 199 + // (inclusive) if set - otherwise it is 0 + + if (informationalStatusCode > 0) { + writer.start(FrameType::HEADERS, FrameFlag::END_HEADERS, streamID); + + HttpHeader informationalHeader; + informationalHeader.push_back({":status", QByteArray::number(informationalStatusCode)}); + informationalHeader.push_back(HeaderField("a_random_header_field", "it_will_be_dropped")); + informationalHeader.push_back(HeaderField("another_random_header_field", "drop_this_too")); + + HPack::BitOStream ostream(writer.outboundFrame().buffer); + const bool result = encoder.encodeResponse(ostream, informationalHeader); + Q_ASSERT(result); + + writer.writeHEADERS(*socket, maxFrameSize); + } + writer.start(FrameType::HEADERS, FrameFlag::END_HEADERS, streamID); if (emptyBody) writer.addFlag(FrameFlag::END_STREAM); + // We assume any auth is correct. Leaves the checking to the test itself + const bool hasAuth = !requestAuthorizationHeader().isEmpty(); + HttpHeader header; if (redirectWhileReading) { if (redirectSent) { @@ -836,7 +885,15 @@ void Http2Server::sendResponse(quint32 streamID, bool emptyBody) const QString url("%1://localhost:%2/"); header.push_back({"location", url.arg(isClearText() ? QStringLiteral("http") : QStringLiteral("https"), QString::number(targetPort)).toLatin1()}); - + } else if (redirectCount > 0) { // Not redirecting while reading, unlike above + --redirectCount; + header.push_back({":status", "308"}); + header.push_back({"location", redirectUrl}); + } else if (!authenticationHeader.isEmpty() && !hasAuth) { + header.push_back({ ":status", "401" }); + header.push_back(HPack::HeaderField("www-authenticate", authenticationHeader)); + } else if (authenticationRequired) { + header.push_back({ ":status", "401" }); } else { header.push_back({":status", "200"}); } diff --git a/tests/auto/network/access/http2/http2srv.h b/tests/auto/network/access/http2/http2srv.h index baf0155988..dc94318527 100644 --- a/tests/auto/network/access/http2/http2srv.h +++ b/tests/auto/network/access/http2/http2srv.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef HTTP2SRV_H #define HTTP2SRV_H @@ -83,16 +58,29 @@ public: ~Http2Server(); + // To send responses with status code 1xx + void setInformationalStatusCode(int code); // To be called before server started: void enablePushPromise(bool enabled, const QByteArray &path = QByteArray()); void setResponseBody(const QByteArray &body); // No content encoding is actually performed, call setResponseBody with already encoded data void setContentEncoding(const QByteArray &contentEncoding); + // No authentication data is generated for the method, the full header value must be set + void setAuthenticationHeader(const QByteArray &authentication); + // Authentication always required, no challenge provided + void setAuthenticationRequired(bool enable); + // Set the redirect URL and count. The server will return a redirect response with the url + // 'count' amount of times + void setRedirect(const QByteArray &redirectUrl, int count); + // Send a trailing HEADERS frame with PRIORITY and END_STREAM flag + void setSendTrailingHEADERS(bool enable); void emulateGOAWAY(int timeout); void redirectOpenStream(quint16 targetPort); bool isClearText() const; + QByteArray requestAuthorizationHeader(); + // Invokables, since we can call them from the main thread, // but server (can) work on its own thread. Q_INVOKABLE void startServer(); @@ -129,6 +117,8 @@ Q_SIGNALS: void decompressionFailed(quint32 streamID); void receivedRequest(quint32 streamID); void receivedData(quint32 streamID); + // Emitted for every DATA frame. Includes the content of the frame as \a body. + void receivedDATAFrame(quint32 streamID, const QByteArray &body); void windowUpdate(quint32 streamID); void sendingData(); @@ -215,6 +205,14 @@ private: QAtomicInt interrupted; QByteArray contentEncoding; + QByteArray authenticationHeader; + bool authenticationRequired = false; + + QByteArray redirectUrl; + int redirectCount = 0; + + bool sendTrailingHEADERS = false; + int informationalStatusCode = 0; protected slots: void ignoreErrorSlot(); }; diff --git a/tests/auto/network/access/http2/tst_http2.cpp b/tests/auto/network/access/http2/tst_http2.cpp index 0282942225..396a6f2fda 100644 --- a/tests/auto/network/access/http2/tst_http2.cpp +++ b/tests/auto/network/access/http2/tst_http2.cpp @@ -1,32 +1,13 @@ -/**************************************************************************** -** -** 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> +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QtNetwork/qtnetworkglobal.h> + +#include <QTest> +#include <QTestEventLoop> +#include <QScopeGuard> +#include <QRandomGenerator> +#include <QSignalSpy> #include "http2srv.h" @@ -36,38 +17,29 @@ #include <QtNetwork/qnetworkrequest.h> #include <QtNetwork/qnetworkreply.h> +#if QT_CONFIG(ssl) +#include <QtNetwork/qsslsocket.h> +#endif + #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 <QtCore/qset.h> #include <cstdlib> #include <memory> #include <string> -#include "emulationdetector.h" - -#if (!defined(QT_NO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(OPENSSL_NO_TLSEXT)) \ - || QT_CONFIG(schannel) -// HTTP/2 over TLS requires ALPN/NPN to negotiate the protocol version. -const bool clearTextHTTP2 = false; -#else -// No ALPN/NPN support to negotiate HTTP/2, we'll use cleartext 'h2c' with -// a protocol upgrade procedure. -const bool clearTextHTTP2 = true; -#endif +#include <QtTest/private/qemulationdetector_p.h> Q_DECLARE_METATYPE(H2Type) Q_DECLARE_METATYPE(QNetworkRequest::Attribute) QT_BEGIN_NAMESPACE +using namespace Qt::StringLiterals; + QHttp2Configuration qt_defaultH2Configuration() { QHttp2Configuration config; @@ -98,8 +70,11 @@ public slots: void init(); private slots: // Tests: + void defaultQnamHttp2Configuration(); void singleRequest_data(); void singleRequest(); + void informationalRequest_data(); + void informationalRequest(); void multipleRequests(); void flowControlClientSide(); void flowControlServerSide(); @@ -110,10 +85,29 @@ private slots: void connectToHost_data(); void connectToHost(); void maxFrameSize(); + void http2DATAFrames(); + + void moreActivitySignals_data(); + void moreActivitySignals(); void contentEncoding_data(); void contentEncoding(); + void authenticationRequired_data(); + void authenticationRequired(); + + void unsupportedAuthenticateChallenge(); + + void h2cAllowedAttribute_data(); + void h2cAllowedAttribute(); + + void redirect_data(); + void redirect(); + + void trailingHEADERS(); + + void duplicateRequestsWithAborts(); + protected slots: // Slots to listen to our in-process server: void serverStarted(quint16 port); @@ -157,6 +151,7 @@ private: int windowUpdates = 0; bool prefaceOK = false; bool serverGotSettingsACK = false; + bool POSTResponseHEADOnly = true; static const RawSettings defaultServerSettings; }; @@ -182,6 +177,8 @@ struct ServerDeleter } }; +bool clearTextHTTP2 = false; + using ServerPtr = QScopedPointer<Http2Server, ServerDeleter>; H2Type defaultConnectionType() @@ -194,6 +191,12 @@ H2Type defaultConnectionType() tst_Http2::tst_Http2() : workerThread(new QThread) { +#if QT_CONFIG(ssl) + const auto features = QSslSocket::supportedFeatures(); + clearTextHTTP2 = !features.contains(QSsl::SupportedFeature::ServerSideAlpn); +#else + clearTextHTTP2 = true; +#endif workerThread->start(); } @@ -215,6 +218,12 @@ void tst_Http2::init() manager.reset(new QNetworkAccessManager); } +void tst_Http2::defaultQnamHttp2Configuration() +{ + // The configuration we also implicitly use in QNAM. + QCOMPARE(qt_defaultH2Configuration(), QNetworkRequest().http2Configuration()); +} + void tst_Http2::singleRequest_data() { QTest::addColumn<QNetworkRequest::Attribute>("h2Attribute"); @@ -245,7 +254,7 @@ void tst_Http2::singleRequest() // we have to use TLS sockets (== private key) and thus suppress a // keychain UI asking for permission to use a private key. // Our CI has this, but somebody testing locally - will have a problem. - qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", QByteArray("1")); + qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", "1"); auto envRollback = qScopeGuard([](){ qunsetenv("QT_SSL_USE_TEMPORARY_KEYCHAIN"); }); @@ -266,10 +275,15 @@ void tst_Http2::singleRequest() url.setPath("/index.html"); QNetworkRequest request(url); + request.setAttribute(QNetworkRequest::Http2CleartextAllowedAttribute, true); QFETCH(const QNetworkRequest::Attribute, h2Attribute); request.setAttribute(h2Attribute, QVariant(true)); auto reply = manager->get(request); +#if QT_CONFIG(ssl) + QSignalSpy encSpy(reply, &QNetworkReply::encrypted); +#endif // QT_CONFIG(ssl) + connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished); // Since we're using self-signed certificates, // ignore SSL errors: @@ -278,12 +292,81 @@ void tst_Http2::singleRequest() runEventLoop(); STOP_ON_FAILURE - QVERIFY(nRequests == 0); + QCOMPARE(nRequests, 0); QVERIFY(prefaceOK); QVERIFY(serverGotSettingsACK); QCOMPARE(reply->error(), QNetworkReply::NoError); QVERIFY(reply->isFinished()); + +#if QT_CONFIG(ssl) + if (connectionType == H2Type::h2Alpn || connectionType == H2Type::h2Direct) + QCOMPARE(encSpy.size(), 1); +#endif // QT_CONFIG(ssl) +} + +void tst_Http2::informationalRequest_data() +{ + QTest::addColumn<int>("statusCode"); + + // 'Clear text' that should always work, either via the protocol upgrade + // or as direct. + QTest::addRow("statusCode-100") << 100; + QTest::addRow("statusCode-125") << 125; + QTest::addRow("statusCode-150") << 150; + QTest::addRow("statusCode-175") << 175; +} + +void tst_Http2::informationalRequest() +{ + clearHTTP2State(); + + serverPort = 0; + nRequests = 1; + + ServerPtr srv(newServer(defaultServerSettings, defaultConnectionType())); + + QFETCH(const int, statusCode); + srv->setInformationalStatusCode(statusCode); + + QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection); + runEventLoop(); + + QVERIFY(serverPort != 0); + + auto url = requestUrl(defaultConnectionType()); + url.setPath("/index.html"); + + QNetworkRequest request(url); + request.setAttribute(QNetworkRequest::Http2CleartextAllowedAttribute, 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(); + STOP_ON_FAILURE + + QCOMPARE(nRequests, 0); + QVERIFY(prefaceOK); + QVERIFY(serverGotSettingsACK); + + QCOMPARE(reply->error(), QNetworkReply::NoError); + QVERIFY(reply->isFinished()); + + const QVariant code(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute)); + + // We are discarding informational headers if the status code is in the range of + // 102-199 or if it is 100. As these header fields were part of the informational + // header used for this test case, we should not see them at this point and the + // status code should be 200. + + QCOMPARE(code.value<int>(), 200); + QVERIFY(!reply->hasRawHeader("a_random_header_field")); + QVERIFY(!reply->hasRawHeader("another_random_header_field")); } void tst_Http2::multipleRequests() @@ -314,7 +397,7 @@ void tst_Http2::multipleRequests() runEventLoop(); STOP_ON_FAILURE - QVERIFY(nRequests == 0); + QCOMPARE(nRequests, 0); QVERIFY(prefaceOK); QVERIFY(serverGotSettingsACK); } @@ -359,7 +442,7 @@ void tst_Http2::flowControlClientSide() runEventLoop(120000); STOP_ON_FAILURE - QVERIFY(nRequests == 0); + QCOMPARE(nRequests, 0); QVERIFY(prefaceOK); QVERIFY(serverGotSettingsACK); QVERIFY(windowUpdates > 0); @@ -375,7 +458,7 @@ void tst_Http2::flowControlServerSide() // to let all replies finish without any error. using namespace Http2; - if (EmulationDetector::isRunningArmOnX86()) + if (QTestPrivate::isRunningArmOnX86()) QSKIP("Test is too slow to run on emulator"); clearHTTP2State(); @@ -400,7 +483,7 @@ void tst_Http2::flowControlServerSide() runEventLoop(120000); STOP_ON_FAILURE - QVERIFY(nRequests == 0); + QCOMPARE(nRequests, 0); QVERIFY(prefaceOK); QVERIFY(serverGotSettingsACK); } @@ -432,6 +515,7 @@ void tst_Http2::pushPromise() url.setPath("/index.html"); QNetworkRequest request(url); + request.setAttribute(QNetworkRequest::Http2CleartextAllowedAttribute, true); request.setAttribute(QNetworkRequest::Http2AllowedAttribute, QVariant(true)); request.setHttp2Configuration(params); @@ -443,7 +527,7 @@ void tst_Http2::pushPromise() runEventLoop(); STOP_ON_FAILURE - QVERIFY(nRequests == 0); + QCOMPARE(nRequests, 0); QVERIFY(prefaceOK); QVERIFY(serverGotSettingsACK); @@ -458,6 +542,7 @@ void tst_Http2::pushPromise() url.setPath("/script.js"); QNetworkRequest promisedRequest(url); + request.setAttribute(QNetworkRequest::Http2CleartextAllowedAttribute, true); promisedRequest.setAttribute(QNetworkRequest::Http2AllowedAttribute, QVariant(true)); reply = manager->get(promisedRequest); connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished); @@ -512,6 +597,7 @@ void tst_Http2::goaway() for (int i = 0; i < nRequests; ++i) { url.setPath(QString("/%1").arg(i)); QNetworkRequest request(url); + request.setAttribute(QNetworkRequest::Http2CleartextAllowedAttribute, true); request.setAttribute(QNetworkRequest::Http2AllowedAttribute, QVariant(true)); replies[i] = manager->get(request); QCOMPARE(replies[i]->error(), QNetworkReply::NoError); @@ -567,7 +653,7 @@ void tst_Http2::earlyResponse() runEventLoop(); STOP_ON_FAILURE - QVERIFY(nRequests == 0); + QCOMPARE(nRequests, 0); QVERIFY(prefaceOK); QVERIFY(serverGotSettingsACK); } @@ -624,7 +710,7 @@ void tst_Http2::connectToHost() // we have to use TLS sockets (== private key) and thus suppress a // keychain UI asking for permission to use a private key. // Our CI has this, but somebody testing locally - will have a problem. - qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", QByteArray("1")); + qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", "1"); auto envRollback = qScopeGuard([](){ qunsetenv("QT_SSL_USE_TEMPORARY_KEYCHAIN"); }); @@ -653,6 +739,7 @@ void tst_Http2::connectToHost() auto copyUrl = url; copyUrl.setScheme(QLatin1String("preconnect-https")); QNetworkRequest request(copyUrl); + request.setAttribute(QNetworkRequest::Http2CleartextAllowedAttribute, true); request.setAttribute(requestAttribute, true); reply = manager->get(request); // Since we're using self-signed certificates, ignore SSL errors: @@ -665,6 +752,7 @@ void tst_Http2::connectToHost() auto copyUrl = url; copyUrl.setScheme(QLatin1String("preconnect-http")); QNetworkRequest request(copyUrl); + request.setAttribute(QNetworkRequest::Http2CleartextAllowedAttribute, true); request.setAttribute(requestAttribute, true); reply = manager->get(request); } @@ -685,6 +773,7 @@ void tst_Http2::connectToHost() QCOMPARE(nRequests, 1); QNetworkRequest request(url); + request.setAttribute(QNetworkRequest::Http2CleartextAllowedAttribute, true); request.setAttribute(requestAttribute, QVariant(true)); reply = manager->get(request); connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished); @@ -695,7 +784,7 @@ void tst_Http2::connectToHost() runEventLoop(); STOP_ON_FAILURE - QVERIFY(nRequests == 0); + QCOMPARE(nRequests, 0); QVERIFY(prefaceOK); QVERIFY(serverGotSettingsACK); @@ -719,7 +808,7 @@ void tst_Http2::maxFrameSize() // we have to use TLS sockets (== private key) and thus suppress a // keychain UI asking for permission to use a private key. // Our CI has this, but somebody testing locally - will have a problem. - qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", QByteArray("1")); + qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", "1"); auto envRollback = qScopeGuard([](){ qunsetenv("QT_SSL_USE_TEMPORARY_KEYCHAIN"); }); @@ -750,6 +839,7 @@ void tst_Http2::maxFrameSize() url.setPath(QString("/stream1.html")); QNetworkRequest request(url); + request.setAttribute(QNetworkRequest::Http2CleartextAllowedAttribute, true); request.setAttribute(attribute, QVariant(true)); request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain")); request.setHttp2Configuration(h2Config); @@ -763,13 +853,168 @@ void tst_Http2::maxFrameSize() // Normally, with a 16kb limit, our server would split such // a response into 3 'DATA' frames (16kb + 16kb + 0|END_STREAM). - QCOMPARE(frameCounter.count(), 1); + QCOMPARE(frameCounter.size(), 1); - QVERIFY(nRequests == 0); + QCOMPARE(nRequests, 0); QVERIFY(prefaceOK); QVERIFY(serverGotSettingsACK); } +void tst_Http2::http2DATAFrames() +{ + using namespace Http2; + + { + // 0. DATA frame with payload, no padding. + + FrameWriter writer(FrameType::DATA, FrameFlag::EMPTY, 1); + writer.append('a'); + writer.append('b'); + writer.append('c'); + + const Frame frame = writer.outboundFrame(); + const auto &buffer = frame.buffer; + // Frame's header is 9 bytes + 3 bytes of payload + // (+ 0 bytes of padding and no padding length): + QCOMPARE(int(buffer.size()), 12); + + QVERIFY(!frame.padding()); + QCOMPARE(int(frame.payloadSize()), 3); + QCOMPARE(int(frame.dataSize()), 3); + QCOMPARE(frame.dataBegin() - buffer.data(), 9); + QCOMPARE(char(*frame.dataBegin()), 'a'); + } + + { + // 1. DATA with padding. + + const int padLength = 10; + FrameWriter writer(FrameType::DATA, FrameFlag::END_STREAM | FrameFlag::PADDED, 1); + writer.append(uchar(padLength)); // The length of padding is 1 byte long. + writer.append('a'); + for (int i = 0; i < padLength; ++i) + writer.append('b'); + + const Frame frame = writer.outboundFrame(); + const auto &buffer = frame.buffer; + // Frame's header is 9 bytes + 1 byte for padding length + // + 1 byte of data + 10 bytes of padding: + QCOMPARE(int(buffer.size()), 21); + + QCOMPARE(frame.padding(), padLength); + QCOMPARE(int(frame.payloadSize()), 12); // Includes padding, its length + data. + QCOMPARE(int(frame.dataSize()), 1); + + // Skipping 9 bytes long header and padding length: + QCOMPARE(frame.dataBegin() - buffer.data(), 10); + + QCOMPARE(char(frame.dataBegin()[0]), 'a'); + QCOMPARE(char(frame.dataBegin()[1]), 'b'); + + QVERIFY(frame.flags().testFlag(FrameFlag::END_STREAM)); + QVERIFY(frame.flags().testFlag(FrameFlag::PADDED)); + } + { + // 2. DATA with PADDED flag, but 0 as padding length. + + FrameWriter writer(FrameType::DATA, FrameFlag::END_STREAM | FrameFlag::PADDED, 1); + + writer.append(uchar(0)); // Number of padding bytes is 1 byte long. + writer.append('a'); + + const Frame frame = writer.outboundFrame(); + const auto &buffer = frame.buffer; + + // Frame's header is 9 bytes + 1 byte for padding length + 1 byte of data + // + 0 bytes of padding: + QCOMPARE(int(buffer.size()), 11); + + QCOMPARE(frame.padding(), 0); + QCOMPARE(int(frame.payloadSize()), 2); // Includes padding (0 bytes), its length + data. + QCOMPARE(int(frame.dataSize()), 1); + + // Skipping 9 bytes long header and padding length: + QCOMPARE(frame.dataBegin() - buffer.data(), 10); + + QCOMPARE(char(*frame.dataBegin()), 'a'); + + QVERIFY(frame.flags().testFlag(FrameFlag::END_STREAM)); + QVERIFY(frame.flags().testFlag(FrameFlag::PADDED)); + } +} + +void tst_Http2::moreActivitySignals_data() +{ + QTest::addColumn<QNetworkRequest::Attribute>("h2Attribute"); + QTest::addColumn<H2Type>("connectionType"); + + QTest::addRow("h2c-upgrade") + << QNetworkRequest::Http2AllowedAttribute << H2Type::h2c; + QTest::addRow("h2c-direct") + << QNetworkRequest::Http2DirectAttribute << H2Type::h2cDirect; + + if (!clearTextHTTP2) + QTest::addRow("h2-ALPN") + << QNetworkRequest::Http2AllowedAttribute << H2Type::h2Alpn; + +#if QT_CONFIG(ssl) + QTest::addRow("h2-direct") + << QNetworkRequest::Http2DirectAttribute << H2Type::h2Direct; +#endif +} + +void tst_Http2::moreActivitySignals() +{ + clearHTTP2State(); + +#if QT_CONFIG(securetransport) + // Normally on macOS we use plain text only for SecureTransport + // does not support ALPN on the server side. With 'direct encrytped' + // we have to use TLS sockets (== private key) and thus suppress a + // keychain UI asking for permission to use a private key. + // Our CI has this, but somebody testing locally - will have a problem. + qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", "1"); + auto envRollback = qScopeGuard([]() { qunsetenv("QT_SSL_USE_TEMPORARY_KEYCHAIN"); }); +#endif + + serverPort = 0; + QFETCH(H2Type, connectionType); + ServerPtr srv(newServer(defaultServerSettings, connectionType)); + QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection); + runEventLoop(100); + QVERIFY(serverPort != 0); + auto url = requestUrl(connectionType); + url.setPath(QString("/stream1.html")); + QNetworkRequest request(url); + request.setAttribute(QNetworkRequest::Http2CleartextAllowedAttribute, true); + QFETCH(const QNetworkRequest::Attribute, h2Attribute); + request.setAttribute(h2Attribute, QVariant(true)); + request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain")); + QSharedPointer<QNetworkReply> reply(manager->get(request)); + nRequests = 1; + connect(reply.data(), &QNetworkReply::finished, this, &tst_Http2::replyFinished); + QSignalSpy spy1(reply.data(), SIGNAL(socketStartedConnecting())); + QSignalSpy spy2(reply.data(), SIGNAL(requestSent())); + QSignalSpy spy3(reply.data(), SIGNAL(metaDataChanged())); + // Since we're using self-signed certificates, + // ignore SSL errors: + reply->ignoreSslErrors(); + + spy1.wait(); + spy2.wait(); + spy3.wait(); + + runEventLoop(); + STOP_ON_FAILURE + + QCOMPARE(nRequests, 0); + QVERIFY(prefaceOK); + QVERIFY(serverGotSettingsACK); + + QVERIFY(reply->error() == QNetworkReply::NoError); + QVERIFY(reply->isFinished()); +} + void tst_Http2::contentEncoding_data() { QTest::addColumn<QByteArray>("encoding"); @@ -839,7 +1084,7 @@ void tst_Http2::contentEncoding() // we have to use TLS sockets (== private key) and thus suppress a // keychain UI asking for permission to use a private key. // Our CI has this, but somebody testing locally - will have a problem. - qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", QByteArray("1")); + qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", "1"); auto envRollback = qScopeGuard([]() { qunsetenv("QT_SSL_USE_TEMPORARY_KEYCHAIN"); }); #endif @@ -862,6 +1107,7 @@ void tst_Http2::contentEncoding() url.setPath("/index.html"); QNetworkRequest request(url); + request.setAttribute(QNetworkRequest::Http2CleartextAllowedAttribute, true); QFETCH(const QNetworkRequest::Attribute, h2Attribute); request.setAttribute(h2Attribute, QVariant(true)); @@ -874,7 +1120,7 @@ void tst_Http2::contentEncoding() runEventLoop(); STOP_ON_FAILURE - QVERIFY(nRequests == 0); + QCOMPARE(nRequests, 0); QVERIFY(prefaceOK); QVERIFY(serverGotSettingsACK); @@ -883,6 +1129,422 @@ void tst_Http2::contentEncoding() QTEST(reply->readAll(), "expected"); } +void tst_Http2::authenticationRequired_data() +{ + QTest::addColumn<bool>("success"); + QTest::addColumn<bool>("responseHEADOnly"); + QTest::addColumn<bool>("withChallenge"); + + QTest::addRow("failed-auth") << false << true << true; + QTest::addRow("successful-auth") << true << true << true; + // Include a DATA frame in the response from the remote server. An example would be receiving a + // JSON response on a request along with the 401 error. + QTest::addRow("failed-auth-with-response") << false << false << true; + QTest::addRow("successful-auth-with-response") << true << false << true; + + // Don't provide a challenge header. This is valid if you are actually just + // denied access for whatever reason. + QTest::addRow("no-challenge") << false << false << false; +} + +void tst_Http2::authenticationRequired() +{ + clearHTTP2State(); + serverPort = 0; + QFETCH(const bool, responseHEADOnly); + POSTResponseHEADOnly = responseHEADOnly; + + QFETCH(const bool, success); + QFETCH(const bool, withChallenge); + + ServerPtr targetServer(newServer(defaultServerSettings, defaultConnectionType())); + QByteArray responseBody = "Hello"_ba; + targetServer->setResponseBody(responseBody); + if (withChallenge) + targetServer->setAuthenticationHeader("Basic realm=\"Shadow\""); + else + targetServer->setAuthenticationRequired(true); + + QMetaObject::invokeMethod(targetServer.data(), "startServer", Qt::QueuedConnection); + runEventLoop(); + + QVERIFY(serverPort != 0); + + nRequests = 1; + + auto url = requestUrl(defaultConnectionType()); + url.setPath("/index.html"); + QNetworkRequest request(url); + request.setAttribute(QNetworkRequest::Http2CleartextAllowedAttribute, true); + + QByteArray expectedBody = "Hello, World!"; + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); + QScopedPointer<QNetworkReply> reply; + reply.reset(manager->post(request, expectedBody)); + + bool authenticationRequested = false; + connect(manager.get(), &QNetworkAccessManager::authenticationRequired, reply.get(), + [&](QNetworkReply *, QAuthenticator *auth) { + authenticationRequested = true; + if (success) { + auth->setUser("admin"); + auth->setPassword("admin"); + } + }); + + QByteArray receivedBody; + connect(targetServer.get(), &Http2Server::receivedDATAFrame, reply.get(), + [&receivedBody](quint32 streamID, const QByteArray &body) { + if (streamID == 3) // The expected body is on the retry, so streamID == 3 + receivedBody += body; + }); + + if (success) { + connect(reply.get(), &QNetworkReply::finished, this, &tst_Http2::replyFinished); + } else { + // Use queued connection so that the finished signal can be emitted and the isFinished + // property can be set. + connect(reply.get(), &QNetworkReply::errorOccurred, this, + &tst_Http2::replyFinishedWithError, Qt::QueuedConnection); + } + // Since we're using self-signed certificates, + // ignore SSL errors: + reply->ignoreSslErrors(); + + runEventLoop(); + STOP_ON_FAILURE + QVERIFY2(reply->isFinished(), + "The reply should error out if authentication fails, or finish if it succeeds"); + + if (!success) + QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError); + // else: no error (is checked in tst_Http2::replyFinished) + + QVERIFY(authenticationRequested || !withChallenge); + + const auto isAuthenticated = [](const QByteArray &bv) { + return bv == "Basic YWRtaW46YWRtaW4="; // admin:admin + }; + // Get the "authorization" header out from the server and make sure it's as expected: + auto reqAuthHeader = targetServer->requestAuthorizationHeader(); + QCOMPARE(isAuthenticated(reqAuthHeader), success); + if (success) + QCOMPARE(receivedBody, expectedBody); + if (responseHEADOnly) { + const QVariant contentLenHeader = reply->header(QNetworkRequest::ContentLengthHeader); + QVERIFY2(!contentLenHeader.isValid(), "We expect no DATA frames to be received"); + QCOMPARE(reply->readAll(), QByteArray()); + } else { + const qint32 contentLen = reply->header(QNetworkRequest::ContentLengthHeader).toInt(); + QCOMPARE(contentLen, responseBody.length()); + QCOMPARE(reply->bytesAvailable(), responseBody.length()); + QCOMPARE(reply->readAll(), QByteArray("Hello")); + } + // In the `!success` case we need to wait for the server to emit this or it might cause issues + // in the next test running after this. In the `success` case we anyway expect it to have been + // received. + QTRY_VERIFY(serverGotSettingsACK); +} + +void tst_Http2::unsupportedAuthenticateChallenge() +{ + clearHTTP2State(); + serverPort = 0; + + if (defaultConnectionType() == H2Type::h2c) + QSKIP("This test requires TLS with ALPN to work"); + + ServerPtr targetServer(newServer(defaultServerSettings, defaultConnectionType())); + QByteArray responseBody = "Hello"_ba; + targetServer->setResponseBody(responseBody); + targetServer->setAuthenticationHeader("Bearer realm=\"qt.io accounts\""); + + QMetaObject::invokeMethod(targetServer.data(), "startServer", Qt::QueuedConnection); + runEventLoop(); + + QVERIFY(serverPort != 0); + + nRequests = 1; + + QUrl url = requestUrl(defaultConnectionType()); + url.setPath("/index.html"); + QNetworkRequest request(url); + + QByteArray expectedBody = "Hello, World!"; + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); + QScopedPointer<QNetworkReply> reply; + reply.reset(manager->post(request, expectedBody)); + + bool authenticationRequested = false; + connect(manager.get(), &QNetworkAccessManager::authenticationRequired, reply.get(), + [&](QNetworkReply *, QAuthenticator *) { + authenticationRequested = true; + }); + + bool finishedReceived = false; + connect(reply.get(), &QNetworkReply::finished, reply.get(), + [&]() { finishedReceived = true; }); + bool errorReceived = false; + connect(reply.get(), &QNetworkReply::errorOccurred, reply.get(), + [&]() { errorReceived = true; }); + + QSet<quint32> receivedDataOnStreams; + connect(targetServer.get(), &Http2Server::receivedDATAFrame, reply.get(), + [&receivedDataOnStreams](quint32 streamID, const QByteArray &body) { + Q_UNUSED(body); + receivedDataOnStreams.insert(streamID); + }); + + // Use queued connection so that the finished signal can be emitted and the + // isFinished property can be set. + connect(reply.get(), &QNetworkReply::errorOccurred, this, + &tst_Http2::replyFinishedWithError, Qt::QueuedConnection); + + // Since we're using self-signed certificates, ignore SSL errors: + reply->ignoreSslErrors(); + + runEventLoop(); + STOP_ON_FAILURE + QVERIFY2(reply->isFinished(), + "The reply should error out if authentication fails, or finish if it succeeds"); + + QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError); + QVERIFY(reply->isFinished()); + QVERIFY(errorReceived); + QVERIFY(finishedReceived); + QCOMPARE(receivedDataOnStreams.size(), 1); + QVERIFY(receivedDataOnStreams.contains(1)); // the original, failed, request + + QVERIFY(!authenticationRequested); + + // We should not have sent any authentication headers to the server, since + // we don't support the challenge. + const QByteArray reqAuthHeader = targetServer->requestAuthorizationHeader(); + QVERIFY(reqAuthHeader.isEmpty()); + + // In the `!success` case we need to wait for the server to emit this or it might cause issues + // in the next test running after this. In the `success` case we anyway expect it to have been + // received. + QTRY_VERIFY(serverGotSettingsACK); + +} + +void tst_Http2::h2cAllowedAttribute_data() +{ + QTest::addColumn<bool>("h2cAllowed"); + QTest::addColumn<bool>("useAttribute"); // true: use attribute, false: use environment variable + QTest::addColumn<bool>("success"); + + QTest::addRow("h2c-not-allowed") << false << false << false; + // Use the attribute to enable/disable the H2C: + QTest::addRow("attribute") << true << true << true; + // Use the QT_NETWORK_H2C_ALLOWED environment variable to enable/disable the H2C: + QTest::addRow("environment-variable") << true << false << true; +} + +void tst_Http2::h2cAllowedAttribute() +{ + QFETCH(const bool, h2cAllowed); + QFETCH(const bool, useAttribute); + QFETCH(const bool, success); + + clearHTTP2State(); + serverPort = 0; + + ServerPtr targetServer(newServer(defaultServerSettings, H2Type::h2c)); + targetServer->setResponseBody("Hello"); + + QMetaObject::invokeMethod(targetServer.data(), "startServer", Qt::QueuedConnection); + runEventLoop(); + + QVERIFY(serverPort != 0); + + nRequests = 1; + + auto url = requestUrl(H2Type::h2c); + url.setPath("/index.html"); + QNetworkRequest request(url); + if (h2cAllowed) { + if (useAttribute) + request.setAttribute(QNetworkRequest::Http2CleartextAllowedAttribute, true); + else + qputenv("QT_NETWORK_H2C_ALLOWED", "1"); + } + auto envCleanup = qScopeGuard([]() { qunsetenv("QT_NETWORK_H2C_ALLOWED"); }); + + QScopedPointer<QNetworkReply> reply; + reply.reset(manager->get(request)); + + if (success) + connect(reply.get(), &QNetworkReply::finished, this, &tst_Http2::replyFinished); + else + connect(reply.get(), &QNetworkReply::errorOccurred, this, &tst_Http2::replyFinishedWithError); + + // Since we're using self-signed certificates, + // ignore SSL errors: + reply->ignoreSslErrors(); + + runEventLoop(); + STOP_ON_FAILURE + + if (!success) { + QCOMPARE(reply->error(), QNetworkReply::ConnectionRefusedError); + } else { + QCOMPARE(reply->readAll(), QByteArray("Hello")); + QTRY_VERIFY(serverGotSettingsACK); + } +} + +void tst_Http2::redirect_data() +{ + QTest::addColumn<int>("maxRedirects"); + QTest::addColumn<int>("redirectCount"); + QTest::addColumn<bool>("success"); + + QTest::addRow("1-redirects-none-allowed-failure") << 0 << 1 << false; + QTest::addRow("1-redirects-success") << 1 << 1 << true; + QTest::addRow("2-redirects-1-allowed-failure") << 1 << 2 << false; +} + +void tst_Http2::redirect() +{ + QFETCH(const int, maxRedirects); + QFETCH(const int, redirectCount); + QFETCH(const bool, success); + const QByteArray redirectUrl = "/b.html"_ba; + + clearHTTP2State(); + serverPort = 0; + + ServerPtr targetServer(newServer(defaultServerSettings, defaultConnectionType())); + targetServer->setRedirect(redirectUrl, redirectCount); + + QMetaObject::invokeMethod(targetServer.data(), "startServer", Qt::QueuedConnection); + runEventLoop(); + + QVERIFY(serverPort != 0); + + nRequests = 1; + + auto originalUrl = requestUrl(defaultConnectionType()); + auto url = originalUrl; + url.setPath("/index.html"); + QNetworkRequest request(url); + request.setMaximumRedirectsAllowed(maxRedirects); + // H2C might be used on macOS where SecureTransport doesn't support server-side ALPN + qputenv("QT_NETWORK_H2C_ALLOWED", "1"); + auto envCleanup = qScopeGuard([]() { qunsetenv("QT_NETWORK_H2C_ALLOWED"); }); + + QScopedPointer<QNetworkReply> reply; + reply.reset(manager->get(request)); + + if (success) { + connect(reply.get(), &QNetworkReply::finished, this, &tst_Http2::replyFinished); + } else { + connect(reply.get(), &QNetworkReply::errorOccurred, this, + &tst_Http2::replyFinishedWithError); + } + + // Since we're using self-signed certificates, + // ignore SSL errors: + reply->ignoreSslErrors(); + + runEventLoop(); + STOP_ON_FAILURE + + QCOMPARE(nRequests, 0); + if (success) { + QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->url().toString(), + originalUrl.resolved(QString::fromLatin1(redirectUrl)).toString()); + } else if (maxRedirects < redirectCount) { + QCOMPARE(reply->error(), QNetworkReply::TooManyRedirectsError); + } + QTRY_VERIFY(serverGotSettingsACK); +} + +void tst_Http2::trailingHEADERS() +{ + clearHTTP2State(); + serverPort = 0; + + ServerPtr targetServer(newServer(defaultServerSettings, defaultConnectionType())); + targetServer->setSendTrailingHEADERS(true); + + QMetaObject::invokeMethod(targetServer.data(), "startServer", Qt::QueuedConnection); + runEventLoop(); + + QVERIFY(serverPort != 0); + + nRequests = 1; + + const auto url = requestUrl(defaultConnectionType()); + QNetworkRequest request(url); + // H2C might be used on macOS where SecureTransport doesn't support server-side ALPN + request.setAttribute(QNetworkRequest::Http2CleartextAllowedAttribute, true); + + std::unique_ptr<QNetworkReply> reply{ manager->get(request) }; + connect(reply.get(), &QNetworkReply::finished, this, &tst_Http2::replyFinished); + + // Since we're using self-signed certificates, ignore SSL errors: + reply->ignoreSslErrors(); + + runEventLoop(); + STOP_ON_FAILURE + + QCOMPARE(nRequests, 0); + + QCOMPARE(reply->error(), QNetworkReply::NoError); + QTRY_VERIFY(serverGotSettingsACK); +} + +void tst_Http2::duplicateRequestsWithAborts() +{ + clearHTTP2State(); + serverPort = 0; + + ServerPtr targetServer(newServer(defaultServerSettings, defaultConnectionType())); + + QMetaObject::invokeMethod(targetServer.data(), "startServer", Qt::QueuedConnection); + runEventLoop(); + + QVERIFY(serverPort != 0); + + constexpr int ExpectedSuccessfulRequests = 1; + nRequests = ExpectedSuccessfulRequests; + + const auto url = requestUrl(defaultConnectionType()); + QNetworkRequest request(url); + // H2C might be used on macOS where SecureTransport doesn't support server-side ALPN + request.setAttribute(QNetworkRequest::Http2CleartextAllowedAttribute, true); + + qint32 finishedCount = 0; + auto connectToSlots = [this, &finishedCount](QNetworkReply *reply){ + const auto onFinished = [&finishedCount, reply, this]() { + ++finishedCount; + if (reply->error() == QNetworkReply::NoError) + replyFinished(); + }; + connect(reply, &QNetworkReply::finished, reply, onFinished); + }; + + std::vector<QNetworkReply *> replies; + for (qint32 i = 0; i < 3; ++i) { + auto &reply = replies.emplace_back(manager->get(request)); + connectToSlots(reply); + if (i < 2) // Delete and abort all-but-one: + reply->deleteLater(); + // Since we're using self-signed certificates, ignore SSL errors: + reply->ignoreSslErrors(); + } + + runEventLoop(); + STOP_ON_FAILURE + + QCOMPARE(nRequests, 0); + QCOMPARE(finishedCount, ExpectedSuccessfulRequests); +} + void tst_Http2::serverStarted(quint16 port) { serverPort = port; @@ -894,6 +1556,7 @@ void tst_Http2::clearHTTP2State() windowUpdates = 0; prefaceOK = false; serverGotSettingsACK = false; + POSTResponseHEADOnly = true; } void tst_Http2::runEventLoop(int ms) @@ -939,6 +1602,7 @@ void tst_Http2::sendRequest(int streamNumber, url.setPath(QString("/stream%1.html").arg(streamNumber)); QNetworkRequest request(url); + request.setAttribute(QNetworkRequest::Http2CleartextAllowedAttribute, true); request.setAttribute(QNetworkRequest::Http2AllowedAttribute, QVariant(true)); request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy); request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain")); @@ -1026,7 +1690,7 @@ void tst_Http2::receivedData(quint32 streamID) Q_ASSERT(srv); QMetaObject::invokeMethod(srv, "sendResponse", Qt::QueuedConnection, Q_ARG(quint32, streamID), - Q_ARG(bool, true /*HEADERS only*/)); + Q_ARG(bool, POSTResponseHEADOnly /*true = HEADERS only*/)); } void tst_Http2::windowUpdated(quint32 streamID) diff --git a/tests/auto/network/access/qabstractnetworkcache/CMakeLists.txt b/tests/auto/network/access/qabstractnetworkcache/CMakeLists.txt index 9ebd765fd4..37c3dbda8a 100644 --- a/tests/auto/network/access/qabstractnetworkcache/CMakeLists.txt +++ b/tests/auto/network/access/qabstractnetworkcache/CMakeLists.txt @@ -1,23 +1,29 @@ -# Generated from qabstractnetworkcache.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qabstractnetworkcache Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qabstractnetworkcache LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + # Collect test data file(GLOB_RECURSE test_data_glob RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} tests/*) list(APPEND test_data ${test_data_glob}) -qt_add_test(tst_qabstractnetworkcache +qt_internal_add_test(tst_qabstractnetworkcache SOURCES tst_qabstractnetworkcache.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Network TESTDATA ${test_data} - QT_TEST_SERVER_LIST "apache2" # special case + QT_TEST_SERVER_LIST "apache2" ) -#### Keys ignored in scope 1:.:.:qabstractnetworkcache.pro:<TRUE>: # QT_TEST_SERVER_LIST = "apache2" diff --git a/tests/auto/network/access/qabstractnetworkcache/qabstractnetworkcache.pro b/tests/auto/network/access/qabstractnetworkcache/qabstractnetworkcache.pro deleted file mode 100644 index c722100ead..0000000000 --- a/tests/auto/network/access/qabstractnetworkcache/qabstractnetworkcache.pro +++ /dev/null @@ -1,9 +0,0 @@ -CONFIG += testcase -TARGET = tst_qabstractnetworkcache -QT = core network testlib -SOURCES += tst_qabstractnetworkcache.cpp - -TESTDATA += tests/* - -CONFIG += unsupported/testserver -QT_TEST_SERVER_LIST = apache2 diff --git a/tests/auto/network/access/qabstractnetworkcache/tst_qabstractnetworkcache.cpp b/tests/auto/network/access/qabstractnetworkcache/tst_qabstractnetworkcache.cpp index 4b392d867c..95f067a66e 100644 --- a/tests/auto/network/access/qabstractnetworkcache/tst_qabstractnetworkcache.cpp +++ b/tests/auto/network/access/qabstractnetworkcache/tst_qabstractnetworkcache.cpp @@ -1,34 +1,11 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTemporaryDir> -#include <QtTest/QtTest> +#include <QTest> #include <QtNetwork/QtNetwork> +#include <QSignalSpy> + #include "../../../network-settings.h" #include <algorithm> @@ -73,11 +50,12 @@ private: }; +#if QT_CONFIG(networkdiskcache) class NetworkDiskCache : public QNetworkDiskCache { Q_OBJECT public: - NetworkDiskCache(QObject *parent = 0) + NetworkDiskCache(QObject *parent = nullptr) : QNetworkDiskCache(parent) , tempDir(QDir::tempPath() + QLatin1String("/tst_qabstractnetworkcache.XXXXXX")) , gotData(false) @@ -95,6 +73,7 @@ public: QTemporaryDir tempDir; bool gotData; }; +#endif tst_QAbstractNetworkCache::tst_QAbstractNetworkCache() @@ -277,10 +256,12 @@ void tst_QAbstractNetworkCache::runTest() QFETCH(bool, fetchFromCache); QNetworkAccessManager manager; +#if QT_CONFIG(networkdiskcache) NetworkDiskCache *diskCache = new NetworkDiskCache(&manager); QVERIFY2(diskCache->tempDir.isValid(), qPrintable(diskCache->tempDir.errorString())); manager.setCache(diskCache); QCOMPARE(diskCache->gotData, false); +#endif QUrl realUrl = url.contains("://") ? url : TESTFILE + url; QNetworkRequest request(realUrl); @@ -288,8 +269,10 @@ void tst_QAbstractNetworkCache::runTest() // prime the cache QNetworkReply *reply = manager.get(request); QSignalSpy downloaded1(reply, SIGNAL(finished())); - QTRY_COMPARE(downloaded1.count(), 1); + QTRY_COMPARE(downloaded1.size(), 1); +#if QT_CONFIG(networkdiskcache) QCOMPARE(diskCache->gotData, false); +#endif QByteArray goodData = reply->readAll(); request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, cacheLoadControl); @@ -297,7 +280,7 @@ void tst_QAbstractNetworkCache::runTest() // should be in the cache now QNetworkReply *reply2 = manager.get(request); QSignalSpy downloaded2(reply2, SIGNAL(finished())); - QTRY_COMPARE(downloaded2.count(), 1); + QTRY_COMPARE(downloaded2.size(), 1); QByteArray secondData = reply2->readAll(); if (!fetchFromCache && cacheLoadControl == QNetworkRequest::AlwaysCache) { @@ -316,7 +299,9 @@ void tst_QAbstractNetworkCache::runTest() std::sort(rawHeaderList.begin(), rawHeaderList.end()); std::sort(rawHeaderList2.begin(), rawHeaderList2.end()); } +#if QT_CONFIG(networkdiskcache) QCOMPARE(diskCache->gotData, fetchFromCache); +#endif } void tst_QAbstractNetworkCache::checkSynchronous() @@ -328,10 +313,12 @@ void tst_QAbstractNetworkCache::checkSynchronous() QFETCH(bool, fetchFromCache); QNetworkAccessManager manager; +#if QT_CONFIG(networkdiskcache) NetworkDiskCache *diskCache = new NetworkDiskCache(&manager); QVERIFY2(diskCache->tempDir.isValid(), qPrintable(diskCache->tempDir.errorString())); manager.setCache(diskCache); QCOMPARE(diskCache->gotData, false); +#endif QUrl realUrl = url.contains("://") ? url : TESTFILE + url; QNetworkRequest request(realUrl); @@ -343,7 +330,9 @@ void tst_QAbstractNetworkCache::checkSynchronous() // prime the cache QNetworkReply *reply = manager.get(request); QVERIFY(reply->isFinished()); // synchronous +#if QT_CONFIG(networkdiskcache) QCOMPARE(diskCache->gotData, false); +#endif QByteArray goodData = reply->readAll(); request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, cacheLoadControl); @@ -371,22 +360,26 @@ void tst_QAbstractNetworkCache::checkSynchronous() std::sort(rawHeaderList.begin(), rawHeaderList.end()); std::sort(rawHeaderList2.begin(), rawHeaderList2.end()); } +#if QT_CONFIG(networkdiskcache) QCOMPARE(diskCache->gotData, fetchFromCache); +#endif } void tst_QAbstractNetworkCache::deleteCache() { QNetworkAccessManager manager; +#if QT_CONFIG(networkdiskcache) NetworkDiskCache *diskCache = new NetworkDiskCache(&manager); QVERIFY2(diskCache->tempDir.isValid(), qPrintable(diskCache->tempDir.errorString())); manager.setCache(diskCache); +#endif QString url = "httpcachetest_cachecontrol.cgi?max-age=1000"; QNetworkRequest request(QUrl(TESTFILE + url)); QNetworkReply *reply = manager.get(request); QSignalSpy downloaded1(reply, SIGNAL(finished())); manager.setCache(0); - QTRY_COMPARE(downloaded1.count(), 1); + QTRY_COMPARE(downloaded1.size(), 1); } diff --git a/tests/auto/network/access/qdecompresshelper/.prev_CMakeLists.txt b/tests/auto/network/access/qdecompresshelper/.prev_CMakeLists.txt deleted file mode 100644 index e8680993cb..0000000000 --- a/tests/auto/network/access/qdecompresshelper/.prev_CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -# Generated from qdecompresshelper.pro. - -##################################################################### -## tst_qdecompresshelper Test: -##################################################################### - -qt_add_test(tst_qdecompresshelper - SOURCES - gzip.rcc.cpp - inflate.rcc.cpp - tst_qdecompresshelper.cpp - DEFINES - SRC_DIR="${CMAKE_CURRENT_SOURCE_DIR}" - PUBLIC_LIBRARIES - Qt::NetworkPrivate -) - -#### Keys ignored in scope 1:.:.:qdecompresshelper.pro:<TRUE>: -# TEMPLATE = "app" diff --git a/tests/auto/network/access/qdecompresshelper/10K.gz b/tests/auto/network/access/qdecompresshelper/10K.gz Binary files differnew file mode 100644 index 0000000000..c5c4959763 --- /dev/null +++ b/tests/auto/network/access/qdecompresshelper/10K.gz diff --git a/tests/auto/network/access/qdecompresshelper/BLACKLIST b/tests/auto/network/access/qdecompresshelper/BLACKLIST new file mode 100644 index 0000000000..d189fd9e00 --- /dev/null +++ b/tests/auto/network/access/qdecompresshelper/BLACKLIST @@ -0,0 +1,2 @@ +[bigZlib] +macos arm diff --git a/tests/auto/network/access/qdecompresshelper/CMakeLists.txt b/tests/auto/network/access/qdecompresshelper/CMakeLists.txt index 3b2f1b5e6f..09317ca3eb 100644 --- a/tests/auto/network/access/qdecompresshelper/CMakeLists.txt +++ b/tests/auto/network/access/qdecompresshelper/CMakeLists.txt @@ -1,20 +1,24 @@ -# Generated from qdecompresshelper.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qdecompresshelper Test: ##################################################################### -qt_add_test(tst_qdecompresshelper +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qdecompresshelper LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qdecompresshelper SOURCES gzip.rcc.cpp inflate.rcc.cpp tst_qdecompresshelper.cpp zstandard.rcc.cpp DEFINES - SRC_DIR=${CMAKE_CURRENT_SOURCE_DIR} # special case - PUBLIC_LIBRARIES + SRC_DIR=${CMAKE_CURRENT_SOURCE_DIR} + LIBRARIES Qt::NetworkPrivate ) - -#### Keys ignored in scope 1:.:.:qdecompresshelper.pro:<TRUE>: -# TEMPLATE = "app" diff --git a/tests/auto/network/access/qdecompresshelper/qdecompresshelper.pro b/tests/auto/network/access/qdecompresshelper/qdecompresshelper.pro deleted file mode 100644 index 254f04a707..0000000000 --- a/tests/auto/network/access/qdecompresshelper/qdecompresshelper.pro +++ /dev/null @@ -1,12 +0,0 @@ -QT = network-private testlib -CONFIG += testcase parallel_test -TEMPLATE = app -TARGET = tst_qdecompresshelper - -SOURCES += \ - tst_qdecompresshelper.cpp \ - gzip.rcc.cpp \ - inflate.rcc.cpp \ - zstandard.rcc.cpp \ - -DEFINES += SRC_DIR="$$PWD" diff --git a/tests/auto/network/access/qdecompresshelper/tst_qdecompresshelper.cpp b/tests/auto/network/access/qdecompresshelper/tst_qdecompresshelper.cpp index 7a3aa37a47..cd5a52c209 100644 --- a/tests/auto/network/access/qdecompresshelper/tst_qdecompresshelper.cpp +++ b/tests/auto/network/access/qdecompresshelper/tst_qdecompresshelper.cpp @@ -1,32 +1,7 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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> +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QTest> #include <QtNetwork/private/qdecompresshelper_p.h> @@ -64,9 +39,10 @@ private Q_SLOTS: void decompressBigData_data(); void decompressBigData(); -#if QT_POINTER_SIZE >= 8 + void archiveBomb_data(); + void archiveBomb(); + void bigZlib(); -#endif }; void tst_QDecompressHelper::initTestCase() @@ -343,23 +319,30 @@ void tst_QDecompressHelper::countAheadPartialRead() void tst_QDecompressHelper::decompressBigData_data() { +#if defined(QT_ASAN_ENABLED) + QSKIP("Tests are too slow with asan enabled"); +#endif QTest::addColumn<QByteArray>("encoding"); QTest::addColumn<QString>("path"); QTest::addColumn<qint64>("size"); + QTest::addColumn<bool>("countAhead"); qint64 fourGiB = 4ll * 1024ll * 1024ll * 1024ll; qint64 fiveGiB = 5ll * 1024ll * 1024ll * 1024ll; - QTest::newRow("gzip-4G") << QByteArray("gzip") << QString(":/4G.gz") << fourGiB; + // Only use countAhead on one of these since they share codepath anyway + QTest::newRow("gzip-counted-4G") << QByteArray("gzip") << QString(":/4G.gz") << fourGiB << true; QTest::newRow("deflate-5G") << QByteArray("deflate") << QString(":/5GiB.txt.inflate") - << fiveGiB; + << fiveGiB << false; #if QT_CONFIG(brotli) - QTest::newRow("brotli-4G") << QByteArray("br") << (srcDir + "/4G.br") << fourGiB; + QTest::newRow("brotli-4G") << QByteArray("br") << (srcDir + "/4G.br") << fourGiB << false; + QTest::newRow("brotli-counted-4G") << QByteArray("br") << (srcDir + "/4G.br") << fourGiB << true; #endif #if QT_CONFIG(zstd) - QTest::newRow("zstandard-4G") << QByteArray("zstd") << (":/4G.zst") << fourGiB; + QTest::newRow("zstandard-4G") << QByteArray("zstd") << (":/4G.zst") << fourGiB << false; + QTest::newRow("zstandard-counted-4G") << QByteArray("zstd") << (":/4G.zst") << fourGiB << true; #endif } @@ -372,15 +355,20 @@ void tst_QDecompressHelper::decompressBigData() const qint64 third = file.bytesAvailable() / 3; QDecompressHelper helper; + QFETCH(bool, countAhead); + helper.setCountingBytesEnabled(countAhead); + helper.setDecompressedSafetyCheckThreshold(-1); QFETCH(QByteArray, encoding); helper.setEncoding(encoding); - QByteArray output(32 * 1024, Qt::Uninitialized); + // The size of 'output' should be at least QDecompressHelper::MaxDecompressedDataBufferSize + 1 + QByteArray output(10 * 1024 * 1024 + 1, Qt::Uninitialized); qint64 totalSize = 0; while (!file.atEnd()) { helper.feed(file.read(third)); while (helper.hasData()) { qsizetype bytesRead = helper.read(output.data(), output.size()); + QVERIFY(bytesRead >= 0); QVERIFY(bytesRead <= output.size()); totalSize += bytesRead; const auto isZero = [](char c) { return c == '\0'; }; @@ -391,9 +379,56 @@ void tst_QDecompressHelper::decompressBigData() QTEST(totalSize, "size"); } -#if QT_POINTER_SIZE >= 8 +void tst_QDecompressHelper::archiveBomb_data() +{ + QTest::addColumn<QByteArray>("encoding"); + QTest::addColumn<QString>("path"); + QTest::addColumn<bool>("shouldFail"); + + QTest::newRow("gzip-10K") << QByteArray("gzip") << (srcDir + "/10K.gz") << false; + QTest::newRow("gzip-4G") << QByteArray("gzip") << QString(":/4G.gz") << true; +} + +void tst_QDecompressHelper::archiveBomb() +{ + QFETCH(bool, shouldFail); + QFETCH(QString, path); + QFile file(path); + QVERIFY(file.open(QIODevice::ReadOnly)); + + QDecompressHelper helper; + QFETCH(QByteArray, encoding); + helper.setEncoding(encoding); + QVERIFY(helper.isValid()); + + constexpr qint64 SafeSizeLimit = 10 * 1024 * 1024; + constexpr qint64 RatioLimit = 40; + qint64 bytesToRead = std::min(SafeSizeLimit / RatioLimit, file.bytesAvailable()); + QByteArray output(1 + bytesToRead * RatioLimit, Qt::Uninitialized); + helper.feed(file.read(bytesToRead)); + qsizetype bytesRead = helper.read(output.data(), output.size()); + QVERIFY(bytesRead <= output.size()); + QVERIFY(helper.isValid()); + + if (shouldFail) { + QCOMPARE(bytesRead, -1); + QVERIFY(!helper.errorString().isEmpty()); + } else { + QVERIFY(bytesRead > 0); + QVERIFY(helper.errorString().isEmpty()); + } +} + void tst_QDecompressHelper::bigZlib() { +#if QT_POINTER_SIZE < 8 + QSKIP("This cannot be tested on 32-bit systems"); +#elif defined(QT_ASAN_ENABLED) + QSKIP("Test is too slow with asan enabled"); +#else +# ifndef QT_NO_EXCEPTIONS + try { +# endif // ZLib uses unsigned integers as their size type internally which creates some special // cases in the internal code that should be tested! QFile file(":/5GiB.txt.inflate"); @@ -401,19 +436,25 @@ void tst_QDecompressHelper::bigZlib() QByteArray compressedData = file.readAll(); QDecompressHelper helper; + helper.setDecompressedSafetyCheckThreshold(-1); helper.setEncoding("deflate"); auto firstHalf = compressedData.left(compressedData.size() - 2); helper.feed(firstHalf); helper.feed(compressedData.mid(firstHalf.size())); // We need the whole thing in one go... which is why this test is not available for 32-bit - qint64 expected = 5ll * 1024ll * 1024ll * 1024ll; - // This can be replaced with QByteArray after the qsizetype change is merged - std::unique_ptr<char[]> output(new char[expected]); - qsizetype size = helper.read(output.get(), expected); + const qint64 expected = 5ll * 1024ll * 1024ll * 1024ll; + // Request a few more byte than what is available, to verify exact size + QByteArray output(expected + 42, Qt::Uninitialized); + const qsizetype size = helper.read(output.data(), output.size()); QCOMPARE(size, expected); -} +# ifndef QT_NO_EXCEPTIONS + } catch (const std::bad_alloc &) { + QSKIP("Encountered most likely OOM."); + } +# endif #endif +} QTEST_MAIN(tst_QDecompressHelper) diff --git a/tests/auto/network/access/qformdatabuilder/CMakeLists.txt b/tests/auto/network/access/qformdatabuilder/CMakeLists.txt new file mode 100644 index 0000000000..dde2dc10e0 --- /dev/null +++ b/tests/auto/network/access/qformdatabuilder/CMakeLists.txt @@ -0,0 +1,22 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qformdatabuilder LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qformdatabuilder + SOURCES + tst_qformdatabuilder.cpp + LIBRARIES + Qt::Core + Qt::Network + TESTDATA + rfc3252.txt + image1.jpg + document.docx + sheet.xlsx +) + diff --git a/tests/auto/network/access/qformdatabuilder/document.docx b/tests/auto/network/access/qformdatabuilder/document.docx Binary files differnew file mode 100644 index 0000000000..49005f14b6 --- /dev/null +++ b/tests/auto/network/access/qformdatabuilder/document.docx diff --git a/tests/auto/network/access/qformdatabuilder/image1.jpg b/tests/auto/network/access/qformdatabuilder/image1.jpg Binary files differnew file mode 100644 index 0000000000..d1d27bf7cf --- /dev/null +++ b/tests/auto/network/access/qformdatabuilder/image1.jpg diff --git a/tests/auto/network/access/qformdatabuilder/rfc3252.txt b/tests/auto/network/access/qformdatabuilder/rfc3252.txt new file mode 100644 index 0000000000..5436ce5b26 --- /dev/null +++ b/tests/auto/network/access/qformdatabuilder/rfc3252.txt @@ -0,0 +1 @@ +some text for reference diff --git a/tests/auto/network/access/qformdatabuilder/sheet.xlsx b/tests/auto/network/access/qformdatabuilder/sheet.xlsx Binary files differnew file mode 100644 index 0000000000..2cb1ec7361 --- /dev/null +++ b/tests/auto/network/access/qformdatabuilder/sheet.xlsx diff --git a/tests/auto/network/access/qformdatabuilder/tst_qformdatabuilder.cpp b/tests/auto/network/access/qformdatabuilder/tst_qformdatabuilder.cpp new file mode 100644 index 0000000000..ad40c79bf9 --- /dev/null +++ b/tests/auto/network/access/qformdatabuilder/tst_qformdatabuilder.cpp @@ -0,0 +1,203 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QtNetwork/qformdatabuilder.h> + +#include <QtCore/qbuffer.h> +#include <QtCore/qfile.h> + +#include <QtTest/qtest.h> + +using namespace Qt::StringLiterals; + +class tst_QFormDataBuilder : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void generateQHttpPartWithDevice_data(); + void generateQHttpPartWithDevice(); + + void escapesBackslashAndQuotesInFilenameAndName_data(); + void escapesBackslashAndQuotesInFilenameAndName(); + + void picksUtf8EncodingOnlyIfL1OrAsciiDontSuffice_data(); + void picksUtf8EncodingOnlyIfL1OrAsciiDontSuffice(); +}; + +void tst_QFormDataBuilder::generateQHttpPartWithDevice_data() +{ + QTest::addColumn<QLatin1StringView>("name_data"); + QTest::addColumn<QString>("real_file_name"); + QTest::addColumn<QString>("body_name_data"); + QTest::addColumn<QByteArray>("expected_content_type_data"); + QTest::addColumn<QByteArray>("expected_content_disposition_data"); + + QTest::newRow("txt-ascii") << "text"_L1 << "rfc3252.txt" << "rfc3252.txt" << "text/plain"_ba + << "form-data; name=\"text\"; filename=rfc3252.txt"_ba; + QTest::newRow("txt-latin") << "text"_L1 << "rfc3252.txt" << "szöveg.txt" << "text/plain"_ba + << "form-data; name=\"text\"; filename*=ISO-8859-1''sz%F6veg.txt"_ba; + QTest::newRow("txt-unicode") << "text"_L1 << "rfc3252.txt" << "テキスト.txt" << "text/plain"_ba + << "form-data; name=\"text\"; filename*=UTF-8''%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88.txt"_ba; + + QTest::newRow("jpg-ascii") << "image"_L1 << "image1.jpg" << "image1.jpg" << "image/jpeg"_ba + << "form-data; name=\"image\"; filename=image1.jpg"_ba; + QTest::newRow("jpg-latin") << "image"_L1 << "image1.jpg" << "kép.jpg" << "image/jpeg"_ba + << "form-data; name=\"image\"; filename*=ISO-8859-1''k%E9p.jpg"_ba; + QTest::newRow("jpg-unicode") << "image"_L1 << "image1.jpg" << "絵.jpg" << "image/jpeg"_ba + << "form-data; name=\"image\"; filename*=UTF-8''%E7%B5%B5"_ba; + + QTest::newRow("doc-ascii") << "text"_L1 << "document.docx" << "word.docx" + << "application/vnd.openxmlformats-officedocument.wordprocessingml.document"_ba + << "form-data; name=\"text\"; filename=word.docx"_ba; + QTest::newRow("doc-latin") << "text"_L1 << "document.docx" << "szöveg.docx" + << "application/vnd.openxmlformats-officedocument.wordprocessingml.document"_ba + << "form-data; name=\"text\"; filename*=ISO-8859-1''sz%F6veg.docx"_ba; + QTest::newRow("doc-unicode") << "text"_L1 << "document.docx" << "テキスト.docx" + << "application/vnd.openxmlformats-officedocument.wordprocessingml.document"_ba + << "form-data; name=\"text\"; filename*=UTF-8''%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88.docx"_ba; + + QTest::newRow("xls-ascii") << "spreadsheet"_L1 << "sheet.xlsx" << "sheet.xlsx" + << "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"_ba + << "form-data; name=\"spreadsheet\"; filename=sheet.xlsx"_ba; + QTest::newRow("xls-latin") << "spreadsheet"_L1 << "sheet.xlsx" << "szöveg.xlsx" + << "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"_ba + << "form-data; name=\"spreadsheet\"; filename*=ISO-8859-1''sz%F6veg.xlsx"_ba; + QTest::newRow("xls-unicode") << "spreadsheet"_L1 << "sheet.xlsx" << "テキスト.xlsx" + << "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"_ba + << "form-data; name=\"spreadsheet\"; filename*=UTF-8''%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88.xlsx"_ba; + +} + +void tst_QFormDataBuilder::generateQHttpPartWithDevice() +{ + QFETCH(const QLatin1StringView, name_data); + QFETCH(const QString, real_file_name); + QFETCH(const QString, body_name_data); + QFETCH(const QByteArray, expected_content_type_data); + QFETCH(const QByteArray, expected_content_disposition_data); + + QString testData = QFileInfo(QFINDTESTDATA(real_file_name)).absoluteFilePath(); + QFile data_file(testData); + + QHttpPart httpPart = QFormDataPartBuilder(name_data, QFormDataPartBuilder::PrivateConstructor()) + .setBodyDevice(&data_file, body_name_data) + .build(); + + QByteArray msg; + { + QBuffer buf(&msg); + QVERIFY(buf.open(QIODevice::WriteOnly)); + QDebug debug(&buf); + debug << httpPart; + } + + QVERIFY(msg.contains(expected_content_type_data)); + QVERIFY(msg.contains(expected_content_disposition_data)); +} + +void tst_QFormDataBuilder::escapesBackslashAndQuotesInFilenameAndName_data() +{ + QTest::addColumn<QLatin1StringView>("name_data"); + QTest::addColumn<QString>("body_name_data"); + QTest::addColumn<QByteArray>("expected_content_type_data"); + QTest::addColumn<QByteArray>("expected_content_disposition_data"); + + QTest::newRow("quote") << "t\"ext"_L1 << "rfc3252.txt" << "text/plain"_ba + << R"(form-data; name="t\"ext"; filename=rfc3252.txt)"_ba; + + QTest::newRow("slash") << "t\\ext"_L1 << "rfc3252.txt" << "text/plain"_ba + << R"(form-data; name="t\\ext"; filename=rfc3252.txt)"_ba; + + QTest::newRow("quotes") << "t\"e\"xt"_L1 << "rfc3252.txt" << "text/plain"_ba + << R"(form-data; name="t\"e\"xt"; filename=rfc3252.txt)"_ba; + + QTest::newRow("slashes") << "t\\\\ext"_L1 << "rfc3252.txt" << "text/plain"_ba + << R"(form-data; name="t\\\\ext"; filename=rfc3252.txt)"_ba; + + QTest::newRow("quote-slash") << "t\"ex\\t"_L1 << "rfc3252.txt" << "text/plain"_ba + << R"(form-data; name="t\"ex\\t"; filename=rfc3252.txt)"_ba; + + QTest::newRow("quotes-slashes") << "t\"e\"x\\t\\"_L1 << "rfc3252.txt" << "text/plain"_ba + << R"(form-data; name="t\"e\"x\\t\\"; filename=rfc3252.txt)"_ba; +} + +void tst_QFormDataBuilder::escapesBackslashAndQuotesInFilenameAndName() +{ + QFETCH(const QLatin1StringView, name_data); + QFETCH(const QString, body_name_data); + QFETCH(const QByteArray, expected_content_type_data); + QFETCH(const QByteArray, expected_content_disposition_data); + + QFile dummy_file(body_name_data); + + QHttpPart httpPart = QFormDataPartBuilder(name_data, QFormDataPartBuilder::PrivateConstructor()) + .setBodyDevice(&dummy_file, body_name_data) + .build(); + + QByteArray msg; + { + QBuffer buf(&msg); + QVERIFY(buf.open(QIODevice::WriteOnly)); + QDebug debug(&buf); + debug << httpPart; + } + + QVERIFY(msg.contains(expected_content_type_data)); + QVERIFY(msg.contains(expected_content_disposition_data)); +} + +void tst_QFormDataBuilder::picksUtf8EncodingOnlyIfL1OrAsciiDontSuffice_data() +{ + QTest::addColumn<QLatin1StringView>("name_data"); + QTest::addColumn<QAnyStringView>("body_name_data"); + QTest::addColumn<QByteArray>("expected_content_type_data"); + QTest::addColumn<QByteArray>("expected_content_disposition_data"); + + QTest::newRow("latin1-ascii") << "text"_L1 << QAnyStringView("rfc3252.txt"_L1) << "text/plain"_ba + << "form-data; name=\"text\"; filename=rfc3252.txt"_ba; + QTest::newRow("u8-ascii") << "text"_L1 << QAnyStringView(u8"rfc3252.txt") << "text/plain"_ba + << "form-data; name=\"text\"; filename=rfc3252.txt"_ba; + QTest::newRow("u-ascii") << "text"_L1 << QAnyStringView(u"rfc3252.txt") << "text/plain"_ba + << "form-data; name=\"text\"; filename=rfc3252.txt"_ba; + + + QTest::newRow("latin1-latin") << "text"_L1 << QAnyStringView("sz\366veg.txt"_L1) << "text/plain"_ba + << "form-data; name=\"text\"; filename*=ISO-8859-1''sz%F6veg.txt"_ba; + QTest::newRow("u8-latin") << "text"_L1 << QAnyStringView(u8"szöveg.txt") << "text/plain"_ba + << "form-data; name=\"text\"; filename*=ISO-8859-1''sz%F6veg.txt"_ba; + QTest::newRow("u-latin") << "text"_L1 << QAnyStringView(u"szöveg.txt") << "text/plain"_ba + << "form-data; name=\"text\"; filename*=ISO-8859-1''sz%F6veg.txt"_ba; + + QTest::newRow("u8-u8") << "text"_L1 << QAnyStringView(u8"テキスト.txt") << "text/plain"_ba + << "form-data; name=\"text\"; filename*=UTF-8''%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88.txt"_ba; +} + +void tst_QFormDataBuilder::picksUtf8EncodingOnlyIfL1OrAsciiDontSuffice() +{ + QFETCH(const QLatin1StringView, name_data); + QFETCH(const QAnyStringView, body_name_data); + QFETCH(const QByteArray, expected_content_type_data); + QFETCH(const QByteArray, expected_content_disposition_data); + + QBuffer buff; + + QHttpPart httpPart = QFormDataPartBuilder(name_data, QFormDataPartBuilder::PrivateConstructor()) + .setBodyDevice(&buff, body_name_data) + .build(); + + QByteArray msg; + { + QBuffer buf(&msg); + QVERIFY(buf.open(QIODevice::WriteOnly)); + QDebug debug(&buf); + debug << httpPart; + } + + QVERIFY(msg.contains(expected_content_type_data)); + QVERIFY(msg.contains(expected_content_disposition_data)); +} + + +QTEST_MAIN(tst_QFormDataBuilder) +#include "tst_qformdatabuilder.moc" diff --git a/tests/auto/network/access/qhttp2connection/CMakeLists.txt b/tests/auto/network/access/qhttp2connection/CMakeLists.txt new file mode 100644 index 0000000000..9a6e7a064e --- /dev/null +++ b/tests/auto/network/access/qhttp2connection/CMakeLists.txt @@ -0,0 +1,16 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qhttp2connection LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qhttp2connection + SOURCES + tst_qhttp2connection.cpp + LIBRARIES + Qt::NetworkPrivate + Qt::Test +) diff --git a/tests/auto/network/access/qhttp2connection/tst_qhttp2connection.cpp b/tests/auto/network/access/qhttp2connection/tst_qhttp2connection.cpp new file mode 100644 index 0000000000..b9d5219ae9 --- /dev/null +++ b/tests/auto/network/access/qhttp2connection/tst_qhttp2connection.cpp @@ -0,0 +1,397 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QtTest/QTest> +#include <QtTest/QSignalSpy> + +#include <QtNetwork/private/qhttp2connection_p.h> +#include <QtNetwork/private/hpack_p.h> +#include <QtNetwork/private/bitstreams_p.h> + +#include <limits> + +using namespace Qt::StringLiterals; + +class tst_QHttp2Connection : public QObject +{ + Q_OBJECT + +private slots: + void construct(); + void constructStream(); + void testSETTINGSFrame(); + void testPING(); + void connectToServer(); + void WINDOW_UPDATE(); + +private: + enum PeerType { Client, Server }; + [[nodiscard]] auto makeFakeConnectedSockets(); + [[nodiscard]] auto getRequiredHeaders(); + [[nodiscard]] QHttp2Connection *makeHttp2Connection(QIODevice *socket, + QHttp2Configuration config, PeerType type); + [[nodiscard]] bool waitForSettingsExchange(QHttp2Connection *client, QHttp2Connection *server); +}; + +class IOBuffer : public QIODevice +{ + Q_OBJECT +public: + IOBuffer(QObject *parent, std::shared_ptr<QBuffer> _in, std::shared_ptr<QBuffer> _out) + : QIODevice(parent), in(std::move(_in)), out(std::move(_out)) + { + connect(in.get(), &QIODevice::readyRead, this, &IOBuffer::readyRead); + connect(out.get(), &QIODevice::bytesWritten, this, &IOBuffer::bytesWritten); + connect(out.get(), &QIODevice::aboutToClose, this, &IOBuffer::readChannelFinished); + connect(out.get(), &QIODevice::aboutToClose, this, &IOBuffer::aboutToClose); + } + + bool open(OpenMode mode) override + { + QIODevice::open(mode); + Q_ASSERT(in->isOpen()); + Q_ASSERT(out->isOpen()); + return false; + } + + bool isSequential() const override { return true; } + + qint64 bytesAvailable() const override { return in->pos() - readHead; } + qint64 bytesToWrite() const override { return 0; } + + qint64 readData(char *data, qint64 maxlen) override + { + qint64 temp = in->pos(); + in->seek(readHead); + qint64 res = in->read(data, std::min(maxlen, temp - readHead)); + readHead += res; + if (readHead == temp) { + // Reached end of buffer, reset + in->seek(0); + in->buffer().resize(0); + readHead = 0; + } else { + in->seek(temp); + } + return res; + } + + qint64 writeData(const char *data, qint64 len) override + { + return out->write(data, len); + } + + std::shared_ptr<QBuffer> in; + std::shared_ptr<QBuffer> out; + + qint64 readHead = 0; +}; + +auto tst_QHttp2Connection::makeFakeConnectedSockets() +{ + auto clientIn = std::make_shared<QBuffer>(); + auto serverIn = std::make_shared<QBuffer>(); + clientIn->open(QIODevice::ReadWrite); + serverIn->open(QIODevice::ReadWrite); + + auto client = std::make_unique<IOBuffer>(this, clientIn, serverIn); + auto server = std::make_unique<IOBuffer>(this, std::move(serverIn), std::move(clientIn)); + + client->open(QIODevice::ReadWrite); + server->open(QIODevice::ReadWrite); + + return std::pair{ std::move(client), std::move(server) }; +} + +auto tst_QHttp2Connection::getRequiredHeaders() +{ + return HPack::HttpHeader{ + { ":authority", "example.com" }, + { ":method", "GET" }, + { ":path", "/" }, + { ":scheme", "https" }, + }; +} + +QHttp2Connection *tst_QHttp2Connection::makeHttp2Connection(QIODevice *socket, + QHttp2Configuration config, + PeerType type) +{ + QHttp2Connection *connection = nullptr; + if (type == PeerType::Server) + connection = QHttp2Connection::createDirectServerConnection(socket, config); + else + connection = QHttp2Connection::createDirectConnection(socket, config); + connect(socket, &QIODevice::readyRead, connection, &QHttp2Connection::handleReadyRead); + return connection; +} + +bool tst_QHttp2Connection::waitForSettingsExchange(QHttp2Connection *client, + QHttp2Connection *server) +{ + bool settingsFrameReceived = false; + bool serverSettingsFrameReceived = false; + + QMetaObject::Connection c = connect(client, &QHttp2Connection::settingsFrameReceived, client, + [&settingsFrameReceived]() { + settingsFrameReceived = true; + }); + QMetaObject::Connection s = connect(server, &QHttp2Connection::settingsFrameReceived, server, + [&serverSettingsFrameReceived]() { + serverSettingsFrameReceived = true; + }); + + client->handleReadyRead(); // handle incoming frames, send response + + bool success = QTest::qWaitFor([&]() { + return settingsFrameReceived && serverSettingsFrameReceived; + }); + + disconnect(c); + disconnect(s); + + return success; +} + +void tst_QHttp2Connection::construct() +{ + QBuffer buffer; + buffer.open(QIODevice::ReadWrite); + auto *connection = QHttp2Connection::createDirectConnection(&buffer, {}); + QVERIFY(!connection->isGoingAway()); + QCOMPARE(connection->maxConcurrentStreams(), 100u); + QCOMPARE(connection->maxHeaderListSize(), std::numeric_limits<quint32>::max()); + QVERIFY(!connection->isUpgradedConnection()); + QVERIFY(!connection->getStream(1)); // No stream has been created yet + + auto *upgradedConnection = QHttp2Connection::createUpgradedConnection(&buffer, {}); + QVERIFY(upgradedConnection->isUpgradedConnection()); + // Stream 1 is created by default for an upgraded connection + QVERIFY(upgradedConnection->getStream(1)); +} + +void tst_QHttp2Connection::constructStream() +{ + QBuffer buffer; + buffer.open(QIODevice::ReadWrite); + auto connection = QHttp2Connection::createDirectConnection(&buffer, {}); + QHttp2Stream *stream = connection->createStream().unwrap(); + QVERIFY(stream); + QCOMPARE(stream->isPromisedStream(), false); + QCOMPARE(stream->isActive(), false); + QCOMPARE(stream->RST_STREAM_code(), 0u); + QCOMPARE(stream->streamID(), 1u); + QCOMPARE(stream->receivedHeaders(), {}); + QCOMPARE(stream->state(), QHttp2Stream::State::Idle); + QCOMPARE(stream->isUploadBlocked(), false); + QCOMPARE(stream->isUploadingDATA(), false); +} + +void tst_QHttp2Connection::testSETTINGSFrame() +{ + constexpr qint32 PrefaceLength = 24; + QBuffer buffer; + buffer.open(QIODevice::ReadWrite); + QHttp2Configuration config; + constexpr quint32 MaxFrameSize = 16394; + constexpr bool ServerPushEnabled = false; + constexpr quint32 StreamReceiveWindowSize = 50000; + constexpr quint32 SessionReceiveWindowSize = 50001; + config.setMaxFrameSize(MaxFrameSize); + config.setServerPushEnabled(ServerPushEnabled); + config.setStreamReceiveWindowSize(StreamReceiveWindowSize); + config.setSessionReceiveWindowSize(SessionReceiveWindowSize); + auto connection = QHttp2Connection::createDirectConnection(&buffer, config); + Q_UNUSED(connection); + QCOMPARE_GE(buffer.size(), PrefaceLength); + + // Preface + QByteArray preface = buffer.data().first(PrefaceLength); + QCOMPARE(preface, "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"); + + // SETTINGS + buffer.seek(PrefaceLength); + const quint32 maxSize = buffer.size() - PrefaceLength; + Http2::FrameReader reader; + Http2::FrameStatus status = reader.read(buffer); + QCOMPARE(status, Http2::FrameStatus::goodFrame); + Http2::Frame f = reader.inboundFrame(); + QCOMPARE(f.type(), Http2::FrameType::SETTINGS); + QCOMPARE_LT(f.payloadSize(), maxSize); + + const qint32 settingsReceived = f.dataSize() / 6; + QCOMPARE_GT(settingsReceived, 0); + QCOMPARE_LE(settingsReceived, 6); + + struct ExpectedSetting + { + Http2::Settings identifier; + quint32 value; + }; + // Commented-out settings are not sent since they are defaults + ExpectedSetting expectedSettings[]{ + // { Http2::Settings::HEADER_TABLE_SIZE_ID, HPack::FieldLookupTable::DefaultSize }, + { Http2::Settings::ENABLE_PUSH_ID, ServerPushEnabled ? 1 : 0 }, + // { Http2::Settings::MAX_CONCURRENT_STREAMS_ID, Http2::maxConcurrentStreams }, + { Http2::Settings::INITIAL_WINDOW_SIZE_ID, StreamReceiveWindowSize }, + { Http2::Settings::MAX_FRAME_SIZE_ID, MaxFrameSize }, + // { Http2::Settings::MAX_HEADER_LIST_SIZE_ID, ??? }, + }; + + QCOMPARE(quint32(settingsReceived), std::size(expectedSettings)); + for (qint32 i = 0; i < settingsReceived; ++i) { + const uchar *it = f.dataBegin() + i * 6; + const quint16 ident = qFromBigEndian<quint16>(it); + const quint32 intVal = qFromBigEndian<quint32>(it + 2); + + ExpectedSetting expectedSetting = expectedSettings[i]; + QVERIFY2(ident == quint16(expectedSetting.identifier), + qPrintable("ident: %1, expected: %2, index: %3"_L1 + .arg(QString::number(ident), + QString::number(quint16(expectedSetting.identifier)), + QString::number(i)))); + QVERIFY2(intVal == expectedSetting.value, + qPrintable("intVal: %1, expected: %2, index: %3"_L1 + .arg(QString::number(intVal), + QString::number(expectedSetting.value), + QString::number(i)))); + } +} + +void tst_QHttp2Connection::testPING() +{ + auto [client, server] = makeFakeConnectedSockets(); + auto connection = makeHttp2Connection(client.get(), {}, Client); + auto serverConnection = makeHttp2Connection(server.get(), {}, Server); + + QVERIFY(waitForSettingsExchange(connection, serverConnection)); + + QSignalSpy serverPingSpy{ serverConnection, &QHttp2Connection::pingFrameRecived }; + QSignalSpy clientPingSpy{ connection, &QHttp2Connection::pingFrameRecived }; + + QByteArray data{"pingpong"}; + connection->sendPing(data); + + QVERIFY(serverPingSpy.wait()); + QVERIFY(clientPingSpy.wait()); + + QCOMPARE(serverPingSpy.last().at(0).toInt(), int(QHttp2Connection::PingState::Ping)); + QCOMPARE(clientPingSpy.last().at(0).toInt(), int(QHttp2Connection::PingState::PongSignatureIdentical)); + + serverConnection->sendPing(); + + QVERIFY(clientPingSpy.wait()); + QVERIFY(serverPingSpy.wait()); + + QCOMPARE(clientPingSpy.last().at(0).toInt(), int(QHttp2Connection::PingState::Ping)); + QCOMPARE(serverPingSpy.last().at(0).toInt(), int(QHttp2Connection::PingState::PongSignatureIdentical)); +} + +void tst_QHttp2Connection::connectToServer() +{ + auto [client, server] = makeFakeConnectedSockets(); + auto connection = makeHttp2Connection(client.get(), {}, Client); + auto serverConnection = makeHttp2Connection(server.get(), {}, Server); + + QVERIFY(waitForSettingsExchange(connection, serverConnection)); + + QSignalSpy newIncomingStreamSpy{ serverConnection, &QHttp2Connection::newIncomingStream }; + QSignalSpy clientIncomingStreamSpy{ connection, &QHttp2Connection::newIncomingStream }; + + QHttp2Stream *clientStream = connection->createStream().unwrap(); + QSignalSpy clientHeaderReceivedSpy{ clientStream, &QHttp2Stream::headersReceived }; + QVERIFY(clientStream); + HPack::HttpHeader headers = getRequiredHeaders(); + clientStream->sendHEADERS(headers, false); + + QVERIFY(newIncomingStreamSpy.wait()); + auto *serverStream = newIncomingStreamSpy.front().front().value<QHttp2Stream *>(); + QVERIFY(serverStream); + const HPack::HttpHeader ExpectedResponseHeaders{ { ":status", "200" } }; + serverStream->sendHEADERS(ExpectedResponseHeaders, true); + + QVERIFY(clientHeaderReceivedSpy.wait()); + const HPack::HttpHeader + headersReceived = clientHeaderReceivedSpy.front().front().value<HPack::HttpHeader>(); + QCOMPARE(headersReceived, ExpectedResponseHeaders); + + QCOMPARE(clientIncomingStreamSpy.count(), 0); +} + +void tst_QHttp2Connection::WINDOW_UPDATE() +{ + auto [client, server] = makeFakeConnectedSockets(); + auto connection = makeHttp2Connection(client.get(), {}, Client); + + QHttp2Configuration config; + config.setStreamReceiveWindowSize(1024); // Small window on server to provoke WINDOW_UPDATE + auto serverConnection = makeHttp2Connection(server.get(), config, Server); + + QVERIFY(waitForSettingsExchange(connection, serverConnection)); + + QSignalSpy newIncomingStreamSpy{ serverConnection, &QHttp2Connection::newIncomingStream }; + + QHttp2Stream *clientStream = connection->createStream().unwrap(); + QSignalSpy clientHeaderReceivedSpy{ clientStream, &QHttp2Stream::headersReceived }; + QSignalSpy clientDataReceivedSpy{ clientStream, &QHttp2Stream::dataReceived }; + QVERIFY(clientStream); + HPack::HttpHeader expectedRequestHeaders = HPack::HttpHeader{ + { ":authority", "example.com" }, + { ":method", "POST" }, + { ":path", "/" }, + { ":scheme", "https" }, + }; + clientStream->sendHEADERS(expectedRequestHeaders, false); + + QVERIFY(newIncomingStreamSpy.wait()); + auto *serverStream = newIncomingStreamSpy.front().front().value<QHttp2Stream *>(); + QVERIFY(serverStream); + QSignalSpy serverDataReceivedSpy{ serverStream, &QHttp2Stream::dataReceived }; + + // Since a stream is only opened on the remote side when the header is received, + // we can check the headers now immediately + QCOMPARE(serverStream->receivedHeaders(), expectedRequestHeaders); + + QBuffer *buffer = new QBuffer(clientStream); + QByteArray uploadedData = "Hello World"_ba.repeated(1000); + buffer->setData(uploadedData); + buffer->open(QIODevice::ReadWrite); + clientStream->sendDATA(buffer, true); + + bool streamEnd = false; + QByteArray serverReceivedData; + while (!streamEnd) { // The window is too small to receive all data at once, so loop + QVERIFY(serverDataReceivedSpy.wait()); + auto latestEmission = serverDataReceivedSpy.back(); + serverReceivedData += latestEmission.front().value<QByteArray>(); + streamEnd = latestEmission.back().value<bool>(); + } + QCOMPARE(serverReceivedData.size(), uploadedData.size()); + QCOMPARE(serverReceivedData, uploadedData); + + QCOMPARE(clientStream->state(), QHttp2Stream::State::HalfClosedLocal); + QCOMPARE(serverStream->state(), QHttp2Stream::State::HalfClosedRemote); + + const HPack::HttpHeader ExpectedResponseHeaders{ { ":status", "200" } }; + serverStream->sendHEADERS(ExpectedResponseHeaders, false); + QBuffer *serverBuffer = new QBuffer(serverStream); + serverBuffer->setData(uploadedData); + serverBuffer->open(QIODevice::ReadWrite); + serverStream->sendDATA(serverBuffer, true); + + QVERIFY(clientHeaderReceivedSpy.wait()); + const HPack::HttpHeader + headersReceived = clientHeaderReceivedSpy.front().front().value<HPack::HttpHeader>(); + QCOMPARE(headersReceived, ExpectedResponseHeaders); + + QTRY_COMPARE_GT(clientDataReceivedSpy.count(), 0); + QCOMPARE(clientDataReceivedSpy.count(), 1); // Only one DATA frame since our window is larger + QCOMPARE(clientDataReceivedSpy.front().front().value<QByteArray>(), uploadedData); + + QCOMPARE(clientStream->state(), QHttp2Stream::State::Closed); + QCOMPARE(serverStream->state(), QHttp2Stream::State::Closed); +} + +QTEST_MAIN(tst_QHttp2Connection) + +#include "tst_qhttp2connection.moc" diff --git a/tests/auto/network/access/qhttpheaderparser/CMakeLists.txt b/tests/auto/network/access/qhttpheaderparser/CMakeLists.txt new file mode 100644 index 0000000000..50deeb3e56 --- /dev/null +++ b/tests/auto/network/access/qhttpheaderparser/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qhttpheaderparser LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +if(NOT QT_FEATURE_private_tests) + return() +endif() + +qt_internal_add_test(tst_qhttpheaderparser + SOURCES + tst_qhttpheaderparser.cpp + LIBRARIES + Qt::NetworkPrivate +) diff --git a/tests/auto/network/access/qhttpheaderparser/tst_qhttpheaderparser.cpp b/tests/auto/network/access/qhttpheaderparser/tst_qhttpheaderparser.cpp new file mode 100644 index 0000000000..9ba889fdb3 --- /dev/null +++ b/tests/auto/network/access/qhttpheaderparser/tst_qhttpheaderparser.cpp @@ -0,0 +1,94 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QtTest/qtest.h> +#include <QObject> +#include <QtNetwork/private/qhttpheaderparser_p.h> + +class tst_QHttpHeaderParser : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void constructor(); + void limitsSetters(); + + void adjustableLimits_data(); + void adjustableLimits(); + + // general parsing tests can be found in tst_QHttpNetworkReply +}; + +void tst_QHttpHeaderParser::constructor() +{ + QHttpHeaderParser parser; + QCOMPARE(parser.getStatusCode(), 100); + QCOMPARE(parser.getMajorVersion(), 0); + QCOMPARE(parser.getMinorVersion(), 0); + QCOMPARE(parser.getReasonPhrase(), QByteArray()); + QCOMPARE(parser.combinedHeaderValue("Location"), QByteArray()); + QCOMPARE(parser.maxHeaderFields(), HeaderConstants::MAX_HEADER_FIELDS); + QCOMPARE(parser.maxHeaderFieldSize(), HeaderConstants::MAX_HEADER_FIELD_SIZE); + QCOMPARE(parser.maxTotalHeaderSize(), HeaderConstants::MAX_TOTAL_HEADER_SIZE); +} + +void tst_QHttpHeaderParser::limitsSetters() +{ + QHttpHeaderParser parser; + parser.setMaxHeaderFields(10); + QCOMPARE(parser.maxHeaderFields(), 10); + parser.setMaxHeaderFieldSize(10); + QCOMPARE(parser.maxHeaderFieldSize(), 10); + parser.setMaxTotalHeaderSize(10); + QCOMPARE(parser.maxTotalHeaderSize(), 10); +} + +void tst_QHttpHeaderParser::adjustableLimits_data() +{ + QTest::addColumn<qsizetype>("maxFieldCount"); + QTest::addColumn<qsizetype>("maxFieldSize"); + QTest::addColumn<qsizetype>("maxTotalSize"); + QTest::addColumn<QByteArray>("headers"); + QTest::addColumn<bool>("success"); + + // We pretend -1 means to not set a new limit. + + QTest::newRow("maxFieldCount-pass") << qsizetype(10) << qsizetype(-1) << qsizetype(-1) + << QByteArray("Location: hi\r\n\r\n") << true; + QTest::newRow("maxFieldCount-fail") << qsizetype(1) << qsizetype(-1) << qsizetype(-1) + << QByteArray("Location: hi\r\nCookie: a\r\n\r\n") << false; + + QTest::newRow("maxFieldSize-pass") << qsizetype(-1) << qsizetype(50) << qsizetype(-1) + << QByteArray("Location: hi\r\n\r\n") << true; + constexpr char cookieHeader[] = "Cookie: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + static_assert(sizeof(cookieHeader) - 1 == 51); + QByteArray fullHeader = QByteArray("Location: hi\r\n") + cookieHeader; + QTest::newRow("maxFieldSize-fail") << qsizetype(-1) << qsizetype(50) << qsizetype(-1) + << (fullHeader + "\r\n\r\n") << false; + + QTest::newRow("maxTotalSize-pass") << qsizetype(-1) << qsizetype(-1) << qsizetype(50) + << QByteArray("Location: hi\r\n\r\n") << true; + QTest::newRow("maxTotalSize-fail") << qsizetype(-1) << qsizetype(-1) << qsizetype(10) + << QByteArray("Location: hi\r\n\r\n") << false; +} + +void tst_QHttpHeaderParser::adjustableLimits() +{ + QFETCH(qsizetype, maxFieldCount); + QFETCH(qsizetype, maxFieldSize); + QFETCH(qsizetype, maxTotalSize); + QFETCH(QByteArray, headers); + QFETCH(bool, success); + + QHttpHeaderParser parser; + if (maxFieldCount != qsizetype(-1)) + parser.setMaxHeaderFields(maxFieldCount); + if (maxFieldSize != qsizetype(-1)) + parser.setMaxHeaderFieldSize(maxFieldSize); + if (maxTotalSize != qsizetype(-1)) + parser.setMaxTotalHeaderSize(maxTotalSize); + + QCOMPARE(parser.parseHeaders(headers), success); +} + +QTEST_MAIN(tst_QHttpHeaderParser) +#include "tst_qhttpheaderparser.moc" diff --git a/tests/auto/network/access/qhttpheaders/CMakeLists.txt b/tests/auto/network/access/qhttpheaders/CMakeLists.txt new file mode 100644 index 0000000000..0de1f96c67 --- /dev/null +++ b/tests/auto/network/access/qhttpheaders/CMakeLists.txt @@ -0,0 +1,16 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qhttpheaders LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qhttpheaders + SOURCES + tst_qhttpheaders.cpp + LIBRARIES + Qt::Core + Qt::Network +) diff --git a/tests/auto/network/access/qhttpheaders/tst_qhttpheaders.cpp b/tests/auto/network/access/qhttpheaders/tst_qhttpheaders.cpp new file mode 100644 index 0000000000..457d30feeb --- /dev/null +++ b/tests/auto/network/access/qhttpheaders/tst_qhttpheaders.cpp @@ -0,0 +1,552 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QtNetwork/qhttpheaders.h> + +#include <QtTest/qtest.h> + +#include <QtCore/qmap.h> +#include <QtCore/qset.h> + +using namespace Qt::StringLiterals; + +class tst_QHttpHeaders : public QObject +{ + Q_OBJECT + +private slots: + void constructors(); + void accessors(); + void wellKnownHeader(); + void headerNameField(); + void headerValueField(); + void valueEncoding(); + void replaceOrAppend(); + +private: + static constexpr QAnyStringView n1{"name1"}; + static constexpr QAnyStringView n2{"name2"}; + static constexpr QAnyStringView n3{"name3"}; + static constexpr QAnyStringView v1{"value1"}; + static constexpr QAnyStringView v2{"value2"}; + static constexpr QAnyStringView v3{"value3"}; + static constexpr QAnyStringView N1{"NAME1"}; + static constexpr QAnyStringView N2{"NAME2"}; + static constexpr QAnyStringView N3{"NAME3"}; + static constexpr QAnyStringView V1{"VALUE1"}; + static constexpr QAnyStringView V2{"VALUE2"}; + static constexpr QAnyStringView V3{"VALUE3"}; +}; + +void tst_QHttpHeaders::constructors() +{ + // Default ctor + QHttpHeaders h1; + QVERIFY(h1.isEmpty()); + + // Copy ctor + QHttpHeaders h2(h1); + QCOMPARE(h2.toListOfPairs(), h1.toListOfPairs()); + + // Copy assignment + QHttpHeaders h3; + h3 = h1; + QCOMPARE(h3.toListOfPairs(), h1.toListOfPairs()); + + // Move assignment + QHttpHeaders h4; + h4 = std::move(h2); + QCOMPARE(h4.toListOfPairs(), h1.toListOfPairs()); + + // Move ctor + QHttpHeaders h5(std::move(h4)); + QCOMPARE(h5.toListOfPairs(), h1.toListOfPairs()); + + // Constructors that are counterparts to 'toXXX()' conversion getters + const QByteArray nb1{"name1"}; + const QByteArray nb2{"name2"}; + const QByteArray nv1{"value1"}; + const QByteArray nv2{"value2"}; + // Initialize three QHttpHeaders with similar content, and verify that they have + // similar header entries +#define CONTAINS_HEADER(NAME, VALUE) \ + QVERIFY(hlist.contains(NAME) && hmap.contains(NAME) && hhash.contains(NAME)); \ + QCOMPARE(hlist.combinedValue(NAME), VALUE); \ + QCOMPARE(hmap.combinedValue(NAME), VALUE); \ + QCOMPARE(hhash.combinedValue(NAME), VALUE); \ + + QList<std::pair<QByteArray, QByteArray>> list{{nb1, nv1}, {nb2, nv2}, {nb2, nv2}}; + QMultiMap<QByteArray, QByteArray> map{{nb1, nv1}, {nb2, nv2}, {nb2, nv2}}; + QMultiHash<QByteArray, QByteArray> hash{{nb1, nv1}, {nb2, nv2}, {nb2, nv2}}; + QHttpHeaders hlist = QHttpHeaders::fromListOfPairs(list); + QHttpHeaders hmap = QHttpHeaders::fromMultiMap(map); + QHttpHeaders hhash = QHttpHeaders::fromMultiHash(hash); + CONTAINS_HEADER(nb1, v1); + CONTAINS_HEADER(nb2, nv2 + ", " + nv2) +#undef CONTAINS_HEADER +} + +void tst_QHttpHeaders::accessors() +{ + QHttpHeaders h1; + + // isEmpty(), clear(), size() + h1.append(n1,v1); + QVERIFY(!h1.isEmpty()); + QCOMPARE(h1.size(), 1); + QVERIFY(h1.append(n1, v1)); + QCOMPARE(h1.size(), 2); + h1.insert(0, n1, v1); + QCOMPARE(h1.size(), 3); + h1.clear(); + QVERIFY(h1.isEmpty()); + + // contains() + h1.append(n1, v1); + QVERIFY(h1.contains(n1)); + QVERIFY(h1.contains(N1)); + QVERIFY(!h1.contains(n2)); + QVERIFY(!h1.contains(QHttpHeaders::WellKnownHeader::Allow)); + h1.append(QHttpHeaders::WellKnownHeader::Accept, "nothing"); + QVERIFY(h1.contains(QHttpHeaders::WellKnownHeader::Accept)); + QVERIFY(h1.contains("accept")); + + // values()/value() +#define EXISTS_NOT(H, N) do { \ + QVERIFY(!H.contains(N)); \ + QCOMPARE(H.value(N, "ENOENT"), "ENOENT"); \ + const auto values = H.values(N); \ + QVERIFY(values.isEmpty()); \ + QVERIFY(H.combinedValue(N).isNull()); \ + } while (false) + +#define EXISTS_N_TIMES(X, H, N, ...) do { \ + const std::array expected = { __VA_ARGS__ }; \ + static_assert(std::tuple_size_v<decltype(expected)> == X); \ + QVERIFY(H.contains(N)); \ + QCOMPARE(H.value(N, "ENOENT"), expected.front()); \ + const auto values = H.values(N); \ + QCOMPARE(values.size(), X); \ + QCOMPARE(values.front(), expected.front()); \ + /* ignore in-between */ \ + QCOMPARE(values.back(), expected.back()); \ + QCOMPARE(H.combinedValue(N), values.join(", ")); \ + } while (false) + +#define EXISTS_ONCE(H, N, V) EXISTS_N_TIMES(1, H, N, V) + + EXISTS_ONCE(h1, n1, v1); + EXISTS_ONCE(h1, N1, v1); + EXISTS_ONCE(h1, QHttpHeaders::WellKnownHeader::Accept, "nothing"); + EXISTS_ONCE(h1, "Accept", "nothing"); + + EXISTS_NOT(h1, N2); + EXISTS_NOT(h1, QHttpHeaders::WellKnownHeader::Allow); + + h1.clear(); + + EXISTS_NOT(h1, n1); + + h1.append(n1, v1); + h1.append(n1, v2); + h1.append(n1, v3); + h1.append(n2, v2); + h1.append(n3, ""); // empty value + + EXISTS_N_TIMES(3, h1, n1, v1, v2, v3); + EXISTS_N_TIMES(3, h1, N1, v1, v2, v3); + EXISTS_ONCE(h1, n3, ""); // empty value + + h1.append(QHttpHeaders::WellKnownHeader::Accept, "nothing"); + h1.append(QHttpHeaders::WellKnownHeader::Accept, "ever"); + + EXISTS_N_TIMES(2, h1, QHttpHeaders::WellKnownHeader::Accept, "nothing", "ever"); + EXISTS_NOT(h1, "nonexistent"); + +#undef EXISTS_ONCE +#undef EXISTS_N_TIMES +#undef EXISTS_NOT + + // valueAt() + h1.clear(); + h1.append(n1, v1); + h1.append(n2, v2); + h1.append(n3, v3); + QCOMPARE(h1.valueAt(0), v1); + QCOMPARE(h1.valueAt(1), v2); + QCOMPARE(h1.valueAt(2), v3); + + // nameAt() + h1.clear(); + h1.append(n1, v1); + h1.append(n2, v2); + h1.append(n3, v3); + QCOMPARE(h1.nameAt(0), n1); + QCOMPARE(h1.nameAt(1), n2); + QCOMPARE(h1.nameAt(2), n3); + + // removeAll() + h1.clear(); + QVERIFY(h1.append(n1, v1)); + QVERIFY(h1.append(QHttpHeaders::WellKnownHeader::Accept, "nothing")); + QVERIFY(h1.append(n1, v1)); + QCOMPARE(h1.size(), 3); + h1.removeAll(n1); + QVERIFY(!h1.contains(n1)); + QCOMPARE(h1.size(), 1); + QVERIFY(h1.contains("accept")); + h1.removeAll(QHttpHeaders::WellKnownHeader::Accept); + QVERIFY(!h1.contains(QHttpHeaders::WellKnownHeader::Accept)); + + // removeAt() + h1.clear(); + h1.append(n1, v1); + h1.append(n2, v2); + h1.append(n3, v3); + + // Valid removals + QVERIFY(h1.contains(n3)); + h1.removeAt(2); + QVERIFY(!h1.contains(n3)); + QVERIFY(h1.contains(n1)); + h1.removeAt(0); + QVERIFY(!h1.contains(n1)); + QVERIFY(h1.contains(n2)); + h1.removeAt(0); + QVERIFY(!h1.contains(n2)); + QVERIFY(h1.isEmpty()); + + // toListOfPairs() + h1.clear(); + h1.append(n1, v1); + h1.append(n2, v2); + h1.append(N3, V3); // uppercase of n3 + auto list = h1.toListOfPairs(); + QCOMPARE(list.size(), h1.size()); + QCOMPARE(list.at(0).first, n1); + QCOMPARE(list.at(0).second, v1); + QCOMPARE(list.at(1).first, n2); + QCOMPARE(list.at(1).second, v2); + QCOMPARE(list.at(2).first, n3); // N3 has been lower-cased + QCOMPARE(list.at(2).second, V3); + + // toMultiMap() + auto map = h1.toMultiMap(); + QCOMPARE(map.size(), h1.size()); + QCOMPARE(map.value(n1.toString().toLatin1()), v1); + QCOMPARE(map.value(n2.toString().toLatin1()), v2); + QCOMPARE(map.value(n3.toString().toLatin1()), V3); + + // toMultiHash() + auto hash = h1.toMultiHash(); + QCOMPARE(hash.size(), h1.size()); + QCOMPARE(hash.value(n1.toString().toLatin1()), v1); + QCOMPARE(hash.value(n2.toString().toLatin1()), v2); + QCOMPARE(hash.value(n3.toString().toLatin1()), V3); + + // insert() + h1.clear(); + h1.append(n3, v3); + QVERIFY(h1.insert(0, n1, v1)); + list = h1.toListOfPairs(); + QCOMPARE(list.size(), 2); + QCOMPARE(list.at(0).first, n1); + QCOMPARE(list.at(0).second, v1); + QCOMPARE(list.at(1).first, n3); + QCOMPARE(list.at(1).second, v3); + QVERIFY(h1.insert(1, n2, v2)); + list = h1.toListOfPairs(); + QCOMPARE(list.size(), 3); + QCOMPARE(list.at(0).first, n1); + QCOMPARE(list.at(0).second, v1); + QCOMPARE(list.at(1).first, n2); + QCOMPARE(list.at(1).second, v2); + QCOMPARE(list.at(2).first, n3); + QCOMPARE(list.at(2).second, v3); + QVERIFY(h1.insert(1, QHttpHeaders::WellKnownHeader::Accept, "nothing")); + QCOMPARE(h1.size(), 4); + list = h1.toListOfPairs(); + QCOMPARE(list.at(1).first, "accept"); + QCOMPARE(list.at(1).second, "nothing"); + QVERIFY(h1.insert(list.size(), "LastName", "lastValue")); + QCOMPARE(h1.size(), 5); + list = h1.toListOfPairs(); + QCOMPARE(list.last().first, "lastname"); + QCOMPARE(list.last().second, "lastValue"); + // Failed insert + QRegularExpression re("HTTP header name contained*"); + QTest::ignoreMessage(QtMsgType::QtWarningMsg, re); + QVERIFY(!h1.insert(0, "a€", "b")); + + // replace + h1.clear(); + h1.append(n1, v1); + h1.append(n2, v2); + QCOMPARE(h1.size(), 2); + QVERIFY(h1.replace(0, n3, v3)); + QVERIFY(h1.replace(1, QHttpHeaders::WellKnownHeader::Accept, "nothing")); + QCOMPARE(h1.size(), 2); + list = h1.toListOfPairs(); + QCOMPARE(list.at(0).first, n3); + QCOMPARE(list.at(0).second, v3); + QCOMPARE(list.at(1).first, "accept"); + QCOMPARE(list.at(1).second, "nothing"); + QVERIFY(h1.replace(1, "ACCEPT", "NOTHING")); + QCOMPARE(h1.size(), 2); + list = h1.toListOfPairs(); + QCOMPARE(list.at(0).first, n3); + QCOMPARE(list.at(0).second, v3); + QCOMPARE(list.at(1).first, "accept"); + QCOMPARE(list.at(1).second, "NOTHING"); + // Failed replace + QTest::ignoreMessage(QtMsgType::QtWarningMsg, re); + QVERIFY(!h1.replace(0, "a€", "b")); + +} + +void tst_QHttpHeaders::wellKnownHeader() +{ + QByteArrayView view = QHttpHeaders::wellKnownHeaderName(QHttpHeaders::WellKnownHeader::AIM); + QCOMPARE(view, "a-im"); +} + +#define TEST_ILLEGAL_HEADER_NAME_CHARACTER(NAME) \ + QTest::ignoreMessage(QtMsgType::QtWarningMsg, re); \ + QVERIFY(!h1.append(NAME, v1)); \ + QVERIFY(h1.isEmpty()); \ + +void tst_QHttpHeaders::headerNameField() +{ + QHttpHeaders h1; + + // All allowed characters in different encodings and types + // const char[] + h1.append("abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%&'*+-.^_`|~", v1); + QCOMPARE(h1.size(), 1); + // UTF-8 + h1.append(u8"abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%&'*+-.^_`|~", + v1); + QCOMPARE(h1.size(), 2); + // UTF-16 + h1.append(u"abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%&'*+-.^_`|~", v1); + QCOMPARE(h1.size(), 3); + // QString (UTF-16) + h1.append(u"abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%&'*+-.^_`|~"_s, + v1); + QCOMPARE(h1.size(), 4); + QCOMPARE(h1.nameAt(0), h1.nameAt(1)); + QCOMPARE(h1.nameAt(1), h1.nameAt(2)); + QCOMPARE(h1.nameAt(2), h1.nameAt(3)); + h1.clear(); + + // Error cases + // Header name must contain at least 1 character + QTest::ignoreMessage(QtMsgType::QtWarningMsg, "HTTP header name cannot be empty"); + h1.append("", v1); + QVERIFY(h1.isEmpty()); + // Disallowed ASCII/extended ASCII characters (not exhaustive list) + QRegularExpression re("HTTP header name contained illegal character*"); + TEST_ILLEGAL_HEADER_NAME_CHARACTER("foo\x08" "bar"); // BS + TEST_ILLEGAL_HEADER_NAME_CHARACTER("foo\x7F" "bar"); // DEL + TEST_ILLEGAL_HEADER_NAME_CHARACTER("foo()" "bar"); // parantheses + TEST_ILLEGAL_HEADER_NAME_CHARACTER("foobar" "¿"); // extended ASCII + TEST_ILLEGAL_HEADER_NAME_CHARACTER("©" "foobar"); // extended ASCII + TEST_ILLEGAL_HEADER_NAME_CHARACTER("foo,bar"); // comma + // Disallowed UTF-8 characters + TEST_ILLEGAL_HEADER_NAME_CHARACTER(u8"€"); + TEST_ILLEGAL_HEADER_NAME_CHARACTER(u8"𝒜𝒴𝟘𝟡𐎀𐎜𐒀𐒐𝓐𝓩𝔸𝔹𝕀𝕁𝕌𝕍𓂀𓂁𓃀𓃁𓇋𓇌𓉐𓉑𓋴𓋵𓎡𓎢𓎣𓏏"); + // Disallowed UTF-16 characters + TEST_ILLEGAL_HEADER_NAME_CHARACTER(u"€"); + TEST_ILLEGAL_HEADER_NAME_CHARACTER(u"𝒜𝒴𝟘𝟡𐎀𐎜𐒀𐒐𝓐𝓩𝔸𝔹𝕀𝕁𝕌𝕍𓂀𓂁𓃀𓃁𓇋𓇌𓉐𓉑𓋴𓋵𓎡𓎢𓎣𓏏"); + + // Non-null-terminated name. The 'x' below is to make sure the strings don't + // null-terminate by happenstance + h1.clear(); + constexpr char L1Array[] = {'a','b','c','x'}; + const QLatin1StringView nonNullLatin1{L1Array, sizeof(L1Array) - 1}; // abc + + constexpr char UTF8Array[] = {0x64, 0x65, 0x66, 0x78}; + const QUtf8StringView nonNullUTF8(UTF8Array, sizeof(UTF8Array) - 1); // def + + constexpr QChar UTF16Array[] = {'g', 'h', 'i', 'x'}; + QStringView nonNullUTF16(UTF16Array, sizeof(UTF16Array) / sizeof(QChar) - 1); // ghi + + h1.append(nonNullLatin1, v1); + QCOMPARE(h1.size(), 1); + QVERIFY(h1.contains(nonNullLatin1)); + QCOMPARE(h1.combinedValue(nonNullLatin1), v1); + + h1.append(nonNullUTF8, v2); + QCOMPARE(h1.size(), 2); + QVERIFY(h1.contains(nonNullUTF8)); + QCOMPARE(h1.combinedValue(nonNullUTF8), v2); + + h1.append(nonNullUTF16, v3); + QCOMPARE(h1.size(), 3); + QVERIFY(h1.contains(nonNullUTF16)); + QCOMPARE(h1.combinedValue(nonNullUTF16), v3); +} + +#define TEST_ILLEGAL_HEADER_VALUE_CHARACTER(VALUE) \ +QTest::ignoreMessage(QtMsgType::QtWarningMsg, re); \ + QVERIFY(!h1.append(n1, VALUE)); \ + QVERIFY(h1.isEmpty()); \ + +void tst_QHttpHeaders::headerValueField() +{ + QHttpHeaders h1; + + // Visible ASCII characters and space and horizontal tab + // const char[] + h1.append(n1, "!\"#$%&'()*+,-./0123456789:; \t<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + "`abcdefghijklmnopqrstuvwxyz{|}~"); + QCOMPARE(h1.size(), 1); + // UTF-8 + h1.append(n1, u8"!\"#$%&'()*+,-./0123456789:; \t<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + "`abcdefghijklmnopqrstuvwxyz{|}~"); + QCOMPARE(h1.size(), 2); + // UTF-16 + h1.append(n1, u"!\"#$%&'()*+,-./0123456789:; \t<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + "`abcdefghijklmnopqrstuvwxyz{|}~"); + QCOMPARE(h1.size(), 3); + // QString / UTF-16 + h1.append(n1, u"!\"#$%&'()*+,-./0123456789:; \t<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + "`abcdefghijklmnopqrstuvwxyz{|}~"_s); + QCOMPARE(h1.size(), 4); + const auto values = h1.values(n1); + QVERIFY(!values.isEmpty() && values.size() == 4); + QVERIFY(values[0] == values[1] + && values[1] == values[2] + && values[2] == values[3]); + // Extended ASCII (explicit on Latin-1 to avoid UTF-8 interpretation) + h1.append(n1, "\x80\x09\xB2\xFF"_L1); + QCOMPARE(h1.size(), 5); + // Empty value + h1.append(n1, ""); + QCOMPARE(h1.size(), 6); + // Leading and trailing space + h1.clear(); + h1.append(n1, " foo "); + QCOMPARE(h1.combinedValue(n1), "foo"); + h1.append(n1, "\tbar\t"); + QCOMPARE(h1.combinedValue(n1), "foo, bar"); + QCOMPARE(h1.size(), 2); + + h1.clear(); + QRegularExpression re("HTTP header value contained illegal character*"); + TEST_ILLEGAL_HEADER_VALUE_CHARACTER("foo\x08" "bar"); // BS + TEST_ILLEGAL_HEADER_VALUE_CHARACTER("foo\x1B" "bar"); // ESC + // Disallowed UTF-8 characters + TEST_ILLEGAL_HEADER_VALUE_CHARACTER(u8"€"); + TEST_ILLEGAL_HEADER_VALUE_CHARACTER(u8"𝒜𝒴𝟘𝟡𐎀𐎜𐒀𐒐𝓐𝓩𝔸𝔹𝕀𝕁𝕌𝕍𓂀𓂁𓃀𓃁𓇋𓇌𓉐𓉑𓋴𓋵𓎡𓎢𓎣𓏏"); + // Disallowed UTF-16 characters + TEST_ILLEGAL_HEADER_VALUE_CHARACTER(u"€"); + TEST_ILLEGAL_HEADER_VALUE_CHARACTER(u"𝒜𝒴𝟘𝟡𐎀𐎜𐒀𐒐𝓐𝓩𝔸𝔹𝕀𝕁𝕌𝕍𓂀𓂁𓃀𓃁𓇋𓇌𓉐𓉑𓋴𓋵𓎡𓎢𓎣𓏏"); + + // Non-null-terminated value. The 'x' below is to make sure the strings don't + // null-terminate by happenstance + h1.clear(); + constexpr char L1Array[] = {'a','b','c','x'}; + const QLatin1StringView nonNullLatin1{L1Array, sizeof(L1Array) - 1}; // abc + + constexpr char UTF8Array[] = {0x64, 0x65, 0x66, 0x78}; + const QUtf8StringView nonNullUTF8(UTF8Array, sizeof(UTF8Array) - 1); // def + + constexpr QChar UTF16Array[] = {'g', 'h', 'i', 'x'}; + QStringView nonNullUTF16(UTF16Array, sizeof(UTF16Array) / sizeof(QChar) - 1); // ghi + + h1.append(n1, nonNullLatin1); + QCOMPARE(h1.size(), 1); + QVERIFY(h1.contains(n1)); + QCOMPARE(h1.combinedValue(n1), "abc"); + + h1.append(n2, nonNullUTF8); + QCOMPARE(h1.size(), 2); + QVERIFY(h1.contains(n2)); + QCOMPARE(h1.combinedValue(n2), "def"); + + h1.append(n3, nonNullUTF16); + QCOMPARE(h1.size(), 3); + QVERIFY(h1.contains(n3)); + QCOMPARE(h1.combinedValue(n3), "ghi"); +} + +void tst_QHttpHeaders::valueEncoding() +{ + // Test that common encodings are possible to set and not blocked by + // header value character filter (ie. don't contain disallowed characters as per RFC 9110) + QHttpHeaders h1; + // Within visible ASCII range + QVERIFY(h1.append(n1, "foo"_ba.toBase64())); + QCOMPARE(h1.values(n1).at(0), "Zm9v"); + h1.replace(0, n1, "foo"_ba.toPercentEncoding()); + QCOMPARE(h1.values(n1).at(0), "foo"); + + // Outside of ASCII/Latin-1 range (€) + h1.replace(0, n1, "foo€"_ba.toBase64()); + QCOMPARE(h1.values(n1).at(0), "Zm9v4oKs"); + h1.replace(0, n1, "foo€"_ba.toPercentEncoding()); + QCOMPARE(h1.values(n1).at(0), "foo%E2%82%AC"); +} + +void tst_QHttpHeaders::replaceOrAppend() +{ + QHttpHeaders h1; + +#define REPLACE_OR_APPEND(NAME, VALUE, INDEX, TOTALSIZE) \ + do { \ + QVERIFY(h1.replaceOrAppend(NAME, VALUE)); \ + QCOMPARE(h1.size(), TOTALSIZE); \ + QCOMPARE(h1.nameAt(INDEX), NAME); \ + QCOMPARE(h1.valueAt(INDEX), VALUE); \ + } while (false) + + // Append to empty container and replace it + REPLACE_OR_APPEND(n1, v1, 0, 1); // Appends + REPLACE_OR_APPEND(n1, v2, 0, 1); // Replaces + + // Replace at beginning, middle, and end + h1.clear(); + REPLACE_OR_APPEND(n1, v1, 0, 1); // Appends + REPLACE_OR_APPEND(n2, v2, 1, 2); // Appends + REPLACE_OR_APPEND(n3, v3, 2, 3); // Appends + REPLACE_OR_APPEND(n1, V1, 0, 3); // Replaces at beginning + REPLACE_OR_APPEND(n2, V2, 1, 3); // Replaces at middle + REPLACE_OR_APPEND(n3, V3, 2, 3); // Replaces at end + + // Pre-existing multiple values (n2) are removed + h1.clear(); + h1.append(n1, v1); + h1.append(n2, v2); // First n2 is at index 1 + h1.append(n2, v2); + h1.append(n3, v3); + h1.append(n2, v2); + QCOMPARE(h1.size(), 5); + QCOMPARE(h1.combinedValue(n2), "value2, value2, value2"); + REPLACE_OR_APPEND(n2, V2, 1, 3); // Replaces value at index 1, and removes the rest + QCOMPARE(h1.combinedValue(n2), "VALUE2"); +#undef REPLACE_OR_APPEND + + // Implicit sharing / detaching + h1.clear(); + h1.append(n1, v1); + QHttpHeaders h2 = h1; + QCOMPARE(h1.size(), h2.size()); + QCOMPARE(h1.valueAt(0), h2.valueAt(0)); // Iniially values are equal + h1.replaceOrAppend(n1, v2); // Change value in h1 => detaches h1 + QCOMPARE_NE(h1.valueAt(0), h2.valueAt(0)); // Values are no more equal + QCOMPARE(h1.valueAt(0), v2); // Value in h1 changed + QCOMPARE(h2.valueAt(0), v1); // Value in h2 remained + + // Failed attempts + h1.clear(); + h1.append(n1, v1); + QRegularExpression re("HTTP header*"); + QTest::ignoreMessage(QtMsgType::QtWarningMsg, re); + QVERIFY(!h1.replaceOrAppend("", V1)); + QTest::ignoreMessage(QtMsgType::QtWarningMsg, re); + QVERIFY(!h1.replaceOrAppend(v1, "foo\x08")); +} + +QTEST_MAIN(tst_QHttpHeaders) +#include "tst_qhttpheaders.moc" diff --git a/tests/auto/network/access/qhttpheadershelper/CMakeLists.txt b/tests/auto/network/access/qhttpheadershelper/CMakeLists.txt new file mode 100644 index 0000000000..75935d2844 --- /dev/null +++ b/tests/auto/network/access/qhttpheadershelper/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qhttpheadershelper LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qhttpheadershelper + SOURCES + tst_qhttpheadershelper.cpp + LIBRARIES + Qt::NetworkPrivate +) diff --git a/tests/auto/network/access/qhttpheadershelper/tst_qhttpheadershelper.cpp b/tests/auto/network/access/qhttpheadershelper/tst_qhttpheadershelper.cpp new file mode 100644 index 0000000000..b204d0cbe3 --- /dev/null +++ b/tests/auto/network/access/qhttpheadershelper/tst_qhttpheadershelper.cpp @@ -0,0 +1,76 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QtNetwork/qhttpheaders.h> +#include <QtNetwork/private/qhttpheadershelper_p.h> + +#include <QtTest/qtest.h> + +using namespace Qt::StringLiterals; + +class tst_QHttpHeadersHelper : public QObject +{ + Q_OBJECT + +private slots: + void testCompareStrict(); + +private: + static constexpr QAnyStringView n1{"name1"}; + static constexpr QAnyStringView n2{"name2"}; + static constexpr QAnyStringView v1{"value1"}; + static constexpr QAnyStringView v2{"value2"}; + static constexpr QAnyStringView N1{"NAME1"}; + static constexpr QAnyStringView N2{"NAME2"}; + static constexpr QAnyStringView V1{"VALUE1"}; + static constexpr QAnyStringView V2{"VALUE2"}; +}; + +void tst_QHttpHeadersHelper::testCompareStrict() +{ + using namespace QHttpHeadersHelper; + + // Basic comparisons + QHttpHeaders h1; + QHttpHeaders h2; + QVERIFY(compareStrict(h1, h2)); // empties + h1.append(n1, v1); + QVERIFY(compareStrict(h1, h1)); // self + h2.append(n1, v1); + QVERIFY(compareStrict(h1, h2)); + h1.append(n2, v2); + QVERIFY(!compareStrict(h1, h2)); + h1.removeAll(n2); + QVERIFY(compareStrict(h1, h2)); + + // Order-sensitivity + h1.clear(); + h2.clear(); + // Same headers but in different order + h1.append(n1, v1); + h1.append(n2, v2); + h2.append(n2, v2); + h2.append(n1, v1); + QVERIFY(!compareStrict(h1, h2)); + + // Different number of headers + h1.clear(); + h2.clear(); + h1.append(n1, v1); + h2.append(n1, v1); + h2.append(n2, v2); + QVERIFY(!compareStrict(h1, h2)); + + // Same header name, multiple values + h1.clear(); + h2.clear(); + h1.append(n1, v1); + h1.append(n1, v2); + h2.append(n1, v1); + QVERIFY(!compareStrict(h1, h2)); + h2.append(n1, v2); + QVERIFY(compareStrict(h1, h2)); +} + +QTEST_MAIN(tst_QHttpHeadersHelper) +#include "tst_qhttpheadershelper.moc" diff --git a/tests/auto/network/access/qhttpnetworkconnection/CMakeLists.txt b/tests/auto/network/access/qhttpnetworkconnection/CMakeLists.txt index ffd9ea934e..679990062f 100644 --- a/tests/auto/network/access/qhttpnetworkconnection/CMakeLists.txt +++ b/tests/auto/network/access/qhttpnetworkconnection/CMakeLists.txt @@ -1,4 +1,11 @@ -# Generated from qhttpnetworkconnection.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qhttpnetworkconnection LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() if(NOT QT_FEATURE_private_tests) return() @@ -8,15 +15,11 @@ endif() ## tst_qhttpnetworkconnection Test: ##################################################################### -qt_add_test(tst_qhttpnetworkconnection +qt_internal_add_test(tst_qhttpnetworkconnection SOURCES tst_qhttpnetworkconnection.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::NetworkPrivate - QT_TEST_SERVER_LIST "apache2" # special case + QT_TEST_SERVER_LIST "apache2" ) - -#### Keys ignored in scope 1:.:.:qhttpnetworkconnection.pro:<TRUE>: -# QT_TEST_SERVER_LIST = "apache2" -# _REQUIREMENTS = "qtConfig(private_tests)" diff --git a/tests/auto/network/access/qhttpnetworkconnection/qhttpnetworkconnection.pro b/tests/auto/network/access/qhttpnetworkconnection/qhttpnetworkconnection.pro deleted file mode 100644 index 84e6f857a1..0000000000 --- a/tests/auto/network/access/qhttpnetworkconnection/qhttpnetworkconnection.pro +++ /dev/null @@ -1,9 +0,0 @@ -CONFIG += testcase -TARGET = tst_qhttpnetworkconnection -SOURCES += tst_qhttpnetworkconnection.cpp -requires(qtConfig(private_tests)) - -QT = core-private network-private testlib - -CONFIG += unsupported/testserver -QT_TEST_SERVER_LIST = apache2 diff --git a/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp b/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp index 00afdd8177..decd442164 100644 --- a/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp +++ b/tests/auto/network/access/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp @@ -1,38 +1,15 @@ -/**************************************************************************** -** -** 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 "private/qhttpnetworkconnection_p.h" -#include "private/qnoncontiguousbytedevice_p.h" +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + + +#include <QTest> +#include <QTestEventLoop> #include <QAuthenticator> #include <QTcpServer> +#include "private/qhttpnetworkconnection_p.h" +#include "private/qnoncontiguousbytedevice_p.h" + #include "../../../network-settings.h" class tst_QHttpNetworkConnection: public QObject @@ -148,7 +125,7 @@ void tst_QHttpNetworkConnection::head() QFETCH(QString, statusString); QFETCH(int, contentLength); - QHttpNetworkConnection connection(host, port, encrypt); + QHttpNetworkConnection connection(QHttpNetworkConnectionPrivate::defaultHttpChannelCount, host, port, encrypt); QCOMPARE(connection.port(), port); QCOMPARE(connection.hostName(), host); QCOMPARE(connection.isSsl(), encrypt); @@ -198,7 +175,7 @@ void tst_QHttpNetworkConnection::get() QFETCH(int, contentLength); QFETCH(int, downloadSize); - QHttpNetworkConnection connection(host, port, encrypt); + QHttpNetworkConnection connection(QHttpNetworkConnectionPrivate::defaultHttpChannelCount, host, port, encrypt); QCOMPARE(connection.port(), port); QCOMPARE(connection.hostName(), host); QCOMPARE(connection.isSsl(), encrypt); @@ -264,7 +241,7 @@ void tst_QHttpNetworkConnection::put() QFETCH(QString, data); QFETCH(bool, succeed); - QHttpNetworkConnection connection(host, port, encrypt); + QHttpNetworkConnection connection(QHttpNetworkConnectionPrivate::defaultHttpChannelCount, host, port, encrypt); QCOMPARE(connection.port(), port); QCOMPARE(connection.hostName(), host); QCOMPARE(connection.isSsl(), encrypt); @@ -346,7 +323,7 @@ void tst_QHttpNetworkConnection::post() QFETCH(int, contentLength); QFETCH(int, downloadSize); - QHttpNetworkConnection connection(host, port, encrypt); + QHttpNetworkConnection connection(QHttpNetworkConnectionPrivate::defaultHttpChannelCount, host, port, encrypt); QCOMPARE(connection.port(), port); QCOMPARE(connection.hostName(), host); QCOMPARE(connection.isSsl(), encrypt); @@ -473,7 +450,7 @@ void tst_QHttpNetworkConnection::get401() QFETCH(QString, password); QFETCH(int, statusCode); - QHttpNetworkConnection connection(host, port, encrypt); + QHttpNetworkConnection connection(QHttpNetworkConnectionPrivate::defaultHttpChannelCount, host, port, encrypt); QCOMPARE(connection.port(), port); QCOMPARE(connection.hostName(), host); QCOMPARE(connection.isSsl(), encrypt); @@ -533,7 +510,7 @@ void tst_QHttpNetworkConnection::compression() QFETCH(bool, autoCompress); QFETCH(QString, contentCoding); - QHttpNetworkConnection connection(host, port, encrypt); + QHttpNetworkConnection connection(QHttpNetworkConnectionPrivate::defaultHttpChannelCount, host, port, encrypt); QCOMPARE(connection.port(), port); QCOMPARE(connection.hostName(), host); QCOMPARE(connection.isSsl(), encrypt); @@ -607,7 +584,7 @@ void tst_QHttpNetworkConnection::ignoresslerror() QFETCH(bool, ignoreFromSignal); QFETCH(int, statusCode); - QHttpNetworkConnection connection(host, port, encrypt); + QHttpNetworkConnection connection(QHttpNetworkConnectionPrivate::defaultHttpChannelCount, host, port, encrypt); QCOMPARE(connection.port(), port); QCOMPARE(connection.hostName(), host); if (ignoreInit) @@ -652,7 +629,7 @@ void tst_QHttpNetworkConnection::nossl() QFETCH(bool, encrypt); QFETCH(QNetworkReply::NetworkError, networkError); - QHttpNetworkConnection connection(host, port, encrypt); + QHttpNetworkConnection connection(QHttpNetworkConnectionPrivate::defaultHttpChannelCount, host, port, encrypt); QCOMPARE(connection.port(), port); QCOMPARE(connection.hostName(), host); @@ -689,7 +666,7 @@ void tst_QHttpNetworkConnection::getMultiple_data() static bool allRepliesFinished(const QList<QHttpNetworkReply*> *_replies) { const QList<QHttpNetworkReply*> &replies = *_replies; - for (int i = 0; i < replies.length(); i++) + for (int i = 0; i < replies.size(); i++) if (!replies.at(i)->isFinished()) return false; return true; @@ -734,7 +711,7 @@ void tst_QHttpNetworkConnection::getMultipleWithPipeliningAndMultiplePriorities( QList<QHttpNetworkReply*> replies; for (int i = 0; i < requestCount; i++) { - QHttpNetworkRequest *request = 0; + QHttpNetworkRequest *request = nullptr; if (i % 3) request = new QHttpNetworkRequest("http://" + httpServerName() + "/qtest/rfc3252.txt", QHttpNetworkRequest::Get); else @@ -758,7 +735,7 @@ void tst_QHttpNetworkConnection::getMultipleWithPipeliningAndMultiplePriorities( QTRY_VERIFY_WITH_TIMEOUT(allRepliesFinished(&replies), 60000); int pipelinedCount = 0; - for (int i = 0; i < replies.length(); i++) { + for (int i = 0; i < replies.size(); i++) { QVERIFY (!(replies.at(i)->request().isPipeliningAllowed() == false && replies.at(i)->isPipeliningUsed())); @@ -812,7 +789,7 @@ void tst_QHttpNetworkConnection::getMultipleWithPriorities() QList<QHttpNetworkReply*> replies; for (int i = 0; i < requestCount; i++) { - QHttpNetworkRequest *request = 0; + QHttpNetworkRequest *request = nullptr; if (i % 3) request = new QHttpNetworkRequest(url, QHttpNetworkRequest::Get); else @@ -867,7 +844,7 @@ void tst_QHttpNetworkConnection::getEmptyWithPipelining() QList<QHttpNetworkReply*> replies; for (int i = 0; i < requestCount; i++) { - QHttpNetworkRequest *request = 0; + QHttpNetworkRequest *request = nullptr; request = new QHttpNetworkRequest(url, QHttpNetworkRequest::Get); request->setPipeliningAllowed(true); @@ -914,7 +891,7 @@ void tst_QHttpNetworkConnection::getAndEverythingShouldBePipelined() GetAndEverythingShouldBePipelinedReceiver receiver(requestCount); for (int i = 0; i < requestCount; i++) { - QHttpNetworkRequest *request = 0; + QHttpNetworkRequest *request = nullptr; request = new QHttpNetworkRequest(url, QHttpNetworkRequest::Get); request->setPipeliningAllowed(true); requests.append(request); @@ -942,7 +919,7 @@ void tst_QHttpNetworkConnection::getAndThenDeleteObject_data() void tst_QHttpNetworkConnection::getAndThenDeleteObject() { // yes, this will leak if the testcase fails. I don't care. It must not fail then :P - QHttpNetworkConnection *connection = new QHttpNetworkConnection(httpServerName()); + QHttpNetworkConnection *connection = new QHttpNetworkConnection(QHttpNetworkConnectionPrivate::defaultHttpChannelCount, httpServerName()); QHttpNetworkRequest request("http://" + httpServerName() + "/qtest/bigfile"); QHttpNetworkReply *reply = connection->sendRequest(request); reply->setDownstreamLimited(true); diff --git a/tests/auto/network/access/qhttpnetworkreply/CMakeLists.txt b/tests/auto/network/access/qhttpnetworkreply/CMakeLists.txt index f9ba96cf13..b4e4a822ee 100644 --- a/tests/auto/network/access/qhttpnetworkreply/CMakeLists.txt +++ b/tests/auto/network/access/qhttpnetworkreply/CMakeLists.txt @@ -1,4 +1,11 @@ -# Generated from qhttpnetworkreply.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qhttpnetworkreply LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() if(NOT QT_FEATURE_private_tests) return() @@ -8,13 +15,10 @@ endif() ## tst_qhttpnetworkreply Test: ##################################################################### -qt_add_test(tst_qhttpnetworkreply +qt_internal_add_test(tst_qhttpnetworkreply SOURCES tst_qhttpnetworkreply.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::NetworkPrivate ) - -#### Keys ignored in scope 1:.:.:qhttpnetworkreply.pro:<TRUE>: -# _REQUIREMENTS = "qtConfig(private_tests)" diff --git a/tests/auto/network/access/qhttpnetworkreply/qhttpnetworkreply.pro b/tests/auto/network/access/qhttpnetworkreply/qhttpnetworkreply.pro deleted file mode 100644 index 31570e6f01..0000000000 --- a/tests/auto/network/access/qhttpnetworkreply/qhttpnetworkreply.pro +++ /dev/null @@ -1,6 +0,0 @@ -CONFIG += testcase -TARGET = tst_qhttpnetworkreply -SOURCES += tst_qhttpnetworkreply.cpp -requires(qtConfig(private_tests)) - -QT = core-private network-private testlib diff --git a/tests/auto/network/access/qhttpnetworkreply/tst_qhttpnetworkreply.cpp b/tests/auto/network/access/qhttpnetworkreply/tst_qhttpnetworkreply.cpp index d230fcad4b..e83d15fdc3 100644 --- a/tests/auto/network/access/qhttpnetworkreply/tst_qhttpnetworkreply.cpp +++ b/tests/auto/network/access/qhttpnetworkreply/tst_qhttpnetworkreply.cpp @@ -1,35 +1,11 @@ -/**************************************************************************** -** -** 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> +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + + +#include <QTest> #include <QtCore/QBuffer> #include <QtCore/QByteArray> +#include <QtCore/QStringBuilder> #include "private/qhttpnetworkconnection_p.h" @@ -40,6 +16,9 @@ private Q_SLOTS: void parseHeader_data(); void parseHeader(); + void parseHeaderVerification_data(); + void parseHeaderVerification(); + void parseEndOfHeader_data(); void parseEndOfHeader(); }; @@ -50,6 +29,7 @@ void tst_QHttpNetworkReply::parseHeader_data() QTest::addColumn<QStringList>("fields"); QTest::addColumn<QStringList>("values"); + QTest::newRow("no-fields") << QByteArray("\r\n") << QStringList() << QStringList(); QTest::newRow("empty-field") << QByteArray("Set-Cookie: \r\n") << (QStringList() << "Set-Cookie") << (QStringList() << ""); @@ -60,6 +40,9 @@ void tst_QHttpNetworkReply::parseHeader_data() " charset=utf-8\r\n") << (QStringList() << "Content-Type") << (QStringList() << "text/html; charset=utf-8"); + QTest::newRow("single-field-on-five-lines") + << QByteArray("Name:\r\n first\r\n \r\n \r\n last\r\n") << (QStringList() << "Name") + << (QStringList() << "first last"); QTest::newRow("multi-field") << QByteArray("Content-Type: text/html; charset=utf-8\r\n" "Content-Length: 1024\r\n" @@ -94,13 +77,100 @@ void tst_QHttpNetworkReply::parseHeader() QHttpNetworkReply reply; reply.parseHeader(headers); - for (int i = 0; i < fields.count(); ++i) { + for (int i = 0; i < fields.size(); ++i) { //qDebug() << "field" << fields.at(i) << "value" << reply.headerField(fields.at(i)) << "expected" << values.at(i); QString field = reply.headerField(fields.at(i).toLatin1()); QCOMPARE(field, values.at(i)); } } +void tst_QHttpNetworkReply::parseHeaderVerification_data() +{ + QTest::addColumn<QByteArray>("headers"); + QTest::addColumn<bool>("success"); + + QTest::newRow("no-header-fields") << QByteArray("\r\n") << true; + QTest::newRow("starting-with-space") << QByteArray(" Content-Encoding: gzip\r\n") << false; + QTest::newRow("starting-with-tab") << QByteArray("\tContent-Encoding: gzip\r\n") << false; + QTest::newRow("only-colon") << QByteArray(":\r\n") << false; + QTest::newRow("colon-and-value") << QByteArray(": only-value\r\n") << false; + QTest::newRow("name-with-space") << QByteArray("Content Length: 10\r\n") << false; + QTest::newRow("missing-colon-1") << QByteArray("Content-Encoding\r\n") << false; + QTest::newRow("missing-colon-2") + << QByteArray("Content-Encoding\r\nContent-Length: 10\r\n") << false; + QTest::newRow("missing-colon-3") + << QByteArray("Content-Encoding: gzip\r\nContent-Length\r\n") << false; + QTest::newRow("header-field-too-long") + << (QByteArray("Content-Type: ") + + QByteArray(HeaderConstants::MAX_HEADER_FIELD_SIZE, 'a') + QByteArray("\r\n")) + << false; + + QByteArray name = "Content-Type: "; + QTest::newRow("max-header-field-size") + << (name + QByteArray(HeaderConstants::MAX_HEADER_FIELD_SIZE - name.size(), 'a') + + QByteArray("\r\n")) + << true; + + QByteArray tooManyHeaders = QByteArray("Content-Type: text/html; charset=utf-8\r\n") + .repeated(HeaderConstants::MAX_HEADER_FIELDS + 1); + QTest::newRow("too-many-headers") << tooManyHeaders << false; + + QByteArray maxHeaders = QByteArray("Content-Type: text/html; charset=utf-8\r\n") + .repeated(HeaderConstants::MAX_HEADER_FIELDS); + QTest::newRow("max-headers") << maxHeaders << true; + + QByteArray firstValue(HeaderConstants::MAX_HEADER_FIELD_SIZE / 2, 'a'); + constexpr int obsFold = 1; + QTest::newRow("max-continuation-size") + << (name + firstValue + QByteArray("\r\n ") + + QByteArray(HeaderConstants::MAX_HEADER_FIELD_SIZE - name.size() + - firstValue.size() - obsFold, + 'b') + + QByteArray("\r\n")) + << true; + QTest::newRow("too-long-continuation-size") + << (name + firstValue + QByteArray("\r\n ") + + QByteArray(HeaderConstants::MAX_HEADER_FIELD_SIZE - name.size() + - firstValue.size() - obsFold + 1, + 'b') + + QByteArray("\r\n")) + << false; + + auto appendLongHeaderElement = [](QByteArray &result, QByteArrayView name) { + const qsizetype size = result.size(); + result += name; + result += ": "; + result.resize(size + HeaderConstants::MAX_HEADER_FIELD_SIZE, 'a'); + }; + QByteArray longHeader; + constexpr qsizetype TrailerLength = sizeof("\r\n\r\n") - 1; // we ignore the trailing newlines + longHeader.reserve(HeaderConstants::MAX_TOTAL_HEADER_SIZE + TrailerLength + 1); + appendLongHeaderElement(longHeader, "Location"); + longHeader += "\r\n"; + appendLongHeaderElement(longHeader, "WWW-Authenticate"); + longHeader += "\r\nProxy-Authenticate: "; + longHeader.resize(HeaderConstants::MAX_TOTAL_HEADER_SIZE, 'a'); + longHeader += "\r\n\r\n"; + + // Test with headers which are just large enough to fit our MAX_TOTAL_HEADER_SIZE limit: + QTest::newRow("total-header-close-to-max-size") << longHeader << true; + // Now add another character to make the total header size exceed the limit: + longHeader.insert(HeaderConstants::MAX_TOTAL_HEADER_SIZE - TrailerLength, 'a'); + QTest::newRow("total-header-too-large") << longHeader << false; +} + +void tst_QHttpNetworkReply::parseHeaderVerification() +{ + QFETCH(QByteArray, headers); + QFETCH(bool, success); + QHttpNetworkReply reply; + reply.parseHeader(headers); + if (success && QByteArrayView(headers).trimmed().size()) + QVERIFY(reply.header().size() > 0); + else + QCOMPARE(reply.header().size(), 0); +} + class TestHeaderSocket : public QAbstractSocket { public: diff --git a/tests/auto/network/access/qnetworkaccessmanager/CMakeLists.txt b/tests/auto/network/access/qnetworkaccessmanager/CMakeLists.txt index 8fc928e8cf..b0fe6eda46 100644 --- a/tests/auto/network/access/qnetworkaccessmanager/CMakeLists.txt +++ b/tests/auto/network/access/qnetworkaccessmanager/CMakeLists.txt @@ -1,12 +1,19 @@ -# Generated from qnetworkaccessmanager.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qnetworkaccessmanager Test: ##################################################################### -qt_add_test(tst_qnetworkaccessmanager +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qnetworkaccessmanager LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qnetworkaccessmanager SOURCES tst_qnetworkaccessmanager.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Network ) diff --git a/tests/auto/network/access/qnetworkaccessmanager/qnetworkaccessmanager.pro b/tests/auto/network/access/qnetworkaccessmanager/qnetworkaccessmanager.pro deleted file mode 100644 index e84f9f7dba..0000000000 --- a/tests/auto/network/access/qnetworkaccessmanager/qnetworkaccessmanager.pro +++ /dev/null @@ -1,4 +0,0 @@ -CONFIG += testcase -TARGET = tst_qnetworkaccessmanager -SOURCES += tst_qnetworkaccessmanager.cpp -QT = core network testlib diff --git a/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp b/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp index 78919e8af6..43db6d5841 100644 --- a/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp +++ b/tests/auto/network/access/qnetworkaccessmanager/tst_qnetworkaccessmanager.cpp @@ -1,32 +1,7 @@ -/**************************************************************************** -** -** 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> +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QTest> #include <QtNetwork/QNetworkAccessManager> #include <QtNetwork/QNetworkReply> diff --git a/tests/auto/network/access/qnetworkcachemetadata/CMakeLists.txt b/tests/auto/network/access/qnetworkcachemetadata/CMakeLists.txt index bcd47c7bcf..2aa918c49c 100644 --- a/tests/auto/network/access/qnetworkcachemetadata/CMakeLists.txt +++ b/tests/auto/network/access/qnetworkcachemetadata/CMakeLists.txt @@ -1,12 +1,19 @@ -# Generated from qnetworkcachemetadata.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qnetworkcachemetadata Test: ##################################################################### -qt_add_test(tst_qnetworkcachemetadata +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qnetworkcachemetadata LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qnetworkcachemetadata SOURCES tst_qnetworkcachemetadata.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Network ) diff --git a/tests/auto/network/access/qnetworkcachemetadata/qnetworkcachemetadata.pro b/tests/auto/network/access/qnetworkcachemetadata/qnetworkcachemetadata.pro deleted file mode 100644 index 0e942cd4f4..0000000000 --- a/tests/auto/network/access/qnetworkcachemetadata/qnetworkcachemetadata.pro +++ /dev/null @@ -1,4 +0,0 @@ -CONFIG += testcase -TARGET = tst_qnetworkcachemetadata -QT = core network testlib -SOURCES += tst_qnetworkcachemetadata.cpp diff --git a/tests/auto/network/access/qnetworkcachemetadata/tst_qnetworkcachemetadata.cpp b/tests/auto/network/access/qnetworkcachemetadata/tst_qnetworkcachemetadata.cpp index 49c3f1b17f..d49195efc6 100644 --- a/tests/auto/network/access/qnetworkcachemetadata/tst_qnetworkcachemetadata.cpp +++ b/tests/auto/network/access/qnetworkcachemetadata/tst_qnetworkcachemetadata.cpp @@ -1,33 +1,10 @@ -/**************************************************************************** -** -** 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> +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + + +#include <QTest> +#include <QBuffer> + #include <qabstractnetworkcache.h> #define EXAMPLE_URL "http://user:pass@www.example.com/#foo" @@ -52,6 +29,8 @@ private slots: void operatorEqualEqual(); void rawHeaders_data(); void rawHeaders(); + void headers_data(); + void headers(); void saveToDisk_data(); void saveToDisk(); void url_data(); @@ -137,6 +116,12 @@ void tst_QNetworkCacheMetaData::isValid_data() QNetworkCacheMetaData data5; data5.setSaveToDisk(false); QTest::newRow("valid-5") << data5 << true; + + QNetworkCacheMetaData data6; + QHttpHeaders httpHeaders; + httpHeaders.append("name", "value"); + data6.setHeaders(httpHeaders); + QTest::newRow("valid-6") << data6 << true; } // public bool isValid() const @@ -176,6 +161,9 @@ void tst_QNetworkCacheMetaData::operatorEqual_data() QNetworkCacheMetaData::RawHeaderList headers; headers.append(QNetworkCacheMetaData::RawHeader("foo", "Bar")); data.setRawHeaders(headers); + QHttpHeaders httpHeaders; + httpHeaders.append("name", "value"); + data.setHeaders(httpHeaders); data.setLastModified(QDateTime::currentDateTime()); data.setExpirationDate(QDateTime::currentDateTime()); data.setSaveToDisk(false); @@ -235,6 +223,18 @@ void tst_QNetworkCacheMetaData::operatorEqualEqual_data() QTest::newRow("valid-5-4") << data5 << data2 << false; QTest::newRow("valid-5-5") << data5 << data3 << false; QTest::newRow("valid-5-6") << data5 << data4 << false; + + QNetworkCacheMetaData data6; + QHttpHeaders httpHeaders; + httpHeaders.append("name", "value"); + data6.setHeaders(httpHeaders); + QTest::newRow("valid-6-1") << data6 << QNetworkCacheMetaData() << false; + QTest::newRow("valid-6-2") << data6 << data6 << true; + QTest::newRow("valid-6-3") << data6 << data1 << false; + QTest::newRow("valid-6-4") << data6 << data2 << false; + QTest::newRow("valid-6-5") << data6 << data3 << false; + QTest::newRow("valid-6-6") << data6 << data4 << false; + QTest::newRow("valid-6-7") << data6 << data5 << false; } // public bool operator==(QNetworkCacheMetaData const& other) const @@ -254,7 +254,11 @@ void tst_QNetworkCacheMetaData::rawHeaders_data() QTest::newRow("null") << QNetworkCacheMetaData::RawHeaderList(); QNetworkCacheMetaData::RawHeaderList headers; headers.append(QNetworkCacheMetaData::RawHeader("foo", "Bar")); - QTest::newRow("valie") << headers; + QTest::newRow("valid") << headers; + headers.append(QNetworkCacheMetaData::RawHeader("n1", "V1, v2, v3")); + headers.append(QNetworkCacheMetaData::RawHeader("n2", "V2")); + headers.append(QNetworkCacheMetaData::RawHeader("set-cookie", "v1\nV2\nV3")); + QTest::newRow("valid-2") << headers; } // public QNetworkCacheMetaData::RawHeaderList rawHeaders() const @@ -268,6 +272,25 @@ void tst_QNetworkCacheMetaData::rawHeaders() QCOMPARE(data.rawHeaders(), rawHeaders); } +void tst_QNetworkCacheMetaData::headers_data() +{ + QTest::addColumn<QHttpHeaders>("httpHeaders"); + QTest::newRow("null") << QHttpHeaders(); + QHttpHeaders headers; + headers.append("foo", "Bar"); + QTest::newRow("valid") << headers; +} + +void tst_QNetworkCacheMetaData::headers() +{ + QFETCH(QHttpHeaders, httpHeaders); + + SubQNetworkCacheMetaData data; + + data.setHeaders(httpHeaders); + QCOMPARE(data.headers().toListOfPairs(), httpHeaders.toListOfPairs()); +} + void tst_QNetworkCacheMetaData::saveToDisk_data() { QTest::addColumn<bool>("saveToDisk"); @@ -312,6 +335,9 @@ void tst_QNetworkCacheMetaData::stream() QNetworkCacheMetaData::RawHeaderList headers; headers.append(QNetworkCacheMetaData::RawHeader("foo", "Bar")); data.setRawHeaders(headers); + QHttpHeaders httpHeaders; + httpHeaders.append("name", "value"); + data.setHeaders(httpHeaders); data.setLastModified(QDateTime::currentDateTime()); data.setExpirationDate(QDateTime::currentDateTime()); data.setSaveToDisk(false); diff --git a/tests/auto/network/access/qnetworkcookie/CMakeLists.txt b/tests/auto/network/access/qnetworkcookie/CMakeLists.txt index 24446c90ef..91773a83fd 100644 --- a/tests/auto/network/access/qnetworkcookie/CMakeLists.txt +++ b/tests/auto/network/access/qnetworkcookie/CMakeLists.txt @@ -1,12 +1,19 @@ -# Generated from qnetworkcookie.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qnetworkcookie Test: ##################################################################### -qt_add_test(tst_qnetworkcookie +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qnetworkcookie LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qnetworkcookie SOURCES tst_qnetworkcookie.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Network ) diff --git a/tests/auto/network/access/qnetworkcookie/qnetworkcookie.pro b/tests/auto/network/access/qnetworkcookie/qnetworkcookie.pro deleted file mode 100644 index 320e3a81c5..0000000000 --- a/tests/auto/network/access/qnetworkcookie/qnetworkcookie.pro +++ /dev/null @@ -1,5 +0,0 @@ -CONFIG += testcase -TARGET = tst_qnetworkcookie -SOURCES += tst_qnetworkcookie.cpp - -QT = core network testlib diff --git a/tests/auto/network/access/qnetworkcookie/tst_qnetworkcookie.cpp b/tests/auto/network/access/qnetworkcookie/tst_qnetworkcookie.cpp index 96c4917473..438c5e6983 100644 --- a/tests/auto/network/access/qnetworkcookie/tst_qnetworkcookie.cpp +++ b/tests/auto/network/access/qnetworkcookie/tst_qnetworkcookie.cpp @@ -1,36 +1,13 @@ -/**************************************************************************** -** -** 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 <QtCore/QUrl> +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + + +#include <QTest> #include <QtNetwork/QNetworkCookie> +#include <QtCore/QDateTime> +#include <QtCore/QTimeZone> +#include <QtCore/QUrl> class tst_QNetworkCookie: public QObject { @@ -44,6 +21,8 @@ private slots: void parseMultipleCookies_data(); void parseMultipleCookies(); + + void sameSite(); }; void tst_QNetworkCookie::getterSetter() @@ -108,6 +87,12 @@ void tst_QNetworkCookie::parseSingleCookie_data() { QTest::addColumn<QString>("cookieString"); QTest::addColumn<QNetworkCookie>("expectedCookie"); + const auto utc = [](int year, int month, int day, + int hour = 0, int minute = 0, int second = 0, int millis = 0) { + return QDateTime(QDate(year, month, day), + QTime(hour, minute, second, millis), + QTimeZone::UTC); + }; QNetworkCookie cookie; cookie.setName("a"); @@ -252,140 +237,140 @@ void tst_QNetworkCookie::parseSingleCookie_data() cookie = QNetworkCookie(); cookie.setName("a"); cookie.setValue("b"); - cookie.setExpirationDate(QDateTime(QDate(2012, 1, 29), QTime(23, 59, 59), Qt::UTC)); + cookie.setExpirationDate(utc(2012, 1, 29, 23, 59, 59)); QTest::newRow("broken-expiration1") << "a=b; expires=Sun, 29-Jan-2012 23:59:59;" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1999, 11, 9), QTime(23, 12, 40), Qt::UTC)); + cookie.setExpirationDate(utc(1999, 11, 9, 23, 12, 40)); QTest::newRow("expiration1") << "a=b;expires=Wednesday, 09-Nov-1999 23:12:40 GMT" << cookie; QTest::newRow("expiration2") << "a=b;expires=Wed, 09-Nov-1999 23:12:40 GMT" << cookie; QTest::newRow("expiration3") << "a=b; expires=Wednesday, 09-Nov-1999 23:12:40 GMT " << cookie; QTest::newRow("expiration-utc") << "a=b;expires=Wednesday, 09-Nov-1999 23:12:40 UTC" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 4, 14), QTime(3, 20, 0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 4, 14, 3, 20)); QTest::newRow("time-0") << "a=b;expires=14 Apr 89 03:20" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 4, 14), QTime(3, 20, 12, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 4, 14, 3, 20, 12)); QTest::newRow("time-1") << "a=b;expires=14 Apr 89 03:20:12" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 4, 14), QTime(3, 20, 12, 88), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 4, 14, 3, 20, 12, 88)); QTest::newRow("time-2") << "a=b;expires=14 Apr 89 03:20:12.88" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 4, 14), QTime(3, 20, 12, 88), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 4, 14, 3, 20, 12, 88)); QTest::newRow("time-3") << "a=b;expires=14 Apr 89 03:20:12.88am" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 4, 14), QTime(15, 20, 12, 88), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 4, 14, 15, 20, 12, 88)); QTest::newRow("time-4") << "a=b;expires=14 Apr 89 03:20:12.88pm" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 4, 14), QTime(3, 20, 12, 88), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 4, 14, 3, 20, 12, 88)); QTest::newRow("time-5") << "a=b;expires=14 Apr 89 03:20:12.88 Am" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 4, 14), QTime(15, 20, 12, 88), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 4, 14, 15, 20, 12, 88)); QTest::newRow("time-6") << "a=b;expires=14 Apr 89 03:20:12.88 PM" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 4, 14), QTime(15, 20, 12, 88), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 4, 14, 15, 20, 12, 88)); QTest::newRow("time-7") << "a=b;expires=14 Apr 89 3:20:12.88 PM" << cookie; // normal months - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(1, 1), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 1, 1, 1)); QTest::newRow("months-1") << "a=b;expires=Jan 1 89 1:1" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 2, 1), QTime(1, 1), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 2, 1, 1, 1)); QTest::newRow("months-2") << "a=b;expires=Feb 1 89 1:1" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 3, 1), QTime(1, 1), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 3, 1, 1, 1)); QTest::newRow("months-3") << "a=b;expires=mar 1 89 1:1" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 4, 1), QTime(1, 1), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 4, 1, 1, 1)); QTest::newRow("months-4") << "a=b;expires=Apr 1 89 1:1" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 5, 1), QTime(1, 1), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 5, 1, 1, 1)); QTest::newRow("months-5") << "a=b;expires=May 1 89 1:1" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 6, 1), QTime(1, 1), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 6, 1, 1, 1)); QTest::newRow("months-6") << "a=b;expires=Jun 1 89 1:1" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 7, 1), QTime(1, 1), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 7, 1, 1, 1)); QTest::newRow("months-7") << "a=b;expires=Jul 1 89 1:1" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 8, 1), QTime(1, 1), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 8, 1, 1, 1)); QTest::newRow("months-8") << "a=b;expires=Aug 1 89 1:1" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 9, 1), QTime(1, 1), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 9, 1, 1, 1)); QTest::newRow("months-9") << "a=b;expires=Sep 1 89 1:1" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 10, 1), QTime(1, 1), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 10, 1, 1, 1)); QTest::newRow("months-10") << "a=b;expires=Oct 1 89 1:1" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 11, 1), QTime(1, 1), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 11, 1, 1, 1)); QTest::newRow("months-11") << "a=b;expires=Nov 1 89 1:1" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 12, 1), QTime(1, 1), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 12, 1, 1, 1)); QTest::newRow("months-12") << "a=b;expires=Dec 1 89 1:1" << cookie; // extra months - cookie.setExpirationDate(QDateTime(QDate(1989, 12, 1), QTime(1, 1), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 12, 1, 1, 1)); QTest::newRow("months-13") << "a=b;expires=December 1 89 1:1" << cookie; QTest::newRow("months-14") << "a=b;expires=1 89 1:1 Dec" << cookie; //cookie.setExpirationDate(QDateTime()); //QTest::newRow("months-15") << "a=b;expires=1 89 1:1 De" << cookie; - cookie.setExpirationDate(QDateTime(QDate(2024, 2, 29), QTime(1, 1), Qt::UTC)); + cookie.setExpirationDate(utc(2024, 2, 29, 1, 1)); QTest::newRow("months-16") << "a=b;expires=2024 29 Feb 1:1" << cookie; - cookie.setExpirationDate(QDateTime(QDate(2024, 2, 29), QTime(1, 1), Qt::UTC)); + cookie.setExpirationDate(utc(2024, 2, 29, 1, 1)); QTest::newRow("months-17") << "a=b;expires=Fri, 29-Feb-2024 01:01:00 GMT" << cookie; QTest::newRow("months-18") << "a=b;expires=2024 29 Feb 1:1 GMT" << cookie; // normal offsets - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 1)); QTest::newRow("zoneoffset-0") << "a=b;expires=Jan 1 89 8:0 PST" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 1)); QTest::newRow("zoneoffset-1") << "a=b;expires=Jan 1 89 8:0 PDT" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 1)); QTest::newRow("zoneoffset-2") << "a=b;expires=Jan 1 89 7:0 MST" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 1)); QTest::newRow("zoneoffset-3") << "a=b;expires=Jan 1 89 7:0 MDT" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 1)); QTest::newRow("zoneoffset-4") << "a=b;expires=Jan 1 89 6:0 CST" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 1)); QTest::newRow("zoneoffset-5") << "a=b;expires=Jan 1 89 6:0 CDT" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 1)); QTest::newRow("zoneoffset-6") << "a=b;expires=Jan 1 89 5:0 EST" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 1)); QTest::newRow("zoneoffset-7") << "a=b;expires=Jan 1 89 5:0 EDT" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 1)); QTest::newRow("zoneoffset-8") << "a=b;expires=Jan 1 89 4:0 AST" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 1)); QTest::newRow("zoneoffset-9") << "a=b;expires=Jan 1 89 3:0 NST" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 1)); QTest::newRow("zoneoffset-10") << "a=b;expires=Jan 1 89 0:0 GMT" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 1)); QTest::newRow("zoneoffset-11") << "a=b;expires=Jan 1 89 0:0 BST" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 2), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 2)); QTest::newRow("zoneoffset-12") << "a=b;expires=Jan 1 89 23:0 MET" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 2), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 2)); QTest::newRow("zoneoffset-13") << "a=b;expires=Jan 1 89 22:0 EET" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 2), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 2)); QTest::newRow("zoneoffset-14") << "a=b;expires=Jan 1 89 15:0 JST" << cookie; // extra offsets - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 2), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 2)); QTest::newRow("zoneoffset-15") << "a=b;expires=Jan 1 89 15:0 JST+1" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(1, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 1, 1)); QTest::newRow("zoneoffset-16") << "a=b;expires=Jan 1 89 0:0 GMT+1" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 1)); QTest::newRow("zoneoffset-17") << "a=b;expires=Jan 1 89 1:0 GMT-1" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(1, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 1, 1)); QTest::newRow("zoneoffset-18") << "a=b;expires=Jan 1 89 0:0 GMT+01" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(1, 5), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 1, 1, 5)); QTest::newRow("zoneoffset-19") << "a=b;expires=Jan 1 89 0:0 GMT+0105" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 1)); QTest::newRow("zoneoffset-20") << "a=b;expires=Jan 1 89 0:0 GMT+015" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 1)); QTest::newRow("zoneoffset-21") << "a=b;expires=Jan 1 89 0:0 GM" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 1)); QTest::newRow("zoneoffset-22") << "a=b;expires=Jan 1 89 0:0 GMT" << cookie; // offsets from gmt - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(1, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 1, 1)); QTest::newRow("zoneoffset-23") << "a=b;expires=Jan 1 89 0:0 +1" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(1, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 1, 1)); QTest::newRow("zoneoffset-24") << "a=b;expires=Jan 1 89 0:0 +01" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(1, 1), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 1, 1, 1)); QTest::newRow("zoneoffset-25") << "a=b;expires=Jan 1 89 0:0 +0101" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 1), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 1)); QTest::newRow("zoneoffset-26") << "a=b;expires=Jan 1 89 1:0 -1" << cookie; // Y2k - cookie.setExpirationDate(QDateTime(QDate(2000, 1, 1), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(2000, 1, 1)); QTest::newRow("year-0") << "a=b;expires=Jan 1 00 0:0" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1970, 1, 1), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1970, 1, 1)); QTest::newRow("year-1") << "a=b;expires=Jan 1 70 0:0" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1971, 1, 1), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1971, 1, 1)); QTest::newRow("year-2") << "a=b;expires=Jan 1 71 0:0" << cookie; // Day, month, year - cookie.setExpirationDate(QDateTime(QDate(2013, 1, 2), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(2013, 1, 2)); QTest::newRow("date-0") << "a=b;expires=Jan 2 13 0:0" << cookie; QTest::newRow("date-1") << "a=b;expires=1-2-13 0:0" << cookie; QTest::newRow("date-2") << "a=b;expires=1/2/13 0:0" << cookie; @@ -395,141 +380,141 @@ void tst_QNetworkCookie::parseSingleCookie_data() QTest::newRow("date-6") << "a=b;expires=1/2/13 0:0" << cookie; // Known Year, determine month and day - cookie.setExpirationDate(QDateTime(QDate(1995, 1, 13), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1995, 1, 13)); QTest::newRow("knownyear-0") << "a=b;expires=13/1/95 0:0" << cookie; QTest::newRow("knownyear-1") << "a=b;expires=95/13/1 0:0" << cookie; QTest::newRow("knownyear-2") << "a=b;expires=1995/1/13 0:0" << cookie; QTest::newRow("knownyear-3") << "a=b;expires=1995/13/1 0:0" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1995, 1, 2), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1995, 1, 2)); QTest::newRow("knownyear-4") << "a=b;expires=1/2/95 0:0" << cookie; QTest::newRow("knownyear-5") << "a=b;expires=95/1/2 0:0" << cookie; // Known Year, Known day, determining month - cookie.setExpirationDate(QDateTime(QDate(1995, 1, 13), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1995, 1, 13)); QTest::newRow("knownYD-0") << "a=b;expires=13/1/95 0:0" << cookie; QTest::newRow("knownYD-1") << "a=b;expires=1/13/95 0:0" << cookie; QTest::newRow("knownYD-2") << "a=b;expires=95/13/1 0:0" << cookie; QTest::newRow("knownYD-3") << "a=b;expires=95/1/13 0:0" << cookie; // Month comes before Year - cookie.setExpirationDate(QDateTime(QDate(2021, 03, 26), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(2021, 03, 26)); QTest::newRow("month-0") << "a=b;expires=26/03/21 0:0" << cookie; - cookie.setExpirationDate(QDateTime(QDate(2015, 12, 30), QTime(16, 25, 0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(2015, 12, 30, 16, 25)); QTest::newRow("month-1") << "a=b;expires=wed 16:25pm December 2015 30" << cookie; - cookie.setExpirationDate(QDateTime(QDate(2031, 11, 11), QTime(16, 25, 0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(2031, 11, 11, 16, 25)); QTest::newRow("month-2") << "a=b;expires=16:25 11 31 11" << cookie; // The very ambiguous cases // Matching Firefox's behavior of guessing month, day, year in those cases - cookie.setExpirationDate(QDateTime(QDate(2013, 10, 2), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(2013, 10, 2)); QTest::newRow("ambiguousd-0") << "a=b;expires=10/2/13 0:0" << cookie; - cookie.setExpirationDate(QDateTime(QDate(2013, 2, 10), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(2013, 2, 10)); QTest::newRow("ambiguousd-1") << "a=b;expires=2/10/13 0:0" << cookie; - cookie.setExpirationDate(QDateTime(QDate(2010, 2, 3), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(2010, 2, 3)); QTest::newRow("ambiguousd-2") << "a=b;expires=2/3/10 0:0" << cookie; // FYI If you try these in Firefox it won't set a cookie for the following two string // because 03 is turned into the year at which point it is expired - cookie.setExpirationDate(QDateTime(QDate(2003, 2, 10), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(2003, 2, 10)); QTest::newRow("ambiguousd-3") << "a=b;expires=2/10/3 0:0" << cookie; - cookie.setExpirationDate(QDateTime(QDate(2003, 10, 2), QTime(0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(2003, 10, 2)); QTest::newRow("ambiguousd-4") << "a=b;expires=10/2/3 0:0" << cookie; // These are the cookies that firefox's source says it can parse - cookie.setExpirationDate(QDateTime(QDate(1989, 4, 14), QTime(3, 20, 0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 4, 14, 3, 20)); QTest::newRow("firefox-0") << "a=b;expires=14 Apr 89 03:20" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 4, 14), QTime(3, 20, 0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 4, 14, 3, 20)); QTest::newRow("firefox-1") << "a=b;expires=14 Apr 89 03:20 GMT" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 3, 17), QTime(4, 1, 33, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 3, 17, 4, 1, 33)); QTest::newRow("firefox-2") << "a=b;expires=Fri, 17 Mar 89 4:01:33" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 3, 17), QTime(4, 1, 0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 3, 17, 4, 1)); QTest::newRow("firefox-3") << "a=b;expires=Fri, 17 Mar 89 4:01 GMT" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 16), QTime(16-8, 12, 0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 16, 16-8, 12)); QTest::newRow("firefox-4") << "a=b;expires=Mon Jan 16 16:12 PDT 1989" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1989, 1, 16), QTime(17, 42, 0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1989, 1, 16, 17, 42)); QTest::newRow("firefox-5") << "a=b;expires=Mon Jan 16 16:12 +0130 1989" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1992, 5, 6), QTime(16-9, 41, 0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1992, 5, 6, 16-9, 41)); QTest::newRow("firefox-6") << "a=b;expires=6 May 1992 16:41-JST (Wednesday)" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1993, 8, 22), QTime(10, 59, 12, 82), Qt::UTC)); + cookie.setExpirationDate(utc(1993, 8, 22, 10, 59, 12, 82)); QTest::newRow("firefox-7") << "a=b;expires=22-AUG-1993 10:59:12.82" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1993, 8, 22), QTime(22, 59, 0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1993, 8, 22, 22, 59)); QTest::newRow("firefox-8") << "a=b;expires=22-AUG-1993 10:59pm" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1993, 8, 22), QTime(12, 59, 0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1993, 8, 22, 12, 59)); QTest::newRow("firefox-9") << "a=b;expires=22-AUG-1993 12:59am" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1993, 8, 22), QTime(12, 59, 0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1993, 8, 22, 12, 59)); QTest::newRow("firefox-10") << "a=b;expires=22-AUG-1993 12:59 PM" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1995, 8, 4), QTime(15, 54, 0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1995, 8, 4, 15, 54)); QTest::newRow("firefox-11") << "a=b;expires=Friday, August 04, 1995 3:54 PM" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1995, 6, 21), QTime(16, 24, 34, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1995, 6, 21, 16, 24, 34)); QTest::newRow("firefox-12") << "a=b;expires=06/21/95 04:24:34 PM" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1995, 6, 20), QTime(21, 7, 0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1995, 6, 20, 21, 7)); QTest::newRow("firefox-13") << "a=b;expires=20/06/95 21:07" << cookie; - cookie.setExpirationDate(QDateTime(QDate(1995, 6, 8), QTime(19-5, 32, 48, 0), Qt::UTC)); + cookie.setExpirationDate(utc(1995, 6, 8, 19-5, 32, 48)); QTest::newRow("firefox-14") << "a=b;expires=95-06-08 19:32:48 EDT" << cookie; // Edge cases caught by fuzzing // These are about the default cause creates dates that don't exits - cookie.setExpirationDate(QDateTime(QDate(2030, 2, 25), QTime(1, 1, 0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(2030, 2, 25, 1, 1)); QTest::newRow("fuzz-0") << "a=b; expires=30 -000002 1:1 25;" << cookie; - cookie.setExpirationDate(QDateTime(QDate(2031, 11, 20), QTime(1, 1, 0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(2031, 11, 20, 1, 1)); QTest::newRow("fuzz-1") << "a=b; expires=31 11 20 1:1;" << cookie; // April only has 30 days - cookie.setExpirationDate(QDateTime(QDate(2031, 4, 30), QTime(1, 1, 0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(2031, 4, 30, 1, 1)); QTest::newRow("fuzz-2") << "a=b; expires=31 30 4 1:1" << cookie; // 9 must be the month so 31 can't be the day - cookie.setExpirationDate(QDateTime(QDate(2031, 9, 21), QTime(1, 1, 0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(2031, 9, 21, 1, 1)); QTest::newRow("fuzz-3") << "a=b; expires=31 21 9 1:1" << cookie; // Year is known, then fallback to defaults of filling in month and day - cookie.setExpirationDate(QDateTime(QDate(2031, 11, 1), QTime(1, 1, 0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(2031, 11, 1, 1, 1)); QTest::newRow("fuzz-4") << "a=b; expires=31 11 01 1:1" << cookie; // 2 must be the month so 30 can't be the day - cookie.setExpirationDate(QDateTime(QDate(2030, 2, 20), QTime(1, 1, 0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(2030, 2, 20, 1, 1)); QTest::newRow("fuzz-5") << "a=b; expires=30 02 20 1:1" << cookie; - cookie.setExpirationDate(QDateTime(QDate(2021, 12, 22), QTime(1, 1, 0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(2021, 12, 22, 1, 1)); QTest::newRow("fuzz-6") << "a=b; expires=2021 12 22 1:1" << cookie; - cookie.setExpirationDate(QDateTime(QDate(2029, 2, 23), QTime(1, 1, 0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(2029, 2, 23, 1, 1)); QTest::newRow("fuzz-7") << "a=b; expires=29 23 Feb 1:1" << cookie; // 11 and 6 don't have 31 days - cookie.setExpirationDate(QDateTime(QDate(2031, 11, 06), QTime(1, 1, 0, 0), Qt::UTC)); + cookie.setExpirationDate(utc(2031, 11, 06, 1, 1)); QTest::newRow("fuzz-8") << "a=b; expires=31 11 06 1:1" << cookie; // two-digit years: // from 70 until 99, we assume 20th century - cookie.setExpirationDate(QDateTime(QDate(1999, 11, 9), QTime(23, 12, 40), Qt::UTC)); + cookie.setExpirationDate(utc(1999, 11, 9, 23, 12, 40)); QTest::newRow("expiration-2digit1") << "a=b; expires=Wednesday, 09-Nov-99 23:12:40 GMT " << cookie; - cookie.setExpirationDate(QDateTime(QDate(1970, 1, 1), QTime(23, 12, 40), Qt::UTC)); + cookie.setExpirationDate(utc(1970, 1, 1, 23, 12, 40)); QTest::newRow("expiration-2digit2") << "a=b; expires=Thursday, 01-Jan-70 23:12:40 GMT " << cookie; // from 00 until 69, we assume 21st century - cookie.setExpirationDate(QDateTime(QDate(2000, 1, 1), QTime(23, 12, 40), Qt::UTC)); + cookie.setExpirationDate(utc(2000, 1, 1, 23, 12, 40)); QTest::newRow("expiration-2digit3") << "a=b; expires=Saturday, 01-Jan-00 23:12:40 GMT " << cookie; - cookie.setExpirationDate(QDateTime(QDate(2020, 1, 1), QTime(23, 12, 40), Qt::UTC)); + cookie.setExpirationDate(utc(2020, 1, 1, 23, 12, 40)); QTest::newRow("expiration-2digit4") << "a=b; expires=Wednesday, 01-Jan-20 23:12:40 GMT " << cookie; - cookie.setExpirationDate(QDateTime(QDate(2069, 1, 1), QTime(23, 12, 40), Qt::UTC)); + cookie.setExpirationDate(utc(2069, 1, 1, 23, 12, 40)); QTest::newRow("expiration-2digit5") << "a=b; expires=Wednesday, 01-Jan-69 23:12:40 GMT " << cookie; - cookie.setExpirationDate(QDateTime(QDate(1999, 11, 9), QTime(23, 12, 40), Qt::UTC)); + cookie.setExpirationDate(utc(1999, 11, 9, 23, 12, 40)); cookie.setPath("/"); QTest::newRow("expires+path") << "a=b; expires=Wed, 09-Nov-1999 23:12:40 GMT; path=/" << cookie; @@ -542,7 +527,7 @@ void tst_QNetworkCookie::parseSingleCookie_data() // cookies obtained from the network: cookie = QNetworkCookie("__siteid", "1"); cookie.setPath("/"); - cookie.setExpirationDate(QDateTime(QDate(9999, 12, 31), QTime(23, 59, 59), Qt::UTC)); + cookie.setExpirationDate(utc(9999, 12, 31, 23, 59, 59)); QTest::newRow("network2") << "__siteid=1; expires=Fri, 31-Dec-9999 23:59:59 GMT; path=/" << cookie; cookie = QNetworkCookie("YM.LC", "v=2&m=9993_262838_159_1558_1063_0_5649_4012_3776161073,9426_260205_549_1295_1336_0_5141_4738_3922731647,6733_258196_952_1364_643_0_3560_-1_0,3677_237633_1294_1294_19267_0_3244_29483_4102206176,1315_235149_1693_1541_941_0_3224_1691_1861378060,1858_214311_2100_1298_19538_0_2873_30900_716411652,6258_212007_2506_1285_1017_0_2868_3606_4288540264,3743_207884_2895_1362_2759_0_2545_7114_3388520216,2654_205253_3257_1297_1332_0_2504_4682_3048534803,1891_184881_3660_1291_19079_0_978_29178_2592538685&f=1&n=20&s=date&o=down&e=1196548712&b=Inbox&u=removed"); @@ -552,13 +537,13 @@ void tst_QNetworkCookie::parseSingleCookie_data() cookie = QNetworkCookie("__ac", "\"c2hhdXNtYW46U2FTYW80Wm8%3D\""); cookie.setPath("/"); - cookie.setExpirationDate(QDateTime(QDate(2008, 8, 30), QTime(20, 21, 49), Qt::UTC)); + cookie.setExpirationDate(utc(2008, 8, 30, 20, 21, 49)); QTest::newRow("network4") << "__ac=\"c2hhdXNtYW46U2FTYW80Wm8%3D\"; Path=/; Expires=Sat, 30 Aug 2008 20:21:49 +0000" << cookie; // linkedin.com sends cookies in quotes and expects the cookie in quotes cookie = QNetworkCookie("leo_auth_token", "\"GST:UroVXaxYA3sVSkoVjMNH9bj4dZxVzK2yekgrAUxMfUsyLTNyPjoP60:1298974875:b675566ae32ab36d7a708c0efbf446a5c22b9fca\""); cookie.setPath("/"); - cookie.setExpirationDate(QDateTime(QDate(2011, 3, 1), QTime(10, 51, 14), Qt::UTC)); + cookie.setExpirationDate(utc(2011, 3, 1, 10, 51, 14)); QTest::newRow("network5") << "leo_auth_token=\"GST:UroVXaxYA3sVSkoVjMNH9bj4dZxVzK2yekgrAUxMfUsyLTNyPjoP60:1298974875:b675566ae32ab36d7a708c0efbf446a5c22b9fca\"; Version=1; Max-Age=1799; Expires=Tue, 01-Mar-2011 10:51:14 GMT; Path=/" << cookie; // cookie containing JSON data (illegal for server, client should accept) - QTBUG-26002 @@ -576,11 +561,11 @@ void tst_QNetworkCookie::parseSingleCookie() QList<QNetworkCookie> result = QNetworkCookie::parseCookies(cookieString.toUtf8()); //QEXPECT_FAIL("network2", "QDateTime parsing problem: the date is beyond year 8000", Abort); - QCOMPARE(result.count(), 1); + QCOMPARE(result.size(), 1); QCOMPARE(result.at(0), expectedCookie); result = QNetworkCookie::parseCookies(result.at(0).toRawForm()); - QCOMPARE(result.count(), 1); + QCOMPARE(result.size(), 1); // Drop any millisecond information, if there's any QDateTime dt = expectedCookie.expirationDate(); @@ -634,7 +619,7 @@ void tst_QNetworkCookie::parseMultipleCookies_data() cookie = QNetworkCookie("id", "51706646077999719"); cookie.setDomain(".bluestreak.com"); cookie.setPath("/"); - cookie.setExpirationDate(QDateTime(QDate(2017, 12, 05), QTime(9, 11, 7), Qt::UTC)); + cookie.setExpirationDate(QDateTime(QDate(2017, 12, 05), QTime(9, 11, 7), QTimeZone::UTC)); list << cookie; cookie.setName("bb"); cookie.setValue("\\\"K14144t\\\"_AAQ\\\"ototrK_A_ttot44AQ4KwoRQtoto|"); @@ -653,8 +638,8 @@ void tst_QNetworkCookie::parseMultipleCookies_data() cookieB.setValue("d"); // NewLine - cookieA.setExpirationDate(QDateTime(QDate(2009, 3, 10), QTime(7, 0, 0, 0), Qt::UTC)); - cookieB.setExpirationDate(QDateTime(QDate(2009, 3, 20), QTime(7, 0, 0, 0), Qt::UTC)); + cookieA.setExpirationDate(QDateTime(QDate(2009, 3, 10), QTime(7, 0), QTimeZone::UTC)); + cookieB.setExpirationDate(QDateTime(QDate(2009, 3, 20), QTime(7, 0), QTimeZone::UTC)); list = QList<QNetworkCookie>() << cookieA << cookieB; QTest::newRow("real-0") << "a=b; expires=Tue Mar 10 07:00:00 2009 GMT\nc=d; expires=Fri Mar 20 07:00:00 2009 GMT" << list; QTest::newRow("real-1") << "a=b; expires=Tue Mar 10 07:00:00 2009 GMT\n\nc=d; expires=Fri Mar 20 07:00:00 2009 GMT" << list; @@ -683,5 +668,16 @@ void tst_QNetworkCookie::parseMultipleCookies() QCOMPARE(result, expectedCookies); } +void tst_QNetworkCookie::sameSite() +{ + QList<QNetworkCookie> result = QNetworkCookie::parseCookies(QByteArrayLiteral("a=b;domain=qt-project.org")); + QCOMPARE(result.first().sameSitePolicy(), QNetworkCookie::SameSite::Default); + result = QNetworkCookie::parseCookies(QByteArrayLiteral("a=b;domain=qt-project.org;samesite=strict")); + QCOMPARE(result.first().sameSitePolicy(), QNetworkCookie::SameSite::Strict); + result = QNetworkCookie::parseCookies(QByteArrayLiteral("a=b;domain=qt-project.org;samesite=none;secure")); + QCOMPARE(result.first().sameSitePolicy(), QNetworkCookie::SameSite::None); + QCOMPARE(result.first().toRawForm(), QByteArrayLiteral("a=b; secure; SameSite=None; domain=qt-project.org")); + +} QTEST_MAIN(tst_QNetworkCookie) #include "tst_qnetworkcookie.moc" diff --git a/tests/auto/network/access/qnetworkcookiejar/CMakeLists.txt b/tests/auto/network/access/qnetworkcookiejar/CMakeLists.txt index f6aafcb69b..0d74a1d84d 100644 --- a/tests/auto/network/access/qnetworkcookiejar/CMakeLists.txt +++ b/tests/auto/network/access/qnetworkcookiejar/CMakeLists.txt @@ -1,16 +1,23 @@ -# Generated from qnetworkcookiejar.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qnetworkcookiejar Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qnetworkcookiejar LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + # Collect test data -list(APPEND test_data "parser.json") +list(APPEND test_data "parser.json" "testdata/publicsuffix/public_suffix_list.dafsa") -qt_add_test(tst_qnetworkcookiejar +qt_internal_add_test(tst_qnetworkcookiejar SOURCES tst_qnetworkcookiejar.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::Network Qt::NetworkPrivate diff --git a/tests/auto/network/access/qnetworkcookiejar/qnetworkcookiejar.pro b/tests/auto/network/access/qnetworkcookiejar/qnetworkcookiejar.pro deleted file mode 100644 index e679f8a930..0000000000 --- a/tests/auto/network/access/qnetworkcookiejar/qnetworkcookiejar.pro +++ /dev/null @@ -1,6 +0,0 @@ -CONFIG += testcase -TARGET = tst_qnetworkcookiejar -SOURCES += tst_qnetworkcookiejar.cpp - -QT = core core-private network network-private testlib -TESTDATA = parser.json diff --git a/tests/auto/network/access/qnetworkcookiejar/testdata/publicsuffix/public_suffix_list.dafsa b/tests/auto/network/access/qnetworkcookiejar/testdata/publicsuffix/public_suffix_list.dafsa Binary files differnew file mode 100644 index 0000000000..f891b16963 --- /dev/null +++ b/tests/auto/network/access/qnetworkcookiejar/testdata/publicsuffix/public_suffix_list.dafsa diff --git a/tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp b/tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp index 10d7aa20f8..9460060dbf 100644 --- a/tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp +++ b/tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp @@ -1,33 +1,7 @@ -/**************************************************************************** -** -** 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> +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QTest> #include <QtCore/QJsonArray> #include <QtCore/QJsonDocument> #include <QtCore/QJsonObject> @@ -37,14 +11,17 @@ #include <QtNetwork/QNetworkRequest> #if QT_CONFIG(topleveldomain) #include "private/qtldurl_p.h" -#include "private/qurltlds_p.h" #endif +#include <memory> + class tst_QNetworkCookieJar: public QObject { Q_OBJECT private slots: + void initTestCase(); + void getterSetter(); void setCookiesFromUrl_data(); void setCookiesFromUrl(); @@ -56,6 +33,8 @@ private slots: #endif void rfc6265_data(); void rfc6265(); +private: + QSharedPointer<QTemporaryDir> m_dataDir; }; class MyCookieJar: public QNetworkCookieJar @@ -83,6 +62,22 @@ void tst_QNetworkCookieJar::getterSetter() QCOMPARE(jar.allCookies(), list); } +void tst_QNetworkCookieJar::initTestCase() +{ +#if QT_CONFIG(topleveldomain) && QT_CONFIG(publicsuffix_system) + QString testDataDir; +#ifdef BUILTIN_TESTDATA + m_dataDir = QEXTRACTTESTDATA("/testdata"); + QVERIFY(m_dataDir); + testDataDir = m_dataDir->path() + "/testdata"; +#else + testDataDir = QFINDTESTDATA("testdata"); +#endif + qDebug() << "Test data dir:" << testDataDir; + qputenv("XDG_DATA_DIRS", QFile::encodeName(testDataDir)); +#endif +} + void tst_QNetworkCookieJar::setCookiesFromUrl_data() { QTest::addColumn<QList<QNetworkCookie> >("preset"); @@ -241,7 +236,7 @@ void tst_QNetworkCookieJar::setCookiesFromUrl() QFETCH(QList<QNetworkCookie>, preset); QFETCH(QNetworkCookie, newCookie); QFETCH(QString, referenceUrl); - QFETCH(QList<QNetworkCookie>, expectedResult); + QFETCH(const QList<QNetworkCookie>, expectedResult); QFETCH(bool, setCookies); QList<QNetworkCookie> cookieList; @@ -251,11 +246,11 @@ void tst_QNetworkCookieJar::setCookiesFromUrl() QCOMPARE(jar.setCookiesFromUrl(cookieList, referenceUrl), setCookies); QList<QNetworkCookie> result = jar.allCookies(); - foreach (QNetworkCookie cookie, expectedResult) { + for (const QNetworkCookie &cookie : expectedResult) { QVERIFY2(result.contains(cookie), cookie.toRawForm()); result.removeAll(cookie); } - QVERIFY2(result.isEmpty(), QTest::toString(result)); + QVERIFY2(result.isEmpty(), std::unique_ptr<char[]>(QTest::toString(result)).get()); } void tst_QNetworkCookieJar::cookiesForUrl_data() @@ -414,13 +409,11 @@ void tst_QNetworkCookieJar::effectiveTLDs_data() QTest::newRow("yes1") << "com" << true; QTest::newRow("yes2") << "de" << true; - QTest::newRow("yes3") << "ulm.museum" << true; QTest::newRow("yes4") << "krodsherad.no" << true; QTest::newRow("yes5") << "1.bg" << true; QTest::newRow("yes6") << "com.cn" << true; QTest::newRow("yes7") << "org.ws" << true; QTest::newRow("yes8") << "co.uk" << true; - QTest::newRow("yes9") << "wallonie.museum" << true; QTest::newRow("yes10") << "hk.com" << true; QTest::newRow("yes11") << "hk.org" << true; @@ -437,33 +430,23 @@ void tst_QNetworkCookieJar::effectiveTLDs_data() QTest::newRow("no11") << "mosreg.ru" << false; const char16_t s1[] = {0x74, 0x72, 0x61, 0x6e, 0xf8, 0x79, 0x2e, 0x6e, 0x6f, 0x00}; // xn--trany-yua.no - const char16_t s2[] = {0x5d9, 0x5e8, 0x5d5, 0x5e9, 0x5dc, 0x5d9, 0x5dd, 0x2e, 0x6d, 0x75, 0x73, 0x65, 0x75, 0x6d, 0x00}; // xn--9dbhblg6di.museum const char16_t s3[] = {0x7ec4, 0x7e54, 0x2e, 0x68, 0x6b, 0x00}; // xn--mk0axi.hk const char16_t s4[] = {0x7f51, 0x7edc, 0x2e, 0x63, 0x6e, 0x00}; // xn--io0a7i.cn const char16_t s5[] = {0x72, 0xe1, 0x68, 0x6b, 0x6b, 0x65, 0x72, 0xe1, 0x76, 0x6a, 0x75, 0x2e, 0x6e, 0x6f, 0x00}; // xn--rhkkervju-01af.no const char16_t s6[] = {0xb9a, 0xbbf, 0xb99, 0xbcd, 0xb95, 0xbaa, 0xbcd, 0xbaa, 0xbc2, 0xbb0, 0xbcd, 0x00}; // xn--clchc0ea0b2g2a9gcd const char16_t s7[] = {0x627, 0x644, 0x627, 0x631, 0x62f, 0x646, 0x00}; // xn--mgbayh7gpa - const char16_t s8[] = {0x63, 0x6f, 0x72, 0x72, 0x65, 0x69, 0x6f, 0x73, 0x2d, 0x65, 0x2d, 0x74, 0x65, 0x6c, 0x65, - 0x63, 0x6f, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0xe7, 0xf5, 0x65, 0x73, 0x2e, 0x6d, 0x75, - 0x73, 0x65, 0x75, 0x6d, 0x00}; // xn--correios-e-telecomunicaes-ghc29a.museum QTest::newRow("yes-specialchars1") << QString::fromUtf16(s1) << true; - QTest::newRow("yes-specialchars2") << QString::fromUtf16(s2) << true; QTest::newRow("yes-specialchars3") << QString::fromUtf16(s3) << true; QTest::newRow("yes-specialchars4") << QString::fromUtf16(s4) << true; QTest::newRow("yes-specialchars5") << QString::fromUtf16(s5) << true; QTest::newRow("yes-specialchars6") << QString::fromUtf16(s6) << true; QTest::newRow("yes-specialchars7") << QString::fromUtf16(s7) << true; - QTest::newRow("yes-specialchars8") << QString::fromUtf16(s8) << true; QTest::newRow("no-specialchars1") << QString::fromUtf16(s1).prepend("something") << false; - QTest::newRow("no-specialchars2") << QString::fromUtf16(s2).prepend(QString::fromUtf16(s2)) << false; - QTest::newRow("no-specialchars2.5") << QString::fromUtf16(s2).prepend("whatever") << false; QTest::newRow("no-specialchars3") << QString::fromUtf16(s3).prepend("foo") << false; QTest::newRow("no-specialchars4") << QString::fromUtf16(s4).prepend("bar") << false; - QTest::newRow("no-specialchars5") << QString::fromUtf16(s5).prepend(QString::fromUtf16(s2)) << false; QTest::newRow("no-specialchars6") << QString::fromUtf16(s6).prepend(QLatin1Char('.') + QString::fromUtf16(s6)) << false; QTest::newRow("no-specialchars7") << QString::fromUtf16(s7).prepend("bla") << false; - QTest::newRow("no-specialchars8") << QString::fromUtf16(s8).append("foo") << false; QTest::newRow("exception1") << "pref.iwate.jp" << false; QTest::newRow("exception2") << "omanpost.om" << false; @@ -477,24 +460,8 @@ void tst_QNetworkCookieJar::effectiveTLDs_data() QTest::newRow("no-wildcard3") << "whatever.uk" << false; // was changed at some point QTest::newRow("yes-wildcard4") << "anything.sendai.jp" << true; QTest::newRow("yes-wildcard5") << "foo.sch.uk" << true; - QTest::newRow("yes-wildcard6") << "something.platform.sh" << true; - - int i; - for (i = 0; tldIndices[i] < tldChunks[0]; i++) { } - Q_ASSERT(i < tldCount); - int TLDsInFirstChunk = i; - - const char *lastGroupFromFirstChunk = &tldData[0][tldIndices[TLDsInFirstChunk - 1]]; - QTest::addRow("lastGroupFromFirstChunk: %s", lastGroupFromFirstChunk) - << lastGroupFromFirstChunk - << true; - - Q_ASSERT(tldChunkCount > 1); // There are enough TLDs to fill 64K bytes - const char *lastGroupFromLastChunk = - &tldData[tldChunkCount-1][tldIndices[tldCount - 1] - tldChunks[tldChunkCount - 2]]; - QTest::addRow("lastGroupFromLastChunk: %s", lastGroupFromLastChunk) - << lastGroupFromLastChunk - << true; + QTest::newRow("yes-platform.sh") << "eu.platform.sh" << true; + QTest::newRow("no-platform.sh") << "something.platform.sh" << false; } void tst_QNetworkCookieJar::effectiveTLDs() @@ -518,7 +485,7 @@ void tst_QNetworkCookieJar::rfc6265_data() QVERIFY(!document.isNull()); QVERIFY(document.isArray()); - foreach (const QJsonValue& testCase, document.array()) { + for (const QJsonValue testCase : document.array()) { QJsonObject testObject = testCase.toObject(); //"test" - the test case name @@ -527,15 +494,15 @@ void tst_QNetworkCookieJar::rfc6265_data() continue; //"received" - the cookies received from the server - QJsonArray received = testObject.value("received").toArray(); + const QJsonArray received = testObject.value("received").toArray(); QStringList receivedList; - foreach (const QJsonValue& receivedCookie, received) + for (const QJsonValue receivedCookie : received) receivedList.append(receivedCookie.toString()); //"sent" - the cookies sent back to the server - QJsonArray sent = testObject.value("sent").toArray(); + const QJsonArray sent = testObject.value("sent").toArray(); QList<QNetworkCookie> sentList; - foreach (const QJsonValue& sentCookie, sent) { + for (const QJsonValue sentCookie : sent) { QJsonObject sentCookieObject = sentCookie.toObject(); QNetworkCookie cookie; cookie.setName(sentCookieObject.value("name").toString().toUtf8()); @@ -550,7 +517,7 @@ void tst_QNetworkCookieJar::rfc6265_data() void tst_QNetworkCookieJar::rfc6265() { - QFETCH(QStringList, received); + QFETCH(const QStringList, received); QFETCH(QList<QNetworkCookie>, sent); QFETCH(QString, sentTo); @@ -561,16 +528,16 @@ void tst_QNetworkCookieJar::rfc6265() QNetworkCookieJar jar; QList<QNetworkCookie> receivedCookies; - foreach (const QString &cookieLine, received) + for (const QString &cookieLine : received) receivedCookies.append(QNetworkCookie::parseCookies(cookieLine.toUtf8())); jar.setCookiesFromUrl(receivedCookies, receivedUrl); QList<QNetworkCookie> cookiesToSend = jar.cookiesForUrl(sentUrl); //compare cookies only using name/value, as the metadata isn't sent over the network - QCOMPARE(cookiesToSend.count(), sent.count()); + QCOMPARE(cookiesToSend.size(), sent.size()); bool ok = true; - for (int i = 0; i < cookiesToSend.count(); i++) { + for (int i = 0; i < cookiesToSend.size(); i++) { if (cookiesToSend.at(i).name() != sent.at(i).name()) { ok = false; break; diff --git a/tests/auto/network/access/qnetworkdiskcache/CMakeLists.txt b/tests/auto/network/access/qnetworkdiskcache/CMakeLists.txt index 484cb47e2b..023868f57e 100644 --- a/tests/auto/network/access/qnetworkdiskcache/CMakeLists.txt +++ b/tests/auto/network/access/qnetworkdiskcache/CMakeLists.txt @@ -1,12 +1,19 @@ -# Generated from qnetworkdiskcache.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qnetworkdiskcache Test: ##################################################################### -qt_add_test(tst_qnetworkdiskcache +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qnetworkdiskcache LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qnetworkdiskcache SOURCES tst_qnetworkdiskcache.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Network ) diff --git a/tests/auto/network/access/qnetworkdiskcache/qnetworkdiskcache.pro b/tests/auto/network/access/qnetworkdiskcache/qnetworkdiskcache.pro deleted file mode 100644 index 4a78544bf8..0000000000 --- a/tests/auto/network/access/qnetworkdiskcache/qnetworkdiskcache.pro +++ /dev/null @@ -1,4 +0,0 @@ -CONFIG += testcase -TARGET = tst_qnetworkdiskcache -QT = core network testlib -SOURCES += tst_qnetworkdiskcache.cpp diff --git a/tests/auto/network/access/qnetworkdiskcache/tst_qnetworkdiskcache.cpp b/tests/auto/network/access/qnetworkdiskcache/tst_qnetworkdiskcache.cpp index 50f118a89f..ec32c780cd 100644 --- a/tests/auto/network/access/qnetworkdiskcache/tst_qnetworkdiskcache.cpp +++ b/tests/auto/network/access/qnetworkdiskcache/tst_qnetworkdiskcache.cpp @@ -1,42 +1,18 @@ -/**************************************************************************** -** -** 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> +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + #include <QtNetwork/QtNetwork> +#include <QTest> +#include <QTestEventLoop> #include <qnetworkdiskcache.h> #include <qrandom.h> #include <algorithm> #define EXAMPLE_URL "http://user:pass@localhost:4/#foo" +#define EXAMPLE_URL2 "http://user:pass@localhost:4/bar" //cached objects are organized into these many subdirs -#define NUM_SUBDIRECTORIES 16 +#define NUM_SUBDIRECTORIES 15 class tst_QNetworkDiskCache : public QObject { @@ -129,7 +105,7 @@ public slots: if (doClose) { client->disconnectFromHost(); disconnect(client, 0, this, 0); - client = 0; + client = nullptr; } } } @@ -141,7 +117,7 @@ class SubQNetworkDiskCache : public QNetworkDiskCache public: ~SubQNetworkDiskCache() { - if (!cacheDirectory().isEmpty()) + if (!cacheDirectory().isEmpty() && clearOnDestruction) clear(); } @@ -155,7 +131,7 @@ public: { setCacheDirectory(path); - QIODevice *d = 0; + QIODevice *d = nullptr; if (metaData.isValid()) { d = prepare(metaData); } else { @@ -170,6 +146,11 @@ public: d->write("Hello World!"); insert(d); } + + void setClearCacheOnDestruction(bool value) { clearOnDestruction = value; } + +private: + bool clearOnDestruction = true; }; tst_QNetworkDiskCache::tst_QNetworkDiskCache() @@ -241,17 +222,39 @@ void tst_QNetworkDiskCache::prepare() // public qint64 cacheSize() const void tst_QNetworkDiskCache::cacheSize() { - SubQNetworkDiskCache cache; - cache.setCacheDirectory(tempDir.path()); - QCOMPARE(cache.cacheSize(), qint64(0)); + qint64 cacheSize = 0; + { + SubQNetworkDiskCache cache; + cache.setCacheDirectory(tempDir.path()); + QCOMPARE(cache.cacheSize(), qint64(0)); - QUrl url(EXAMPLE_URL); - QNetworkCacheMetaData metaData; - metaData.setUrl(url); - QIODevice *d = cache.prepare(metaData); - cache.insert(d); - QVERIFY(cache.cacheSize() > qint64(0)); + { + QUrl url(EXAMPLE_URL); + QNetworkCacheMetaData metaData; + metaData.setUrl(url); + QIODevice *d = cache.prepare(metaData); + cache.insert(d); + cacheSize = cache.cacheSize(); + QVERIFY(cacheSize > qint64(0)); + } + // Add a second item, some difference in behavior when the cache is not empty + { + QUrl url(EXAMPLE_URL2); + QNetworkCacheMetaData metaData; + metaData.setUrl(url); + QIODevice *d = cache.prepare(metaData); + cache.insert(d); + QVERIFY(cache.cacheSize() > cacheSize); + cacheSize = cache.cacheSize(); + } + // Don't clear the cache on destruction so we can re-open the cache and test its size. + cache.setClearCacheOnDestruction(false); + } + + SubQNetworkDiskCache cache; + cache.setCacheDirectory(tempDir.path()); + QCOMPARE(cache.cacheSize(), cacheSize); cache.clear(); QCOMPARE(cache.cacheSize(), qint64(0)); } @@ -275,17 +278,17 @@ void tst_QNetworkDiskCache::clear() QVERIFY(cache.cacheSize() > qint64(0)); QString cacheDirectory = cache.cacheDirectory(); - QCOMPARE(countFiles(cacheDirectory).count(), NUM_SUBDIRECTORIES + 3); + QCOMPARE(countFiles(cacheDirectory).size(), NUM_SUBDIRECTORIES + 3); cache.clear(); - QCOMPARE(countFiles(cacheDirectory).count(), NUM_SUBDIRECTORIES + 2); + QCOMPARE(countFiles(cacheDirectory).size(), NUM_SUBDIRECTORIES + 2); // don't delete files that it didn't create QTemporaryFile file(cacheDirectory + "/XXXXXX"); if (file.open()) { file.fileName(); // make sure it exists with a name - QCOMPARE(countFiles(cacheDirectory).count(), NUM_SUBDIRECTORIES + 3); + QCOMPARE(countFiles(cacheDirectory).size(), NUM_SUBDIRECTORIES + 3); cache.clear(); - QCOMPARE(countFiles(cacheDirectory).count(), NUM_SUBDIRECTORIES + 3); + QCOMPARE(countFiles(cacheDirectory).size(), NUM_SUBDIRECTORIES + 3); } } @@ -352,9 +355,9 @@ void tst_QNetworkDiskCache::remove() QUrl url(EXAMPLE_URL); cache.setupWithOne(tempDir.path(), url); QString cacheDirectory = cache.cacheDirectory(); - QCOMPARE(countFiles(cacheDirectory).count(), NUM_SUBDIRECTORIES + 3); + QCOMPARE(countFiles(cacheDirectory).size(), NUM_SUBDIRECTORIES + 3); cache.remove(url); - QCOMPARE(countFiles(cacheDirectory).count(), NUM_SUBDIRECTORIES + 2); + QCOMPARE(countFiles(cacheDirectory).size(), NUM_SUBDIRECTORIES + 2); } void tst_QNetworkDiskCache::accessAfterRemove() // QTBUG-17400 @@ -473,9 +476,9 @@ void tst_QNetworkDiskCache::fileMetaData() url.setFragment(QString()); QString cacheDirectory = cache.cacheDirectory(); - QStringList list = countFiles(cacheDirectory); - QCOMPARE(list.count(), NUM_SUBDIRECTORIES + 3); - foreach(QString fileName, list) { + const QStringList list = countFiles(cacheDirectory); + QCOMPARE(list.size(), NUM_SUBDIRECTORIES + 3); + for (const QString &fileName : list) { QFileInfo info(fileName); if (info.isFile()) { QNetworkCacheMetaData metaData = cache.call_fileMetaData(fileName); @@ -518,9 +521,9 @@ void tst_QNetworkDiskCache::expire() } QString cacheDirectory = cache.cacheDirectory(); - QStringList list = countFiles(cacheDirectory); + const QStringList list = countFiles(cacheDirectory); QStringList cacheList; - foreach(QString fileName, list) { + for (const QString &fileName : list) { QFileInfo info(fileName); if (info.isFile()) { QNetworkCacheMetaData metaData = cache.call_fileMetaData(fileName); @@ -528,7 +531,7 @@ void tst_QNetworkDiskCache::expire() } } std::sort(cacheList.begin(), cacheList.end()); - for (int i = 0; i < cacheList.count(); ++i) { + for (int i = 0; i < cacheList.size(); ++i) { QString fileName = cacheList[i]; QCOMPARE(fileName, QLatin1String("http://localhost:4/") + QString::number(i + 6)); } @@ -566,11 +569,11 @@ void tst_QNetworkDiskCache::oldCacheVersionFile() QVERIFY(!metaData.isValid()); QVERIFY(!QFile::exists(name)); } else { - QStringList files = countFiles(cache.cacheDirectory()); - QCOMPARE(files.count(), NUM_SUBDIRECTORIES + 3); + const QStringList files = countFiles(cache.cacheDirectory()); + QCOMPARE(files.size(), NUM_SUBDIRECTORIES + 3); // find the file QString cacheFile; - foreach (QString file, files) { + for (const QString &file : files) { QFileInfo info(file); if (info.isFile()) cacheFile = file; @@ -607,8 +610,8 @@ void tst_QNetworkDiskCache::streamVersion() QString cacheFile; // find the file - QStringList files = countFiles(cache.cacheDirectory()); - foreach (const QString &file, files) { + const QStringList files = countFiles(cache.cacheDirectory()); + for (const QString &file : files) { QFileInfo info(file); if (info.isFile()) { cacheFile = file; @@ -654,6 +657,7 @@ void tst_QNetworkDiskCache::streamVersion() QIODevice *dataDevice = cache.data(url); QVERIFY(dataDevice != 0); QByteArray cachedData = dataDevice->readAll(); + delete dataDevice; QCOMPARE(cachedData, data); } } @@ -690,8 +694,6 @@ public: QNetworkDiskCache cache; cache.setCacheDirectory(cachePath); - int read = 0; - int i = 0; for (; i < 5000; ++i) { if (other && other->isFinished()) @@ -733,7 +735,7 @@ public: if (d) { QByteArray x = d->readAll(); if (x != longString && x != longString2) { - qDebug() << x.length() << QString(x); + qDebug() << x.size() << QString(x); gotMetaData = cache.metaData(url); qDebug() << (gotMetaData.url().toString()) << gotMetaData.lastModified() @@ -742,7 +744,6 @@ public: } if (gotMetaData.isValid()) QVERIFY(x == longString || x == longString2); - read++; delete d; } } @@ -750,9 +751,8 @@ public: cache.remove(url); if (QRandomGenerator::global()->bounded(5) == 1) cache.clear(); - sleep(0); + sleep(std::chrono::seconds{0}); } - //qDebug() << "read!" << read << i; } QDateTime dt; diff --git a/tests/auto/network/access/qnetworkreply/4G.br b/tests/auto/network/access/qnetworkreply/4G.br Binary files differnew file mode 100644 index 0000000000..dabd553ed7 --- /dev/null +++ b/tests/auto/network/access/qnetworkreply/4G.br diff --git a/tests/auto/network/access/qnetworkreply/BLACKLIST b/tests/auto/network/access/qnetworkreply/BLACKLIST index 915c30bfb3..a4c7c1ee30 100644 --- a/tests/auto/network/access/qnetworkreply/BLACKLIST +++ b/tests/auto/network/access/qnetworkreply/BLACKLIST @@ -1,40 +1,11 @@ # See qtbase/src/testlib/qtestblacklist.cpp for format -[authenticationCacheAfterCancel] -windows-7sp1 -windows-10 msvc-2015 -[backgroundRequestInterruption] -opensuse-leap -windows-10 msvc-2015 -b2qt -ubuntu -osx -[backgroundRequestInterruption:ftp, bg, nobg] -* [getErrors:ftp-host] linux -# QTBUG-71953 -[getFromHttp] -* !android -[getFromHttpIntoBuffer] -osx -[getFromHttpIntoBuffer2] -windows-10 -[headFromHttp] -windows-10 msvc-2017 [ioPostToHttpFromSocket] -# QTBUG-66247 -windows-7sp1 -windows-10 msvc-2017 osx -[ioHttpRedirect] -# QTBUG-66602 -windows-10 [ioHttpRedirectMultipartPost] -# QTBUG-66247 b2qt -windows-10 msvc-2015 -ubuntu -rhel +linux [ioHttpRedirectPolicy] opensuse-leap b2qt @@ -42,34 +13,18 @@ ubuntu windows-10 [putToFtp] windows-10 -[putWithServerClosingConnectionImmediately] -windows-7sp1 -windows-10 -osx [backgroundRequest] macos -[connectToIPv6Address] -macos [deleteFromHttp] macos -[downloadProgress] -macos -[encrypted] -macos [httpCanReadLine] macos [httpRecursiveCreation] osx [httpWithNoCredentialUsage] macos -[ignoreSslErrorsList] -osx -[ignoreSslErrorsListWithSlot] -osx [ioGetFromBuiltinHttp] osx -[ioGetFromHttp] -macos [ioPostToHttpFromFile] macos [ioPostToHttpFromSocketSynchronous] @@ -80,47 +35,18 @@ osx macos [lastModifiedHeaderForHttp] macos -[multipartSkipIndices] -macos -[nestedEventLoops] -osx -[postToHttp] -macos -[postToHttpMultipart] -macos [postToHttpSynchronous] macos -[postToHttps] -osx -[postToHttpsMultipart] -osx -[postToHttpsSynchronous] -osx -[putGetDeleteGetFromHttp] -macos [putToHttpSynchronous] macos -[putToHttps] -osx [putToHttpsSynchronous] osx -[putWithRateLimiting] -macos -[qtbug13431replyThrottling] -macos -[receiveCookiesFromHttp] -osx [receiveCookiesFromHttpSynchronous] osx -[sendCookies] -osx [sendCookiesSynchronous] osx -[sendCustomRequestToHttp] -macos -[sslConfiguration] -osx -[synchronousRequest] -osx [backgroundRequestConnectInBackground] osx +#QTBUG-103055 +[ioGetFromHttpWithProxyAuth] +qnx diff --git a/tests/auto/network/access/qnetworkreply/CMakeLists.txt b/tests/auto/network/access/qnetworkreply/CMakeLists.txt index 3b138b3918..9bfd90cd56 100644 --- a/tests/auto/network/access/qnetworkreply/CMakeLists.txt +++ b/tests/auto/network/access/qnetworkreply/CMakeLists.txt @@ -1,4 +1,11 @@ -# Generated from qnetworkreply.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qnetworkreply LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() add_subdirectory(echo) add_subdirectory(test) diff --git a/tests/auto/network/access/qnetworkreply/certs/qt-test-server-cacert.pem b/tests/auto/network/access/qnetworkreply/certs/qt-test-server-cacert.pem index c5aea0d7c9..29fd755de7 100644 --- a/tests/auto/network/access/qnetworkreply/certs/qt-test-server-cacert.pem +++ b/tests/auto/network/access/qnetworkreply/certs/qt-test-server-cacert.pem @@ -1,17 +1,17 @@ -----BEGIN CERTIFICATE----- -MIICpzCCAhACCQCzAF1hyRVzAjANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UEBhMC -Tk8xDTALBgNVBAgTBE9zbG8xDTALBgNVBAcTBE9zbG8xDjAMBgNVBAoTBU5va2lh -MTUwMwYDVQQLFCxRdCBTb2Z0d2FyZS9lbWFpbEFkZHJlc3M9bm9ib2R5QG5vZG9t -YWluLm9yZzEjMCEGA1UEAxMacXQtdGVzdC1zZXJ2ZXIucXQtdGVzdC1uZXQwHhcN -MTkwNjI0MTI0OTIxWhcNMjIwNjIzMTI0OTIxWjCBlzELMAkGA1UEBhMCTk8xDTAL -BgNVBAgTBE9zbG8xDTALBgNVBAcTBE9zbG8xDjAMBgNVBAoTBU5va2lhMTUwMwYD -VQQLFCxRdCBTb2Z0d2FyZS9lbWFpbEFkZHJlc3M9bm9ib2R5QG5vZG9tYWluLm9y -ZzEjMCEGA1UEAxMacXQtdGVzdC1zZXJ2ZXIucXQtdGVzdC1uZXQwgZ8wDQYJKoZI -hvcNAQEBBQADgY0AMIGJAoGBAM2q22/WNMmn8cC+5EEYGeICySLmp9W6Ay6eKHr0 -Xxp3X3epETuPfvAuxp7rOtkS18EMUegkUj8jw0IMEcbyHKFC/rTCaYOt93CxGBXM -IChiMPAsFeYzGa/D6xzAkfcRaJRQ+Ek3CDLXPnXfo7xpABXezYcPXAJrgsgBfWrw -HdxzAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEASCKbqEX5ysC549mq90ydk4jyDW3m -PUyet01fKpcRqVs+OJxdExFBTra3gho6WzzpTSPsuX2ZKOLF5k6KkCvdCGvhC1Kv -HHPIExurfzvdlSRzj6HbKyPuSfxyOloH0bBp7/Gg5RIuBPKlbmfbnTLtwEjhhbMU -SoYI8HZd3HfY87c= +MIICyjCCAjMCFHPGDqJR+klHni4XbETMk6GLn/UEMA0GCSqGSIb3DQEBDQUAMIGj +MRcwFQYDVQQKEw5UaGUgUXQgQ29tcGFueTEUMBIGA1UECxMLUXQgU29mdHdhcmUx +IjAgBgkqhkiG9w0BCQEWE25vYm9keUBub2RvbWFpbi5vcmcxDTALBgNVBAcTBE9z +bG8xDTALBgNVBAgTBE9zbG8xCzAJBgNVBAYTAk5PMSMwIQYDVQQDExpxdC10ZXN0 +LXNlcnZlci5xdC10ZXN0LW5ldDAeFw0yMjA2MjQxMTU4NDlaFw0zMjA2MjExMTU4 +NDlaMIGjMRcwFQYDVQQKEw5UaGUgUXQgQ29tcGFueTEUMBIGA1UECxMLUXQgU29m +dHdhcmUxIjAgBgkqhkiG9w0BCQEWE25vYm9keUBub2RvbWFpbi5vcmcxDTALBgNV +BAcTBE9zbG8xDTALBgNVBAgTBE9zbG8xCzAJBgNVBAYTAk5PMSMwIQYDVQQDExpx +dC10ZXN0LXNlcnZlci5xdC10ZXN0LW5ldDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw +gYkCgYEAzarbb9Y0yafxwL7kQRgZ4gLJIuan1boDLp4oevRfGndfd6kRO49+8C7G +nus62RLXwQxR6CRSPyPDQgwRxvIcoUL+tMJpg633cLEYFcwgKGIw8CwV5jMZr8Pr +HMCR9xFolFD4STcIMtc+dd+jvGkAFd7Nhw9cAmuCyAF9avAd3HMCAwEAATANBgkq +hkiG9w0BAQ0FAAOBgQCZyRe25WqOjrNS6BKPs7ep7eyCON3NKdWnfABZrSjGJQ87 +PoFKl6+9YBSlSpl8qk7c29ic+wA4qFQzPJkrbYIXjwVMAr+cC1kVrlUVqcwmvnKo +5vj57/v8S0Uc4/GesIsxZR7QM+3diPDyk7Bsc3IkpINb31Dl0mlg25nztg8NxA== -----END CERTIFICATE----- diff --git a/tests/auto/network/access/qnetworkreply/certs/server.key b/tests/auto/network/access/qnetworkreply/certs/server.key index 9d1664d609..b8d0d0449b 100644 --- a/tests/auto/network/access/qnetworkreply/certs/server.key +++ b/tests/auto/network/access/qnetworkreply/certs/server.key @@ -1,15 +1,27 @@ -----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= +MIIEowIBAAKCAQEAyinVk3QBbjS+UczWP+jnugFn5YZuOnCPlPK0SmeUiZW0x4PA +kXoks7LSra+XT2hg07rPBhEyQUE13qYw+RVBSexvhw2RDg76oV17jt7jVjb04hhK +bSBKisW4UHF0rvyzoWzJzVxaqxfcFcYT7uE+t0cnCHi/MGX+9gUI8Dz46IopCA5k +fKmA+XnF//Ov8wokIN4Wk0lqkAyWDCg/O5Av6H/zbr/U3CCI5eI5cRRIwSMDxbPX +v9b+dgvxhMJGMku6UMMhSfk9ac6FCSNghYB7w3C9zIGiA/tOHysujwGzpzRKDzT5 +P/qNqLkLOxvspUh32BD/jgopAhoNi9pDm60iLQIDAQABAoIBAA/E45v02Ie4JYBL +8gpaKHkh0vDcY4y7ave7VsTW/4cb3lYRuNugI2zA7h4OLEdNZQAe+jcG8FyWsZUE +cZ18QvN5Ndna/Q2TrYkYuaKTUDhRYRihvGx2sFnSwmXD884SeBCHY9ZY9dmSquAn +6zYe671wF2NZx9AGpLSb/+59Uw0QVkCDf23tb7ey5vHXJnNq5NINOnv1sNH/zbYR +hJnUEVgRLkpda0r2LqIHbrCpcgjWQeoKscTzxTI016LAozBSqAvoLt4QYuvY8kI7 +boK8KF49HEwTydjgDI/W3Xa0YEzbXVLEReuWoMKFeayNp+GSFy0SwkzjY4zpUP1N +xX6/2CECgYEA83fifDH8e4g1y8MuI8LzDRsMPOsvl3ZnB31JAcvUlLheVF1H3Slt +NEGSKYtx4zb0o+5VKy6k6dqF8VXDcPDyyvItyZYZtv7YLIhu/HBJypr9NfdICNnK +aPQWRZ/piAEi73vxx1qwIZapz1cJWg95mRv/QYVf8Xb7PgKcu5UL+ysCgYEA1JGv +t1gNsKc4BtHmYmTnzdxz4GhkgJY1y/XfGzc2CfRPxo16Fob1WqQCTf1DtsCm0zTi +sJdUBq/acMeeyTA6eA4LyfgEVVRVY4+kurW7JNGkR6xbWtWQX11jkVGOZ65MIvtY +ZMg3xo3w+hYvMhK0ZC9aSXgnl0crvGAJtd8ZzAcCgYAwnTmODvUZPYNwYlKuNVkO +vt3ctCFWnv/HkQ6o2yhhYccEFXQqBwGVM5qZzQw6kFic+xPqgW/Qeh/Qpo1V2ebA ++0aFQAF2dsB3c+6lXU5+tB/nTK8HhWVTO5nO4TViQMfXBeqrIcKVkl3p1rk5UGm5 +VsvLK3SS5G0aXq8pDYPM7QKBgQChsQvjP8RyGlCAx4siTzUQH1+5VE8WjKvxMF58 +OjwNyFwiYR18Iz5gqx7hqgOm8NY1FCZXQ1T0HTHg1cdPrDLdfXm0MMdDDPpC2FHq +gDARarI2nsGCz66ZC9WgBVR4Q1nAxkXPq4jZrMCfyt4tjZLQHkDkX9RluwpmqPrZ +8BGUYwKBgB1u8mPXIxyGSHYitqf40eIr5yzlrCgDWoqRQf4jFSUNyB/+YT2VqIXu +WfixkX9WW0sx/c79c9791Sf+vp9+DPPtMYDGc6y0xrbxyC+yT7Uo4Azbs/g3Kftl +WhYt/L1CB5oOcilYGR+YodN0l2tV1WrCNSNdtbPyoDHrM9S22Rjm -----END RSA PRIVATE KEY----- diff --git a/tests/auto/network/access/qnetworkreply/certs/server.pem b/tests/auto/network/access/qnetworkreply/certs/server.pem index 67eb495319..47c22d9f29 100644 --- a/tests/auto/network/access/qnetworkreply/certs/server.pem +++ b/tests/auto/network/access/qnetworkreply/certs/server.pem @@ -1,24 +1,22 @@ -----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 +MIIDrzCCApcCFGtyyXYbHuuIIseKAiLxL5nMKEnwMA0GCSqGSIb3DQEBCwUAMIGT +MQswCQYDVQQGEwJOTzENMAsGA1UECAwET3NsbzEQMA4GA1UEBwwHTnlkYWxlbjEN +MAsGA1UECgwEVFF0QzEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxFzAVBgNVBAMMDmZs +dWtlLnRyb2xsLm5vMSUwIwYJKoZIhvcNAQkBFhZhaGFuc3NlbkB0cm9sbHRlY2gu +Y29tMB4XDTIyMDcwODA2Mjc1OVoXDTMyMDcwNTA2Mjc1OVowgZMxCzAJBgNVBAYT +Ak5PMQ0wCwYDVQQIDARPc2xvMRAwDgYDVQQHDAdOeWRhbGVuMQ0wCwYDVQQKDARU +UXRDMRQwEgYDVQQLDAtEZXZlbG9wbWVudDEXMBUGA1UEAwwOZmx1a2UudHJvbGwu +bm8xJTAjBgkqhkiG9w0BCQEWFmFoYW5zc2VuQHRyb2xsdGVjaC5jb20wggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDKKdWTdAFuNL5RzNY/6Oe6AWflhm46 +cI+U8rRKZ5SJlbTHg8CReiSzstKtr5dPaGDTus8GETJBQTXepjD5FUFJ7G+HDZEO +DvqhXXuO3uNWNvTiGEptIEqKxbhQcXSu/LOhbMnNXFqrF9wVxhPu4T63RycIeL8w +Zf72BQjwPPjoiikIDmR8qYD5ecX/86/zCiQg3haTSWqQDJYMKD87kC/of/Nuv9Tc +IIjl4jlxFEjBIwPFs9e/1v52C/GEwkYyS7pQwyFJ+T1pzoUJI2CFgHvDcL3MgaID ++04fKy6PAbOnNEoPNPk/+o2ouQs7G+ylSHfYEP+OCikCGg2L2kObrSItAgMBAAEw +DQYJKoZIhvcNAQELBQADggEBALHdGWQ4YqucGJSP1n1ANrLILy+sXqEP7hMdG5HH +GDZ/ygUhjTZ/k5Cj0+auC4Aw490l8Tj8gmzt68KJmgSH+z1erY67+fhWtAewDzU5 +zIMqKHja1hSb5JIdWaD7ZFBQzor2beBO0u+VzegWqe20kw2mkFAcdQTsV28hvr1v +rcgpVkegQcmHpr6FBpYFmtnizpPnX5Zm+JJAlvSGvoYMI5i9Vc7/gdx790NeaXmy +yD1ueFMfsPtAcZq8cSbGSCS5/pcuhIx+5O9+V8iwN9lKdYksTCLAn4SREHzlgi68 +SGY0OUMlXeD82K0+mDv+hzSmq4sk7CDGbSxVV5TwzFXDgNc= -----END CERTIFICATE----- diff --git a/tests/auto/network/access/qnetworkreply/data/gzip.rcc.cpp b/tests/auto/network/access/qnetworkreply/data/gzip.rcc.cpp new file mode 100644 index 0000000000..4716ebbc02 --- /dev/null +++ b/tests/auto/network/access/qnetworkreply/data/gzip.rcc.cpp @@ -0,0 +1,1235 @@ +/**************************************************************************** +** Resource object code +** +** Created by: The Resource Compiler for Qt version 6.0.0 +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +static const unsigned char qt_resource_data[] = { + // D:/projects/qt/dev/src/qtbase/tests/auto/network/access/decompresshelper/4G.gz + 0x0,0x0,0x47,0x6b, + 0x0, + 0x47,0x80,0x16,0x78,0xda,0xec,0xce,0xb1,0xd,0x82,0x50,0x14,0x40,0xd1,0x27,0x36, + 0x34,0xce,0x40,0x18,0x81,0x41,0xc,0x33,0x58,0xd8,0x62,0x42,0x49,0x45,0x4f,0x6f, + 0xfd,0x37,0x70,0x3,0x92,0xef,0x3c,0xdf,0xd2,0x5a,0x61,0xa,0x9a,0x73,0xbb,0xdb, + 0x9d,0x66,0xa9,0xeb,0xd8,0xaa,0xce,0xd3,0x7d,0x7c,0x44,0xc9,0xdd,0x69,0xbb,0x77, + 0xfa,0xf6,0x9f,0xdb,0x25,0xc5,0xb1,0xd,0x25,0xb7,0x3b,0x67,0x4e,0xbf,0xd7,0x75, + 0x3d,0x18,0x13,0xcf,0xc0,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1, + 0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xc1,0xf9,0xb7,0x3b,0xc7,0x34,0x0,0xc0,0x20, + 0x0,0xc0,0x92,0x89,0xc0,0xf5,0xcc,0xcd,0xc7,0x82,0x5,0x82,0xa,0x38,0xfa,0xf5, + 0xac,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e, + 0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0x8e,0xce,0x40,0xe7,0x6f, + 0xea,0xc4,0xcd,0xf3,0x1a,0x5,0xc6,0xd3,0x33,0xd2, + +}; + +static const unsigned char qt_resource_name[] = { + // 4G.gz + 0x0,0x5, + 0x0,0x38,0xa4,0xea, + 0x0,0x34, + 0x0,0x47,0x0,0x2e,0x0,0x67,0x0,0x7a, + +}; + +static const unsigned char qt_resource_struct[] = { + // : + 0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + // :/4G.gz + 0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0, +0x0,0x0,0x1,0x72,0x1c,0xb0,0xf0,0xe2, + +}; + +#ifdef QT_NAMESPACE +# define QT_RCC_PREPEND_NAMESPACE(name) ::QT_NAMESPACE::name +# define QT_RCC_MANGLE_NAMESPACE0(x) x +# define QT_RCC_MANGLE_NAMESPACE1(a, b) a##_##b +# define QT_RCC_MANGLE_NAMESPACE2(a, b) QT_RCC_MANGLE_NAMESPACE1(a,b) +# define QT_RCC_MANGLE_NAMESPACE(name) QT_RCC_MANGLE_NAMESPACE2( \ + QT_RCC_MANGLE_NAMESPACE0(name), QT_RCC_MANGLE_NAMESPACE0(QT_NAMESPACE)) +#else +# define QT_RCC_PREPEND_NAMESPACE(name) name +# define QT_RCC_MANGLE_NAMESPACE(name) name +#endif + +#ifdef QT_NAMESPACE +namespace QT_NAMESPACE { +#endif + +bool qRegisterResourceData(int, const unsigned char *, const unsigned char *, const unsigned char *); +bool qUnregisterResourceData(int, const unsigned char *, const unsigned char *, const unsigned char *); + +#if defined(__ELF__) || defined(__APPLE__) +static inline unsigned char qResourceFeatureZlib() +{ + extern const unsigned char qt_resourceFeatureZlib; + return qt_resourceFeatureZlib; +} +#else +unsigned char qResourceFeatureZlib(); +#endif + +#ifdef QT_NAMESPACE +} +#endif + +int QT_RCC_MANGLE_NAMESPACE(qInitResources_gzip)(); +int QT_RCC_MANGLE_NAMESPACE(qInitResources_gzip)() +{ + int version = 3; + QT_RCC_PREPEND_NAMESPACE(qRegisterResourceData) + (version, qt_resource_struct, qt_resource_name, qt_resource_data); + return 1; +} + +int QT_RCC_MANGLE_NAMESPACE(qCleanupResources_gzip)(); +int QT_RCC_MANGLE_NAMESPACE(qCleanupResources_gzip)() +{ + int version = 3; + version += QT_RCC_PREPEND_NAMESPACE(qResourceFeatureZlib()); + QT_RCC_PREPEND_NAMESPACE(qUnregisterResourceData) + (version, qt_resource_struct, qt_resource_name, qt_resource_data); + return 1; +} + +namespace { + struct initializer { + initializer() { QT_RCC_MANGLE_NAMESPACE(qInitResources_gzip)(); } + ~initializer() { QT_RCC_MANGLE_NAMESPACE(qCleanupResources_gzip)(); } + } dummy; +} diff --git a/tests/auto/network/access/qnetworkreply/data/zstandard.rcc.cpp b/tests/auto/network/access/qnetworkreply/data/zstandard.rcc.cpp new file mode 100644 index 0000000000..c8a435192f --- /dev/null +++ b/tests/auto/network/access/qnetworkreply/data/zstandard.rcc.cpp @@ -0,0 +1,116 @@ +/**************************************************************************** +** Resource object code +** +** Created by: The Resource Compiler for Qt version 6.0.0 +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +static const unsigned char qt_resource_data[] = { + // D:/projects/qt/dev/src/qtbase/tests/auto/network/access/decompresshelper/4G.zst + 0x0,0x0,0x1,0x75, + 0x0, + 0x2,0x3,0x93,0x78,0xda,0xed,0xd4,0x21,0xe,0x83,0x40,0x10,0x86,0xd1,0x29,0x98, + 0x26,0x98,0x3d,0x46,0x1d,0x1a,0x8f,0xec,0x29,0x50,0xdc,0x84,0x13,0xe1,0x2b,0x90, + 0x1c,0x89,0xcd,0x32,0xe9,0x25,0x2a,0xfa,0x26,0x79,0xc9,0xe8,0x5f,0x7c,0xaf,0x7d, + 0xac,0xc7,0x1a,0x79,0x8f,0xf4,0x8e,0x78,0xe6,0x73,0xb5,0xa9,0x74,0x5d,0x94,0x0, + 0xfe,0xcf,0xfc,0xed,0x41,0x6d,0xe7,0x50,0xcc,0x1,0x32,0x60,0xe,0x90,0x1,0x73, + 0x80,0xc,0x98,0x4,0x64,0x0,0x90,0x1,0x40,0x6,0x0,0x19,0x0,0x64,0x0,0x90, + 0x1,0x40,0x6,0x0,0x19,0x0,0x64,0x0,0x90,0x1,0x40,0x6,0x0,0x19,0x0,0x64, + 0x0,0x90,0x1,0x40,0x6,0x0,0x19,0x0,0x64,0x0,0x90,0x1,0x40,0x6,0x0,0x19, + 0x0,0x64,0x0,0x90,0x1,0x40,0x6,0x0,0x19,0x0,0x64,0x0,0x90,0x1,0x40,0x6, + 0x0,0x19,0x0,0x64,0x0,0x90,0x1,0x40,0x6,0x0,0x19,0x0,0x64,0x0,0x90,0x1, + 0x40,0x6,0x0,0x19,0x0,0x64,0x0,0x90,0x1,0x40,0x6,0x0,0x19,0x0,0x64,0x0, + 0x90,0x1,0x40,0x6,0x0,0x19,0x0,0x64,0x0,0x90,0x1,0x40,0x6,0x0,0x19,0x0, + 0x64,0x0,0x90,0x1,0x40,0x6,0x0,0x19,0x0,0x64,0x0,0x90,0x1,0x40,0x6,0x0, + 0x19,0x0,0x64,0x0,0x90,0x1,0x40,0x6,0x0,0x19,0x0,0x64,0x0,0x90,0x1,0x40, + 0x6,0x0,0x19,0x0,0x64,0x0,0x90,0x1,0x40,0x6,0x0,0x19,0x0,0x64,0x0,0x90, + 0x1,0x40,0x6,0x0,0x19,0x0,0x64,0x0,0x90,0x1,0x40,0x6,0x0,0x19,0x0,0x64, + 0x0,0x90,0x1,0x40,0x6,0x0,0x19,0x0,0x64,0x0,0x90,0x1,0x40,0x6,0x0,0x19, + 0x0,0x64,0x0,0x90,0x1,0x40,0x6,0x0,0x19,0x0,0x64,0x0,0x90,0x1,0x40,0x6, + 0x0,0x19,0x0,0x64,0x0,0x90,0x1,0x40,0x6,0x0,0x19,0x0,0x64,0x0,0x90,0x1, + 0x40,0x6,0x0,0x19,0x0,0x64,0x0,0x90,0x1,0x40,0x6,0x0,0x19,0x0,0x64,0x0, + 0x90,0x1,0x40,0x6,0x0,0x19,0x0,0x64,0x0,0x90,0x1,0x40,0x6,0x0,0x19,0x0, + 0x64,0x0,0x90,0x1,0x40,0x6,0x0,0x19,0x0,0x64,0x0,0x90,0x1,0x40,0x6,0x0, + 0x19,0x0,0x64,0x0,0x90,0x1,0x40,0x6,0x80,0x5f,0xe8,0xd3,0xf2,0x69,0xdb,0xd, + 0xcd,0x15,0x90,0xe9, + +}; + +static const unsigned char qt_resource_name[] = { + // 4G.zst + 0x0,0x6, + 0x3,0x8a,0x61,0xa4, + 0x0,0x34, + 0x0,0x47,0x0,0x2e,0x0,0x7a,0x0,0x73,0x0,0x74, + +}; + +static const unsigned char qt_resource_struct[] = { + // : + 0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + // :/4G.zst + 0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0, +0x0,0x0,0x1,0x72,0x1c,0x8d,0x7,0xac, + +}; + +#ifdef QT_NAMESPACE +# define QT_RCC_PREPEND_NAMESPACE(name) ::QT_NAMESPACE::name +# define QT_RCC_MANGLE_NAMESPACE0(x) x +# define QT_RCC_MANGLE_NAMESPACE1(a, b) a##_##b +# define QT_RCC_MANGLE_NAMESPACE2(a, b) QT_RCC_MANGLE_NAMESPACE1(a,b) +# define QT_RCC_MANGLE_NAMESPACE(name) QT_RCC_MANGLE_NAMESPACE2( \ + QT_RCC_MANGLE_NAMESPACE0(name), QT_RCC_MANGLE_NAMESPACE0(QT_NAMESPACE)) +#else +# define QT_RCC_PREPEND_NAMESPACE(name) name +# define QT_RCC_MANGLE_NAMESPACE(name) name +#endif + +#ifdef QT_NAMESPACE +namespace QT_NAMESPACE { +#endif + +bool qRegisterResourceData(int, const unsigned char *, const unsigned char *, const unsigned char *); +bool qUnregisterResourceData(int, const unsigned char *, const unsigned char *, const unsigned char *); + +#if defined(__ELF__) || defined(__APPLE__) +static inline unsigned char qResourceFeatureZlib() +{ + extern const unsigned char qt_resourceFeatureZlib; + return qt_resourceFeatureZlib; +} +#else +unsigned char qResourceFeatureZlib(); +#endif + +#ifdef QT_NAMESPACE +} +#endif + +int QT_RCC_MANGLE_NAMESPACE(qInitResources_zstandard)(); +int QT_RCC_MANGLE_NAMESPACE(qInitResources_zstandard)() +{ + int version = 3; + QT_RCC_PREPEND_NAMESPACE(qRegisterResourceData) + (version, qt_resource_struct, qt_resource_name, qt_resource_data); + return 1; +} + +int QT_RCC_MANGLE_NAMESPACE(qCleanupResources_zstandard)(); +int QT_RCC_MANGLE_NAMESPACE(qCleanupResources_zstandard)() +{ + int version = 3; + version += QT_RCC_PREPEND_NAMESPACE(qResourceFeatureZlib()); + QT_RCC_PREPEND_NAMESPACE(qUnregisterResourceData) + (version, qt_resource_struct, qt_resource_name, qt_resource_data); + return 1; +} + +namespace { + struct initializer { + initializer() { QT_RCC_MANGLE_NAMESPACE(qInitResources_zstandard)(); } + ~initializer() { QT_RCC_MANGLE_NAMESPACE(qCleanupResources_zstandard)(); } + } dummy; +} diff --git a/tests/auto/network/access/qnetworkreply/echo/.prev_CMakeLists.txt b/tests/auto/network/access/qnetworkreply/echo/.prev_CMakeLists.txt deleted file mode 100644 index 17b6b275c9..0000000000 --- a/tests/auto/network/access/qnetworkreply/echo/.prev_CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -# Generated from echo.pro. - -##################################################################### -## echo Binary: -##################################################################### - -qt_add_executable(echo - SOURCES - main.cpp -) diff --git a/tests/auto/network/access/qnetworkreply/echo/CMakeLists.txt b/tests/auto/network/access/qnetworkreply/echo/CMakeLists.txt index e06066ea4f..137b29110d 100644 --- a/tests/auto/network/access/qnetworkreply/echo/CMakeLists.txt +++ b/tests/auto/network/access/qnetworkreply/echo/CMakeLists.txt @@ -1,11 +1,12 @@ -# Generated from echo.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## echo Binary: ##################################################################### -qt_add_executable(echo - OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} # special case +qt_internal_add_executable(echo + OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} SOURCES main.cpp ) diff --git a/tests/auto/network/access/qnetworkreply/echo/echo.pro b/tests/auto/network/access/qnetworkreply/echo/echo.pro deleted file mode 100644 index 3e304f4105..0000000000 --- a/tests/auto/network/access/qnetworkreply/echo/echo.pro +++ /dev/null @@ -1,4 +0,0 @@ -SOURCES += main.cpp -QT = core -CONFIG -= debug_and_release_target -CONFIG += cmdline diff --git a/tests/auto/network/access/qnetworkreply/echo/main.cpp b/tests/auto/network/access/qnetworkreply/echo/main.cpp index 9085de7898..b10eaa745c 100644 --- a/tests/auto/network/access/qnetworkreply/echo/main.cpp +++ b/tests/auto/network/access/qnetworkreply/echo/main.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtCore/QFile> @@ -37,11 +12,13 @@ int main(int argc, char **) } QFile file; - file.open(stdin, QFile::ReadWrite); + if (!file.open(stdin, QFile::ReadWrite)) + return 1; QByteArray data = file.readAll(); file.close(); - file.open(stdout, QFile::WriteOnly); + if (!file.open(stdout, QFile::WriteOnly)) + return 1; file.write(data); file.close(); return 0; diff --git a/tests/auto/network/access/qnetworkreply/qnetworkreply.pro b/tests/auto/network/access/qnetworkreply/qnetworkreply.pro deleted file mode 100644 index ec6f35a8b1..0000000000 --- a/tests/auto/network/access/qnetworkreply/qnetworkreply.pro +++ /dev/null @@ -1,5 +0,0 @@ -TEMPLATE = subdirs - -SUBDIRS += echo -test.depends += $$SUBDIRS -SUBDIRS += test diff --git a/tests/auto/network/access/qnetworkreply/qnetworkreply.qrc b/tests/auto/network/access/qnetworkreply/qnetworkreply.qrc deleted file mode 100644 index 85ca6312af..0000000000 --- a/tests/auto/network/access/qnetworkreply/qnetworkreply.qrc +++ /dev/null @@ -1,5 +0,0 @@ -<!DOCTYPE RCC><RCC version="1.0"> -<qresource> - <file>resource</file> -</qresource> -</RCC> diff --git a/tests/auto/network/access/qnetworkreply/test/.prev_CMakeLists.txt b/tests/auto/network/access/qnetworkreply/test/.prev_CMakeLists.txt deleted file mode 100644 index 19b430b159..0000000000 --- a/tests/auto/network/access/qnetworkreply/test/.prev_CMakeLists.txt +++ /dev/null @@ -1,59 +0,0 @@ -# Generated from test.pro. - -##################################################################### -## tst_qnetworkreply Test: -##################################################################### - -# Collect test data -list(APPEND test_data "../empty") -list(APPEND test_data "../rfc3252.txt") -list(APPEND test_data "../resource") -list(APPEND test_data "../bigfile") -file(GLOB_RECURSE test_data_glob - RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} - ../*.jpg) -list(APPEND test_data ${test_data_glob}) -list(APPEND test_data "../certs") -list(APPEND test_data "../index.html") -list(APPEND test_data "../smb-file.txt") - -qt_add_test(tst_qnetworkreply - SOURCES - ../../../../../shared/emulationdetector.h - ../tst_qnetworkreply.cpp - INCLUDE_DIRECTORIES - ../../../../../shared - PUBLIC_LIBRARIES - Qt::CorePrivate - Qt::NetworkPrivate - TESTDATA ${test_data} -) - -# Resources: -set_source_files_properties("../resource" - PROPERTIES QT_RESOURCE_ALIAS "resource" -) -set(qnetworkreply_resource_files - "resource" -) - -qt_add_resource(tst_qnetworkreply "qnetworkreply" - PREFIX - "/" - BASE - ".." - FILES - ${qnetworkreply_resource_files} -) - - -#### Keys ignored in scope 1:.:.:test.pro:<TRUE>: -# QT_FOR_CONFIG = "gui-private" -# QT_TEST_SERVER_LIST = "vsftpd" "apache2" "ftp-proxy" "danted" "squid" -# testcase.timeout = "600" - -## Scopes: -##################################################################### - -#### Keys ignored in scope 2:.:.:test.pro:NOT ANDROID: -# TEST_HELPER_INSTALLS = "../echo/echo" diff --git a/tests/auto/network/access/qnetworkreply/test/CMakeLists.txt b/tests/auto/network/access/qnetworkreply/test/CMakeLists.txt index 24f264703f..fa353b2769 100644 --- a/tests/auto/network/access/qnetworkreply/test/CMakeLists.txt +++ b/tests/auto/network/access/qnetworkreply/test/CMakeLists.txt @@ -1,4 +1,5 @@ -# Generated from test.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qnetworkreply Test: @@ -17,29 +18,27 @@ list(APPEND test_data "../certs") list(APPEND test_data "../index.html") list(APPEND test_data "../smb-file.txt") -qt_add_test(tst_qnetworkreply - OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../" # special case +qt_internal_add_test(tst_qnetworkreply + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../" SOURCES - ../../../../../shared/emulationdetector.h ../tst_qnetworkreply.cpp - INCLUDE_DIRECTORIES - ../../../../../shared - PUBLIC_LIBRARIES + ../data/gzip.rcc.cpp + ../data/zstandard.rcc.cpp + LIBRARIES Qt::CorePrivate Qt::NetworkPrivate TESTDATA ${test_data} - QT_TEST_SERVER_LIST "vsftpd" "apache2" "ftp-proxy" "danted" "squid" # special case + QT_TEST_SERVER_LIST "vsftpd" "apache2" "ftp-proxy" "danted" "squid" + BUNDLE_ANDROID_OPENSSL_LIBS ) +add_dependencies(tst_qnetworkreply echo) # Resources: -set_source_files_properties("../resource" - PROPERTIES QT_RESOURCE_ALIAS "resource" -) set(qnetworkreply_resource_files - "resource" + "../resource" ) -qt_add_resource(tst_qnetworkreply "qnetworkreply" +qt_internal_add_resource(tst_qnetworkreply "qnetworkreply" PREFIX "/" BASE @@ -47,15 +46,3 @@ qt_add_resource(tst_qnetworkreply "qnetworkreply" FILES ${qnetworkreply_resource_files} ) - - -#### Keys ignored in scope 1:.:.:test.pro:<TRUE>: -# QT_FOR_CONFIG = "gui-private" -# QT_TEST_SERVER_LIST = "vsftpd" "apache2" "ftp-proxy" "danted" "squid" -# testcase.timeout = "600" - -## Scopes: -##################################################################### - -#### Keys ignored in scope 2:.:.:test.pro:NOT ANDROID: -# TEST_HELPER_INSTALLS = "../echo/echo" diff --git a/tests/auto/network/access/qnetworkreply/test/test.pro b/tests/auto/network/access/qnetworkreply/test/test.pro deleted file mode 100644 index bf09a99d27..0000000000 --- a/tests/auto/network/access/qnetworkreply/test/test.pro +++ /dev/null @@ -1,19 +0,0 @@ -CONFIG += testcase -testcase.timeout = 600 # this test is slow -CONFIG -= debug_and_release_target -INCLUDEPATH += ../../../../../shared/ -HEADERS += ../../../../../shared/emulationdetector.h -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 - -!android: TEST_HELPER_INSTALLS = ../echo/echo - -CONFIG += unsupported/testserver -QT_TEST_SERVER_LIST = vsftpd apache2 ftp-proxy danted squid diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp index 0766cd26fc..64e7716e0c 100644 --- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp @@ -1,49 +1,44 @@ -/**************************************************************************** -** -** 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> +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QtNetwork/qtnetworkglobal.h> + +#include <QTest> +#include <QSemaphore> +#include <QTestEventLoop> +#include <QSignalSpy> +#if QT_CONFIG(process) +#include <QProcess> +#endif +#include <QTimer> +#include <QWaitCondition> +#include <QScopeGuard> +#include <QBuffer> +#include <QMap> + #include <QtCore/QCryptographicHash> #include <QtCore/QDataStream> -#include <QtCore/QUrl> +#include <QtCore/QDateTime> #include <QtCore/QEventLoop> #include <QtCore/QElapsedTimer> #include <QtCore/QFile> +#include <QtCore/QList> #include <QtCore/QRandomGenerator> #include <QtCore/QRegularExpression> #include <QtCore/QRegularExpressionMatch> +#include <QtCore/QSet> #include <QtCore/QSharedPointer> #include <QtCore/QScopedPointer> #include <QtCore/QTemporaryFile> +#include <QtCore/QTimeZone> +#include <QtCore/QUrl> + #include <QtNetwork/QTcpServer> #include <QtNetwork/QTcpSocket> +#if QT_CONFIG(localserver) #include <QtNetwork/QLocalSocket> #include <QtNetwork/QLocalServer> +#endif #include <QtNetwork/QHostInfo> #include <QtNetwork/QNetworkAccessManager> #include <QtNetwork/QNetworkRequest> @@ -51,17 +46,23 @@ #include <QtNetwork/QAbstractNetworkCache> #include <QtNetwork/qauthenticator.h> #include <QtNetwork/qnetworkaccessmanager.h> +#if QT_CONFIG(networkdiskcache) #include <QtNetwork/qnetworkdiskcache.h> +#endif #include <QtNetwork/qnetworkrequest.h> #include <QtNetwork/qnetworkreply.h> #include <QtNetwork/qnetworkcookie.h> #include <QtNetwork/QNetworkCookieJar> +#if QT_CONFIG(http) #include <QtNetwork/QHttpPart> #include <QtNetwork/QHttpMultiPart> +#include <QtNetwork/QHttp1Configuration> +#endif #include <QtNetwork/QNetworkProxyQuery> -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) #include <QtNetwork/qsslerror.h> #include <QtNetwork/qsslconfiguration.h> +#include <QtNetwork/qsslsocket.h> #ifdef QT_BUILD_INTERNAL #include <QtNetwork/private/qsslconfiguration_p.h> #endif @@ -73,6 +74,9 @@ Q_DECLARE_METATYPE(QSharedPointer<char>) #endif +#include <memory> +#include <optional> + #ifdef Q_OS_UNIX # include <sys/types.h> # include <unistd.h> // for getuid() @@ -81,25 +85,23 @@ Q_DECLARE_METATYPE(QSharedPointer<char>) #include "../../../network-settings.h" -// Non-OpenSSL backends are not able to report a specific error code -// for self-signed certificates. -#ifndef QT_NO_OPENSSL -#define FLUKE_CERTIFICATE_ERROR QSslError::SelfSignedCertificate -#else -#define FLUKE_CERTIFICATE_ERROR QSslError::CertificateUntrusted +#ifdef Q_OS_INTEGRITY +#include "qplatformdefs.h" #endif Q_DECLARE_METATYPE(QAuthenticator*) -#ifndef QT_NO_NETWORKPROXY +#if QT_CONFIG(networkproxy) Q_DECLARE_METATYPE(QNetworkProxyQuery) #endif -#include "emulationdetector.h" - typedef QSharedPointer<QNetworkReply> QNetworkReplyPtr; -#ifndef QT_NO_OPENSSL +using namespace Qt::StringLiterals; +using namespace std::chrono_literals; + +#if QT_CONFIG(ssl) QT_BEGIN_NAMESPACE +// Technically, a workaround, and only needed for OpenSSL: void qt_ForceTlsSecurityLevel(); QT_END_NAMESPACE #endif @@ -109,7 +111,7 @@ class tst_QNetworkReply: public QObject { Q_OBJECT -#ifndef QT_NO_NETWORKPROXY +#if QT_CONFIG(networkproxy) struct ProxyData { ProxyData(const QNetworkProxy &p, const QByteArray &t, bool auth) @@ -118,7 +120,7 @@ class tst_QNetworkReply: public QObject QNetworkProxy proxy; bool requiresAuthentication; }; -#endif // !QT_NO_NETWORKPROXY +#endif // QT_CONFIG(networkproxy) static bool seedCreated; static QString createUniqueExtension() @@ -133,7 +135,30 @@ class tst_QNetworkReply: public QObject static QString tempRedirectReplyStr() { QString s = "HTTP/1.1 307 Temporary Redirect\r\n" - "Content-Type: text/plain\r\n" + "content-type: text/plain\r\n" + "location: %1\r\n" + "\r\n"; + return s; + } + static QString movedReplyStr() { + QString s = "HTTP/1.1 301 Moved Permanently\r\n" + "content-type: text/plain\r\n" + "location: %1\r\n" + "\r\n"; + return s; + } + + static QString foundReplyStr() { + QString s = "HTTP/1.1 302 Found\r\n" + "content-type: text/plain\r\n" + "location: %1\r\n" + "\r\n"; + return s; + } + + static QString permRedirectReplyStr() { + QString s = "HTTP/1.1 308 Permanent Redirect\r\n" + "content-type: text/plain\r\n" "location: %1\r\n" "\r\n"; return s; @@ -151,16 +176,18 @@ class tst_QNetworkReply: public QObject QString wronlyFileName; #endif QString uniqueExtension; -#ifndef QT_NO_NETWORKPROXY +#if QT_CONFIG(networkproxy) QList<ProxyData> proxies; #endif QNetworkAccessManager manager; MyCookieJar *cookieJar; -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) QSslConfiguration storedSslConfiguration; QList<QSslError> storedExpectedSslErrors; static const QString certsFilePath; -#endif + bool isSecureTransport = false; + bool isSchannel = false; +#endif // QT_CONFIG(ssl) using QObject::connect; static bool connect(const QNetworkReplyPtr &ptr, const char *signal, const QObject *receiver, const char *slot, Qt::ConnectionType ct = Qt::AutoConnection) @@ -173,8 +200,10 @@ public: ~tst_QNetworkReply(); QString runSimpleRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &request, QNetworkReplyPtr &reply, const QByteArray &data = QByteArray()); +#if QT_CONFIG(http) QString runMultipartRequest(const QNetworkRequest &request, QNetworkReplyPtr &reply, QHttpMultiPart *multiPart, const QByteArray &verb); +#endif QString runCustomRequest(const QNetworkRequest &request, QNetworkReplyPtr &reply, const QByteArray &verb, QIODevice *data); @@ -188,7 +217,7 @@ public Q_SLOTS: void pipeliningHelperSlot(); void emitErrorForAllRepliesSlot(); -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) void sslErrors(QNetworkReply*,const QList<QSslError> &); void storeSslConfiguration(); void ignoreSslErrorListSlot(QNetworkReply *reply, const QList<QSslError> &); @@ -219,12 +248,18 @@ private Q_SLOTS: void getFromFtpAfterError(); // QTBUG-40797 void getFromHttp_data(); void getFromHttp(); + void getWithBodyFromHttp_data(); + void getWithBodyFromHttp(); + void getWithAndWithoutBodyFromHttp_data(); + void getWithAndWithoutBodyFromHttp(); + void getWithBodyRedirected_data(); + void getWithBodyRedirected(); void getErrors_data(); void getErrors(); -#ifndef QT_NO_NETWORKPROXY +#if QT_CONFIG(networkproxy) void headFromHttp_data(); void headFromHttp(); -#endif // !QT_NO_NETWORKPROXY +#endif // QT_CONFIG(networkproxy) void putToFile_data(); void putToFile(); void putToFtp_data(); @@ -234,16 +269,24 @@ private Q_SLOTS: void putToHttp(); void putToHttpSynchronous_data(); void putToHttpSynchronous(); +#if QT_CONFIG(http) void putToHttpMultipart_data(); void putToHttpMultipart(); +#endif + void putWithoutBody(); + void putWithoutBody_data(); void postToHttp_data(); void postToHttp(); void postToHttpSynchronous_data(); void postToHttpSynchronous(); +#if QT_CONFIG(http) void postToHttpMultipart_data(); void postToHttpMultipart(); void multipartSkipIndices(); // QTBUG-32534 -#ifndef QT_NO_SSL +#endif + void postWithoutBody_data(); + void postWithoutBody(); +#if QT_CONFIG(ssl) void putToHttps_data(); void putToHttps(); void putToHttpsSynchronous_data(); @@ -270,6 +313,7 @@ private Q_SLOTS: void ioGetFromFileSpecial(); void ioGetFromFile_data(); void ioGetFromFile(); + void ioGetFromFileUrl(); void ioGetFromFtp_data(); void ioGetFromFtp(); void ioGetFromFtpWithReuse(); @@ -282,36 +326,38 @@ private Q_SLOTS: void ioGetFromHttpWithAuth_data(); void ioGetFromHttpWithAuth(); void ioGetFromHttpWithAuthSynchronous(); -#ifndef QT_NO_NETWORKPROXY +#if QT_CONFIG(networkproxy) void ioGetFromHttpWithProxyAuth(); void ioGetFromHttpWithProxyAuthSynchronous(); void ioGetFromHttpWithSocksProxy(); -#endif // !QT_NO_NETWORKPROXY -#ifndef QT_NO_SSL +#endif // QT_CONFIG(networkproxy) +#if QT_CONFIG(ssl) void ioGetFromHttpsWithSslErrors(); void ioGetFromHttpsWithIgnoreSslErrors(); void ioGetFromHttpsWithSslHandshakeError(); #endif void ioGetFromHttpBrokenServer_data(); void ioGetFromHttpBrokenServer(); - void ioGetFromHttpStatus100_data(); - void ioGetFromHttpStatus100(); + void ioGetFromHttpStatusInformational_data(); + void ioGetFromHttpStatusInformational(); void ioGetFromHttpNoHeaders_data(); void ioGetFromHttpNoHeaders(); void ioGetFromHttpWithCache_data(); void ioGetFromHttpWithCache(); -#ifndef QT_NO_NETWORKPROXY +#if QT_CONFIG(networkproxy) void ioGetWithManyProxies_data(); void ioGetWithManyProxies(); -#endif // !QT_NO_NETWORKPROXY +#endif // QT_CONFIG(networkproxy) void ioPutToFileFromFile_data(); void ioPutToFileFromFile(); void ioPutToFileFromSocket_data(); void ioPutToFileFromSocket(); +#if QT_CONFIG(localserver) void ioPutToFileFromLocalSocket_data(); void ioPutToFileFromLocalSocket(); +#endif void ioPutToFileFromProcess_data(); void ioPutToFileFromProcess(); void ioPutToFtpFromFile_data(); @@ -320,12 +366,12 @@ private Q_SLOTS: void ioPutToHttpFromFile(); void ioPostToHttpFromFile_data(); void ioPostToHttpFromFile(); -#ifndef QT_NO_NETWORKPROXY +#if QT_CONFIG(networkproxy) void ioPostToHttpFromSocket_data(); void ioPostToHttpFromSocket(); void ioPostToHttpFromSocketSynchronous(); void ioPostToHttpFromSocketSynchronous_data(); -#endif // !QT_NO_NETWORKPROXY +#endif // QT_CONFIG(networkproxy) void ioPostToHttpFromMiddleOfFileToEnd(); void ioPostToHttpFromMiddleOfFileFiveBytes(); void ioPostToHttpFromMiddleOfQBufferFiveBytes(); @@ -365,13 +411,13 @@ private Q_SLOTS: void nestedEventLoops(); -#ifndef QT_NO_NETWORKPROXY +#if QT_CONFIG(networkproxy) void httpProxyCommands_data(); void httpProxyCommands(); void httpProxyCommandsSynchronous_data(); void httpProxyCommandsSynchronous(); void proxyChange(); -#endif // !QT_NO_NETWORKPROXY +#endif // QT_CONFIG(networkproxy) void authorizationError_data(); void authorizationError(); @@ -385,7 +431,7 @@ private Q_SLOTS: void httpRecursiveCreation(); -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) void ioPostToHttpsUploadProgress(); void ignoreSslErrorsList_data(); void ignoreSslErrorsList(); @@ -417,7 +463,9 @@ private Q_SLOTS: void ioGetFromHttpWithoutContentLength(); void ioGetFromHttpBrokenChunkedEncoding(); +#if QT_CONFIG(http) void qtbug12908compressedHttpReply(); +#endif void compressedHttpReplyBrokenGzip(); void getFromUnreachableIp(); @@ -436,26 +484,37 @@ private Q_SLOTS: void qtbug27161httpHeaderMayBeDamaged_data(); void qtbug27161httpHeaderMayBeDamaged(); +#if QT_CONFIG(networkdiskcache) void qtbug28035browserDoesNotLoadQtProjectOrgCorrectly(); +#endif void qtbug45581WrongReplyStatusCode(); void synchronousRequest_data(); void synchronousRequest(); -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) void synchronousRequestSslFailure(); #endif void httpAbort(); + void closeClientSideConnectionEagerlyQtbug20726(); + void varyingCacheExpiry_data(); + void varyingCacheExpiry(); + +#if QT_CONFIG(http) + void amountOfHttp1ConnectionsQtbug25280_data(); + void amountOfHttp1ConnectionsQtbug25280(); +#endif + void dontInsertPartialContentIntoTheCache(); void httpUserAgent(); -#ifndef QT_NO_NETWORKPROXY +#if QT_CONFIG(networkproxy) void authenticationCacheAfterCancel_data(); void authenticationCacheAfterCancel(); void authenticationWithDifferentRealm(); -#endif // !QT_NO_NETWORKPROXY +#endif // QT_CONFIG(networkproxy) void synchronousAuthenticationCache(); void pipelining(); @@ -482,16 +541,21 @@ private Q_SLOTS: void ioHttpCookiesDuringRedirect(); void ioHttpRedirect_data(); void ioHttpRedirect(); +#if QT_CONFIG(networkdiskcache) + void ioHttpRedirectWithCache(); +#endif void ioHttpRedirectFromLocalToRemote(); void ioHttpRedirectPostPut_data(); void ioHttpRedirectPostPut(); +#if QT_CONFIG(http) void ioHttpRedirectMultipartPost_data(); void ioHttpRedirectMultipartPost(); +#endif void ioHttpRedirectDelete(); void ioHttpRedirectCustom(); void ioHttpRedirectWithUploadDevice_data(); void ioHttpRedirectWithUploadDevice(); -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) void putWithServerClosingConnectionImmediately(); #endif @@ -500,11 +564,39 @@ private Q_SLOTS: void autoDeleteReplies_data(); void autoDeleteReplies(); - void getWithTimeout(); - void postWithTimeout(); +#if QT_CONFIG(http) || defined (Q_OS_WASM) + void requestWithTimeout_data(); + void requestWithTimeout(); +#endif + + void moreActivitySignals_data(); + void moreActivitySignals(); void contentEncoding_data(); void contentEncoding(); +#if QT_CONFIG(http) + void contentEncodingBigPayload_data(); + void contentEncodingBigPayload(); +#endif + void cacheWithContentEncoding_data(); + void cacheWithContentEncoding(); + void downloadProgressWithContentEncoding_data(); + void downloadProgressWithContentEncoding(); + void contentEncodingError_data(); + void contentEncodingError(); + void compressedReadyRead(); + void notFoundWithCompression_data(); + void notFoundWithCompression(); + +#if QT_CONFIG(http) + void qhttpPartDebug_data(); + void qhttpPartDebug(); + + void qtbug68821proxyError_data(); + void qtbug68821proxyError(); +#endif + + void abortAndError(); // NOTE: This test must be last! void parentingRepliesToTheApp(); @@ -515,6 +607,9 @@ private: bool notEnoughDataForFastSender; bool ftpSupported = false; +#if QT_CONFIG(ssl) + QSslError::SslError flukeCertTlsError = QSslError::CertificateUntrusted; +#endif }; const QByteArray tst_QNetworkReply::httpEmpty200Response = @@ -541,7 +636,7 @@ static bool validateRedirectedResponseHeaders(QNetworkReplyPtr reply) && !reply->header(QNetworkRequest::LocationHeader).isValid(); } -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) static void setupSslServer(QSslSocket* serverSocket) { QString testDataDir = QFileInfo(QFINDTESTDATA("rfc3252.txt")).absolutePath(); @@ -567,7 +662,7 @@ const QString tst_QNetworkReply::certsFilePath = "/certs/qt-test-server-host-net const QString tst_QNetworkReply::certsFilePath = "/certs/qt-test-server-cacert.pem"; #endif -#endif // !QT_NO_SSL +#endif // QT_CONFIG(ssl) // NOTE: MiniHttpServer has a very limited support of PUT/POST requests! Make // sure you understand the server's code before PUTting/POSTing data (and @@ -587,7 +682,8 @@ public: int totalConnections; bool stopTransfer = false; - bool hasContent = false; + bool checkedContentLength = false; + bool foundContentLength = false; int contentRead = 0; int contentLength = 0; @@ -619,13 +715,14 @@ public: { contentLength = 0; receivedData.clear(); + foundContentLength = false; } protected: void incomingConnection(qintptr socketDescriptor) override { //qDebug() << "incomingConnection" << socketDescriptor << "doSsl:" << doSsl << "ipv6:" << ipv6; -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) if (doSsl) { QSslSocket *serverSocket = new QSslSocket(this); if (!serverSocket->setSocketDescriptor(socketDescriptor)) { @@ -675,8 +772,13 @@ private: void parseContentLength() { - int index = receivedData.indexOf("Content-Length:"); - index += sizeof("Content-Length:") - 1; + int index = receivedData.indexOf("content-length:"); + if (index == -1) + return; + + foundContentLength = true; + + index += sizeof("content-length:") - 1; const auto end = std::find(receivedData.cbegin() + index, receivedData.cend(), '\r'); auto num = receivedData.mid(index, std::distance(receivedData.cbegin() + index, end)); bool ok; @@ -686,7 +788,7 @@ private: } private slots: -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) void slotSslErrors(const QList<QSslError>& errors) { QTcpSocket *currentClient = qobject_cast<QTcpSocket *>(sender()); @@ -716,12 +818,14 @@ public slots: if (doubleEndlPos != -1) { const int endOfHeader = doubleEndlPos + 4; - hasContent = receivedData.startsWith("POST") || receivedData.startsWith("PUT") - || receivedData.startsWith("CUSTOM_WITH_PAYLOAD"); - if (hasContent && contentLength == 0) + contentRead = receivedData.size() - endOfHeader; + + if (!checkedContentLength) { parseContentLength(); - contentRead = receivedData.length() - endOfHeader; - if (hasContent && contentRead < contentLength) + checkedContentLength = true; + } + + if (contentRead < contentLength) return; // multiple requests incoming. remove the bytes of the current one @@ -757,7 +861,7 @@ public: { QNetworkCookieJar::setAllCookies(cookieList); } }; -#ifndef QT_NO_NETWORKPROXY +#if QT_CONFIG(networkproxy) class MyProxyFactory: public QNetworkProxyFactory { public: @@ -780,7 +884,7 @@ public: return toReturn; } }; -#endif // !QT_NO_NETWORKPROXY +#endif // QT_CONFIG(networkproxy) class MyMemoryCache: public QAbstractNetworkCache { @@ -822,7 +926,7 @@ public: qint64 cacheSize() const override { qint64 total = 0; - foreach (const CachedContent &entry, cache) + for (const auto &[_, entry] : cache.asKeyValueRange()) total += entry.second.size(); return total; } @@ -864,9 +968,15 @@ public: { } - QIODevice *data(const QUrl &) override + QIODevice *data(const QUrl &url) override { - return 0; + QIODevice *device = nullptr; + auto it = m_buffers.constFind(url); + if (it != m_buffers.cend()) { + device = *it; + device->seek(0); + } + return device; } bool remove(const QUrl &url) override @@ -893,7 +1003,6 @@ public: { QUrl url = buffer->property("url").toUrl(); m_insertedUrls << url; - delete m_buffers.take(url); } void clear() override { m_insertedUrls.clear(); } @@ -939,10 +1048,10 @@ class SocketPair: public QObject public: QIODevice *endPoints[2]; - SocketPair(QObject *parent = 0) + SocketPair(QObject *parent = nullptr) : QObject(parent) { - endPoints[0] = endPoints[1] = 0; + endPoints[0] = endPoints[1] = nullptr; } bool create() @@ -976,7 +1085,7 @@ class BlockingTcpServer : public QTcpServer { Q_OBJECT public: - BlockingTcpServer(bool ssl) : doSsl(ssl), sslSocket(0) {} + BlockingTcpServer(bool ssl) : doSsl(ssl), sslSocket(nullptr) {} QTcpSocket* waitForNextConnectionSocket() { @@ -993,7 +1102,7 @@ public: } virtual void incomingConnection(qintptr socketDescriptor) override { -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) if (doSsl) { QSslSocket *serverSocket = new QSslSocket; serverSocket->setParent(this); @@ -1009,7 +1118,7 @@ public: } private slots: -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) void slotSslErrors(const QList<QSslError>& errors) { qDebug() << "slotSslErrors" << sslSocket->errorString() << errors; @@ -1279,12 +1388,17 @@ tst_QNetworkReply::tst_QNetworkReply() { qRegisterMetaType<QNetworkReply *>(); // for QSignalSpy qRegisterMetaType<QAuthenticator *>(); -#ifndef QT_NO_NETWORKPROXY +#if QT_CONFIG(networkproxy) qRegisterMetaType<QNetworkProxy>(); #endif -#ifndef QT_NO_SSL + +#if QT_CONFIG(ssl) qRegisterMetaType<QList<QSslError> >(); + isSecureTransport = QSslSocket::activeBackend() == QStringLiteral("securetransport"); + if (!isSecureTransport) + isSchannel = QSslSocket::activeBackend() == QStringLiteral("schannel"); #endif + qRegisterMetaType<QNetworkReply::NetworkError>(); uniqueExtension = createUniqueExtension(); @@ -1292,7 +1406,7 @@ tst_QNetworkReply::tst_QNetworkReply() cookieJar = new MyCookieJar; manager.setCookieJar(cookieJar); -#ifndef QT_NO_NETWORKPROXY +#if QT_CONFIG(networkproxy) QHostInfo hostInfo = QHostInfo::fromName(QtNetworkSettings::httpProxyServerName()); proxies << ProxyData(QNetworkProxy::NoProxy, "", false); @@ -1311,13 +1425,13 @@ tst_QNetworkReply::tst_QNetworkReply() << ProxyData(QNetworkProxy(QNetworkProxy::Socks5Proxy, socksProxy, 1081), "+socksauth", true); } else { -#endif // !QT_NO_NETWORKPROXY +#endif // QT_CONFIG(networkproxy) fprintf(stderr, "==================================================================\n"); fprintf(stderr, "Proxy could not be looked up. No proxy will be used while testing!\n"); fprintf(stderr, "==================================================================\n"); -#ifndef QT_NO_NETWORKPROXY +#if QT_CONFIG(networkproxy) } -#endif // !QT_NO_NETWORKPROXY +#endif // QT_CONFIG(networkproxy) ftpSupported = manager.supportedSchemes().contains("ftp"); } @@ -1339,7 +1453,7 @@ void tst_QNetworkReply::proxyAuthenticationRequired(const QNetworkProxy &, QAuth auth->setPassword("password"); } -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) void tst_QNetworkReply::sslErrors(QNetworkReply *reply, const QList<QSslError> &errors) { reply->ignoreSslErrors(); @@ -1356,6 +1470,7 @@ void tst_QNetworkReply::storeSslConfiguration() } #endif +#if QT_CONFIG(http) QString tst_QNetworkReply::runMultipartRequest(const QNetworkRequest &request, QNetworkReplyPtr &reply, QHttpMultiPart *multiPart, @@ -1387,6 +1502,7 @@ QString tst_QNetworkReply::runMultipartRequest(const QNetworkRequest &request, } return QString(); } +#endif QString tst_QNetworkReply::runSimpleRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &request, @@ -1437,11 +1553,11 @@ QString tst_QNetworkReply::runSimpleRequest(QNetworkAccessManager::Operation op, while (!reply->isFinished()) { QTimer::singleShot(20000, loop, SLOT(quit())); code = loop->exec(); - if (count == spy.count() && !reply->isFinished()) { + if (count == spy.size() && !reply->isFinished()) { code = Timeout; break; } - count = spy.count(); + count = spy.size(); } delete loop; loop = 0; @@ -1507,11 +1623,11 @@ int tst_QNetworkReply::waitForFinish(QNetworkReplyPtr &reply) QSignalSpy spy(reply.data(), SIGNAL(downloadProgress(qint64,qint64))); while (!reply->isFinished()) { QTimer::singleShot(5000, loop, SLOT(quit())); - if (loop->exec() == Timeout && count == spy.count() && !reply->isFinished()) { + if (loop->exec() == Timeout && count == spy.size() && !reply->isFinished()) { returnCode = Timeout; break; } - count = spy.count(); + count = spy.size(); } delete loop; loop = 0; @@ -1539,8 +1655,10 @@ void tst_QNetworkReply::initTestCase() testDataDir = QCoreApplication::applicationDirPath(); #if defined(QT_TEST_SERVER) - QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpServerName(), 21)); - QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpProxyServerName(), 2121)); + if (ftpSupported) { + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpServerName(), 21)); + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpProxyServerName(), 2121)); + } QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpServerName(), 80)); QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpServerName(), 443)); QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpProxyServerName(), 3128)); @@ -1561,7 +1679,7 @@ void tst_QNetworkReply::initTestCase() #endif QDir::setSearchPaths("testdata", QStringList() << testDataDir); -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) QSslConfiguration::defaultConfiguration().caCertificates(); //preload certificates #endif @@ -1570,10 +1688,18 @@ void tst_QNetworkReply::initTestCase() QString::fromLatin1("Couldn't find echo dir starting from %1.").arg(QDir::currentPath()))); cleanupTestData(); -#ifndef QT_NO_OPENSSL +#if QT_CONFIG(ssl) QT_PREPEND_NAMESPACE(qt_ForceTlsSecurityLevel)(); -#endif // QT_NO_OPENSSL + if (QSslSocket::activeBackend() == QStringLiteral("openssl")) + flukeCertTlsError = QSslError::SelfSignedCertificate; +#endif + + // For content encoding tests + Q_INIT_RESOURCE(gzip); +#if defined(QT_BUILD_INTERNAL) && QT_CONFIG(zstd) + Q_INIT_RESOURCE(zstandard); +#endif } void tst_QNetworkReply::cleanupTestCase() @@ -1582,6 +1708,12 @@ void tst_QNetworkReply::cleanupTestCase() if (!wronlyFileName.isNull()) QFile::remove(wronlyFileName); #endif + + // For content encoding tests +#if defined(QT_BUILD_INTERNAL) && QT_CONFIG(zstd) + Q_CLEANUP_RESOURCE(zstandard); +#endif + Q_CLEANUP_RESOURCE(gzip); } void tst_QNetworkReply::cleanupTestData() @@ -1591,7 +1723,7 @@ void tst_QNetworkReply::cleanupTestData() // clear the internal cache manager.clearAccessCache(); -#ifndef QT_NO_NETWORKPROXY +#if QT_CONFIG(networkproxy) manager.setProxy(QNetworkProxy()); #endif manager.setCache(0); @@ -1600,7 +1732,7 @@ void tst_QNetworkReply::cleanupTestData() cookieJar->setAllCookies(QList<QNetworkCookie>()); // disconnect manager signals -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) manager.disconnect(SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>))); #endif manager.disconnect(SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*))); @@ -1939,7 +2071,254 @@ void tst_QNetworkReply::getFromHttp() QCOMPARE(reply->readAll(), reference.readAll()); } -#ifndef QT_NO_NETWORKPROXY +void tst_QNetworkReply::getWithBodyFromHttp_data() +{ + QTest::addColumn<QByteArray>("dataFromClientToServer"); + QTest::addColumn<bool>("useDevice"); + QTest::newRow("with-bytearray") << QByteArray("Body 1") << false; + QTest::newRow("with-bytearray2") << QByteArray("Body 2") << false; + QTest::newRow("with-bytearray3") << QByteArray("Body 3") << false; + QTest::newRow("with-device") << QByteArray("Body 1") << true; + QTest::newRow("with-device2") << QByteArray("Body 2") << true; + QTest::newRow("with-device3") << QByteArray("Body 3") << true; +} + +void tst_QNetworkReply::getWithBodyFromHttp() +{ + QFETCH(QByteArray, dataFromClientToServer); + QFETCH(bool, useDevice); + + QBuffer buff; + buff.setData(dataFromClientToServer); + buff.open(QIODevice::ReadOnly); + + QByteArray dataFromServerToClient = QByteArray("Long first line\r\nLong second line"); + QByteArray httpResponse = QByteArray("HTTP/1.0 200 OK\r\nContent-Length: "); + httpResponse += QByteArray::number(dataFromServerToClient.size()); + httpResponse += "\r\n\r\n"; + httpResponse += dataFromServerToClient; + + MiniHttpServer server(httpResponse); + server.doClose = true; + + QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); + QNetworkReplyPtr reply; + + if (useDevice) + reply.reset(manager.get(request, &buff)); + else + reply.reset(manager.get(request, dataFromClientToServer)); + + QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply)); + QCOMPARE(server.contentLength, dataFromClientToServer.size()); + QCOMPARE(server.receivedData.right(dataFromClientToServer.size()), dataFromClientToServer); + QByteArray content = reply->readAll(); + QCOMPARE(content, dataFromServerToClient); +} + +void tst_QNetworkReply::getWithAndWithoutBodyFromHttp_data() +{ + QTest::addColumn<QByteArray>("dataFromClientToServer"); + QTest::addColumn<bool>("alwaysCache"); + QTest::addColumn<tst_QNetworkReply::RunSimpleRequestReturn>("requestReturn"); + QTest::addColumn<bool>("useDevice"); + QTest::newRow("with-bytearray") << QByteArray("Body 1") << false << Success << false; + QTest::newRow("with-bytearray2") << QByteArray("Body 2") << false << Success << false; + QTest::newRow("with-bytearray3") << QByteArray("Body 3") << false << Success << false; + QTest::newRow("with-bytearray-cache") << QByteArray("Body 1") << true << Failure << false; + QTest::newRow("with-bytearray-cache2") << QByteArray("Body 2") << true << Failure << false; + QTest::newRow("with-bytearray-cache3") << QByteArray("Body 3") << true << Failure << false; + QTest::newRow("with-device") << QByteArray("Body 1") << false << Success << true; + QTest::newRow("with-device2") << QByteArray("Body 2") << false << Success << true; + QTest::newRow("with-device3") << QByteArray("Body 3") << false << Success << true; + QTest::newRow("with-device-cache") << QByteArray("Body 1") << true << Failure << true; + QTest::newRow("with-device-cache2") << QByteArray("Body 2") << true << Failure << true; + QTest::newRow("with-device-cache3") << QByteArray("Body 3") << true << Failure << true; +} + +void tst_QNetworkReply::getWithAndWithoutBodyFromHttp() +{ + QFETCH(QByteArray, dataFromClientToServer); + QFETCH(bool, alwaysCache); + QFETCH(tst_QNetworkReply::RunSimpleRequestReturn, requestReturn); + QFETCH(bool, useDevice); + + QBuffer buff; + buff.setData(dataFromClientToServer); + buff.open(QIODevice::ReadOnly); + + QNetworkAccessManager qnam; + MyMemoryCache *memoryCache = new MyMemoryCache(&qnam); + qnam.setCache(memoryCache); + + const int sizeOfDataFromServerToClient =3; + QByteArray dataFromServerToClient1 = QByteArray("aaa"); + QByteArray dataFromServerToClient2 = QByteArray("bbb"); + QByteArray dataFromServerToClient3 = QByteArray("ccc"); + + QByteArray baseHttpResponse = QByteArray("HTTP/1.0 200 OK\r\nContent-Length: "); + baseHttpResponse += QByteArray::number(sizeOfDataFromServerToClient); + baseHttpResponse += "\r\n\r\n"; + + MiniHttpServer server(baseHttpResponse + dataFromServerToClient1); + server.doClose = true; + + QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); + + // Send request without body + QNetworkReplyPtr reply(manager.get(request)); + QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply)); + QByteArray content = reply->readAll(); + QCOMPARE(content, dataFromServerToClient1); + + if (alwaysCache) { + request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, + QNetworkRequest::AlwaysCache); + } + + server.dataToTransmit = baseHttpResponse + dataFromServerToClient2; + + // Send request with body + QNetworkReplyPtr reply2; + if (useDevice) + reply2.reset(manager.get(request, &buff)); + else + reply2.reset(manager.get(request, dataFromClientToServer)); + + QVERIFY2(waitForFinish(reply2) == requestReturn, msgWaitForFinished(reply2)); + content = reply2->readAll(); + + if (alwaysCache) + QVERIFY(content.isEmpty()); + else + QCOMPARE(content, dataFromServerToClient2); + + QCOMPARE(reply2->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool(), false); + + if (alwaysCache) { + request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, + QNetworkRequest::PreferNetwork); + } + + server.dataToTransmit = baseHttpResponse + dataFromServerToClient3; + + // Send another request without a body + QNetworkReplyPtr reply3(manager.get(request)); + QVERIFY2(waitForFinish(reply3) == Success, msgWaitForFinished(reply3)); + content = reply3->readAll(); + QCOMPARE(content, dataFromServerToClient3); + QCOMPARE(reply3->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool(), false); +} + +void tst_QNetworkReply::getWithBodyRedirected_data() +{ + QTest::addColumn<QByteArray>("dataFromClientToServer"); + QTest::addColumn<bool>("useDevice"); + QTest::addColumn<int>("status"); + QTest::newRow("with-bytearray - 301") << QByteArray("Body 1") << false << 301; + QTest::newRow("with-bytearray2 - 301") << QByteArray("Body 2") << false << 301; + QTest::newRow("with-bytearray3 - 301") << QByteArray("Body 3") << false << 301; + QTest::newRow("with-device - 301") << QByteArray("Body 1") << true << 301; + QTest::newRow("with-device2 - 301") << QByteArray("Body 2") << true << 301; + QTest::newRow("with-device3 - 301") << QByteArray("Body 3") << true << 301; + QTest::newRow("with-bytearray - 302") << QByteArray("Body 1") << false << 302; + QTest::newRow("with-bytearray2 - 302") << QByteArray("Body 2") << false << 302; + QTest::newRow("with-bytearray3 - 302") << QByteArray("Body 3") << false << 302; + QTest::newRow("with-device - 302") << QByteArray("Body 1") << true << 302; + QTest::newRow("with-device2 - 302") << QByteArray("Body 2") << true << 302; + QTest::newRow("with-device3 - 302") << QByteArray("Body 3") << true << 302; + QTest::newRow("with-bytearray - 307") << QByteArray("Body 1") << false << 307; + QTest::newRow("with-bytearray2 - 307") << QByteArray("Body 2") << false << 307; + QTest::newRow("with-bytearray3 - 307") << QByteArray("Body 3") << false << 307; + QTest::newRow("with-device - 307") << QByteArray("Body 1") << true << 307; + QTest::newRow("with-device2 - 307") << QByteArray("Body 2") << true << 307; + QTest::newRow("with-device3 - 307") << QByteArray("Body 3") << true << 307; + QTest::newRow("with-bytearray - 308") << QByteArray("Body 1") << false << 308; + QTest::newRow("with-bytearray2 - 308") << QByteArray("Body 2") << false << 308; + QTest::newRow("with-bytearray3 - 308") << QByteArray("Body 3") << false << 308; + QTest::newRow("with-device - 308") << QByteArray("Body 1") << true << 308; + QTest::newRow("with-device2 - 308") << QByteArray("Body 2") << true << 308; + QTest::newRow("with-device3 - 308") << QByteArray("Body 3") << true << 308; +} + +void tst_QNetworkReply::getWithBodyRedirected() +{ + QFETCH(QByteArray, dataFromClientToServer); + QFETCH(bool, useDevice); + QFETCH(int, status); + + QBuffer buff; + buff.setData(dataFromClientToServer); + buff.open(QIODevice::ReadOnly); + + QUrl localhost = QUrl("http://localhost"); + + // Setup server to which the second server will redirect to + MiniHttpServer server2(httpEmpty200Response); + + QUrl redirectUrl = QUrl(localhost); + redirectUrl.setPort(server2.serverPort()); + + QByteArray redirectReply; + switch (status) { + case 301: redirectReply = + foundReplyStr().arg(QString(redirectUrl.toEncoded())).toLatin1(); break; + case 302: redirectReply = + movedReplyStr().arg(QString(redirectUrl.toEncoded())).toLatin1(); break; + case 307: redirectReply = + tempRedirectReplyStr().arg(QString(redirectUrl.toEncoded())).toLatin1(); break; + case 308: redirectReply = + permRedirectReplyStr().arg(QString(redirectUrl.toEncoded())).toLatin1(); break; + default: QFAIL("Unexpected status code"); break; + } + + // Setup redirect server + MiniHttpServer server(redirectReply); + + localhost.setPort(server.serverPort()); + QNetworkRequest request(localhost); + request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, + QNetworkRequest::NoLessSafeRedirectPolicy); + + QNetworkReplyPtr reply; + if (useDevice) + reply.reset(manager.get(request, &buff)); + else + reply.reset(manager.get(request, dataFromClientToServer)); + + QSignalSpy redSpy(reply.data(), SIGNAL(redirected(QUrl))); + QSignalSpy finSpy(reply.data(), SIGNAL(finished())); + + QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply)); + + // Redirected and finished should be emitted exactly once + QCOMPARE(redSpy.size(), 1); + QCOMPARE(finSpy.size(), 1); + + // Original URL should not be changed after redirect + QCOMPARE(request.url(), localhost); + + // Verify Redirect url + QList<QVariant> args = redSpy.takeFirst(); + QCOMPARE(args.at(0).toUrl(), redirectUrl); + + // Reply url is set to the redirect url + QCOMPARE(reply->url(), redirectUrl); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QVERIFY(validateRedirectedResponseHeaders(reply)); + + // Verify that the message body has arrived to the server + if (status > 302) { + QVERIFY(server2.contentLength != 0); + QCOMPARE(server2.contentLength, dataFromClientToServer.size()); + QCOMPARE(server2.receivedData.right(dataFromClientToServer.size()), dataFromClientToServer); + } else { + // In these cases the message body should not reach the server + QVERIFY(server2.contentLength == 0); + } +} + +#if QT_CONFIG(networkproxy) void tst_QNetworkReply::headFromHttp_data() { QTest::addColumn<qint64>("referenceSize"); @@ -1958,7 +2337,7 @@ void tst_QNetworkReply::headFromHttp_data() QString httpServer = QtNetworkSettings::httpServerName(); //testing proxies, mainly for the 407 response from http proxy - for (int i = 0; i < proxies.count(); ++i) { + for (int i = 0; i < proxies.size(); ++i) { QTest::newRow("rfc" + proxies.at(i).tag) << rfcsize << QUrl("http://" + httpServer + "/qtest/rfc3252.txt") @@ -2028,7 +2407,7 @@ void tst_QNetworkReply::headFromHttp() if (reply->header(QNetworkRequest::ContentTypeHeader).isValid()) QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader).toString(), contentType); } -#endif // !QT_NO_NETWORKPROXY +#endif // QT_CONFIG(networkproxy) void tst_QNetworkReply::getErrors_data() { @@ -2118,14 +2497,6 @@ void tst_QNetworkReply::getErrors() QSKIP("Running this test as root doesn't make sense"); } - - if (EmulationDetector::isRunningArmOnX86() - && qstrcmp(QTest::currentDataTag(), "file-permissions") == 0) { - QFileInfo filePermissionFile = QFileInfo(filePermissionFileName.toLatin1()); - if (filePermissionFile.ownerId() == ::geteuid()) { - QSKIP("Sysroot directories are owned by the current user"); - } - } #endif QNetworkReplyPtr reply(manager.get(request)); @@ -2248,9 +2619,9 @@ void tst_QNetworkReply::putToFtp() QSignalSpy spy(r, SIGNAL(downloadProgress(qint64,qint64))); while (!r->isFinished()) { QTestEventLoop::instance().enterLoop(10); - if (count == spy.count() && !r->isFinished()) + if (count == spy.size() && !r->isFinished()) break; - count = spy.count(); + count = spy.size(); } QObject::disconnect(r, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); @@ -2365,6 +2736,48 @@ void tst_QNetworkReply::putToHttpSynchronous() QCOMPARE(uploadedData, data); } +void tst_QNetworkReply::putWithoutBody_data() +{ + QTest::addColumn<bool>("client_data"); + + QTest::newRow("client_has_data") << true; + QTest::newRow("client_does_not_have_data") << false; +} + +void tst_QNetworkReply::putWithoutBody() +{ + QFETCH(bool, client_data); + + QBuffer buff; + + if (client_data) { + buff.setData("Dummy data from client to server"); + buff.open(QIODevice::ReadOnly); + } + + QByteArray dataFromServerToClient = QByteArray("Some ridiculous dummy data"); + QByteArray httpResponse = QByteArray("HTTP/1.0 200 OK\r\nContent-Length: "); + httpResponse += QByteArray::number(dataFromServerToClient.size()); + httpResponse += "\r\n\r\n"; + httpResponse += dataFromServerToClient; + + MiniHttpServer server(httpResponse); + server.doClose = true; + + QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); + request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain")); + + QNetworkReplyPtr reply; + if (client_data) + reply.reset(manager.put(request, &buff)); + else + reply.reset(manager.put(request, nullptr)); + + QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply)); + QCOMPARE(server.foundContentLength, client_data); +} + + void tst_QNetworkReply::postToHttp_data() { putToFile_data(); @@ -2375,7 +2788,7 @@ void tst_QNetworkReply::postToHttp() QUrl url("http://" + QtNetworkSettings::httpServerName() + "/qtest/cgi-bin/md5sum.cgi"); QNetworkRequest request(url); - request.setRawHeader("Content-Type", "application/octet-stream"); + request.setRawHeader("content-type", "application/octet-stream"); QNetworkReplyPtr reply; QFETCH(QByteArray, data); @@ -2402,7 +2815,7 @@ void tst_QNetworkReply::postToHttpSynchronous() QUrl url("http://" + QtNetworkSettings::httpServerName() + "/qtest/cgi-bin/md5sum.cgi"); QNetworkRequest request(url); - request.setRawHeader("Content-Type", "application/octet-stream"); + request.setRawHeader("content-type", "application/octet-stream"); request.setAttribute( QNetworkRequest::SynchronousRequestAttribute, @@ -2424,6 +2837,7 @@ void tst_QNetworkReply::postToHttpSynchronous() QCOMPARE(uploadedData, md5sum.toHex()); } +#if QT_CONFIG(http) void tst_QNetworkReply::postToHttpMultipart_data() { QTest::addColumn<QUrl>("url"); @@ -2463,8 +2877,8 @@ void tst_QNetworkReply::postToHttpMultipart_data() QHttpMultiPart *customMultiPart = new QHttpMultiPart; customMultiPart->append(textPart); - expectedData = "header: Content-Type, value: 'text/plain'\n" - "header: Content-Disposition, value: 'form-data; name=\"text\"'\n" + expectedData = "header: content-type, value: 'text/plain'\n" + "header: content-disposition, value: 'form-data; name=\"text\"'\n" "content: 7 bytes\n" "\n"; QTest::newRow("text-custom") << url << customMultiPart << expectedData << QByteArray("custom"); @@ -2500,18 +2914,18 @@ void tst_QNetworkReply::postToHttpMultipart_data() multiPart3->append(textPart); multiPart3->append(textPart2); multiPart3->append(textPart3); - expectedData = "header: Content-Type, value: 'text/plain'\n" - "header: Content-Disposition, value: 'form-data; name=\"text\"'\n" + expectedData = "header: content-type, value: 'text/plain'\n" + "header: content-disposition, value: 'form-data; name=\"text\"'\n" "content: 7 bytes\n" "\n" - "header: Content-Type, value: 'text/plain'\n" - "header: myRawHeader, value: 'myValue'\n" - "header: Content-Disposition, value: 'form-data; name=\"text2\"'\n" + "header: content-type, value: 'text/plain'\n" + "header: myrawheader, value: 'myValue'\n" + "header: content-disposition, value: 'form-data; name=\"text2\"'\n" "content: some more bytes\n" "\n" - "header: Content-Type, value: 'text/plain'\n" - "header: Content-Disposition, value: 'form-data; name=\"text3\"'\n" - "header: Content-Location, value: 'http://my.test.location.tld'\n" + "header: content-type, value: 'text/plain'\n" + "header: content-disposition, value: 'form-data; name=\"text3\"'\n" + "header: content-location, value: 'http://my.test.location.tld'\n" "content: even more bytes\n\n"; QTest::newRow("text-text-text") << url << multiPart3 << expectedData << QByteArray("alternative"); @@ -2682,8 +3096,8 @@ void tst_QNetworkReply::postToHttpMultipart() QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok - QVERIFY(multiPart->boundary().count() > 20); // check that there is randomness after the "boundary_.oOo._" string - QVERIFY(multiPart->boundary().count() < 70); + QVERIFY(multiPart->boundary().size() > 20); // check that there is randomness after the "boundary_.oOo._" string + QVERIFY(multiPart->boundary().size() < 70); QByteArray replyData = reply->readAll(); expectedReplyData.prepend("content type: multipart/" + contentType + "; boundary=\"" + multiPart->boundary() + "\"\n"); @@ -2733,7 +3147,50 @@ void tst_QNetworkReply::multipartSkipIndices() // QTBUG-32534 } multiPart->deleteLater(); } +#endif + +void tst_QNetworkReply::postWithoutBody_data() +{ + QTest::addColumn<bool>("client_data"); + + QTest::newRow("client_has_data") << true; + QTest::newRow("client_does_not_have_data") << false; +} + +void tst_QNetworkReply::postWithoutBody() +{ + QFETCH(bool, client_data); + + QBuffer buff; + + if (client_data) { + buff.setData("Dummy data from client to server"); + buff.open(QIODevice::ReadOnly); + } + + QByteArray dataFromServerToClient = QByteArray("Some ridiculous dummy data"); + QByteArray httpResponse = QByteArray("HTTP/1.0 200 OK\r\nContent-Length: "); + httpResponse += QByteArray::number(dataFromServerToClient.size()); + httpResponse += "\r\n\r\n"; + httpResponse += dataFromServerToClient; + MiniHttpServer server(httpResponse); + server.doClose = true; + + QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); + request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain")); + + QNetworkReplyPtr reply; + if (client_data) + reply.reset(manager.post(request, &buff)); + else + reply.reset(manager.post(request, nullptr)); + + QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply)); + QCOMPARE(server.foundContentLength, client_data); +} + +#if QT_CONFIG(http) void tst_QNetworkReply::putToHttpMultipart_data() { postToHttpMultipart_data(); @@ -2770,18 +3227,22 @@ void tst_QNetworkReply::putToHttpMultipart() QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok - QVERIFY(multiPart->boundary().count() > 20); // check that there is randomness after the "boundary_.oOo._" string - QVERIFY(multiPart->boundary().count() < 70); + QVERIFY(multiPart->boundary().size() > 20); // check that there is randomness after the "boundary_.oOo._" string + QVERIFY(multiPart->boundary().size() < 70); QByteArray replyData = reply->readAll(); expectedReplyData.prepend("content type: multipart/" + contentType + "; boundary=\"" + multiPart->boundary() + "\"\n"); // QEXPECT_FAIL("nested", "the server does not understand nested multipart messages", Continue); // see above QCOMPARE(replyData, expectedReplyData); } +#endif -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) void tst_QNetworkReply::putToHttps_data() { + if (isSecureTransport) + QSKIP("SecTrustEvaluate() returns recoverable error, update the certificate on server"); + uniqueExtension = createUniqueExtension(); putToFile_data(); } @@ -2823,6 +3284,9 @@ void tst_QNetworkReply::putToHttps() void tst_QNetworkReply::putToHttpsSynchronous_data() { + if (isSecureTransport) + QSKIP("SecTrustEvalueate() retruns recoverable error, update the server's certificate"); + uniqueExtension = createUniqueExtension(); putToFile_data(); } @@ -2868,6 +3332,9 @@ void tst_QNetworkReply::putToHttpsSynchronous() void tst_QNetworkReply::postToHttps_data() { + if (isSecureTransport) + QSKIP("SecTrustEvaluate() returns recoverable error, update the certificate on server"); + putToFile_data(); } @@ -2880,7 +3347,7 @@ void tst_QNetworkReply::postToHttps() QSslConfiguration conf; conf.setCaCertificates(certs); request.setSslConfiguration(conf); - request.setRawHeader("Content-Type", "application/octet-stream"); + request.setRawHeader("content-type", "application/octet-stream"); QNetworkReplyPtr reply; QFETCH(QByteArray, data); @@ -2899,6 +3366,9 @@ void tst_QNetworkReply::postToHttps() void tst_QNetworkReply::postToHttpsSynchronous_data() { + if (isSecureTransport) + QSKIP("SecTrustEvaluate() returns recoverable error, update the certificate on server"); + putToFile_data(); } @@ -2911,7 +3381,7 @@ void tst_QNetworkReply::postToHttpsSynchronous() QSslConfiguration conf; conf.setCaCertificates(certs); request.setSslConfiguration(conf); - request.setRawHeader("Content-Type", "application/octet-stream"); + request.setRawHeader("content-type", "application/octet-stream"); request.setAttribute( QNetworkRequest::SynchronousRequestAttribute, @@ -2933,8 +3403,12 @@ void tst_QNetworkReply::postToHttpsSynchronous() QCOMPARE(uploadedData, md5sum.toHex()); } +#if QT_CONFIG(http) void tst_QNetworkReply::postToHttpsMultipart_data() { + if (isSecureTransport) + QSKIP("SecTrustEvaluate() returns recoverable error, update the certificate on server"); + postToHttpMultipart_data(); } @@ -2973,15 +3447,15 @@ void tst_QNetworkReply::postToHttpsMultipart() QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 Ok - QVERIFY(multiPart->boundary().count() > 20); // check that there is randomness after the "boundary_.oOo._" string - QVERIFY(multiPart->boundary().count() < 70); + QVERIFY(multiPart->boundary().size() > 20); // check that there is randomness after the "boundary_.oOo._" string + QVERIFY(multiPart->boundary().size() < 70); QByteArray replyData = reply->readAll(); expectedReplyData.prepend("content type: multipart/" + contentType + "; boundary=\"" + multiPart->boundary() + "\"\n"); QCOMPARE(replyData, expectedReplyData); } - -#endif // QT_NO_SSL +#endif +#endif // QT_CONFIG(ssl) void tst_QNetworkReply::deleteFromHttp_data() { @@ -3110,7 +3584,7 @@ void tst_QNetworkReply::connectToIPv6Address() if (!QtNetworkSettings::hasIPv6()) QSKIP("system doesn't support ipv6!"); - QByteArray httpResponse = QByteArray("HTTP/1.0 200 OK\r\nContent-Length: "); + QByteArray httpResponse = QByteArray("HTTP/1.0 200 OK\r\ncontent-length: "); httpResponse += QByteArray::number(dataToSend.size()); httpResponse += "\r\n\r\n"; httpResponse += dataToSend; @@ -3125,7 +3599,7 @@ void tst_QNetworkReply::connectToIPv6Address() QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply)); QByteArray content = reply->readAll(); //qDebug() << server.receivedData; - QByteArray hostinfo = "\r\nHost: " + hostfield + ':' + QByteArray::number(server.serverPort()) + "\r\n"; + QByteArray hostinfo = "\r\nhost: " + hostfield + ':' + QByteArray::number(server.serverPort()) + "\r\n"; QVERIFY(server.receivedData.contains(hostinfo)); QCOMPARE(content, dataToSend); QCOMPARE(reply->url(), request.url()); @@ -3287,6 +3761,18 @@ void tst_QNetworkReply::ioGetFromFile() QCOMPARE(reader.data, data); } +void tst_QNetworkReply::ioGetFromFileUrl() +{ + // This immediately fails on non-windows platforms: + QNetworkRequest request(QUrl("file://unc-server/some/path")); + QNetworkReplyPtr reply(manager.get(request)); + QSignalSpy finishedSpy(reply.get(), &QNetworkReply::finished); + // QTBUG-105618: This would, on non-Windows platforms, never happen because the signal + // was emitted before the constructor finished, leaving no chance at all to connect to the + // signal + QVERIFY(finishedSpy.wait()); +} + void tst_QNetworkReply::ioGetFromFtp_data() { if (!ftpSupported) @@ -3304,7 +3790,9 @@ void tst_QNetworkReply::ioGetFromFtp() { QFETCH(QString, fileName); QFile reference(fileName); - reference.open(QIODevice::ReadOnly); // will fail for bigfile + const bool ok = reference.open(QIODevice::ReadOnly); // will fail for bigfile + if (fileName != "bigfile") + QVERIFY(ok); QNetworkRequest request("ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/" + fileName); QNetworkReplyPtr reply(manager.get(request)); @@ -3329,7 +3817,7 @@ void tst_QNetworkReply::ioGetFromFtpWithReuse() QSKIP("FTP is not supported"); QString fileName = testDataDir + "/rfc3252.txt"; QFile reference(fileName); - reference.open(QIODevice::ReadOnly); + QVERIFY(reference.open(QIODevice::ReadOnly)); QNetworkRequest request(QUrl("ftp://" + QtNetworkSettings::ftpServerName() + "/qtest/rfc3252.txt")); @@ -3459,7 +3947,7 @@ void tst_QNetworkReply::ioGetFromHttpWithAuth_data() QTest::addColumn<int>("expectedAuth"); QFile reference(testDataDir + "/rfc3252.txt"); - reference.open(QIODevice::ReadOnly); + QVERIFY(reference.open(QIODevice::ReadOnly)); QByteArray referenceData = reference.readAll(); QString httpServer = QtNetworkSettings::httpServerName(); QTest::newRow("basic") @@ -3533,7 +4021,7 @@ void tst_QNetworkReply::ioGetFromHttpWithAuth() QCOMPARE(reader1.data, expectedData); QCOMPARE(reader2.data, expectedData); - QCOMPARE(authspy.count(), (expectedAuth ? 1 : 0)); + QCOMPARE(authspy.size(), (expectedAuth ? 1 : 0)); expectedAuth = qMax(0, expectedAuth - 1); } @@ -3554,7 +4042,7 @@ void tst_QNetworkReply::ioGetFromHttpWithAuth() QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); QCOMPARE(reader.data, expectedData); - QCOMPARE(authspy.count(), (expectedAuth ? 1 : 0)); + QCOMPARE(authspy.size(), (expectedAuth ? 1 : 0)); expectedAuth = qMax(0, expectedAuth - 1); } @@ -3571,7 +4059,7 @@ void tst_QNetworkReply::ioGetFromHttpWithAuth() // bad credentials in a synchronous request should just fail QCOMPARE(replySync->error(), QNetworkReply::AuthenticationRequiredError); } else { - QCOMPARE(authspy.count(), 0); + QCOMPARE(authspy.size(), 0); // we cannot use a data reader here, since that connects to the readyRead signal, // just use readAll() @@ -3597,7 +4085,7 @@ void tst_QNetworkReply::ioGetFromHttpWithAuth() // bad credentials in a synchronous request should just fail QCOMPARE(replySync->error(), QNetworkReply::AuthenticationRequiredError); } else { - QCOMPARE(authspy.count(), 0); + QCOMPARE(authspy.size(), 0); // we cannot use a data reader here, since that connects to the readyRead signal, // just use readAll() @@ -3623,11 +4111,11 @@ void tst_QNetworkReply::ioGetFromHttpWithAuthSynchronous() QNetworkReplyPtr replySync(manager.get(request)); QVERIFY(replySync->isFinished()); // synchronous QCOMPARE(replySync->error(), QNetworkReply::AuthenticationRequiredError); - QCOMPARE(authspy.count(), 0); + QCOMPARE(authspy.size(), 0); QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 401); } -#ifndef QT_NO_NETWORKPROXY +#if QT_CONFIG(networkproxy) void tst_QNetworkReply::ioGetFromHttpWithProxyAuth() { // This test sends three requests @@ -3664,7 +4152,7 @@ void tst_QNetworkReply::ioGetFromHttpWithProxyAuth() QCOMPARE(reader1.data, referenceData); QCOMPARE(reader2.data, referenceData); - QCOMPARE(authspy.count(), 1); + QCOMPARE(authspy.size(), 1); } reference.seek(0); @@ -3687,7 +4175,7 @@ void tst_QNetworkReply::ioGetFromHttpWithProxyAuth() QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); QCOMPARE(reader.data, reference.readAll()); - QCOMPARE(authspy.count(), 0); + QCOMPARE(authspy.size(), 0); } // now check with synchronous calls: @@ -3700,7 +4188,7 @@ void tst_QNetworkReply::ioGetFromHttpWithProxyAuth() QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); QNetworkReplyPtr replySync(manager.get(request)); QVERIFY(replySync->isFinished()); // synchronous - QCOMPARE(authspy.count(), 0); + QCOMPARE(authspy.size(), 0); // we cannot use a data reader here, since that connects to the readyRead signal, // just use readAll() @@ -3728,7 +4216,7 @@ void tst_QNetworkReply::ioGetFromHttpWithProxyAuthSynchronous() manager.setProxy(QNetworkProxy()); // reset QVERIFY(replySync->isFinished()); // synchronous QCOMPARE(replySync->error(), QNetworkReply::ProxyAuthenticationRequiredError); - QCOMPARE(authspy.count(), 0); + QCOMPARE(authspy.size(), 0); QCOMPARE(replySync->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 407); } @@ -3760,7 +4248,7 @@ void tst_QNetworkReply::ioGetFromHttpWithSocksProxy() QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); QCOMPARE(reader.data, reference.readAll()); - QCOMPARE(authspy.count(), 0); + QCOMPARE(authspy.size(), 0); } // set an invalid proxy just to make sure that we can't load @@ -3784,15 +4272,14 @@ void tst_QNetworkReply::ioGetFromHttpWithSocksProxy() QVERIFY(reader.data.isEmpty()); QVERIFY(int(reply->error()) > 0); - QEXPECT_FAIL("", "QTcpSocket doesn't return enough information yet", Continue); QCOMPARE(int(reply->error()), int(QNetworkReply::ProxyConnectionRefusedError)); - QCOMPARE(authspy.count(), 0); + QCOMPARE(authspy.size(), 0); } } -#endif // !QT_NO_NETWORKPROXY +#endif // QT_CONFIG(networkproxy) -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) void tst_QNetworkReply::ioGetFromHttpsWithSslErrors() { QFile reference(testDataDir + "/rfc3252.txt"); @@ -3815,7 +4302,7 @@ void tst_QNetworkReply::ioGetFromHttpsWithSslErrors() QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); QCOMPARE(reader.data, reference.readAll()); - QCOMPARE(sslspy.count(), 1); + QCOMPARE(sslspy.size(), 1); QVERIFY(!storedSslConfiguration.isNull()); QVERIFY(!reply->sslConfiguration().isNull()); @@ -3843,7 +4330,7 @@ void tst_QNetworkReply::ioGetFromHttpsWithIgnoreSslErrors() QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); QCOMPARE(reader.data, reference.readAll()); - QCOMPARE(sslspy.count(), 1); + QCOMPARE(sslspy.size(), 1); QVERIFY(!storedSslConfiguration.isNull()); QVERIFY(!reply->sslConfiguration().isNull()); @@ -3866,7 +4353,7 @@ void tst_QNetworkReply::ioGetFromHttpsWithSslHandshakeError() QCOMPARE(waitForFinish(reply), int(Failure)); QCOMPARE(reply->error(), QNetworkReply::SslHandshakeFailedError); - QCOMPARE(sslspy.count(), 0); + QCOMPARE(sslspy.size(), 0); } #endif @@ -3924,11 +4411,11 @@ void tst_QNetworkReply::ioGetFromHttpBrokenServer() QCOMPARE(waitForFinish(reply), int(Failure)); QCOMPARE(reply->url(), request.url()); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QVERIFY(reply->error() != QNetworkReply::NoError); } -void tst_QNetworkReply::ioGetFromHttpStatus100_data() +void tst_QNetworkReply::ioGetFromHttpStatusInformational_data() { QTest::addColumn<QByteArray>("dataToSend"); QTest::addColumn<int>("statusCode"); @@ -3939,9 +4426,25 @@ void tst_QNetworkReply::ioGetFromHttpStatus100_data() QTest::newRow("minimal+404") << QByteArray("HTTP/1.1 100 Continue\n\nHTTP/1.0 204 No Content\r\n\r\n") << 204; QTest::newRow("with_headers") << QByteArray("HTTP/1.1 100 Continue\r\nBla: x\r\n\r\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200; QTest::newRow("with_headers2") << QByteArray("HTTP/1.1 100 Continue\nBla: x\n\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200; + + QTest::newRow("normal-custom") << QByteArray("HTTP/1.1 133 Custom\r\n\r\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200; + QTest::newRow("minimal-custom") << QByteArray("HTTP/1.1 133 Custom\n\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200; + QTest::newRow("minimal2-custom") << QByteArray("HTTP/1.1 133 Custom\n\nHTTP/1.0 200 OK\r\n\r\n") << 200; + QTest::newRow("minimal3-custom") << QByteArray("HTTP/1.1 133 Custom\n\nHTTP/1.0 200 OK\n\n") << 200; + QTest::newRow("minimal+404-custom") << QByteArray("HTTP/1.1 133 Custom\n\nHTTP/1.0 204 No Content\r\n\r\n") << 204; + QTest::newRow("with_headers-custom") << QByteArray("HTTP/1.1 133 Custom\r\nBla: x\r\n\r\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200; + QTest::newRow("with_headers2-custom") << QByteArray("HTTP/1.1 133 Custom\nBla: x\n\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200; + + QTest::newRow("normal-custom2") << QByteArray("HTTP/1.1 179 Custom2\r\n\r\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200; + QTest::newRow("minimal-custom2") << QByteArray("HTTP/1.1 179 Custom2\n\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200; + QTest::newRow("minimal2-custom2") << QByteArray("HTTP/1.1 179 Custom2\n\nHTTP/1.0 200 OK\r\n\r\n") << 200; + QTest::newRow("minimal3-custom2") << QByteArray("HTTP/1.1 179 Custom2\n\nHTTP/1.0 200 OK\n\n") << 200; + QTest::newRow("minimal+404-custom2") << QByteArray("HTTP/1.1 179 Custom2\n\nHTTP/1.0 204 No Content\r\n\r\n") << 204; + QTest::newRow("with_headers-custom2") << QByteArray("HTTP/1.1 179 Custom2\r\nBla: x\r\n\r\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200; + QTest::newRow("with_headers2-custom2") << QByteArray("HTTP/1.1 179 Custom2\nBla: x\n\nHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n") << 200; } -void tst_QNetworkReply::ioGetFromHttpStatus100() +void tst_QNetworkReply::ioGetFromHttpStatusInformational() { QFETCH(QByteArray, dataToSend); QFETCH(int, statusCode); @@ -3995,7 +4498,7 @@ void tst_QNetworkReply::ioGetFromHttpWithCache_data() QByteArray reply200 = "HTTP/1.0 200\r\n" "Connection: keep-alive\r\n" - "Content-Type: text/plain\r\n" + "content-type: text/plain\r\n" "Cache-control: no-store\r\n" "Content-length: 8\r\n" "\r\n" @@ -4130,7 +4633,7 @@ void tst_QNetworkReply::ioGetFromHttpWithCache_data() QByteArray reply206 = "HTTP/1.0 206\r\n" "Connection: keep-alive\r\n" - "Content-Type: text/plain\r\n" + "content-type: text/plain\r\n" "Cache-control: no-cache\r\n" "Content-Range: bytes 2-6/8\r\n" "Content-length: 4\r\n" @@ -4179,7 +4682,7 @@ void tst_QNetworkReply::ioGetFromHttpWithCache() QCOMPARE(reply->readAll().constData(), qPrintable(body)); } -#ifndef QT_NO_NETWORKPROXY +#if QT_CONFIG(networkproxy) void tst_QNetworkReply::ioGetWithManyProxies_data() { QTest::addColumn<QList<QNetworkProxy> >("proxyList"); @@ -4240,7 +4743,7 @@ void tst_QNetworkReply::ioGetWithManyProxies_data() << QNetworkReply::NoError; } -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) // HTTPS with HTTP transparent proxy proxyList.clear(); proxyList << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::httpProxyServerName(), 3129); @@ -4260,15 +4763,15 @@ void tst_QNetworkReply::ioGetWithManyProxies_data() // Tests that fail: - // HTTP request with FTP caching proxy - proxyList.clear(); - proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121); - QTest::newRow("http-on-ftp") - << proxyList << QNetworkProxy() - << "http://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt" - << QNetworkReply::ProxyNotFoundError; - if (ftpSupported) { + // HTTP request with FTP caching proxy + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121); + QTest::newRow("http-on-ftp") + << proxyList << QNetworkProxy() + << "http://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt" + << QNetworkReply::ProxyNotFoundError; + // FTP request with HTTP caching proxy proxyList.clear(); proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, @@ -4290,7 +4793,7 @@ void tst_QNetworkReply::ioGetWithManyProxies_data() << QNetworkReply::ProxyNotFoundError; } -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) // HTTPS with HTTP caching proxy proxyList.clear(); proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3129); @@ -4299,13 +4802,15 @@ void tst_QNetworkReply::ioGetWithManyProxies_data() << "https://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt" << QNetworkReply::ProxyNotFoundError; - // HTTPS with FTP caching proxy - proxyList.clear(); - proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121); - QTest::newRow("https-on-ftp") - << proxyList << QNetworkProxy() - << "https://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt" - << QNetworkReply::ProxyNotFoundError; + if (ftpSupported) { + // HTTPS with FTP caching proxy + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121); + QTest::newRow("https-on-ftp") + << proxyList << QNetworkProxy() + << "https://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt" + << QNetworkReply::ProxyNotFoundError; + } #endif // Complex requests: @@ -4328,15 +4833,17 @@ void tst_QNetworkReply::ioGetWithManyProxies_data() << "http://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt" << QNetworkReply::NoError; - // HTTP request with FTP + HTTP + SOCKS - proxyList.clear(); - proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121) - << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3129) - << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1081); - QTest::newRow("http-on-ftp+http+socks") - << proxyList << proxyList.at(1) // second proxy should be used - << "http://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt" - << QNetworkReply::NoError; + if (ftpSupported) { + // HTTP request with FTP + HTTP + SOCKS + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121) + << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3129) + << QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::socksProxyServerName(), 1081); + QTest::newRow("http-on-ftp+http+socks") + << proxyList << proxyList.at(1) // second proxy should be used + << "http://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt" + << QNetworkReply::NoError; + } // HTTP request with NoProxy + HTTP proxyList.clear(); @@ -4348,15 +4855,15 @@ void tst_QNetworkReply::ioGetWithManyProxies_data() << QNetworkReply::NoError; // HTTP request with FTP + NoProxy - proxyList.clear(); - proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121) - << QNetworkProxy(QNetworkProxy::NoProxy); - QTest::newRow("http-on-ftp+noproxy") - << proxyList << proxyList.at(1) // second proxy should be used - << "http://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt" - << QNetworkReply::NoError; - if (ftpSupported) { + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121) + << QNetworkProxy(QNetworkProxy::NoProxy); + QTest::newRow("http-on-ftp+noproxy") + << proxyList << proxyList.at(1) // second proxy should be used + << "http://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt" + << QNetworkReply::NoError; + // FTP request with HTTP Caching + FTP proxyList.clear(); proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, @@ -4369,7 +4876,7 @@ void tst_QNetworkReply::ioGetWithManyProxies_data() << QNetworkReply::NoError; } -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) // HTTPS request with HTTP Caching + HTTP transparent proxyList.clear(); proxyList << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3129) @@ -4379,15 +4886,17 @@ void tst_QNetworkReply::ioGetWithManyProxies_data() << "https://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt" << QNetworkReply::NoError; - // HTTPS request with FTP + HTTP C + HTTP T - proxyList.clear(); - proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121) - << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3129) - << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::httpProxyServerName(), 3129); - QTest::newRow("https-on-ftp+httpcaching+http") - << proxyList << proxyList.at(2) // skip the first two - << "https://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt" - << QNetworkReply::NoError; + if (ftpSupported) { + // HTTPS request with FTP + HTTP C + HTTP T + proxyList.clear(); + proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121) + << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3129) + << QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::httpProxyServerName(), 3129); + QTest::newRow("https-on-ftp+httpcaching+http") + << proxyList << proxyList.at(2) // skip the first two + << "https://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt" + << QNetworkReply::NoError; + } #endif } @@ -4413,7 +4922,7 @@ void tst_QNetworkReply::ioGetWithManyProxies() QSignalSpy authspy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)), SLOT(sslErrors(QNetworkReply*,QList<QSslError>))); #endif @@ -4422,7 +4931,7 @@ void tst_QNetworkReply::ioGetWithManyProxies() manager.disconnect(SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) manager.disconnect(SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)), this, SLOT(sslErrors(QNetworkReply*,QList<QSslError>))); #endif @@ -4442,19 +4951,19 @@ void tst_QNetworkReply::ioGetWithManyProxies() // now verify that the proxies worked: QFETCH(QNetworkProxy, proxyUsed); if (proxyUsed.type() == QNetworkProxy::NoProxy) { - QCOMPARE(authspy.count(), 0); + QCOMPARE(authspy.size(), 0); } else { if (QByteArray(QTest::currentDataTag()).startsWith("ftp-")) return; // No authentication with current FTP or with FTP proxies - QCOMPARE(authspy.count(), 1); + QCOMPARE(authspy.size(), 1); QCOMPARE(qvariant_cast<QNetworkProxy>(authspy.at(0).at(0)), proxyUsed); } } else { // request failed - QCOMPARE(authspy.count(), 0); + QCOMPARE(authspy.size(), 0); } } -#endif // !QT_NO_NETWORKPROXY +#endif // QT_CONFIG(networkproxy) void tst_QNetworkReply::ioPutToFileFromFile_data() { @@ -4527,6 +5036,7 @@ void tst_QNetworkReply::ioPutToFileFromSocket() QCOMPARE(contents, data); } +#if QT_CONFIG(localserver) void tst_QNetworkReply::ioPutToFileFromLocalSocket_data() { putToFile_data(); @@ -4557,10 +5067,6 @@ void tst_QNetworkReply::ioPutToFileFromLocalSocket() QNetworkReplyPtr reply(manager.put(QNetworkRequest(url), passive)); passive->setParent(reply.data()); -#ifdef Q_OS_WIN - if (!data.isEmpty()) - QEXPECT_FAIL("", "QTBUG-18385", Abort); -#endif QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply)); QCOMPARE(reply->error(), QNetworkReply::NoError); @@ -4574,6 +5080,7 @@ void tst_QNetworkReply::ioPutToFileFromLocalSocket() QByteArray contents = file.readAll(); QCOMPARE(contents, data); } +#endif // Currently no stdin/out supported for Windows CE. void tst_QNetworkReply::ioPutToFileFromProcess_data() @@ -4623,6 +5130,10 @@ void tst_QNetworkReply::ioPutToFileFromProcess() QByteArray contents = file.readAll(); QCOMPARE(contents, data); + if (process.state() == QProcess::Running) + QVERIFY(process.waitForFinished()); + QCOMPARE(process.exitCode(), 0); + #endif // QT_CONFIG(process) } @@ -4733,7 +5244,7 @@ void tst_QNetworkReply::ioPostToHttpFromFile() QUrl url("http://" + QtNetworkSettings::httpServerName() + "/qtest/cgi-bin/md5sum.cgi"); QNetworkRequest request(url); - request.setRawHeader("Content-Type", "application/octet-stream"); + request.setRawHeader("content-type", "application/octet-stream"); QNetworkReplyPtr reply(manager.post(request, &sourceFile)); @@ -4751,7 +5262,7 @@ void tst_QNetworkReply::ioPostToHttpFromFile() QCOMPARE(reply->readAll().trimmed(), md5sum(sourceFile.readAll()).toHex()); } -#ifndef QT_NO_NETWORKPROXY +#if QT_CONFIG(networkproxy) void tst_QNetworkReply::ioPostToHttpFromSocket_data() { QTest::addColumn<QByteArray>("data"); @@ -4761,7 +5272,7 @@ void tst_QNetworkReply::ioPostToHttpFromSocket_data() QTest::addColumn<int>("authenticationRequiredCount"); QTest::addColumn<int>("proxyAuthenticationRequiredCount"); - for (int i = 0; i < proxies.count(); ++i) + for (int i = 0; i < proxies.size(); ++i) for (int auth = 0; auth < 2; ++auth) { QUrl url; if (auth) @@ -4810,7 +5321,7 @@ void tst_QNetworkReply::ioPostToHttpFromSocket() socketpair.endPoints[0]->write(data); QNetworkRequest request(url); - request.setRawHeader("Content-Type", "application/octet-stream"); + request.setRawHeader("content-type", "application/octet-stream"); manager.setProxy(proxy); QNetworkReplyPtr reply(manager.post(request, socketpair.endPoints[1])); @@ -4839,8 +5350,8 @@ void tst_QNetworkReply::ioPostToHttpFromSocket() QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex()); - QTEST(int(authenticationRequiredSpy.count()), "authenticationRequiredCount"); - QTEST(int(proxyAuthenticationRequiredSpy.count()), "proxyAuthenticationRequiredCount"); + QTEST(int(authenticationRequiredSpy.size()), "authenticationRequiredCount"); + QTEST(int(proxyAuthenticationRequiredSpy.size()), "proxyAuthenticationRequiredCount"); } void tst_QNetworkReply::ioPostToHttpFromSocketSynchronous_data() @@ -4884,7 +5395,7 @@ void tst_QNetworkReply::ioPostToHttpFromSocketSynchronous() QUrl url("http://" + QtNetworkSettings::httpServerName() + "/qtest/cgi-bin/md5sum.cgi"); QNetworkRequest request(url); - request.setRawHeader("Content-Type", "application/octet-stream"); + request.setRawHeader("content-type", "application/octet-stream"); request.setAttribute( QNetworkRequest::SynchronousRequestAttribute, true); @@ -4902,7 +5413,7 @@ void tst_QNetworkReply::ioPostToHttpFromSocketSynchronous() QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex()); } -#endif // !QT_NO_NETWORKPROXY +#endif // QT_CONFIG(networkproxy) // this tests checks if rewinding the POST-data to some place in the middle // worked. @@ -4915,7 +5426,7 @@ void tst_QNetworkReply::ioPostToHttpFromMiddleOfFileToEnd() QUrl url = "http://" + QtNetworkSettings::httpServerName() + "/qtest/protected/cgi-bin/md5sum.cgi"; QNetworkRequest request(url); - request.setRawHeader("Content-Type", "application/octet-stream"); + request.setRawHeader("content-type", "application/octet-stream"); QNetworkReplyPtr reply(manager.post(request, &sourceFile)); connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), @@ -4941,7 +5452,7 @@ void tst_QNetworkReply::ioPostToHttpFromMiddleOfFileFiveBytes() QUrl url = "http://" + QtNetworkSettings::httpServerName() + "/qtest/protected/cgi-bin/md5sum.cgi"; QNetworkRequest request(url); - request.setRawHeader("Content-Type", "application/octet-stream"); + request.setRawHeader("content-type", "application/octet-stream"); // only send 5 bytes request.setHeader(QNetworkRequest::ContentLengthHeader, 5); QVERIFY(request.header(QNetworkRequest::ContentLengthHeader).isValid()); @@ -4972,7 +5483,7 @@ void tst_QNetworkReply::ioPostToHttpFromMiddleOfQBufferFiveBytes() QUrl url = "http://" + QtNetworkSettings::httpServerName() + "/qtest/protected/cgi-bin/md5sum.cgi"; QNetworkRequest request(url); - request.setRawHeader("Content-Type", "application/octet-stream"); + request.setRawHeader("content-type", "application/octet-stream"); QNetworkReplyPtr reply(manager.post(request, &uploadBuffer)); connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), @@ -5000,7 +5511,7 @@ void tst_QNetworkReply::ioPostToHttpNoBufferFlag() QUrl url = "http://" + QtNetworkSettings::httpServerName() + "/qtest/protected/cgi-bin/md5sum.cgi"; QNetworkRequest request(url); - request.setRawHeader("Content-Type", "application/octet-stream"); + request.setRawHeader("content-type", "application/octet-stream"); // disallow buffering request.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, true); request.setHeader(QNetworkRequest::ContentLengthHeader, data.size()); @@ -5019,7 +5530,7 @@ void tst_QNetworkReply::ioPostToHttpNoBufferFlag() QCOMPARE(reply->error(), QNetworkReply::ContentReSendError); } -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) class SslServer : public QTcpServer { Q_OBJECT @@ -5085,7 +5596,7 @@ void tst_QNetworkReply::ioPostToHttpsUploadProgress() QUrl url = QUrl(QLatin1String("https://127.0.0.1:") + QString::number(server.serverPort()) + QLatin1Char('/')); QNetworkRequest request(url); - request.setRawHeader("Content-Type", "application/octet-stream"); + request.setRawHeader("content-type", "application/octet-stream"); QNetworkReplyPtr reply(manager.post(request, sourceFile)); QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64))); @@ -5135,7 +5646,7 @@ void tst_QNetworkReply::ioGetFromBuiltinHttp_data() QTest::addColumn<int>("bufferSize"); QTest::newRow("http+unlimited") << false << 0; QTest::newRow("http+limited") << false << 4096; -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) QTest::newRow("https+unlimited") << true << 0; QTest::newRow("https+limited") << true << 4096; #endif @@ -5239,7 +5750,7 @@ void tst_QNetworkReply::ioPostToHttpUploadProgress() // create the request QUrl url = QUrl(QString("http://127.0.0.1:%1/").arg(server.serverPort())); QNetworkRequest request(url); - request.setRawHeader("Content-Type", "application/octet-stream"); + request.setRawHeader("content-type", "application/octet-stream"); QNetworkReplyPtr reply(manager.post(request, &sourceFile)); QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64))); connect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop())); @@ -5307,18 +5818,14 @@ void tst_QNetworkReply::emitAllUploadProgressSignals() QUrl url = QUrl(QLatin1String("http://127.0.0.1:") + QString::number(server.serverPort()) + QLatin1Char('/')); QNetworkRequest normalRequest(url); - normalRequest.setRawHeader("Content-Type", "application/octet-stream"); + normalRequest.setRawHeader("content-type", "application/octet-stream"); QNetworkRequest catchAllSignalsRequest(normalRequest); catchAllSignalsRequest.setAttribute(QNetworkRequest::EmitAllUploadProgressSignalsAttribute, true); - QList<QNetworkRequest> requests; - requests << normalRequest << catchAllSignalsRequest; - QList<int> signalCount; - foreach (const QNetworkRequest &request, requests) { - + for (const QNetworkRequest &request : {normalRequest, catchAllSignalsRequest}) { sourceFile.seek(0); QNetworkReplyPtr reply(manager.post(request, &sourceFile)); QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64))); @@ -5339,7 +5846,7 @@ void tst_QNetworkReply::emitAllUploadProgressSignals() QVERIFY(!QTestEventLoop::instance().timeout()); incomingSocket->close(); - signalCount.append(spy.count()); + signalCount.append(spy.size()); reply->deleteLater(); } server.close(); @@ -5362,7 +5869,7 @@ void tst_QNetworkReply::ioPostToHttpEmptyUploadProgress() // create the request QUrl url = QUrl(QLatin1String("http://127.0.0.1:") + QString::number(server.serverPort()) + QLatin1Char('/')); QNetworkRequest request(url); - request.setRawHeader("Content-Type", "application/octet-stream"); + request.setRawHeader("content-type", "application/octet-stream"); QNetworkReplyPtr reply(manager.post(request, &buffer)); QSignalSpy spy(reply.data(), SIGNAL(uploadProgress(qint64,qint64))); connect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop())); @@ -5385,7 +5892,7 @@ void tst_QNetworkReply::ioPostToHttpEmptyUploadProgress() QVERIFY(!QTestEventLoop::instance().timeout()); // final check: only 1 uploadProgress has been emitted - QCOMPARE(spy.length(), 1); + QCOMPARE(spy.size(), 1); QList<QVariant> args = spy.last(); QVERIFY(!args.isEmpty()); QCOMPARE(args.at(0).toLongLong(), buffer.size()); @@ -5408,7 +5915,11 @@ void tst_QNetworkReply::lastModifiedHeaderForFile() QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply)); QDateTime header = reply->header(QNetworkRequest::LastModifiedHeader).toDateTime(); - QCOMPARE(header, fileInfo.lastModified()); + QDateTime expected = fileInfo.lastModified(); + // remove msecs, HTTP dates don't support it + expected = expected.addMSecs(-expected.time().msec()); + + QCOMPARE(header.toUTC(), expected.toUTC()); } void tst_QNetworkReply::lastModifiedHeaderForHttp() @@ -5423,7 +5934,7 @@ void tst_QNetworkReply::lastModifiedHeaderForHttp() QDateTime header = reply->header(QNetworkRequest::LastModifiedHeader).toDateTime(); QDateTime realDate = QDateTime::fromString("2007-05-22T12:04:57", Qt::ISODate); - realDate.setTimeSpec(Qt::UTC); + realDate.setTimeZone(QTimeZone::UTC); QCOMPARE(header, realDate); } @@ -5556,7 +6067,7 @@ void tst_QNetworkReply::downloadProgress() QVERIFY(!QTestEventLoop::instance().timeout()); QVERIFY(reply->isFinished()); - QVERIFY(spy.count() > 0); + QVERIFY(spy.size() > 0); //final progress should have equal current & total QList<QVariant> args = spy.takeLast(); @@ -5602,14 +6113,14 @@ void tst_QNetworkReply::uploadProgress() QVERIFY(server.hasPendingConnections()); QTcpSocket *receiver = server.nextPendingConnection(); - if (finished.count() == 0) { + if (finished.size() == 0) { // it's not finished yet, so wait for it to be QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply)); } delete receiver; - QVERIFY(finished.count() > 0); - QVERIFY(spy.count() > 0); + QVERIFY(finished.size() > 0); + QVERIFY(spy.size() > 0); QList<QVariant> args = spy.last(); QCOMPARE(args.at(0).toInt(), data.size()); @@ -5714,7 +6225,7 @@ void tst_QNetworkReply::receiveCookiesFromHttp() QByteArray data = cookieString.toLatin1() + '\n'; QUrl url("http://" + QtNetworkSettings::httpServerName() + "/qtest/cgi-bin/set-cookie.cgi"); QNetworkRequest request(url); - request.setRawHeader("Content-Type", "application/octet-stream"); + request.setRawHeader("content-type", "application/octet-stream"); QNetworkReplyPtr reply; RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data)); @@ -5742,7 +6253,7 @@ void tst_QNetworkReply::receiveCookiesFromHttpSynchronous() QUrl url("http://" + QtNetworkSettings::httpServerName() + "/qtest/cgi-bin/set-cookie.cgi"); QNetworkRequest request(url); - request.setRawHeader("Content-Type", "application/octet-stream"); + request.setRawHeader("content-type", "application/octet-stream"); request.setAttribute( QNetworkRequest::SynchronousRequestAttribute, true); @@ -5891,11 +6402,11 @@ void tst_QNetworkReply::nestedEventLoops() QTestEventLoop::instance().enterLoop(20); QVERIFY2(!QTestEventLoop::instance().timeout(), "Network timeout"); - QCOMPARE(finishedspy.count(), 1); - QCOMPARE(errorspy.count(), 0); + QCOMPARE(finishedspy.size(), 1); + QCOMPARE(errorspy.size(), 0); } -#ifndef QT_NO_NETWORKPROXY +#if QT_CONFIG(networkproxy) void tst_QNetworkReply::httpProxyCommands_data() { QTest::addColumn<QUrl>("url"); @@ -5906,7 +6417,7 @@ void tst_QNetworkReply::httpProxyCommands_data() << QUrl("http://0.0.0.0:4443/http-request") << QByteArray("HTTP/1.0 200 OK\r\nProxy-Connection: close\r\nContent-Length: 1\r\n\r\n1") << "GET http://0.0.0.0:4443/http-request HTTP/1."; -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) QTest::newRow("https") << QUrl("https://0.0.0.0:4443/https-request") << QByteArray("HTTP/1.0 200 Connection Established\r\n\r\n") @@ -5925,7 +6436,7 @@ void tst_QNetworkReply::httpProxyCommands() manager.setProxy(proxy); QNetworkRequest request(url); - request.setRawHeader("User-Agent", "QNetworkReplyAutoTest/1.0"); + request.setRawHeader("user-agent", "QNetworkReplyAutoTest/1.0"); QNetworkReplyPtr reply(manager.get(request)); // wait for the finished signal @@ -5938,14 +6449,15 @@ void tst_QNetworkReply::httpProxyCommands() // especially since it won't succeed in the HTTPS case // so just check that the command was correct - QString receivedHeader = proxyServer.receivedData.left(expectedCommand.length()); + QString receivedHeader = proxyServer.receivedData.left(expectedCommand.size()); QCOMPARE(receivedHeader, expectedCommand); //QTBUG-17223 - make sure the user agent from the request is sent to proxy server even for CONNECT - int uapos = proxyServer.receivedData.indexOf("User-Agent"); + const QByteArray cUserAgent = "user-agent: "; + int uapos = proxyServer.receivedData.toLower().indexOf(cUserAgent) + cUserAgent.size(); int uaend = proxyServer.receivedData.indexOf("\r\n", uapos); QByteArray uaheader = proxyServer.receivedData.mid(uapos, uaend - uapos); - QCOMPARE(uaheader, QByteArray("User-Agent: QNetworkReplyAutoTest/1.0")); + QCOMPARE(uaheader, QByteArray("QNetworkReplyAutoTest/1.0")); } class ProxyChangeHelper : public QObject @@ -5968,7 +6480,7 @@ void tst_QNetworkReply::httpProxyCommandsSynchronous_data() { httpProxyCommands_data(); } -#endif // !QT_NO_NETWORKPROXY +#endif // QT_CONFIG(networkproxy) struct QThreadCleanup { @@ -5982,15 +6494,7 @@ struct QThreadCleanup } }; -struct QDeleteLaterCleanup -{ - static inline void cleanup(QObject *o) - { - o->deleteLater(); - } -}; - -#ifndef QT_NO_NETWORKPROXY +#if QT_CONFIG(networkproxy) void tst_QNetworkReply::httpProxyCommandsSynchronous() { QFETCH(QUrl, url); @@ -6001,7 +6505,7 @@ void tst_QNetworkReply::httpProxyCommandsSynchronous() // the server thread, because the client is never returning to the // event loop QScopedPointer<QThread, QThreadCleanup> serverThread(new QThread); - QScopedPointer<MiniHttpServer, QDeleteLaterCleanup> proxyServer(new MiniHttpServer(responseToSend, false, serverThread.data())); + QScopedPointer<MiniHttpServer, QScopedPointerDeleteLater> proxyServer(new MiniHttpServer(responseToSend, false, serverThread.data())); QNetworkProxy proxy(QNetworkProxy::HttpProxy, "127.0.0.1", proxyServer->serverPort()); manager.setProxy(proxy); @@ -6022,7 +6526,7 @@ void tst_QNetworkReply::httpProxyCommandsSynchronous() // especially since it won't succeed in the HTTPS case // so just check that the command was correct - QString receivedHeader = proxyServer->receivedData.left(expectedCommand.length()); + QString receivedHeader = proxyServer->receivedData.left(expectedCommand.size()); QCOMPARE(receivedHeader, expectedCommand); } @@ -6080,7 +6584,7 @@ void tst_QNetworkReply::proxyChange() QVERIFY(int(reply3->error()) > 0); } -#endif // !QT_NO_NETWORKPROXY +#endif // QT_CONFIG(networkproxy) void tst_QNetworkReply::authorizationError_data() { @@ -6119,9 +6623,9 @@ void tst_QNetworkReply::authorizationError() QCOMPARE(waitForFinish(reply), int(Failure)); QFETCH(int, errorSignalCount); - QCOMPARE(errorSpy.count(), errorSignalCount); + QCOMPARE(errorSpy.size(), errorSignalCount); QFETCH(int, finishedSignalCount); - QCOMPARE(finishedSpy.count(), finishedSignalCount); + QCOMPARE(finishedSpy.size(), finishedSignalCount); QFETCH(int, error); QCOMPARE(reply->error(), QNetworkReply::NetworkError(error)); @@ -6159,7 +6663,6 @@ void tst_QNetworkReply::httpConnectionCount() } QVERIFY(server->listen()); - QCoreApplication::instance()->processEvents(); QUrl url("http://127.0.0.1:" + QString::number(server->serverPort()) + QLatin1Char('/')); if (encrypted) @@ -6170,7 +6673,7 @@ void tst_QNetworkReply::httpConnectionCount() QUrl urlCopy = url; urlCopy.setPath(u'/' + QString::number(i)); // Differentiate the requests a bit QNetworkRequest request(urlCopy); - request.setAttribute(QNetworkRequest::Http2AllowedAttribute, http2Enabled); + request.setAttribute(QNetworkRequest::Http2CleartextAllowedAttribute, http2Enabled); QNetworkReply* reply = manager.get(request); reply->setParent(server.data()); if (encrypted) @@ -6178,26 +6681,39 @@ void tst_QNetworkReply::httpConnectionCount() } int pendingConnectionCount = 0; - QElapsedTimer timer; - timer.start(); - while(pendingConnectionCount <= 20) { - QTestEventLoop::instance().enterLoop(1); + const auto newPendingConnection = [&server]() { return server->hasPendingConnections(); }; + // If we have http2 enabled then the second connection will take a little + // longer to be established because we will wait for the first one to finish + // to see if we should upgrade: + const int rampDown = http2Enabled ? 2 : 1; + while (pendingConnectionCount <= 6) { + if (!QTest::qWaitFor(newPendingConnection, pendingConnectionCount >= rampDown ? 3s : 7s)) + break; QTcpSocket *socket = server->nextPendingConnection(); - while (socket != 0) { - if (pendingConnectionCount == 0) { - // respond to the first connection so we know to transition to HTTP/1.1 when using - // HTTP/2 - socket->write(httpEmpty200Response); + while (socket) { + if (pendingConnectionCount == 0 && http2Enabled) { + // Respond to the first connection so we know to transition to HTTP/1.1 when using + // HTTP/2. + // Because of some internal state machinery we need to wait until the request has + // actually been written to the server before we can reply. + auto connection = std::make_shared<QMetaObject::Connection>(); + auto replyOnRequest = [=, buffer = QByteArray()]() mutable { + buffer += socket->readAll(); + if (!buffer.contains("\r\n\r\n")) + return; + socket->write(httpEmpty200Response); + QObject::disconnect(*connection); + }; + *connection = QObject::connect(socket, &QTcpSocket::readyRead, socket, + std::move(replyOnRequest)); + if (socket->bytesAvailable()) // If we already have data, check it now + emit socket->readyRead(); } pendingConnectionCount++; socket->setParent(server.data()); socket = server->nextPendingConnection(); } - - // at max. wait 10 sec - if (timer.elapsed() > 10000) - break; } QCOMPARE(pendingConnectionCount, 6); @@ -6377,7 +6893,7 @@ void tst_QNetworkReply::httpRecursiveCreation() QVERIFY(!QTestEventLoop::instance().timeout()); } -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) void tst_QNetworkReply::ignoreSslErrorsList_data() { QTest::addColumn<QList<QSslError> >("expectedSslErrors"); @@ -6385,8 +6901,8 @@ void tst_QNetworkReply::ignoreSslErrorsList_data() QList<QSslError> expectedSslErrors; QList<QSslCertificate> certs = QSslCertificate::fromPath(testDataDir + certsFilePath); - QSslError rightError(FLUKE_CERTIFICATE_ERROR, certs.at(0)); - QSslError wrongError(FLUKE_CERTIFICATE_ERROR); + QSslError rightError(flukeCertTlsError, certs.at(0)); + QSslError wrongError(flukeCertTlsError); QTest::newRow("SSL-failure-empty-list") << expectedSslErrors << QNetworkReply::SslHandshakeFailedError; expectedSslErrors.append(wrongError); @@ -6453,16 +6969,23 @@ void tst_QNetworkReply::sslConfiguration_data() QTest::newRow("empty") << QSslConfiguration() << false; QSslConfiguration conf = QSslConfiguration::defaultConfiguration(); QTest::newRow("default") << conf << false; // does not contain test server cert - QList<QSslCertificate> testServerCert = QSslCertificate::fromPath(testDataDir + certsFilePath); - conf.setCaCertificates(testServerCert); - QTest::newRow("set-root-cert") << conf << true; - conf.setProtocol(QSsl::SecureProtocols); - QTest::newRow("secure") << conf << true; + if (isSecureTransport) { + qWarning("SecTrustEvaluate() will fail, update the certificate on server"); + } else { + QList<QSslCertificate> testServerCert = QSslCertificate::fromPath(testDataDir + certsFilePath); + conf.setCaCertificates(testServerCert); + + QTest::newRow("set-root-cert") << conf << true; + conf.setProtocol(QSsl::SecureProtocols); + QTest::newRow("secure") << conf << true; + } } void tst_QNetworkReply::encrypted() { - qDebug() << QtNetworkSettings::httpServerName(); + if (isSecureTransport) + QSKIP("SecTrustEvalute() fails with old server certificate"); + QUrl url("https://" + QtNetworkSettings::httpServerName()); QNetworkRequest request(url); QNetworkReply *reply = manager.get(request); @@ -6473,7 +6996,7 @@ void tst_QNetworkReply::encrypted() QTestEventLoop::instance().enterLoop(20); QVERIFY(!QTestEventLoop::instance().timeout()); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); reply->deleteLater(); } @@ -6488,8 +7011,7 @@ void tst_QNetworkReply::abortOnEncrypted() server.connect(&server, &SslServer::newEncryptedConnection, [&server]() { // MSVC 201X C4573-misunderstands connect() or QObject::connect(), so use server.connect(): server.connect(server.socket, &QTcpSocket::readyRead, server.socket, []() { - // This slot must not be invoked! - QVERIFY(false); + QFAIL("This slot must not be invoked!"); }); }); @@ -6503,7 +7025,7 @@ void tst_QNetworkReply::abortOnEncrypted() }); QSignalSpy spyEncrypted(reply, &QNetworkReply::encrypted); - QTRY_COMPARE(spyEncrypted.count(), 1); + QTRY_COMPARE(spyEncrypted.size(), 1); // Wait for the socket to be closed again in order to be sure QTcpSocket::readyRead would have been emitted. QTRY_VERIFY(server.socket != nullptr); @@ -6535,9 +7057,8 @@ void tst_QNetworkReply::sslSessionSharing_data() void tst_QNetworkReply::sslSessionSharing() { -#if QT_CONFIG(schannel) || defined(QT_SECURETRANSPORT) - QSKIP("Not implemented with SecureTransport/Schannel"); -#endif + if (isSchannel || isSecureTransport) + QSKIP("Not implemented with SecureTransport/Schannel"); QString urlString("https://" + QtNetworkSettings::httpServerName()); QList<QNetworkReplyPtr> replies; @@ -6606,9 +7127,8 @@ void tst_QNetworkReply::sslSessionSharingFromPersistentSession_data() void tst_QNetworkReply::sslSessionSharingFromPersistentSession() { -#if QT_CONFIG(schannel) || defined(QT_SECURETRANSPORT) - QSKIP("Not implemented with SecureTransport/Schannel"); -#endif + if (isSchannel || isSecureTransport) + QSKIP("Not implemented with SecureTransport/Schannel"); QString urlString("https://" + QtNetworkSettings::httpServerName()); @@ -6661,7 +7181,7 @@ void tst_QNetworkReply::sslSessionSharingFromPersistentSession() } #endif // QT_BUILD_INTERNAL -#endif // QT_NO_SSL +#endif // QT_CONFIG(ssl) void tst_QNetworkReply::getAndThenDeleteObject_data() { @@ -6699,7 +7219,20 @@ void tst_QNetworkReply::getAndThenDeleteObject() // see https://bugs.webkit.org/show_bug.cgi?id=38935 void tst_QNetworkReply::symbianOpenCDataUrlCrash() { - QString requestUrl("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAWCAYAAAA1vze2AAAAB3RJTUUH2AUSEgolrgBvVQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAARnQU1BAACxjwv8YQUAAAHlSURBVHja5VbNShxBEK6ZaXtnHTebQPA1gngNmfaeq+QNPIlIXkC9iQdJxJNvEHLN3VkxhxxE8gTmEhAVddXZ6Z3f9Ndriz89/sHmkBQUVVT1fB9d9c3uOERUKTunIdn3HzstxGpYBDS4wZk7TAJj/wlJ90J+jnuygqs8svSj+/rGHBos3rE18XBvfU3no7NzlJfUaY/5whAwl8Lr/WDUv4ODxTMb+P5xLExe5LmO559WqTX/MQR4WZYEAtSePS4pE0qSnuhnRUcBU5Gm2k9XljU4Z26I3NRxBrd80rj2fh+KNE0FY4xevRgTjREvPFpasAK8Xli6MUbbuKw3afAGgSBXozo5u4hkmncAlkl5wx8iMGbdyQjnCFEiEwGiosj1UQA/x2rVddiVoi+l4IxE0PTDnx+mrQBvvnx9cFz3krhVvuhzFn579/aq/n5rW8fbtTqiWhIQZEo17YBvbkxOXNVndnYpTvod7AtiuN2re0+siwcB9oH8VxxrNwQQAhzyRs30n7wTI2HIN2g2QtQwjjhJIQatOq7E8bIVCLwzpl83Lvtvl+NohWWlE8UZTWEMAGCcR77fHKhPnZF5tYie6dfdxCphACmLPM+j8bYfmTryg64kV9Vh3mV8jP0b/4wO/YUPiT/8i0MLf55lSQAAAABJRU5ErkJggg=="); + QString requestUrl("data:image/" + "png;base64," + "iVBORw0KGgoAAAANSUhEUgAAABkAAAAWCAYAAAA1vze2AAAAB3RJTUUH2AUSEgolrgBvVQAAAAl" + "wSFlzAAALEwAACxMBAJqcGAAAAARnQU1BAACxjwv8YQUAAAHlSURBVHja5VbNShxBEK6ZaXtnHT" + "ebQPA1gngNmfaeq+QNPIlIXkC9iQdJxJNvEHLN3VkxhxxE8gTmEhAVddXZ6Z3f9Ndriz89/" + "sHmkBQUVVT1fB9d9c3uOERUKTunIdn3HzstxGpYBDS4wZk7TAJj/wlJ90J+jnuygqs8svSj+/" + "rGHBos3rE18XBvfU3no7NzlJfUaY/5whAwl8Lr/WDUv4ODxTMb+P5xLExe5LmO559WqTX/" + "MQR4WZYEAtSePS4pE0qSnuhnRUcBU5Gm2k9XljU4Z26I3NRxBrd80rj2fh+" + "KNE0FY4xevRgTjREvPFpasAK8Xli6MUbbuKw3afAGgSBXozo5u4hkmncAlkl5wx8iMGbdyQjnCF" + "EiEwGiosj1UQA/x2rVddiVoi+l4IxE0PTDnx+mrQBvvnx9cFz3krhVvuhzFn579/aq/" + "n5rW8fbtTqiWhIQZEo17YBvbkxOXNVndnYpTvod7AtiuN2re0+" + "siwcB9oH8VxxrNwQQAhzyRs30n7wTI2HIN2g2QtQwjjhJIQatOq7E8bIVCLwzpl83Lvtvl+" + "NohWWlE8UZTWEMAGCcR77fHKhPnZF5tYie6dfdxCphACmLPM+j8bYfmTryg64kV9Vh3mV8jP0b/" + "4wO/YUPiT/8i0MLf55lSQAAAABJRU5ErkJggg=="); QUrl url = QUrl::fromEncoded(requestUrl.toLatin1()); QNetworkRequest req(url); QNetworkReplyPtr reply; @@ -6875,13 +7408,8 @@ public: // bytesAvailable must never be 0 QVERIFY(bytesAvailable != 0); - if (bytesAvailableList.length() < 5) { - // We assume that the first few times the bytes available must be less than the complete size, e.g. - // the bytesAvailable() function works correctly in case of a downloadBuffer. - QVERIFY(bytesAvailable < uploadSize); - } if (!bytesAvailableList.isEmpty()) { - // Also check that the same bytesAvailable is not coming twice in a row + // Check that the same bytesAvailable is not coming twice in a row QVERIFY(bytesAvailableList.last() != bytesAvailable); } @@ -6893,6 +7421,12 @@ public: { // We should have already received all readyRead QVERIFY(!bytesAvailableList.isEmpty()); + for (int i = 0; i < std::min(int(bytesAvailableList.size() - 1), 5); ++i) { + // We assume that, at least, the first time the bytes available must be less than the + // complete size, e.g. the bytesAvailable() function works correctly in case of a + // downloadBuffer. + QVERIFY(bytesAvailableList.at(i) < uploadSize); + } QCOMPARE(bytesAvailableList.last(), uploadSize); } }; @@ -6996,6 +7530,7 @@ void tst_QNetworkReply::ioGetFromHttpBrokenChunkedEncoding() QCOMPARE(reply->error(), QNetworkReply::NoError); } +#if QT_CONFIG(http) // TODO: // Prepare a gzip that has one chunk that expands to the size mentioned in the bugreport. // Then have a custom HTTP server that waits after this chunk so the returning gets @@ -7013,6 +7548,9 @@ void tst_QNetworkReply::qtbug12908compressedHttpReply() server.doClose = true; QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); + // QDecompressHelper will abort the download if the compressed to decompressed size ratio + // differs too much, so we override it + request.setDecompressedSafetyCheckThreshold(-1); QNetworkReplyPtr reply(manager.get(request)); QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply)); @@ -7021,6 +7559,7 @@ void tst_QNetworkReply::qtbug12908compressedHttpReply() QCOMPARE(reply->size(), qint64(16384)); QCOMPARE(reply->readAll(), QByteArray(16384, '\0')); } +#endif void tst_QNetworkReply::compressedHttpReplyBrokenGzip() { @@ -7040,7 +7579,7 @@ void tst_QNetworkReply::compressedHttpReplyBrokenGzip() QCOMPARE(waitForFinish(reply), int(Failure)); - QCOMPARE(reply->error(), QNetworkReply::ProtocolFailure); + QCOMPARE(reply->error(), QNetworkReply::UnknownContentError); } // TODO add similar test for FTP @@ -7084,25 +7623,25 @@ void tst_QNetworkReply::qtbug4121unknownAuthentication() QTestEventLoop::instance().enterLoop(10); QVERIFY(!QTestEventLoop::instance().timeout()); - QCOMPARE(authSpy.count(), 0); - QCOMPARE(finishedSpy.count(), 1); - QCOMPARE(errorSpy.count(), 1); + QCOMPARE(authSpy.size(), 0); + QCOMPARE(finishedSpy.size(), 1); + QCOMPARE(errorSpy.size(), 1); QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError); } -#ifndef QT_NO_NETWORKPROXY +#if QT_CONFIG(networkproxy) void tst_QNetworkReply::authenticationCacheAfterCancel_data() { QTest::addColumn<QNetworkProxy>("proxy"); QTest::addColumn<bool>("proxyAuth"); QTest::addColumn<QUrl>("url"); - for (int i = 0; i < proxies.count(); ++i) { + for (int i = 0; i < proxies.size(); ++i) { QTest::newRow("http" + proxies.at(i).tag) << proxies.at(i).proxy << proxies.at(i).requiresAuthentication << QUrl("http://" + QtNetworkSettings::httpServerName() + "/qtest/rfcs-auth/rfc3252.txt"); -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) QTest::newRow("https" + proxies.at(i).tag) << proxies.at(i).proxy << proxies.at(i).requiresAuthentication @@ -7158,7 +7697,7 @@ void tst_QNetworkReply::authenticationCacheAfterCancel() QFETCH(bool, proxyAuth); QFETCH(QUrl, url); QNetworkAccessManager manager; -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)), SLOT(sslErrors(QNetworkReply*,QList<QSslError>))); #endif @@ -7180,8 +7719,8 @@ void tst_QNetworkReply::authenticationCacheAfterCancel() QVERIFY(!QTestEventLoop::instance().timeout()); QCOMPARE(reply->error(), QNetworkReply::ProxyAuthenticationRequiredError); - QCOMPARE(authSpy.count(), 0); - QCOMPARE(proxyAuthSpy.count(), 1); + QCOMPARE(authSpy.size(), 0); + QCOMPARE(proxyAuthSpy.size(), 1); proxyAuthSpy.clear(); //should fail due to bad credentials @@ -7195,8 +7734,8 @@ void tst_QNetworkReply::authenticationCacheAfterCancel() // Work round known quirk in the old test server (danted -v < v1.1.19): if (reply->error() != QNetworkReply::HostNotFoundError) QCOMPARE(reply->error(), QNetworkReply::ProxyAuthenticationRequiredError); - QCOMPARE(authSpy.count(), 0); - QVERIFY(proxyAuthSpy.count() > 0); + QCOMPARE(authSpy.size(), 0); + QVERIFY(proxyAuthSpy.size() > 0); proxyAuthSpy.clear(); // QTBUG-23136 workaround (needed even with danted v1.1.19): @@ -7221,10 +7760,10 @@ void tst_QNetworkReply::authenticationCacheAfterCancel() QVERIFY(!QTestEventLoop::instance().timeout()); QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError); - QVERIFY(authSpy.count() > 0); + QVERIFY(authSpy.size() > 0); authSpy.clear(); if (proxyAuth) { - QVERIFY(proxyAuthSpy.count() > 0); + QVERIFY(proxyAuthSpy.size() > 0); proxyAuthSpy.clear(); } @@ -7237,11 +7776,11 @@ void tst_QNetworkReply::authenticationCacheAfterCancel() QVERIFY(!QTestEventLoop::instance().timeout()); QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError); - QVERIFY(authSpy.count() > 0); + QVERIFY(authSpy.size() > 0); authSpy.clear(); if (proxyAuth) { //should be supplied from cache - QCOMPARE(proxyAuthSpy.count(), 0); + QCOMPARE(proxyAuthSpy.size(), 0); proxyAuthSpy.clear(); } @@ -7255,11 +7794,11 @@ void tst_QNetworkReply::authenticationCacheAfterCancel() QVERIFY(!QTestEventLoop::instance().timeout()); QCOMPARE(reply->error(), QNetworkReply::NoError); - QVERIFY(authSpy.count() > 0); + QVERIFY(authSpy.size() > 0); authSpy.clear(); if (proxyAuth) { //should be supplied from cache - QCOMPARE(proxyAuthSpy.count(), 0); + QCOMPARE(proxyAuthSpy.size(), 0); proxyAuthSpy.clear(); } @@ -7271,11 +7810,11 @@ void tst_QNetworkReply::authenticationCacheAfterCancel() QCOMPARE(reply->error(), QNetworkReply::NoError); //should be supplied from cache - QCOMPARE(authSpy.count(), 0); + QCOMPARE(authSpy.size(), 0); authSpy.clear(); if (proxyAuth) { //should be supplied from cache - QCOMPARE(proxyAuthSpy.count(), 0); + QCOMPARE(proxyAuthSpy.size(), 0); proxyAuthSpy.clear(); } @@ -7285,7 +7824,7 @@ void tst_QNetworkReply::authenticationWithDifferentRealm() { AuthenticationCacheHelper helper; QNetworkAccessManager manager; -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)), SLOT(sslErrors(QNetworkReply*,QList<QSslError>))); #endif @@ -7312,7 +7851,7 @@ void tst_QNetworkReply::authenticationWithDifferentRealm() QVERIFY(!QTestEventLoop::instance().timeout()); QCOMPARE(reply->error(), QNetworkReply::NoError); } -#endif // !QT_NO_NETWORKPROXY +#endif // QT_CONFIG(networkproxy) class QtBug13431Helper : public QObject { @@ -7377,8 +7916,8 @@ void tst_QNetworkReply::httpWithNoCredentialUsage() QNetworkReplyPtr reply(manager.get(request)); QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply)); // credentials in URL, so don't expect authentication signal - QCOMPARE(authSpy.count(), 0); - QCOMPARE(finishedSpy.count(), 1); + QCOMPARE(authSpy.size(), 0); + QCOMPARE(finishedSpy.size(), 1); finishedSpy.clear(); } @@ -7388,8 +7927,8 @@ void tst_QNetworkReply::httpWithNoCredentialUsage() QNetworkReplyPtr reply(manager.get(request)); QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply)); // credentials in cache, so don't expect authentication signal - QCOMPARE(authSpy.count(), 0); - QCOMPARE(finishedSpy.count(), 1); + QCOMPARE(authSpy.size(), 0); + QCOMPARE(finishedSpy.size(), 1); finishedSpy.clear(); } @@ -7406,9 +7945,9 @@ void tst_QNetworkReply::httpWithNoCredentialUsage() QVERIFY(!QTestEventLoop::instance().timeout()); // We check if authenticationRequired was emitted, however we do not anything in it so it should be 401 - QCOMPARE(authSpy.count(), 1); - QCOMPARE(finishedSpy.count(), 1); - QCOMPARE(errorSpy.count(), 1); + QCOMPARE(authSpy.size(), 1); + QCOMPARE(finishedSpy.size(), 1); + QCOMPARE(errorSpy.size(), 1); QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError); } @@ -7547,11 +8086,12 @@ void tst_QNetworkReply::qtbug27161httpHeaderMayBeDamaged(){ QCOMPARE(reply->readAll(), QByteArray("ABC")); } +#if QT_CONFIG(networkdiskcache) void tst_QNetworkReply::qtbug28035browserDoesNotLoadQtProjectOrgCorrectly() { QByteArray getReply = "HTTP/1.1 200\r\n" "Connection: keep-alive\r\n" - "Content-Type: text/plain\r\n" + "content-type: text/plain\r\n" "Cache-control: max-age = 6000\r\n" "\r\n" "GET"; @@ -7559,7 +8099,7 @@ void tst_QNetworkReply::qtbug28035browserDoesNotLoadQtProjectOrgCorrectly() { QByteArray postReply = "HTTP/1.1 200\r\n" "Connection: keep-alive\r\n" - "Content-Type: text/plain\r\n" + "content-type: text/plain\r\n" "Cache-control: max-age = 6000\r\n" "Content-length: 4\r\n" "\r\n" @@ -7568,7 +8108,7 @@ void tst_QNetworkReply::qtbug28035browserDoesNotLoadQtProjectOrgCorrectly() { QByteArray putReply = "HTTP/1.1 201\r\n" "Connection: keep-alive\r\n" - "Content-Type: text/plain\r\n" + "content-type: text/plain\r\n" "Cache-control: max-age = 6000\r\n" "\r\n"; @@ -7606,7 +8146,7 @@ void tst_QNetworkReply::qtbug28035browserDoesNotLoadQtProjectOrgCorrectly() { server.clearHeaderParserState(); server.setDataToTransmit(postReply); - request.setRawHeader("Content-Type", "text/plain"); + request.setRawHeader("content-type", "text/plain"); reply.reset(manager.post(request, postData)); QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply)); @@ -7671,6 +8211,7 @@ void tst_QNetworkReply::qtbug28035browserDoesNotLoadQtProjectOrgCorrectly() { QCOMPARE(reply->readAll(), QByteArray("GET")); QCOMPARE(reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool(), true); } +#endif void tst_QNetworkReply::qtbug45581WrongReplyStatusCode() { @@ -7693,8 +8234,8 @@ void tst_QNetworkReply::qtbug45581WrongReplyStatusCode() QCOMPARE(reply->readAll(), expectedContent); - QCOMPARE(finishedSpy.count(), 0); - QCOMPARE(sslErrorsSpy.count(), 0); + QCOMPARE(finishedSpy.size(), 0); + QCOMPARE(sslErrorsSpy.size(), 0); QCOMPARE(reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), expectedContent.size()); @@ -7726,13 +8267,17 @@ void tst_QNetworkReply::synchronousRequest_data() // ### we would need to enflate (un-deflate) the file content and compare the sizes << QString("text/plain"); -#ifndef QT_NO_SSL - QTest::newRow("https") - << QUrl("https://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt") - << QString("file:" + testDataDir + "/rfc3252.txt") - << true - << QString("text/plain"); -#endif +#if QT_CONFIG(ssl) + if (isSecureTransport) { + qWarning("Skipping https scheme, SecTrustEvalue() fails, update the certificate on server"); + } else { + QTest::newRow("https") + << QUrl("https://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt") + << QString("file:" + testDataDir + "/rfc3252.txt") + << true + << QString("text/plain"); + } +#endif // QT_CONFIG(ssl) QTest::newRow("data") << QUrl(QString::fromLatin1("data:text/plain,hello world")) @@ -7757,7 +8302,7 @@ void tst_QNetworkReply::synchronousRequest() QNetworkRequest request(url); -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) // workaround for HTTPS requests: add self-signed server cert to list of CA certs, // since we cannot react to the sslErrors() signal // to fix this properly we would need to have an ignoreSslErrors() method in the @@ -7779,8 +8324,8 @@ void tst_QNetworkReply::synchronousRequest() QSignalSpy sslErrorsSpy(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>))); RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply, 0)); QVERIFY(reply->isFinished()); - QCOMPARE(finishedSpy.count(), 0); - QCOMPARE(sslErrorsSpy.count(), 0); + QCOMPARE(finishedSpy.size(), 0); + QCOMPARE(sslErrorsSpy.size(), 0); QCOMPARE(reply->header(QNetworkRequest::ContentTypeHeader).toString(), mimeType); @@ -7789,7 +8334,7 @@ void tst_QNetworkReply::synchronousRequest() if (expected.startsWith("file:")) { QString path = expected.mid(5); QFile file(path); - file.open(QIODevice::ReadOnly); + QVERIFY(file.open(QIODevice::ReadOnly)); expectedContent = file.readAll(); } else if (expected.startsWith("data:")) { expectedContent = expected.mid(5).toUtf8(); @@ -7802,7 +8347,7 @@ void tst_QNetworkReply::synchronousRequest() reply->deleteLater(); } -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) void tst_QNetworkReply::synchronousRequestSslFailure() { // test that SSL won't be accepted with self-signed certificate, @@ -7819,7 +8364,7 @@ void tst_QNetworkReply::synchronousRequestSslFailure() runSimpleRequest(QNetworkAccessManager::GetOperation, request, reply, 0); QVERIFY(reply->isFinished()); QCOMPARE(reply->error(), QNetworkReply::SslHandshakeFailedError); - QCOMPARE(sslErrorsSpy.count(), 0); + QCOMPARE(sslErrorsSpy.size(), 0); } #endif @@ -7881,12 +8426,226 @@ void tst_QNetworkReply::httpAbort() QCOMPARE(reply3->error(), QNetworkReply::NoError); } +void tst_QNetworkReply::closeClientSideConnectionEagerlyQtbug20726() +{ + QNetworkAccessManager manager; // function local instance + // Setup HTTP servers + MiniHttpServer server("HTTP/1.1 200 OK\r\nContent-Length: 0\r\nConnection: Keep-Alive\r\n\r\n", false); + server.doClose = false; // server should not disconnect. + + MiniHttpServer serverNotEagerClientClose("HTTP/1.1 200 OK\r\nContent-Length: 0\r\nConnection: Keep-Alive\r\n\r\n", false); + serverNotEagerClientClose.doClose = false; // server should not disconnect. + QUrl urlNotEager(QLatin1String("http://localhost")); + urlNotEager.setPort(serverNotEagerClientClose.serverPort()); + QNetworkRequest requestNotEager(urlNotEager); + QNetworkReplyPtr replyNotEager(manager.get(requestNotEager)); + QCOMPARE(waitForFinish(replyNotEager), Success); + // The reply was finished, the connection should be hanging and waiting to be expired + + // Another server not eager to close, the connection should be hanging and waiting to be expired + MiniHttpServer serverNotEagerClientClose2("HTTP/1.1 200 OK\r\nContent-Length: 0\r\nConnection: Keep-Alive\r\n\r\n", false); + serverNotEagerClientClose2.doClose = false; // server should not disconnect. + QUrl urlNotEager2(QLatin1String("http://localhost")); + urlNotEager2.setPort(serverNotEagerClientClose2.serverPort()); + QNetworkRequest requestNotEager2(urlNotEager2); + QNetworkReplyPtr replyNotEager2(manager.get(requestNotEager2)); + QCOMPARE(waitForFinish(replyNotEager2), Success); + + // However for this one we want to eagerly close. + QUrl url(QLatin1String("http://localhost")); + url.setPort(server.serverPort()); + QNetworkRequest request(url); + request.setAttribute(QNetworkRequest::ConnectionCacheExpiryTimeoutSecondsAttribute, 0); + QNetworkReplyPtr reply(manager.get(request)); + // The server just uses a normal TCP socket and prints out this error when the client disconnects: + QTest::ignoreMessage(QtDebugMsg, + "slotError QAbstractSocket::RemoteHostClosedError " + "\"The remote host closed the connection\""); + QCOMPARE(waitForFinish(reply), Success); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + // Socket from server to QNAM still connected? + QVERIFY (!server.client.isNull()); + QVERIFY (server.client->state() == QTcpSocket::ConnectedState); + // Wait a bit + QTest::qWait(1*1000); + // The QNAM should have disconnected the socket, so on our server it's disconnected now. + QVERIFY (!server.client.isNull()); + QVERIFY (server.client->state() != QTcpSocket::ConnectedState); + + // Now we check the not eager reply, it should still be connected. + QCOMPARE(replyNotEager->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + QCOMPARE(serverNotEagerClientClose.client->state(), QTcpSocket::ConnectedState); + QCOMPARE(replyNotEager2->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + QCOMPARE(serverNotEagerClientClose2.client->state(), QTcpSocket::ConnectedState); +} + +void tst_QNetworkReply::varyingCacheExpiry_data() +{ + QTest::addColumn<int>("firstExpiry"); + QTest::addColumn<int>("secondExpiry"); + QTest::addColumn<int>("thirdExpiry"); + QTest::addColumn<int>("fourthExpiry"); + + // The datatags signify the Keep-Alive time-outs of the successive requests: + QTest::newRow("1-2-3-4") << 1 << 2 << 3 << 4; + QTest::newRow("4-1-2-3") << 4 << 1 << 2 << 3; + QTest::newRow("3-4-1-2") << 3 << 4 << 1 << 2; + QTest::newRow("2-3-4-1") << 2 << 3 << 4 << 1; + QTest::newRow("1-2-2-1") << 1 << 2 << 2 << 1; +} + +// Test creating a few requests with various expiry timeouts. +// We do this because the internal QNetworkAccessCache inserts them in sorted +// order, so make sure it gets it right. +void tst_QNetworkReply::varyingCacheExpiry() +{ + // Local QNAM instance because there may be leftover entries from other + // tests. Which wouldn't be a big deal, it would just get in the way of our + // pattern + QNetworkAccessManager qnam; + QFETCH(int, firstExpiry); + QFETCH(int, secondExpiry); + QFETCH(int, thirdExpiry); + QFETCH(int, fourthExpiry); + + int expiryTimes[4] = { + firstExpiry, + secondExpiry, + thirdExpiry, + fourthExpiry, + }; + + // We need multiple servers because we want to have multiple connections + // in the QNetworkAccessCache, not to just reuse one connection from the + // cache. + MiniHttpServer servers[4] = { + { httpEmpty200Response }, + { httpEmpty200Response }, + { httpEmpty200Response }, + { httpEmpty200Response }, + }; + for (MiniHttpServer &server : servers) + server.doClose = false; + + QUrl urls[4] = { + u"http://localhost"_s, + u"http://localhost"_s, + u"http://localhost"_s, + u"http://localhost"_s, + }; + for (size_t i = 0; i < std::size(urls); ++i) + urls[i].setPort(servers[i].serverPort()); + + // After the initial request is completed the connection is kept alive + // (Keep-Alive). Internally they are added to a sorted linked-list based on + // expiry. So, set the requests to be torn down at varying timeouts. + + QNetworkRequest requests[4] = { + QNetworkRequest(urls[0]), + QNetworkRequest(urls[1]), + QNetworkRequest(urls[2]), + QNetworkRequest(urls[3]), + }; + + for (int i = 0; i < 4; ++i) { + requests[i].setAttribute(QNetworkRequest::Http2AllowedAttribute, + QVariant::fromValue(false)); + requests[i].setAttribute(QNetworkRequest::ConnectionCacheExpiryTimeoutSecondsAttribute, + expiryTimes[i]); + } + + // The server just uses a normal TCP socket and prints out this error when the client + // disconnects: + for (int i = 0; i < 4; ++i) { + QTest::ignoreMessage(QtDebugMsg, + "slotError QAbstractSocket::RemoteHostClosedError " + "\"The remote host closed the connection\""); + } + + // Start each request and wait for it to finish before starting the next + // one, we must do this because the connections are only added to the expiry + // list once finished + for (const auto &request : requests) { + QNetworkReplyPtr reply(qnam.get(request)); + QCOMPARE(waitForFinish(reply), Success); + } + + int lastExpiry = *std::max_element(std::begin(expiryTimes), std::end(expiryTimes)); + auto allServersDisconnected = [&servers]() { + auto socketDisconnected = [](const MiniHttpServer &s) { + return s.client->state() == QAbstractSocket::UnconnectedState; + }; + return std::all_of(std::begin(servers), std::end(servers), socketDisconnected); + }; + // At least +5 seconds due to CI. Completes much faster locally + bool success = QTest::qWaitFor(allServersDisconnected, lastExpiry * 1000 + 5000); + + QVERIFY(success); +} + +class Qtbug25280Server : public MiniHttpServer +{ +public: + Qtbug25280Server(QByteArray qba) : MiniHttpServer(qba, false) {} + QSet<QTcpSocket*> receivedSockets; + void reply() override + { + // Save sockets in a list + receivedSockets.insert((QTcpSocket*)sender()); + qobject_cast<QTcpSocket*>(sender())->write(dataToTransmit); + //qDebug() << "count=" << receivedSockets.count(); + } +}; + +#if QT_CONFIG(http) +void tst_QNetworkReply::amountOfHttp1ConnectionsQtbug25280_data() +{ + QTest::addColumn<int>("amount"); + QTest::addRow("default") << 6; + QTest::addRow("minimize") << 1; + QTest::addRow("increase") << 12; +} + +// Also kind of QTBUG-8468 +void tst_QNetworkReply::amountOfHttp1ConnectionsQtbug25280() +{ + QFETCH(const int, amount); + QNetworkAccessManager manager; // function local instance + Qtbug25280Server server(tst_QNetworkReply::httpEmpty200Response); + server.doClose = false; + server.multiple = true; + QUrl url(QLatin1String("http://127.0.0.1")); // not "localhost" to prevent "Happy Eyeballs" + // from skewing the counting + url.setPort(server.serverPort()); + std::optional<QHttp1Configuration> http1Configuration; + if (amount != 6) // don't set if it's the default + http1Configuration.emplace().setNumberOfConnectionsPerHost(amount); + constexpr int NumRequests = 200; // send a lot more than we have sockets + int finished = 0; + std::array<std::unique_ptr<QNetworkReply>, NumRequests> replies; + for (auto &reply : replies) { + QNetworkRequest request(url); + if (http1Configuration) + request.setHttp1Configuration(*http1Configuration); + reply.reset(manager.get(request)); + QObject::connect(reply.get(), &QNetworkReply::finished, + [&finished] { ++finished; }); + } + QTRY_COMPARE_WITH_TIMEOUT(finished, NumRequests, 60'000); + for (const auto &reply : replies) { + QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + } + QCOMPARE(server.receivedSockets.size(), amount); +} +#endif + void tst_QNetworkReply::dontInsertPartialContentIntoTheCache() { QByteArray reply206 = "HTTP/1.0 206\r\n" "Connection: keep-alive\r\n" - "Content-Type: text/plain\r\n" + "content-type: text/plain\r\n" "Cache-control: no-cache\r\n" "Content-Range: bytes 2-6/8\r\n" "Content-length: 4\r\n" @@ -7909,7 +8668,7 @@ void tst_QNetworkReply::dontInsertPartialContentIntoTheCache() QVERIFY(server.totalConnections > 0); QCOMPARE(reply->readAll().constData(), "load"); - QCOMPARE(memoryCache->m_insertedUrls.count(), 0); + QCOMPARE(memoryCache->m_insertedUrls.size(), 0); } void tst_QNetworkReply::httpUserAgent() @@ -7926,7 +8685,7 @@ void tst_QNetworkReply::httpUserAgent() QVERIFY(reply->isFinished()); QCOMPARE(reply->error(), QNetworkReply::NoError); - QVERIFY(server.receivedData.contains("\r\nUser-Agent: abcDEFghi\r\n")); + QVERIFY(server.receivedData.contains("\r\nuser-agent: abcDEFghi\r\n")); } void tst_QNetworkReply::synchronousAuthenticationCache() @@ -7943,16 +8702,16 @@ void tst_QNetworkReply::synchronousAuthenticationCache() "WWW-Authenticate: Basic realm=\"QNetworkAccessManager Test Realm\"\r\n" "Content-Length: 4\r\n" "Connection: close\r\n" - "Content-Type: text/plain\r\n" + "content-type: text/plain\r\n" "\r\n" "auth"; - QRegularExpression rx("Authorization: Basic ([^\r\n]*)\r\n"); + QRegularExpression rx("authorization: Basic ([^\r\n]*)\r\n"); QRegularExpressionMatch match = rx.match(receivedData); if (match.hasMatch()) { if (QByteArray::fromBase64(match.captured(1).toLatin1()) == "login:password") { dataToTransmit = "HTTP/1.0 200 OK\r\n" - "Content-Type: text/plain\r\n" + "content-type: text/plain\r\n" "Content-Length: 2\r\n" "\r\n" "OK"; @@ -7967,7 +8726,7 @@ void tst_QNetworkReply::synchronousAuthenticationCache() // the server thread, because the client is never returning to the // event loop QScopedPointer<QThread, QThreadCleanup> serverThread(new QThread); - QScopedPointer<MiniHttpServer, QDeleteLaterCleanup> server(new MiniAuthServer(serverThread.data())); + QScopedPointer<MiniHttpServer, QScopedPointerDeleteLater> server(new MiniAuthServer(serverThread.data())); server->doClose = true; //1) URL without credentials, we are not authenticated @@ -8106,31 +8865,33 @@ void tst_QNetworkReply::ftpAuthentication() void tst_QNetworkReply::emitErrorForAllReplies() // QTBUG-36890 { // port 100 is not well-known and should be closed - QList<QUrl> urls = QList<QUrl>() << QUrl("http://localhost:100/request1") - << QUrl("http://localhost:100/request2") - << QUrl("http://localhost:100/request3"); - QList<QNetworkReply *> replies; - QList<QSignalSpy *> errorSpies; - QList<QSignalSpy *> finishedSpies; - for (int a = 0; a < urls.count(); ++a) { - QNetworkRequest request(urls.at(a)); + const QUrl urls[] = { + QUrl("http://localhost:100/request1"), + QUrl("http://localhost:100/request2"), + QUrl("http://localhost:100/request3"), + }; + constexpr auto NUrls = std::size(urls); + + std::unique_ptr<QNetworkReply, QScopedPointerDeleteLater> replies[NUrls]; + std::optional<QSignalSpy> errorSpies[NUrls]; + std::optional<QSignalSpy> finishedSpies[NUrls]; + + for (size_t i = 0; i < NUrls; ++i) { + QNetworkRequest request(urls[i]); QNetworkReply *reply = manager.get(request); - replies.append(reply); - QSignalSpy *errorSpy = new QSignalSpy(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError))); - errorSpies.append(errorSpy); - QSignalSpy *finishedSpy = new QSignalSpy(reply, SIGNAL(finished())); - finishedSpies.append(finishedSpy); + replies[i].reset(reply); + errorSpies[i].emplace(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError))); + finishedSpies[i].emplace(reply, SIGNAL(finished())); QObject::connect(reply, SIGNAL(finished()), SLOT(emitErrorForAllRepliesSlot())); } + QTestEventLoop::instance().enterLoop(10); QVERIFY(!QTestEventLoop::instance().timeout()); - for (int a = 0; a < urls.count(); ++a) { - QVERIFY(replies.at(a)->isFinished()); - QCOMPARE(errorSpies.at(a)->count(), 1); - errorSpies.at(a)->deleteLater(); - QCOMPARE(finishedSpies.at(a)->count(), 1); - finishedSpies.at(a)->deleteLater(); - replies.at(a)->deleteLater(); + + for (size_t i = 0; i < NUrls; ++i) { + QVERIFY(replies[i]->isFinished()); + QCOMPARE(errorSpies[i]->size(), 1); + QCOMPARE(finishedSpies[i]->size(), 1); } } @@ -8178,7 +8939,7 @@ public: return ret; } virtual bool atEnd() const override { return buffer.atEnd(); } - virtual qint64 size() const override { return data.length(); } + virtual qint64 size() const override { return data.size(); } qint64 bytesAvailable() const override { return buffer.bytesAvailable() + QIODevice::bytesAvailable(); @@ -8199,9 +8960,9 @@ protected slots: void tst_QNetworkReply::putWithRateLimiting() { QFile reference(testDataDir + "/rfc3252.txt"); - reference.open(QIODevice::ReadOnly); + QVERIFY(reference.open(QIODevice::ReadOnly)); QByteArray data = reference.readAll(); - QVERIFY(data.length() > 0); + QVERIFY(data.size() > 0); QUrl url = QUrl::fromUserInput("http://" + QtNetworkSettings::httpServerName()+ "/qtest/cgi-bin/echo.cgi?"); @@ -8216,7 +8977,7 @@ void tst_QNetworkReply::putWithRateLimiting() QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); QByteArray uploadedData = reply->readAll(); - QCOMPARE(uploadedData.length(), data.length()); + QCOMPARE(uploadedData.size(), data.size()); QCOMPARE(uploadedData, data); } @@ -8248,8 +9009,8 @@ void tst_QNetworkReply::ioHttpSingleRedirect() QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply)); // Redirected and finished should be emitted exactly once - QCOMPARE(redSpy.count(), 1); - QCOMPARE(finSpy.count(), 1); + QCOMPARE(redSpy.size(), 1); + QCOMPARE(finSpy.size(), 1); // Original URL should not be changed after redirect QCOMPARE(request.url(), localhost); @@ -8295,8 +9056,8 @@ void tst_QNetworkReply::ioHttpChangeMaxRedirects() QCOMPARE(waitForFinish(reply), int(Failure)); - QCOMPARE(redSpy.count(), request.maximumRedirectsAllowed()); - QCOMPARE(spy.count(), 1); + QCOMPARE(redSpy.size(), request.maximumRedirectsAllowed()); + QCOMPARE(spy.size(), 1); QCOMPARE(reply->error(), QNetworkReply::TooManyRedirectsError); // Increase max redirects to allow successful completion @@ -8307,7 +9068,7 @@ void tst_QNetworkReply::ioHttpChangeMaxRedirects() QVERIFY2(waitForFinish(reply2) == Success, msgWaitForFinished(reply2)); - QCOMPARE(redSpy2.count(), 2); + QCOMPARE(redSpy2.size(), 2); QCOMPARE(reply2->url(), server3Url); QCOMPARE(reply2->error(), QNetworkReply::NoError); QVERIFY(validateRedirectedResponseHeaders(reply2)); @@ -8320,7 +9081,7 @@ void tst_QNetworkReply::ioHttpRedirectErrors_data() QTest::addColumn<QNetworkReply::NetworkError>("error"); QString tempRedirectReply = QString("HTTP/1.1 307 Temporary Redirect\r\n" - "Content-Type: text/plain\r\n" + "content-type: text/plain\r\n" "location: http://localhost:%1\r\n\r\n"); QTest::newRow("too-many-redirects") << "http://localhost" << tempRedirectReply << QNetworkReply::TooManyRedirectsError; @@ -8440,8 +9201,8 @@ void tst_QNetworkReply::ioHttpRedirectPolicy() QSignalSpy redirectSpy(reply.data(), SIGNAL(redirected(QUrl))); QSignalSpy finishedSpy(reply.data(), SIGNAL(finished())); QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply)); - QCOMPARE(finishedSpy.count(), 1); - QCOMPARE(redirectSpy.count(), redirectCount); + QCOMPARE(finishedSpy.size(), 1); + QCOMPARE(redirectSpy.size(), redirectCount); QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), statusCode); QVERIFY(validateRedirectedResponseHeaders(reply) || statusCode != 200); } @@ -8524,7 +9285,7 @@ void tst_QNetworkReply::ioHttpRedirectPolicyErrors() QSignalSpy spy(reply.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); QCOMPARE(waitForFinish(reply), int(Failure)); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(reply->error(), expectedError); } @@ -8574,7 +9335,7 @@ void tst_QNetworkReply::ioHttpUserVerifiedRedirect() QSignalSpy finishedSpy(reply.data(), SIGNAL(finished())); waitForFinish(reply); - QCOMPARE(finishedSpy.count(), 1); + QCOMPARE(finishedSpy.size(), 1); QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), statusCode); QVERIFY(validateRedirectedResponseHeaders(reply) || statusCode != 200); } @@ -8586,7 +9347,7 @@ void tst_QNetworkReply::ioHttpCookiesDuringRedirect() const QString cookieHeader = QStringLiteral("Set-Cookie: hello=world; Path=/;\r\n"); QString redirect = tempRedirectReplyStr(); // Insert 'cookieHeader' before the final \r\n - redirect.insert(redirect.length() - 2, cookieHeader); + redirect.insert(redirect.size() - 2, cookieHeader); QUrl url("http://localhost/"); url.setPort(target.serverPort()); @@ -8603,7 +9364,7 @@ void tst_QNetworkReply::ioHttpCookiesDuringRedirect() manager.setRedirectPolicy(oldRedirectPolicy); QVERIFY(waitForFinish(reply) == Success); - QVERIFY(target.receivedData.contains("\r\nCookie: hello=world\r\n")); + QVERIFY(target.receivedData.contains("\r\ncookie: hello=world\r\n")); QVERIFY(validateRedirectedResponseHeaders(reply)); } @@ -8628,7 +9389,7 @@ void tst_QNetworkReply::ioHttpRedirect() targetUrl.setPort(target.serverPort()); QString redirectReply = QStringLiteral("HTTP/1.1 %1\r\n" - "Content-Type: text/plain\r\n" + "content-type: text/plain\r\n" "location: %2\r\n" "\r\n").arg(status, targetUrl.toString()); MiniHttpServer redirectServer(redirectReply.toLatin1(), false); @@ -8646,6 +9407,66 @@ void tst_QNetworkReply::ioHttpRedirect() QVERIFY(validateRedirectedResponseHeaders(reply)); } +#if QT_CONFIG(networkdiskcache) +/* + Test that, if we load a redirect from cache, we don't treat the request to + the destination of the redirect as a redirect. + + If it was treated as a redirect the finished() signal was never emitted! +*/ +void tst_QNetworkReply::ioHttpRedirectWithCache() +{ + // Disallow caching the result so that the second request must also send the request + QByteArray http200ResponseNoCache = "HTTP/1.1 200 OK\r\n" + "content-type: text/plain\r\n" + "Cache-Control: no-cache\r\n" + "\r\nHello"; + + MiniHttpServer target(http200ResponseNoCache, false); + QUrl targetUrl("http://localhost/"); + targetUrl.setPort(target.serverPort()); + + // A cache-able redirect reply + QString redirectReply = QStringLiteral("HTTP/1.1 308\r\n" + "content-type: text/plain\r\n" + "location: %1\r\n" + "Cache-Control: max-age=3600\r\n" + "\r\nYou're being redirected").arg(targetUrl.toString()); + MiniHttpServer redirectServer(redirectReply.toLatin1(), false); + QUrl url("http://localhost/"); + url.setPort(redirectServer.serverPort()); + + QTemporaryDir tempDir(QDir::tempPath() + "/tmp_cache_28035"); + QVERIFY2(tempDir.isValid(), qPrintable(tempDir.errorString())); + tempDir.setAutoRemove(true); + + QNetworkDiskCache *diskCache = new QNetworkDiskCache(); + diskCache->setCacheDirectory(tempDir.path()); + // Manager takes ownership of the cache: + manager.setCache(diskCache); + QCOMPARE(diskCache->cacheSize(), 0); + + // Send the first request, we end up caching the redirect reply + QNetworkRequest request(url); + QNetworkReplyPtr reply(manager.get(request)); + + QCOMPARE(waitForFinish(reply), int(Success)); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + QVERIFY(validateRedirectedResponseHeaders(reply)); + + QVERIFY(diskCache->cacheSize() != 0); + + // Now for the second request, we will use the cache, and we test that the finished() + // signal is still emitted. + request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); + reply.reset(manager.get(request)); + + QCOMPARE(waitForFinish(reply), int(Success)); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + QVERIFY(validateRedirectedResponseHeaders(reply)); +} +#endif + void tst_QNetworkReply::ioHttpRedirectFromLocalToRemote() { QUrl targetUrl("http://" + QtNetworkSettings::httpServerName() + "/qtest/rfc3252.txt"); @@ -8720,7 +9541,7 @@ void tst_QNetworkReply::ioHttpRedirectPostPut() QUrl targetUrl("http://" + QtNetworkSettings::httpServerName() + "/qtest/cgi-bin/md5sum.cgi"); QString redirectReply = QStringLiteral("HTTP/1.1 %1\r\n" - "Content-Type: text/plain\r\n" + "content-type: text/plain\r\n" "location: %2\r\n" "\r\n").arg(status, targetUrl.toString()); MiniHttpServer redirectServer(redirectReply.toLatin1()); @@ -8739,6 +9560,7 @@ void tst_QNetworkReply::ioHttpRedirectPostPut() QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex()); } +#if QT_CONFIG(http) void tst_QNetworkReply::ioHttpRedirectMultipartPost_data() { postToHttpMultipart_data(); @@ -8791,14 +9613,15 @@ void tst_QNetworkReply::ioHttpRedirectMultipartPost() QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); // 200 OK - QVERIFY(multiPart->boundary().count() > 20); // check that there is randomness after the "boundary_.oOo._" string - QVERIFY(multiPart->boundary().count() < 70); + QVERIFY(multiPart->boundary().size() > 20); // check that there is randomness after the "boundary_.oOo._" string + QVERIFY(multiPart->boundary().size() < 70); QByteArray replyData = reply->readAll(); expectedReplyData.prepend("content type: multipart/" + contentType + "; boundary=\"" + multiPart->boundary() + "\"\n"); // QEXPECT_FAIL("nested", "the server does not understand nested multipart messages", Continue); // see above QCOMPARE(replyData, expectedReplyData); } +#endif void tst_QNetworkReply::ioHttpRedirectDelete() { @@ -8874,7 +9697,7 @@ void tst_QNetworkReply::ioHttpRedirectWithUploadDevice() targetUrl.setPort(target.serverPort()); QString redirectReply = QStringLiteral("HTTP/1.1 %1\r\n" - "Content-Type: text/plain\r\n" + "content-type: text/plain\r\n" "location: %2\r\n" "\r\n").arg(status, targetUrl.toString()); MiniHttpServer redirectServer(redirectReply.toLatin1()); @@ -8908,12 +9731,12 @@ void tst_QNetworkReply::ioHttpRedirectWithUploadDevice() // we shouldn't send Content-Length with not content (esp. for GET) QVERIFY2(!target.receivedData.contains("Content-Length"), "Target server should not have received a Content-Length header"); - QVERIFY2(!target.receivedData.contains("Content-Type"), - "Target server should not have received a Content-Type header"); + QVERIFY2(!target.receivedData.contains("content-type"), + "Target server should not have received a content-type header"); } } -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) class PutWithServerClosingConnectionImmediatelyHandler: public QObject { @@ -8955,9 +9778,9 @@ public slots: //qDebug() << m_receivedData.left(m_receivedData.indexOf("\r\n\r\n")); m_receivedData = m_receivedData.mid(m_receivedData.indexOf("\r\n\r\n")+4); // check only actual data } - if (m_receivedData.length() > 0 && !m_expectedData.startsWith(m_receivedData)) { + if (m_receivedData.size() > 0 && !m_expectedData.startsWith(m_receivedData)) { // We had received some data but it is corrupt! - qDebug() << "CORRUPT" << m_receivedData.count(); + qDebug() << "CORRUPT" << m_receivedData.size(); #if 0 // Use this to track down the pattern of the corruption and conclude the source QFile a("/tmp/corrupt"); @@ -9046,6 +9869,9 @@ void tst_QNetworkReply::putWithServerClosingConnectionImmediately() for (int i = 0; i < numUploads; i++) { // create the request QNetworkRequest request(QUrl(urlPrefix + QString::number(i))); + // Disable http2 so we get the 6 simultaneous channels as when + // the test was originally written + request.setAttribute(QNetworkRequest::Http2AllowedAttribute, false); QNetworkReply *reply = manager.put(request, sourceFile); connect(reply, SIGNAL(sslErrors(QList<QSslError>)), reply, SLOT(ignoreSslErrors())); connect(reply, SIGNAL(finished()), &server, SLOT(replyFinished())); @@ -9076,8 +9902,12 @@ void tst_QNetworkReply::autoDeleteRepliesAttribute_data() { QTest::addColumn<QUrl>("destination"); - QTest::newRow("http") << QUrl("http://QInvalidDomain.qt/test"); - QTest::newRow("https") << QUrl("https://QInvalidDomain.qt/test"); + QUrl webServerUrl = QtNetworkSettings::httpServerIp().toString(); + webServerUrl.setPath("/notfound"); + webServerUrl.setScheme("http"); + QTest::newRow("http") << webServerUrl; + webServerUrl.setScheme("https"); + QTest::newRow("https") << webServerUrl; if (ftpSupported) QTest::newRow("ftp") << QUrl("ftp://QInvalidDomain.qt/test"); QTest::newRow("file") << QUrl("file:///thisfolderdoesn'texist/probably.txt"); @@ -9100,7 +9930,7 @@ void tst_QNetworkReply::autoDeleteRepliesAttribute() QSignalSpy finishedSpy(reply, &QNetworkReply::finished); QSignalSpy destroyedSpy(reply, &QObject::destroyed); QVERIFY(finishedSpy.wait()); - QCOMPARE(destroyedSpy.count(), 0); + QCOMPARE(destroyedSpy.size(), 0); QVERIFY(destroyedSpy.wait()); } { @@ -9111,7 +9941,7 @@ void tst_QNetworkReply::autoDeleteRepliesAttribute() QSignalSpy finishedSpy(reply, &QNetworkReply::finished); QSignalSpy destroyedSpy(reply, &QObject::destroyed); QVERIFY(finishedSpy.wait()); - QCOMPARE(destroyedSpy.count(), 0); + QCOMPARE(destroyedSpy.size(), 0); QVERIFY(destroyedSpy.wait()); } // Now repeated, but without the attribute to make sure it does not get deleted automatically. @@ -9125,10 +9955,10 @@ void tst_QNetworkReply::autoDeleteRepliesAttribute() QSignalSpy finishedSpy(reply.data(), &QNetworkReply::finished); QSignalSpy destroyedSpy(reply.data(), &QObject::destroyed); QVERIFY(finishedSpy.wait()); - QCOMPARE(destroyedSpy.count(), 0); + QCOMPARE(destroyedSpy.size(), 0); QCoreApplication::processEvents(); QCoreApplication::processEvents(); - QCOMPARE(destroyedSpy.count(), 0); + QCOMPARE(destroyedSpy.size(), 0); } { // Post @@ -9137,10 +9967,10 @@ void tst_QNetworkReply::autoDeleteRepliesAttribute() QSignalSpy finishedSpy(reply.data(), &QNetworkReply::finished); QSignalSpy destroyedSpy(reply.data(), &QObject::destroyed); QVERIFY(finishedSpy.wait()); - QCOMPARE(destroyedSpy.count(), 0); + QCOMPARE(destroyedSpy.size(), 0); QCoreApplication::processEvents(); QCoreApplication::processEvents(); - QCOMPARE(destroyedSpy.count(), 0); + QCOMPARE(destroyedSpy.size(), 0); } } @@ -9161,7 +9991,7 @@ void tst_QNetworkReply::autoDeleteReplies() QSignalSpy finishedSpy(reply, &QNetworkReply::finished); QSignalSpy destroyedSpy(reply, &QObject::destroyed); QVERIFY(finishedSpy.wait()); - QCOMPARE(destroyedSpy.count(), 0); + QCOMPARE(destroyedSpy.size(), 0); QVERIFY(destroyedSpy.wait()); } { @@ -9171,7 +10001,7 @@ void tst_QNetworkReply::autoDeleteReplies() QSignalSpy finishedSpy(reply, &QNetworkReply::finished); QSignalSpy destroyedSpy(reply, &QObject::destroyed); QVERIFY(finishedSpy.wait()); - QCOMPARE(destroyedSpy.count(), 0); + QCOMPARE(destroyedSpy.size(), 0); QVERIFY(destroyedSpy.wait()); } // Here we repeat the test, but override the auto-deletion in the QNetworkRequest @@ -9186,10 +10016,10 @@ void tst_QNetworkReply::autoDeleteReplies() QSignalSpy finishedSpy(reply.data(), &QNetworkReply::finished); QSignalSpy destroyedSpy(reply.data(), &QObject::destroyed); QVERIFY(finishedSpy.wait()); - QCOMPARE(destroyedSpy.count(), 0); + QCOMPARE(destroyedSpy.size(), 0); QCoreApplication::processEvents(); QCoreApplication::processEvents(); - QCOMPARE(destroyedSpy.count(), 0); + QCOMPARE(destroyedSpy.size(), 0); } { // Post @@ -9199,10 +10029,10 @@ void tst_QNetworkReply::autoDeleteReplies() QSignalSpy finishedSpy(reply.data(), &QNetworkReply::finished); QSignalSpy destroyedSpy(reply.data(), &QObject::destroyed); QVERIFY(finishedSpy.wait()); - QCOMPARE(destroyedSpy.count(), 0); + QCOMPARE(destroyedSpy.size(), 0); QCoreApplication::processEvents(); QCoreApplication::processEvents(); - QCOMPARE(destroyedSpy.count(), 0); + QCOMPARE(destroyedSpy.size(), 0); } // Now we repeat the test with autoDeleteReplies set to false cleanup.dismiss(); @@ -9214,10 +10044,10 @@ void tst_QNetworkReply::autoDeleteReplies() QSignalSpy finishedSpy(reply.data(), &QNetworkReply::finished); QSignalSpy destroyedSpy(reply.data(), &QObject::destroyed); QVERIFY(finishedSpy.wait()); - QCOMPARE(destroyedSpy.count(), 0); + QCOMPARE(destroyedSpy.size(), 0); QCoreApplication::processEvents(); QCoreApplication::processEvents(); - QCOMPARE(destroyedSpy.count(), 0); + QCOMPARE(destroyedSpy.size(), 0); } { // Post @@ -9226,89 +10056,140 @@ void tst_QNetworkReply::autoDeleteReplies() QSignalSpy finishedSpy(reply.data(), &QNetworkReply::finished); QSignalSpy destroyedSpy(reply.data(), &QObject::destroyed); QVERIFY(finishedSpy.wait()); - QCOMPARE(destroyedSpy.count(), 0); + QCOMPARE(destroyedSpy.size(), 0); QCoreApplication::processEvents(); QCoreApplication::processEvents(); - QCOMPARE(destroyedSpy.count(), 0); + QCOMPARE(destroyedSpy.size(), 0); } } -void tst_QNetworkReply::getWithTimeout() +#if QT_CONFIG(http) || defined (Q_OS_WASM) +void tst_QNetworkReply::requestWithTimeout_data() { - MiniHttpServer server(tst_QNetworkReply::httpEmpty200Response, false); + using Operation = QNetworkAccessManager::Operation; + QTest::addColumn<Operation>("method"); + QTest::addColumn<int>("reqInt"); + QTest::addColumn<std::chrono::milliseconds>("reqChrono"); + QTest::addColumn<int>("mgrInt"); + QTest::addColumn<std::chrono::milliseconds>("mgrChrono"); - QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); - QNetworkReplyPtr reply(manager.get(request)); - QSignalSpy spy(reply.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); + QTest::addRow("get_req_int") << Operation::GetOperation << 500 << 0ms << 0 << 0ms; + QTest::addRow("get_req_chrono") << Operation::GetOperation << 0 << 500ms << 0 << 0ms; + QTest::addRow("get_mgr_int") << Operation::GetOperation << 0 << 0ms << 500 << 0ms; + QTest::addRow("get_mgr_chrono") << Operation::GetOperation << 0 << 0ms << 0 << 500ms; - QCOMPARE(waitForFinish(reply), int(Success)); + QTest::addRow("post_req_int") << Operation::PostOperation << 500 << 0ms << 0 << 0ms; + QTest::addRow("post_req_chrono") << Operation::PostOperation << 0 << 500ms << 0 << 0ms; + QTest::addRow("post_mgr_int") << Operation::PostOperation << 0 << 0ms << 500 << 0ms; + QTest::addRow("post_mgr_chrono") << Operation::PostOperation << 0 << 0ms << 0 << 500ms; +} - QCOMPARE(spy.count(), 0); - QVERIFY(reply->error() == QNetworkReply::NoError); +void tst_QNetworkReply::requestWithTimeout() +{ + QFETCH(QNetworkAccessManager::Operation, method); + QFETCH(int, reqInt); + QFETCH(int, mgrInt); + QFETCH(std::chrono::milliseconds, reqChrono); + QFETCH(std::chrono::milliseconds, mgrChrono); + const auto data = "some data"_ba; + // Manager instance remains between case runs => always reset it's transferTimeout to + // ensure setting its transferTimeout in this case has effect + manager.setTransferTimeout(0ms); + auto cleanup = qScopeGuard([this] { manager.setTransferTimeout(0ms); }); - request.setTransferTimeout(1000); + MiniHttpServer server(tst_QNetworkReply::httpEmpty200Response, false); server.stopTransfer = true; - QNetworkReplyPtr reply2(manager.get(request)); - QSignalSpy spy2(reply2.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); - - QCOMPARE(waitForFinish(reply2), int(Failure)); - - QCOMPARE(spy2.count(), 1); - QVERIFY(reply2->error() == QNetworkReply::OperationCanceledError); - - request.setTransferTimeout(0); - manager.setTransferTimeout(1000); - - QNetworkReplyPtr reply3(manager.get(request)); - QSignalSpy spy3(reply3.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); - - QCOMPARE(waitForFinish(reply3), int(Failure)); + QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); + request.setRawHeader("content-type", "application/octet-stream"); + if (reqInt > 0) + request.setTransferTimeout(reqInt); + if (reqChrono > 0ms) + request.setTransferTimeout(reqChrono); + if (mgrInt > 0) + manager.setTransferTimeout(mgrInt); + if (mgrChrono > 0ms) + manager.setTransferTimeout(mgrChrono); - QCOMPARE(spy3.count(), 1); - QVERIFY(reply3->error() == QNetworkReply::OperationCanceledError); + QNetworkReplyPtr reply; + if (method == QNetworkAccessManager::GetOperation) + reply.reset(manager.get(request)); + else if (method == QNetworkAccessManager::PostOperation) + reply.reset(manager.post(request, data)); + QVERIFY(reply); - manager.setTransferTimeout(0); + QSignalSpy spy(reply.data(), &QNetworkReply::errorOccurred); + QCOMPARE(waitForFinish(reply), int(Failure)); + QCOMPARE(spy.size(), 1); + QCOMPARE(reply->error(), QNetworkReply::OperationCanceledError); } +#endif -void tst_QNetworkReply::postWithTimeout() +void tst_QNetworkReply::moreActivitySignals_data() { - MiniHttpServer server(tst_QNetworkReply::httpEmpty200Response, false); - - QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); - request.setRawHeader("Content-Type", "application/octet-stream"); - QByteArray postData("Just some nonsense"); - QNetworkReplyPtr reply(manager.post(request, postData)); - QSignalSpy spy(reply.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); - - QCOMPARE(waitForFinish(reply), int(Success)); + QTest::addColumn<QUrl>("url"); + QTest::addColumn<bool>("useipv6"); + QTest::addColumn<bool>("postWithData"); + QTest::addRow("local4") << QUrl("http://127.0.0.1") << false << false; + QTest::addRow("local6") << QUrl("http://[::1]") << true << false; + if (qEnvironmentVariable("QTEST_ENVIRONMENT").split(' ').contains("ci")) { + // On CI server + QTest::addRow("localDns") << QUrl("http://localhost") << false << false; // will find v6 + } else { + // For manual testing + QTest::addRow("localDns4") << QUrl("http://localhost") << true << false; // will find both v4 and v6 + QTest::addRow("localDns6") << QUrl("http://localhost") << false << false; // will find both v4 and v6 + } + QTest::addRow("post-with-data") << QUrl("http://[::1]") << true << true; +} - QCOMPARE(spy.count(), 0); +void tst_QNetworkReply::moreActivitySignals() +{ + QFETCH(QUrl, url); + QFETCH(bool, useipv6); + QFETCH(bool, postWithData); + MiniHttpServer server(tst_QNetworkReply::httpEmpty200Response, false, nullptr/*thread*/, useipv6); + server.doClose = false; + url.setPort(server.serverPort()); + QNetworkRequest request(url); + QNetworkReplyPtr reply; + if (postWithData) { + request.setRawHeader("content-type", "text/plain"); + reply.reset(manager.post(request, "Hello, world!")); + } else { + reply.reset(manager.get(request)); + } + QSignalSpy spy1(reply.data(), SIGNAL(socketStartedConnecting())); + QSignalSpy spy2(reply.data(), SIGNAL(requestSent())); + QSignalSpy spy3(reply.data(), SIGNAL(metaDataChanged())); + QSignalSpy spy4(reply.data(), SIGNAL(finished())); + spy1.wait(); + QCOMPARE(spy1.size(), 1); + spy2.wait(); + QCOMPARE(spy2.size(), 1); + spy3.wait(); + QCOMPARE(spy3.size(), 1); + spy4.wait(); + QCOMPARE(spy4.size(), 1); QVERIFY(reply->error() == QNetworkReply::NoError); - - request.setTransferTimeout(1000); - server.stopTransfer = true; - - QNetworkReplyPtr reply2(manager.post(request, postData)); - QSignalSpy spy2(reply2.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); - - QCOMPARE(waitForFinish(reply2), int(Failure)); - - QCOMPARE(spy2.count(), 1); - QVERIFY(reply2->error() == QNetworkReply::OperationCanceledError); - - request.setTransferTimeout(0); - manager.setTransferTimeout(1000); - - QNetworkReplyPtr reply3(manager.post(request, postData)); - QSignalSpy spy3(reply3.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError))); - - QCOMPARE(waitForFinish(reply3), int(Failure)); - - QCOMPARE(spy3.count(), 1); - QVERIFY(reply3->error() == QNetworkReply::OperationCanceledError); - - manager.setTransferTimeout(0); + // Second request will not send socketStartedConnecting because of keep-alive, so don't check it. + QNetworkReplyPtr secondreply; + if (postWithData) { + request.setRawHeader("content-type", "text/plain"); + secondreply.reset(manager.post(request, "Hello, world!")); + } else { + secondreply.reset(manager.get(request)); + } + QSignalSpy secondspy2(secondreply.data(), SIGNAL(requestSent())); + QSignalSpy secondspy3(secondreply.data(), SIGNAL(metaDataChanged())); + QSignalSpy secondspy4(secondreply.data(), SIGNAL(finished())); + secondspy2.wait(); + QCOMPARE(secondspy2.size(), 1); + secondspy3.wait(); + QCOMPARE(secondspy3.size(), 1); + secondspy4.wait(); + QCOMPARE(secondspy4.size(), 1); + QVERIFY(secondreply->error() == QNetworkReply::NoError); } void tst_QNetworkReply::contentEncoding_data() @@ -9316,25 +10197,53 @@ void tst_QNetworkReply::contentEncoding_data() QTest::addColumn<QByteArray>("encoding"); QTest::addColumn<QByteArray>("body"); QTest::addColumn<QByteArray>("expected"); + QTest::addColumn<bool>("decompress"); + + const QByteArray helloWorld = "hello world"; + const QByteArray gzipBody = QByteArray::fromBase64("H4sIAAAAAAAAA8tIzcnJVyjPL8pJAQCFEUoNCwAAAA=="); QTest::newRow("gzip-hello-world") << QByteArray("gzip") - << QByteArray::fromBase64("H4sIAAAAAAAAA8tIzcnJVyjPL8pJAQCFEUoNCwAAAA==") - << QByteArray("hello world"); + << gzipBody + << helloWorld + << true; + QTest::newRow("gzip-hello-world-no-decompress") + << QByteArray("gzip") + << gzipBody + << helloWorld + << false; + const QByteArray deflateBody = QByteArray::fromBase64("eJzLSM3JyVcozy/KSQEAGgsEXQ=="); QTest::newRow("deflate-hello-world") - << QByteArray("deflate") << QByteArray::fromBase64("eJzLSM3JyVcozy/KSQEAGgsEXQ==") - << QByteArray("hello world"); + << QByteArray("deflate") << deflateBody + << helloWorld + << true; + QTest::newRow("deflate-hello-world-no-decompress") + << QByteArray("deflate") << deflateBody + << helloWorld + << false; #if QT_CONFIG(brotli) + const QByteArray brotliBody = QByteArray::fromBase64("DwWAaGVsbG8gd29ybGQD"); QTest::newRow("brotli-hello-world") - << QByteArray("br") << QByteArray::fromBase64("DwWAaGVsbG8gd29ybGQD") - << QByteArray("hello world"); + << QByteArray("br") << brotliBody + << helloWorld + << true; + QTest::newRow("brotli-hello-world-no-decompress") + << QByteArray("br") << brotliBody + << helloWorld + << false; #endif #if defined(QT_BUILD_INTERNAL) && QT_CONFIG(zstd) + const QByteArray zstdBody = QByteArray::fromBase64("KLUv/QRYWQAAaGVsbG8gd29ybGRoaR6y"); QTest::newRow("zstandard-hello-world") - << QByteArray("zstd") << QByteArray::fromBase64("KLUv/QRYWQAAaGVsbG8gd29ybGRoaR6y") - << QByteArray("hello world"); + << QByteArray("zstd") << zstdBody + << helloWorld + << true; + QTest::newRow("zstandard-hello-world-no-decompress") + << QByteArray("zstd") << zstdBody + << helloWorld + << false; #else qDebug("Note: ZStandard testdata is only available for developer builds."); #endif @@ -9344,12 +10253,19 @@ void tst_QNetworkReply::contentEncoding() { QFETCH(QByteArray, encoding); QFETCH(QByteArray, body); + QFETCH(bool, decompress); QString header("HTTP/1.0 200 OK\r\nContent-Encoding: %1\r\nContent-Length: %2\r\n\r\n"); header = header.arg(encoding, QString::number(body.size())); MiniHttpServer server(header.toLatin1() + body); QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); + if (!decompress) { + // This disables decompression of the received content: + request.setRawHeader("accept-encoding", QLatin1String("%1").arg(encoding).toLatin1()); + // This disables the zerocopy optimization + request.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, 0); + } QNetworkReplyPtr reply(manager.get(request)); QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply)); @@ -9358,7 +10274,7 @@ void tst_QNetworkReply::contentEncoding() { // Check that we included the content encoding method in our Accept-Encoding header const QByteArray &receivedData = server.receivedData; - int start = receivedData.indexOf("Accept-Encoding"); + int start = receivedData.indexOf("accept-encoding"); QVERIFY(start != -1); int end = receivedData.indexOf("\r\n", start); QVERIFY(end != -1); @@ -9370,12 +10286,395 @@ void tst_QNetworkReply::contentEncoding() QVERIFY2(list.contains(encoding), acceptedEncoding.data()); } + if (decompress) { + QFETCH(QByteArray, expected); + QCOMPARE(reply->bytesAvailable(), expected.size()); + QCOMPARE(reply->readAll(), expected); + } else { + QCOMPARE(reply->bytesAvailable(), body.size()); + QCOMPARE(reply->readAll(), body); + } +} + +#if QT_CONFIG(http) +void tst_QNetworkReply::contentEncodingBigPayload_data() +{ + QTest::addColumn<QByteArray>("encoding"); + QTest::addColumn<QString>("path"); + QTest::addColumn<qint64>("expectedSize"); + + qint64 fourGiB = 4ll * 1024ll * 1024ll * 1024ll; + + QTest::addRow("gzip-4GB") << QByteArray("gzip") << (":/4G.gz") << fourGiB; + +#if QT_CONFIG(brotli) + QTest::addRow("brotli-4GB") << QByteArray("br") << (testDataDir + "/4G.br") << fourGiB; +#endif +#if defined(QT_BUILD_INTERNAL) && QT_CONFIG(zstd) + QTest::addRow("zstd-4GB") << QByteArray("zstd") << (":/4G.zst") << fourGiB; +#else + qDebug("Note: ZStandard testdata is only available for developer builds."); +#endif +} + +void tst_QNetworkReply::contentEncodingBigPayload() +{ + QFETCH(QString, path); + QFile compressedFile(path); + QVERIFY(compressedFile.open(QIODevice::ReadOnly)); + QByteArray body = compressedFile.readAll(); + + QFETCH(QByteArray, encoding); + QString header("HTTP/1.0 200 OK\r\nContent-Encoding: %1\r\nContent-Length: %2\r\n\r\n"); + header = header.arg(encoding, QString::number(body.size())); + + MiniHttpServer server(header.toLatin1() + body); + + QNetworkRequest request(QUrl("http://localhost:" + QString::number(server.serverPort()))); + // QDecompressHelper will abort the download if the compressed to decompressed size ratio + // differs too much, so we override it + request.setDecompressedSafetyCheckThreshold(-1); + QNetworkReplyPtr reply(manager.get(request)); + + QTRY_VERIFY2_WITH_TIMEOUT(reply->isFinished(), qPrintable(reply->errorString()), 15000); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QFETCH(qint64, expectedSize); + + QCOMPARE(reply->bytesAvailable(), expectedSize); + QByteArray output(512 * 1024 * 1024, Qt::Uninitialized); + qint64 total = 0; + while (reply->bytesAvailable()) { + qint64 read = reply->read(output.data(), output.size()); + QVERIFY(read != -1); + total += read; + + static const auto isZero = [](char c) { return c == '\0'; }; + bool allZero = std::all_of(output.cbegin(), output.cbegin() + read, isZero); + QVERIFY(allZero); + } + QCOMPARE(total, expectedSize); +} +#endif + +void tst_QNetworkReply::cacheWithContentEncoding_data() +{ + contentEncoding_data(); +} + +void tst_QNetworkReply::cacheWithContentEncoding() +{ + QFETCH(QByteArray, encoding); + QFETCH(QByteArray, body); QFETCH(QByteArray, expected); + QString header("HTTP/1.0 200 OK\r\nContent-Encoding: %1\r\nContent-Length: %2\r\n\r\n"); + header = header.arg(encoding, QString::number(body.size())); + + MiniHttpServer server(header.toLatin1() + body); + + MySpyMemoryCache *cache = new MySpyMemoryCache(this); + manager.setCache(cache); + auto unsetCache = qScopeGuard([this](){ manager.setCache(nullptr); }); + + QUrl url("http://localhost:" + QString::number(server.serverPort())); + QNetworkRequest request(url); + QNetworkReplyPtr reply(manager.get(request)); + + QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply)); + QCOMPARE(reply->error(), QNetworkReply::NoError); + + QByteArray output = reply->readAll(); + QIODevice *device = cache->data(url); + QVERIFY(device); + QByteArray fromCache = device->readAll(); + QCOMPARE(output, expected); + QCOMPARE(fromCache, expected); +} + +void tst_QNetworkReply::downloadProgressWithContentEncoding_data() +{ + contentEncoding_data(); +} + +void tst_QNetworkReply::downloadProgressWithContentEncoding() +{ + QFETCH(QByteArray, encoding); + QFETCH(QByteArray, body); + QFETCH(QByteArray, expected); + QString header("HTTP/1.0 200 OK\r\nContent-Encoding: %1\r\nContent-Length: %2\r\n\r\n"); + header = header.arg(encoding, QString::number(body.size())); + + MiniHttpServer server(header.toLatin1() + body); + + QUrl url("http://localhost:" + QString::number(server.serverPort())); + QNetworkRequest request(url); + QNetworkReplyPtr reply(manager.get(request)); + // Limit the amount of bytes we read so we get more than one downloadProgress emission + reply->setReadBufferSize(5); + + qint64 bytesReceived = -1; + connect(reply.data(), &QNetworkReply::downloadProgress, this, + [reply = reply.data(), &expected, &bytesReceived](qint64 recv, qint64 /*total*/) { + qint64 previous = bytesReceived; + bytesReceived = recv; + if (bytesReceived > expected.size()) { + qWarning("bytesReceived greater than expected size!"); + reply->abort(); + } + if (bytesReceived < previous) { + qWarning("bytesReceived shrank!"); + reply->abort(); + } + }); + + SlowReader reader(reply.data()); + + QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply)); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(bytesReceived, expected.size()); +} + +void tst_QNetworkReply::contentEncodingError_data() +{ + QTest::addColumn<QByteArray>("encoding"); + QTest::addColumn<QString>("path"); + QTest::addColumn<QNetworkReply::NetworkError>("expectedError"); + + QTest::addRow("archive-bomb") << QByteArray("gzip") << (":/4G.gz") + << QNetworkReply::UnknownContentError; +} + +void tst_QNetworkReply::contentEncodingError() +{ + QFETCH(QString, path); + QFile compressedFile(path); + QVERIFY(compressedFile.open(QIODevice::ReadOnly)); + QByteArray body = compressedFile.readAll(); + + QFETCH(QByteArray, encoding); + QString header("HTTP/1.0 200 OK\r\nContent-Encoding: %1\r\nContent-Length: %2\r\n\r\n"); + header = header.arg(encoding, QString::number(body.size())); + + MiniHttpServer server(header.toLatin1() + body); - QCOMPARE(reply->bytesAvailable(), expected.size()); + QNetworkRequest request( + QUrl(QLatin1String("http://localhost:%1").arg(QString::number(server.serverPort())))); + QNetworkReplyPtr reply(manager.get(request)); + + QTRY_VERIFY2_WITH_TIMEOUT(reply->isFinished(), qPrintable(reply->errorString()), 15000); + QTEST(reply->error(), "expectedError"); +} + +// When this test is failing it will appear flaky because it relies on the +// timing of delivery from one socket to another in the OS. +// + we have to send all the data at once, so the readyRead emissions are +// compressed into a single emission, so we cannot artificially time it with +// waits and sleeps. +void tst_QNetworkReply::compressedReadyRead() +{ + // There were historically an issue where a mix of signal compression and + // data decompression made it so we accidentally didn't emit the final + // readyRead signal before emitting finished(). Test this here to make sure + // it happens: + const QByteArray gzipPayload = + QByteArray::fromBase64("H4sIAAAAAAAAA8tIzcnJVyjPL8pJAQCFEUoNCwAAAA=="); + const QByteArray expected = "hello world"; + + QString header("HTTP/1.0 200 OK\r\nContent-Encoding: gzip\r\nContent-Length: %1\r\n\r\n"); + header = header.arg(gzipPayload.size()); + MiniHttpServer server(header.toLatin1()); // only send header automatically + server.doClose = false; // don't close and delete client socket right away + + QNetworkRequest request( + QUrl(QLatin1String("http://localhost:%1").arg(QString::number(server.serverPort())))); + QNetworkReplyPtr reply(manager.get(request)); + + QObject::connect(reply.get(), &QNetworkReply::metaDataChanged, reply.get(), + [&server, &gzipPayload]() { + // Client received headers, now send data: + // We do this awkward write,flush,write dance to try to + // make sure the data does not all arrive at the same + // time. By design we send the final "=" byte by itself + qsizetype boundary = gzipPayload.size() - 1; + server.client->write(gzipPayload.sliced(0, boundary)); + server.client->flush(); + // Let the server take care of deleting the client once + // the rest of the data is written: + server.doClose = true; + server.client->write(gzipPayload.sliced(boundary)); + }); + + QByteArray received; + QObject::connect(reply.get(), &QNetworkReply::readyRead, reply.get(), + [reply = reply.get(), &received]() { + received += reply->readAll(); + }); + QTRY_VERIFY(reply->isFinished()); + QCOMPARE(received, expected); +} + +void tst_QNetworkReply::notFoundWithCompression_data() +{ + contentEncoding_data(); +} + +void tst_QNetworkReply::notFoundWithCompression() +{ + QFETCH(QByteArray, encoding); + QFETCH(QByteArray, body); + QString header("HTTP/1.0 404 OK\r\nContent-Encoding: %1\r\nContent-Length: %2\r\n\r\n"); + header = header.arg(encoding, QString::number(body.size())); + + MiniHttpServer server(header.toLatin1() + body); + + QNetworkRequest request( + QUrl(QLatin1String("http://localhost:%1").arg(QString::number(server.serverPort())))); + QNetworkReplyPtr reply(manager.get(request)); + + QTRY_VERIFY2_WITH_TIMEOUT(reply->isFinished(), qPrintable(reply->errorString()), 15000); + QCOMPARE(reply->error(), QNetworkReply::ContentNotFoundError); + + QFETCH(QByteArray, expected); QCOMPARE(reply->readAll(), expected); } +#if QT_CONFIG(http) +void tst_QNetworkReply::qhttpPartDebug_data() +{ + QTest::addColumn<QByteArray>("header_data"); + QTest::addColumn<QByteArray>("raw_header_data"); + QTest::addColumn<QList<QByteArray>>("expected_header_values"); + QTest::addColumn<bool>("overwrite"); + + QTest::newRow("header-data-set") << "form-data; name=\"prompt\""_ba << ""_ba + << (QList<QByteArray>() << "form-data; name=\"prompt\""_ba) << false; + QTest::newRow("raw-header-data-set") << ""_ba << "thisismykeyherebutnotreally"_ba + << (QList<QByteArray>() << "thisismykeyherebutnotreally"_ba) << false; + QTest::newRow("both-set") << "form-data; name=\"prompt\""_ba + << "thisismykeyherebutnotreally"_ba + << (QList<QByteArray>() + << "form-data; name=\"prompt\""_ba + << "thisismykeyherebutnotreally"_ba) << false; + QTest::newRow("overwrite") << "form-data; name=\"prompt\""_ba + << "thisismykeyherebutnotreally"_ba + << (QList<QByteArray>() + << "thisismykeyherebutnotreally"_ba + << "thisismykeyherebutnotreally"_ba) << true; +} + +void tst_QNetworkReply::qhttpPartDebug() +{ + QFETCH(const QByteArray, header_data); + QFETCH(const QByteArray, raw_header_data); + QFETCH(const QList<QByteArray>, expected_header_values); + QFETCH(bool, overwrite); + + QHttpPart httpPart; + + if (!header_data.isEmpty()) + httpPart.setHeader(QNetworkRequest::ContentDispositionHeader, header_data); + + if (!raw_header_data.isEmpty()) + httpPart.setRawHeader("Authorization", raw_header_data); + + if (overwrite) + httpPart.setRawHeader("Content-Disposition", raw_header_data); + + QByteArray msg; + { + QBuffer buf(&msg); + QVERIFY(buf.open(QIODevice::WriteOnly)); + QDebug debug(&buf); + debug << httpPart; + } + + for (const auto &value : expected_header_values) + QVERIFY2(msg.contains(value), "Missing header value: " + value); +} + +void tst_QNetworkReply::qtbug68821proxyError_data() +{ + QTest::addColumn<QString>("proxyHost"); + QTest::addColumn<QString>("scheme"); + QTest::addColumn<QNetworkReply::NetworkError>("error"); + + QTest::newRow("invalidhost+http") << "this-host-will-never-exist.qt-project.org" + << "http" << QNetworkReply::ProxyNotFoundError; + QTest::newRow("localhost+http") << "localhost" + << "http" << QNetworkReply::ProxyConnectionRefusedError; +#ifndef QT_NO_SSL + QTest::newRow("invalidhost+https") << "this-host-will-never-exist.qt-project.org" + << "https" << QNetworkReply::ProxyNotFoundError; + QTest::newRow("localhost+https") << "localhost" + << "https" << QNetworkReply::ProxyConnectionRefusedError; +#endif +} + +void tst_QNetworkReply::qtbug68821proxyError() +{ + auto getUnusedPort = []() -> std::optional<quint16> { + QTcpServer probeServer; + if (!probeServer.listen()) + return std::nullopt; + // If we can listen on it, it was unused, and hopefully is also + // still unused after we stop listening. + return probeServer.serverPort(); + }; + + auto proxyPort = getUnusedPort(); + QVERIFY(proxyPort); + + QFETCH(QString, proxyHost); + QNetworkProxy proxy(QNetworkProxy::HttpProxy, proxyHost, proxyPort.value()); + + manager.setProxy(proxy); + + QFETCH(QString, scheme); + QNetworkReply *reply = manager.get(QNetworkRequest(QUrl(scheme + "://example.com"))); + QSignalSpy spy(reply, &QNetworkReply::errorOccurred); + QVERIFY(spy.isValid()); + + QVERIFY(spy.wait(15000)); + + QFETCH(QNetworkReply::NetworkError, error); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.at(0).at(0), error); +} +#endif + +void tst_QNetworkReply::abortAndError() +{ + const QByteArray response = + R"(HTTP/1.0 500 Internal Server Error +Content-Length: 12 +Content-Type: text/plain + +Hello World!)"_ba; + + MiniHttpServer server(response); + + QNetworkAccessManager manager; + QNetworkRequest req(QUrl("http://127.0.0.1:" + QString::number(server.serverPort()))); + std::unique_ptr<QNetworkReply> reply(manager.post(req, "my data goes here"_ba)); + QSignalSpy errorSignal(reply.get(), &QNetworkReply::errorOccurred); + QSignalSpy finishedSignal(reply.get(), &QNetworkReply::finished); + + reply->abort(); + + // We don't want to print this warning in this case because it is impossible + // for users to avoid it. + QTest::failOnWarning("QNetworkReplyImplPrivate::error: Internal problem, this method must only " + "be called once."); + // Process any signals from the http thread: + QTest::qWait(1s); + if (QTest::currentTestFailed()) + return; + + QCOMPARE(finishedSignal.count(), 1); + QCOMPARE(errorSignal.count(), 1); + QCOMPARE(reply->error(), QNetworkReply::OperationCanceledError); +} + // NOTE: This test must be last testcase in tst_qnetworkreply! void tst_QNetworkReply::parentingRepliesToTheApp() { diff --git a/tests/auto/network/access/qnetworkreply_local/CMakeLists.txt b/tests/auto/network/access/qnetworkreply_local/CMakeLists.txt new file mode 100644 index 0000000000..13a60afb13 --- /dev/null +++ b/tests/auto/network/access/qnetworkreply_local/CMakeLists.txt @@ -0,0 +1,9 @@ +qt_internal_add_test(tst_qnetworkreply_local + SOURCES + minihttpserver.h + tst_qnetworkreply_local.cpp + LIBRARIES + Qt::CorePrivate + Qt::NetworkPrivate + BUNDLE_ANDROID_OPENSSL_LIBS +) diff --git a/tests/auto/network/access/qnetworkreply_local/minihttpserver.h b/tests/auto/network/access/qnetworkreply_local/minihttpserver.h new file mode 100644 index 0000000000..eb0697a6f8 --- /dev/null +++ b/tests/auto/network/access/qnetworkreply_local/minihttpserver.h @@ -0,0 +1,246 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#ifndef MINIHTTPSERVER_H +#define MINIHTTPSERVER_H + +#include <QtNetwork/qtnetworkglobal.h> + +#include <QtNetwork/qtcpserver.h> +#include <QtNetwork/qtcpsocket.h> +#include <QtNetwork/qlocalsocket.h> +#if QT_CONFIG(ssl) +# include <QtNetwork/qsslsocket.h> +#endif +#if QT_CONFIG(localserver) +# include <QtNetwork/qlocalserver.h> +#endif + +#include <QtCore/qpointer.h> +#include <QtCore/qhash.h> + +#include <utility> + +static inline QByteArray default200Response() +{ + return QByteArrayLiteral("HTTP/1.1 200 OK\r\n" + "Content-Type: text/plain\r\n" + "Content-Length: 12\r\n" + "\r\n" + "Hello World!"); +} +class MiniHttpServerV2 : public QObject +{ + Q_OBJECT + +public: + struct State; + +#if QT_CONFIG(localserver) + void bind(QLocalServer *server) + { + Q_ASSERT(!localServer); + localServer = server; + connect(server, &QLocalServer::newConnection, this, + &MiniHttpServerV2::incomingLocalConnection); + } +#endif + + void bind(QTcpServer *server) + { + Q_ASSERT(!tcpServer); + tcpServer = server; + connect(server, &QTcpServer::pendingConnectionAvailable, this, + &MiniHttpServerV2::incomingConnection); + } + + void setDataToTransmit(QByteArray data) { dataToTransmit = std::move(data); } + + void clearServerState() + { + auto copy = std::exchange(clientStates, {}); + for (auto [socket, _] : copy.asKeyValueRange()) { + if (auto *tcpSocket = qobject_cast<QTcpSocket *>(socket)) + tcpSocket->disconnectFromHost(); + else if (auto *localSocket = qobject_cast<QLocalSocket *>(socket)) + localSocket->disconnectFromServer(); + else + Q_UNREACHABLE_RETURN(); + socket->deleteLater(); + } + } + + bool hasPendingConnections() const + { + return +#if QT_CONFIG(localserver) + (localServer && localServer->hasPendingConnections()) || +#endif + (tcpServer && tcpServer->hasPendingConnections()); + } + + QString addressForScheme(QStringView scheme) const + { + using namespace Qt::StringLiterals; + if (scheme.startsWith("unix"_L1) || scheme.startsWith("local"_L1)) { +#if QT_CONFIG(localserver) + if (localServer) + return localServer->serverName(); +#endif + } else if (scheme == "http"_L1) { + if (tcpServer) + return "%1:%2"_L1.arg(tcpServer->serverAddress().toString(), + QString::number(tcpServer->serverPort())); + } + return {}; + } + + QList<State> peerStates() const { return clientStates.values(); } + +protected: +#if QT_CONFIG(localserver) + void incomingLocalConnection() + { + auto *socket = localServer->nextPendingConnection(); + connectSocketSignals(socket); + } +#endif + + void incomingConnection() + { + auto *socket = tcpServer->nextPendingConnection(); + connectSocketSignals(socket); + } + + void reply(QIODevice *socket) + { + Q_ASSERT(socket); + if (dataToTransmit.isEmpty()) { + emit socket->bytesWritten(0); // emulate having written the data + return; + } + if (!stopTransfer) + socket->write(dataToTransmit); + } + +private: + void connectSocketSignals(QIODevice *socket) + { + connect(socket, &QIODevice::readyRead, this, [this, socket]() { readyReadSlot(socket); }); + connect(socket, &QIODevice::bytesWritten, this, + [this, socket]() { bytesWrittenSlot(socket); }); +#if QT_CONFIG(ssl) + if (auto *sslSocket = qobject_cast<QSslSocket *>(socket)) + connect(sslSocket, &QSslSocket::sslErrors, this, &MiniHttpServerV2::slotSslErrors); +#endif + + if (auto *tcpSocket = qobject_cast<QTcpSocket *>(socket)) { + connect(tcpSocket, &QAbstractSocket::errorOccurred, this, &MiniHttpServerV2::slotError); + } else if (auto *localSocket = qobject_cast<QLocalSocket *>(socket)) { + connect(localSocket, &QLocalSocket::errorOccurred, this, + [this](QLocalSocket::LocalSocketError error) { + slotError(QAbstractSocket::SocketError(error)); + }); + } else { + Q_UNREACHABLE_RETURN(); + } + } + + void parseContentLength(State &st, QByteArrayView header) + { + qsizetype index = header.indexOf("\r\ncontent-length:"); + if (index == -1) + return; + st.foundContentLength = true; + + index += sizeof("\r\ncontent-length:") - 1; + const auto *end = std::find(header.cbegin() + index, header.cend(), '\r'); + QByteArrayView num = header.mid(index, std::distance(header.cbegin() + index, end)); + bool ok = false; + st.contentLength = num.toInt(&ok); + if (!ok) + st.contentLength = -1; + } + +private slots: +#if QT_CONFIG(ssl) + void slotSslErrors(const QList<QSslError> &errors) + { + QTcpSocket *currentClient = qobject_cast<QTcpSocket *>(sender()); + Q_ASSERT(currentClient); + qDebug() << "slotSslErrors" << currentClient->errorString() << errors; + } +#endif + void slotError(QAbstractSocket::SocketError err) + { + QTcpSocket *currentClient = qobject_cast<QTcpSocket *>(sender()); + Q_ASSERT(currentClient); + qDebug() << "slotError" << err << currentClient->errorString(); + } + +public slots: + + void readyReadSlot(QIODevice *socket) + { + if (stopTransfer) + return; + State &st = clientStates[socket]; + st.receivedData += socket->readAll(); + const qsizetype doubleEndlPos = st.receivedData.indexOf("\r\n\r\n"); + + if (doubleEndlPos != -1) { + const qsizetype endOfHeader = doubleEndlPos + 4; + st.contentRead = st.receivedData.size() - endOfHeader; + + if (!st.checkedContentLength) { + parseContentLength(st, QByteArrayView(st.receivedData).first(endOfHeader)); + st.checkedContentLength = true; + } + + if (st.contentRead < st.contentLength) + return; + + // multiple requests incoming, remove the bytes of the current one + if (multiple) + st.receivedData.remove(0, endOfHeader); + + reply(socket); + } + } + + void bytesWrittenSlot(QIODevice *socket) + { + // Disconnect and delete in next cycle (else Windows clients will fail with + // RemoteHostClosedError). + if (doClose && socket->bytesToWrite() == 0) { + disconnect(socket, nullptr, this, nullptr); + socket->deleteLater(); + } + } + +private: + QByteArray dataToTransmit = default200Response(); + + QTcpServer *tcpServer = nullptr; +#if QT_CONFIG(localserver) + QLocalServer *localServer = nullptr; +#endif + + QHash<QIODevice *, State> clientStates; + +public: + struct State + { + QByteArray receivedData; + qsizetype contentLength = 0; + qsizetype contentRead = 0; + bool checkedContentLength = false; + bool foundContentLength = false; + }; + + bool doClose = true; + bool multiple = false; + bool stopTransfer = false; +}; + +#endif // MINIHTTPSERVER_H diff --git a/tests/auto/network/access/qnetworkreply_local/tst_qnetworkreply_local.cpp b/tests/auto/network/access/qnetworkreply_local/tst_qnetworkreply_local.cpp new file mode 100644 index 0000000000..6d78c81593 --- /dev/null +++ b/tests/auto/network/access/qnetworkreply_local/tst_qnetworkreply_local.cpp @@ -0,0 +1,177 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QtNetwork/qtnetworkglobal.h> + +#include <QtTest/qtest.h> + +#include <QtNetwork/qnetworkreply.h> +#include <QtNetwork/qnetworkaccessmanager.h> + +#include "minihttpserver.h" + +using namespace Qt::StringLiterals; + +/* + The tests here are meant to be self-contained, using servers in the same + process if needed. This enables externals to more easily run the tests too. +*/ +class tst_QNetworkReply_local : public QObject +{ + Q_OBJECT +private slots: + void initTestCase_data(); + + void get(); + void post(); + +#if QT_CONFIG(localserver) + void fullServerName_data(); + void fullServerName(); +#endif +}; + +void tst_QNetworkReply_local::initTestCase_data() +{ + QTest::addColumn<QString>("scheme"); + + QTest::newRow("http") << "http"; +#if QT_CONFIG(localserver) + QTest::newRow("unix") << "unix+http"; + QTest::newRow("local") << "local+http"; // equivalent to unix, but test that it works +#endif +} + +static std::unique_ptr<MiniHttpServerV2> getServerForCurrentScheme() +{ + auto server = std::make_unique<MiniHttpServerV2>(); + QFETCH_GLOBAL(QString, scheme); + if (scheme.startsWith("unix"_L1) || scheme.startsWith("local"_L1)) { +#if QT_CONFIG(localserver) + QLocalServer *localServer = new QLocalServer(server.get()); + localServer->listen(u"qt_networkreply_test_"_s + % QLatin1StringView(QTest::currentTestFunction()) + % QString::number(QCoreApplication::applicationPid())); + server->bind(localServer); +#endif + } else if (scheme == "http") { + QTcpServer *tcpServer = new QTcpServer(server.get()); + tcpServer->listen(QHostAddress::LocalHost, 0); + server->bind(tcpServer); + } + return server; +} + +static QUrl getUrlForCurrentScheme(MiniHttpServerV2 *server) +{ + QFETCH_GLOBAL(QString, scheme); + const QString address = server->addressForScheme(scheme); + const QString urlString = QLatin1StringView("%1://%2").arg(scheme, address); + return { urlString }; +} + +void tst_QNetworkReply_local::get() +{ + std::unique_ptr<MiniHttpServerV2> server = getServerForCurrentScheme(); + const QUrl url = getUrlForCurrentScheme(server.get()); + + QNetworkAccessManager manager; + std::unique_ptr<QNetworkReply> reply(manager.get(QNetworkRequest(url))); + + const bool res = QTest::qWaitFor([reply = reply.get()] { return reply->isFinished(); }); + QVERIFY(res); + + QCOMPARE(reply->readAll(), QByteArray("Hello World!")); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); +} + +void tst_QNetworkReply_local::post() +{ + std::unique_ptr<MiniHttpServerV2> server = getServerForCurrentScheme(); + const QUrl url = getUrlForCurrentScheme(server.get()); + + QNetworkAccessManager manager; + const QByteArray payload = "Hello from the other side!"_ba; + QNetworkRequest req(url); + req.setHeader(QNetworkRequest::ContentTypeHeader, "text/plain"); + std::unique_ptr<QNetworkReply> reply(manager.post(req, payload)); + + const bool res = QTest::qWaitFor([reply = reply.get()] { return reply->isFinished(); }); + QVERIFY(res); + + QCOMPARE(reply->readAll(), QByteArray("Hello World!")); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + + auto states = server->peerStates(); + QCOMPARE(states.size(), 1); + + const auto &firstRequest = states.at(0); + + QVERIFY(firstRequest.checkedContentLength); + QCOMPARE(firstRequest.contentLength, payload.size()); + QCOMPARE_GT(firstRequest.receivedData.size(), payload.size() + 4); + QCOMPARE(firstRequest.receivedData.last(payload.size() + 4), "\r\n\r\n" + payload); +} + +#if QT_CONFIG(localserver) +void tst_QNetworkReply_local::fullServerName_data() +{ +#if defined(Q_OS_ANDROID) || defined(QT_PLATFORM_UIKIT) + QSKIP("While partially supported, the test as-is doesn't make sense on this platform."); +#else + + QTest::addColumn<QString>("hostAndPath"); + + QTest::newRow("dummy-host") << u"://irrelevant/test"_s; + QTest::newRow("no-host") << u":///test"_s; +#endif +} + +void tst_QNetworkReply_local::fullServerName() +{ + QFETCH_GLOBAL(QString, scheme); + if (!scheme.startsWith("unix"_L1) && !scheme.startsWith("local"_L1)) + return; // only relevant for local sockets + + MiniHttpServerV2 server; + QLocalServer localServer; + + QString path; +#ifdef Q_OS_WIN + path = uR"(\\.\pipe\qt_networkreply_test_fullServerName)"_s + % QString::number(QCoreApplication::applicationPid()); +#else + path = u"/tmp/qt_networkreply_test_fullServerName"_s + % QString::number(QCoreApplication::applicationPid()) % u".sock"_s; +#endif + + QVERIFY(localServer.listen(path)); + server.bind(&localServer); + + QFETCH(QString, hostAndPath); + QUrl url(scheme % hostAndPath); + QNetworkRequest req(url); + req.setAttribute(QNetworkRequest::FullLocalServerNameAttribute, path); + + QNetworkAccessManager manager; + std::unique_ptr<QNetworkReply> reply(manager.get(req)); + + const bool res = QTest::qWaitFor([reply = reply.get()] { return reply->isFinished(); }); + QVERIFY(res); + + QCOMPARE(reply->readAll(), QByteArray("Hello World!")); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + + const QByteArray receivedData = server.peerStates().at(0).receivedData; + const QByteArray expectedGet = "GET " % url.path().toUtf8() % " HTTP/1.1\r\n"; + QVERIFY(receivedData.startsWith(expectedGet)); + + const QByteArray expectedHost = "host: " % url.host().toUtf8() % "\r\n"; + QVERIFY(receivedData.contains(expectedHost)); +} +#endif + +QTEST_MAIN(tst_QNetworkReply_local) + +#include "tst_qnetworkreply_local.moc" +#include "moc_minihttpserver.cpp" diff --git a/tests/auto/network/access/qnetworkrequest/CMakeLists.txt b/tests/auto/network/access/qnetworkrequest/CMakeLists.txt index 2334165c3a..2c4a7dd7ca 100644 --- a/tests/auto/network/access/qnetworkrequest/CMakeLists.txt +++ b/tests/auto/network/access/qnetworkrequest/CMakeLists.txt @@ -1,12 +1,19 @@ -# Generated from qnetworkrequest.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qnetworkrequest Test: ##################################################################### -qt_add_test(tst_qnetworkrequest +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qnetworkrequest LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qnetworkrequest SOURCES tst_qnetworkrequest.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Network ) diff --git a/tests/auto/network/access/qnetworkrequest/qnetworkrequest.pro b/tests/auto/network/access/qnetworkrequest/qnetworkrequest.pro deleted file mode 100644 index c00c2c30a2..0000000000 --- a/tests/auto/network/access/qnetworkrequest/qnetworkrequest.pro +++ /dev/null @@ -1,5 +0,0 @@ -CONFIG += testcase -TARGET = tst_qnetworkrequest -SOURCES += tst_qnetworkrequest.cpp - -QT = core network testlib diff --git a/tests/auto/network/access/qnetworkrequest/tst_qnetworkrequest.cpp b/tests/auto/network/access/qnetworkrequest/tst_qnetworkrequest.cpp index 6637be0174..f0b02ae91d 100644 --- a/tests/auto/network/access/qnetworkrequest/tst_qnetworkrequest.cpp +++ b/tests/auto/network/access/qnetworkrequest/tst_qnetworkrequest.cpp @@ -1,37 +1,19 @@ -/**************************************************************************** -** -** 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 <QtCore/QUrl> +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QTest> + +#if QT_CONFIG(http) +#include <QtNetwork/QHttp1Configuration> +#include <QtNetwork/QHttp2Configuration> +#endif #include <QtNetwork/QNetworkRequest> #include <QtNetwork/QNetworkCookie> +#include <QtCore/QDateTime> +#include <QtCore/QTimeZone> +#include <QtCore/QUrl> + Q_DECLARE_METATYPE(QNetworkRequest::KnownHeaders) class tst_QNetworkRequest: public QObject @@ -53,6 +35,10 @@ private slots: void rawHeaderParsing_data(); void rawHeaderParsing(); void originatingObject(); + void setHeaders_data(); + void setHeaders(); + void operatorEqual_data(); + void operatorEqual(); void removeHeader(); }; @@ -188,11 +174,11 @@ void tst_QNetworkRequest::rawHeaderList_data() void tst_QNetworkRequest::rawHeaderList() { - QFETCH(QList<QByteArray>, set); + QFETCH(const QList<QByteArray>, set); QFETCH(QList<QByteArray>, expected); QNetworkRequest request; - foreach (QByteArray header, set) + for (const QByteArray &header : set) request.setRawHeader(header, "a value"); QList<QByteArray> got = request.rawHeaderList(); @@ -236,12 +222,30 @@ void tst_QNetworkRequest::setHeader_data() << QVariant(QDate(2007, 11, 01)) << true << "Last-Modified" << "Thu, 01 Nov 2007 00:00:00 GMT"; - QTest::newRow("Last-Modified-DateTime") << QNetworkRequest::LastModifiedHeader - << QVariant(QDateTime(QDate(2007, 11, 01), - QTime(18, 8, 30), - Qt::UTC)) - << true << "Last-Modified" - << "Thu, 01 Nov 2007 18:08:30 GMT"; + QTest::newRow("Last-Modified-DateTime-UTC") + << QNetworkRequest::LastModifiedHeader + << QVariant(QDateTime(QDate(2007, 11, 1), QTime(18, 8, 30), QTimeZone::UTC)) + << true << "Last-Modified" << "Thu, 01 Nov 2007 18:08:30 GMT"; + // QTBUG-80666: format dates correctly (as GMT) even if the date passed in isn't in UTC: + QTest::newRow("Last-Modified-DateTime-Local") + << QNetworkRequest::LastModifiedHeader + << QVariant(QDateTime(QDate(2007, 11, 1), QTime(18, 8, 30), QTimeZone::UTC).toLocalTime()) + << true << "Last-Modified" << "Thu, 01 Nov 2007 18:08:30 GMT"; + QTest::newRow("Last-Modified-DateTime-Offset") + << QNetworkRequest::LastModifiedHeader + << QVariant(QDateTime(QDate(2007, 11, 1), QTime(18, 8, 30), + QTimeZone::UTC).toOffsetFromUtc(3600)) + << true << "Last-Modified" << "Thu, 01 Nov 2007 18:08:30 GMT"; +#if QT_CONFIG(timezone) + QTimeZone cet("Europe/Oslo"); + if (cet.isValid()) { + QTest::newRow("Last-Modified-DateTime-CET") + << QNetworkRequest::LastModifiedHeader + << QVariant(QDateTime(QDate(2007, 11, 1), QTime(18, 8, 30), + QTimeZone::UTC).toTimeZone(cet)) + << true << "Last-Modified" << "Thu, 01 Nov 2007 18:08:30 GMT"; + } +#endif QTest::newRow("If-Modified-Since-Date") << QNetworkRequest::IfModifiedSinceHeader << QVariant(QDate(2017, 7, 01)) @@ -250,7 +254,7 @@ void tst_QNetworkRequest::setHeader_data() QTest::newRow("If-Modified-Since-DateTime") << QNetworkRequest::IfModifiedSinceHeader << QVariant(QDateTime(QDate(2017, 7, 01), QTime(3, 14, 15), - Qt::UTC)) + QTimeZone::UTC)) << true << "If-Modified-Since" << "Sat, 01 Jul 2017 03:14:15 GMT"; @@ -351,45 +355,45 @@ void tst_QNetworkRequest::rawHeaderParsing_data() << true << "Content-Type" << "text/html"; QTest::newRow("Content-Length") << QNetworkRequest::ContentLengthHeader << QVariant(qint64(1)) - << true << "Content-Length" << " 1 "; + << true << "Content-Length" << "1"; QTest::newRow("Location") << QNetworkRequest::LocationHeader << QVariant(QUrl("http://foo/with space")) << true << "Location" << "http://foo/with%20space"; QTest::newRow("Last-Modified-RFC1123") << QNetworkRequest::LastModifiedHeader << QVariant(QDateTime(QDate(1994, 11, 06), QTime(8, 49, 37), - Qt::UTC)) + QTimeZone::UTC)) << true << "Last-Modified" << "Sun, 06 Nov 1994 08:49:37 GMT"; QTest::newRow("Last-Modified-RFC850") << QNetworkRequest::LastModifiedHeader << QVariant(QDateTime(QDate(1994, 11, 06), QTime(8, 49, 37), - Qt::UTC)) + QTimeZone::UTC)) << true << "Last-Modified" << "Sunday, 06-Nov-94 08:49:37 GMT"; QTest::newRow("Last-Modified-asctime") << QNetworkRequest::LastModifiedHeader << QVariant(QDateTime(QDate(1994, 11, 06), QTime(8, 49, 37), - Qt::UTC)) + QTimeZone::UTC)) << true << "Last-Modified" << "Sun Nov 6 08:49:37 1994"; QTest::newRow("If-Modified-Since-RFC1123") << QNetworkRequest::IfModifiedSinceHeader << QVariant(QDateTime(QDate(1994, 8, 06), QTime(8, 49, 37), - Qt::UTC)) + QTimeZone::UTC)) << true << "If-Modified-Since" << "Sun, 06 Aug 1994 08:49:37 GMT"; QTest::newRow("If-Modified-Since-RFC850") << QNetworkRequest::IfModifiedSinceHeader << QVariant(QDateTime(QDate(1994, 8, 06), QTime(8, 49, 37), - Qt::UTC)) + QTimeZone::UTC)) << true << "If-Modified-Since" << "Sunday, 06-Aug-94 08:49:37 GMT"; QTest::newRow("If-Modified-Since-asctime") << QNetworkRequest::IfModifiedSinceHeader << QVariant(QDateTime(QDate(1994, 8, 06), QTime(8, 49, 37), - Qt::UTC)) + QTimeZone::UTC)) << true << "If-Modified-Since" << "Sun Aug 6 08:49:37 1994"; @@ -498,7 +502,7 @@ void tst_QNetworkRequest::rawHeaderParsing() QCOMPARE(QString(request.rawHeader(rawHeader.toLatin1())), rawValue); QCOMPARE(request.header(cookedHeader).isNull(), !success); - if (cookedValue.type() != QVariant::UserType) + if (cookedValue.metaType().id() < QMetaType::User) QCOMPARE(request.header(cookedHeader), cookedValue); else if (cookedValue.userType() == qMetaTypeId<QList<QNetworkCookie> >()) QCOMPARE(qvariant_cast<QList<QNetworkCookie> >(request.header(cookedHeader)), @@ -556,5 +560,155 @@ void tst_QNetworkRequest::originatingObject() QVERIFY(!request.originatingObject()); } +void tst_QNetworkRequest::setHeaders_data() +{ + QTest::addColumn<QHttpHeaders>("h"); + QTest::newRow("null") << QHttpHeaders(); + QHttpHeaders headers; + headers.append("name1", "value1"); + QTest::newRow("valid") << headers; +} + +void tst_QNetworkRequest::setHeaders() +{ + QFETCH(QHttpHeaders, h); + + QNetworkRequest r1; + + auto result = r1.headers(); + QVERIFY(result.isEmpty()); + + r1.setHeaders(h); + QCOMPARE(r1.headers().toListOfPairs(), h.toListOfPairs()); + + QNetworkRequest r2; + auto tmp = h; + r2.setHeaders(std::move(tmp)); + QCOMPARE(r2.headers().toListOfPairs(), h.toListOfPairs()); +} + +void tst_QNetworkRequest::operatorEqual_data() +{ + QTest::addColumn<QNetworkRequest>("a"); + QTest::addColumn<QNetworkRequest>("b"); + QTest::addColumn<bool>("expectedToMatch"); + QTest::newRow("null") << QNetworkRequest() << QNetworkRequest() << true; + + QNetworkRequest data1; + data1.setUrl(QUrl("http://qt-project.org")); + QTest::newRow("url-1-1") << data1 << QNetworkRequest() << false; + QTest::newRow("url-1-2") << data1 << data1 << true; + + QNetworkRequest data2; + QHttpHeaders headers; + headers.append("name1", "value1"); + data2.setHeaders(headers); + QTest::newRow("headers-2-1") << data2 << QNetworkRequest() << false; + QTest::newRow("headers-2-2") << data2 << data2 << true; + QTest::newRow("headers-2-3") << data2 << data1 << false; + + QNetworkRequest data3; + data3.setPeerVerifyName("peerName"); + QTest::newRow("peerName-3-1") << data3 << QNetworkRequest() << false; + QTest::newRow("peerName-3-2") << data3 << data3 << true; + QTest::newRow("peerName-3-3") << data3 << data1 << false; + QTest::newRow("peerName-3-4") << data3 << data2 << false; + + QNetworkRequest data4; + data4.setAttribute(QNetworkRequest::Http2AllowedAttribute, true); + QTest::newRow("attribute-4-1") << data4 << QNetworkRequest() << false; + QTest::newRow("attribute-4-2") << data4 << data4 << true; + QTest::newRow("attribute-4-3") << data4 << data1 << false; + QTest::newRow("attribute-4-4") << data4 << data2 << false; + QTest::newRow("attribute-4-5") << data4 << data3 << false; + + QNetworkRequest data5; + data5.setPriority(QNetworkRequest::Priority::HighPriority); + QTest::newRow("priority-5-1") << data5 << QNetworkRequest() << false; + QTest::newRow("priority-5-2") << data5 << data5 << true; + QTest::newRow("priority-5-3") << data5 << data1 << false; + QTest::newRow("priority-5-4") << data5 << data2 << false; + QTest::newRow("priority-5-5") << data5 << data3 << false; + QTest::newRow("priority-5-6") << data5 << data4 << false; + + QNetworkRequest data6; + data6.setMaximumRedirectsAllowed(3); + QTest::newRow("maxRedirects-6-1") << data6 << QNetworkRequest() << false; + QTest::newRow("maxRedirects-6-2") << data6 << data6 << true; + QTest::newRow("maxRedirects-6-3") << data6 << data1 << false; + QTest::newRow("maxRedirects-6-4") << data6 << data2 << false; + QTest::newRow("maxRedirects-6-5") << data6 << data3 << false; + QTest::newRow("maxRedirects-6-6") << data6 << data4 << false; + QTest::newRow("maxRedirects-6-7") << data6 << data5 << false; + +#if QT_CONFIG(http) + QNetworkRequest data7; + QHttp1Configuration http1Configuration; + http1Configuration.setNumberOfConnectionsPerHost(5); + data7.setHttp1Configuration(http1Configuration); + QTest::newRow("http1Config-7-1") << data7 << QNetworkRequest() << false; + QTest::newRow("http1Config-7-2") << data7 << data7 << true; + QTest::newRow("http1Config-7-3") << data7 << data1 << false; + QTest::newRow("http1Config-7-4") << data7 << data2 << false; + QTest::newRow("http1Config-7-5") << data7 << data3 << false; + QTest::newRow("http1Config-7-6") << data7 << data4 << false; + QTest::newRow("http1Config-7-7") << data7 << data5 << false; + QTest::newRow("http1Config-7-8") << data7 << data6 << false; + + QNetworkRequest data8; + QHttp2Configuration http2Configuration; + http2Configuration.setMaxFrameSize(16386); + data8.setHttp2Configuration(http2Configuration); + QTest::newRow("http2Config-8-1") << data8 << QNetworkRequest() << false; + QTest::newRow("http2Config-8-2") << data8 << data8 << true; + QTest::newRow("http2Config-8-3") << data8 << data1 << false; + QTest::newRow("http2Config-8-4") << data8 << data2 << false; + QTest::newRow("http2Config-8-5") << data8 << data3 << false; + QTest::newRow("http2Config-8-6") << data8 << data4 << false; + QTest::newRow("http2Config-8-7") << data8 << data5 << false; + QTest::newRow("http2Config-8-8") << data8 << data6 << false; + QTest::newRow("http2Config-8-9") << data8 << data7 << false; + + QNetworkRequest data9; + data9.setDecompressedSafetyCheckThreshold(-1); + QTest::newRow("threshold-9-1") << data9 << QNetworkRequest() << false; + QTest::newRow("threshold-9-2") << data9 << data9 << true; + QTest::newRow("threshold-9-3") << data9 << data1 << false; + QTest::newRow("threshold-9-4") << data9 << data2 << false; + QTest::newRow("threshold-9-5") << data9 << data3 << false; + QTest::newRow("threshold-9-6") << data9 << data4 << false; + QTest::newRow("threshold-9-7") << data9 << data5 << false; + QTest::newRow("threshold-9-8") << data9 << data6 << false; + QTest::newRow("threshold-9-9") << data9 << data7 << false; + QTest::newRow("threshold-9-10") << data9 << data8 << false; +#endif + +#if QT_CONFIG(http) || defined (Q_OS_WASM) + QNetworkRequest data10; + data10.setTransferTimeout(50000); + QTest::newRow("timeout-10-1") << data10 << QNetworkRequest() << false; + QTest::newRow("timeout-10-2") << data10 << data10 << true; + QTest::newRow("timeout-10-3") << data10 << data1 << false; + QTest::newRow("timeout-10-4") << data10 << data2 << false; + QTest::newRow("timeout-10-5") << data10 << data3 << false; + QTest::newRow("timeout-10-6") << data10 << data4 << false; + QTest::newRow("timeout-10-7") << data10 << data5 << false; + QTest::newRow("timeout-10-8") << data10 << data6 << false; + QTest::newRow("timeout-10-9") << data10 << data7 << false; + QTest::newRow("timeout-10-10") << data10 << data8 << false; + QTest::newRow("timeout-10-11") << data10 << data9 << false; +#endif +} + +// public bool operator==(const QNetworkRequest &other) const +void tst_QNetworkRequest::operatorEqual() +{ + QFETCH(QNetworkRequest, a); + QFETCH(QNetworkRequest, b); + QFETCH(bool, expectedToMatch); + + QCOMPARE(a == b, expectedToMatch); +} + QTEST_MAIN(tst_QNetworkRequest) #include "tst_qnetworkrequest.moc" diff --git a/tests/auto/network/access/qnetworkrequestfactory/CMakeLists.txt b/tests/auto/network/access/qnetworkrequestfactory/CMakeLists.txt new file mode 100644 index 0000000000..d2112de58f --- /dev/null +++ b/tests/auto/network/access/qnetworkrequestfactory/CMakeLists.txt @@ -0,0 +1,17 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qnetworkrequestfactory LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qnetworkrequestfactory + SOURCES + tst_qnetworkrequestfactory.cpp + LIBRARIES + Qt::Core + Qt::Test + Qt::Network +) diff --git a/tests/auto/network/access/qnetworkrequestfactory/tst_qnetworkrequestfactory.cpp b/tests/auto/network/access/qnetworkrequestfactory/tst_qnetworkrequestfactory.cpp new file mode 100644 index 0000000000..d04a7ff3ec --- /dev/null +++ b/tests/auto/network/access/qnetworkrequestfactory/tst_qnetworkrequestfactory.cpp @@ -0,0 +1,423 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QtTest/qtest.h> +#include <QtNetwork/qnetworkrequestfactory.h> +#ifndef QT_NO_SSL +#include <QtNetwork/qsslconfiguration.h> +#endif +#include <QtCore/qurlquery.h> +#include <QtCore/qurl.h> + +using namespace Qt::StringLiterals; +using namespace std::chrono_literals; + +class tst_QNetworkRequestFactory : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void urlAndPath_data(); + void urlAndPath(); + void queryParameters(); + void sslConfiguration(); + void headers(); + void bearerToken(); + void operators(); + void timeout(); + void userInfo(); + void priority(); + void attributes(); + +private: + const QUrl url1{u"http://foo.io"_s}; + const QUrl url2{u"http://bar.io"_s}; + const QByteArray bearerToken1{"bearertoken1"}; + const QByteArray bearerToken2{"bearertoken2"}; +}; + +void tst_QNetworkRequestFactory::urlAndPath_data() +{ + QTest::addColumn<QUrl>("baseUrl"); + QTest::addColumn<QString>("requestPath"); + QTest::addColumn<QUrl>("expectedRequestUrl"); + + QUrl base{"http://xyz.io"}; + QUrl result{"http://xyz.io/path/to"}; + QTest::newRow("baseUrl_nopath_noslash_1") << base << u""_s << base; + QTest::newRow("baseUrl_nopath_noslash_2") << base << u"/path/to"_s << result; + QTest::newRow("baseUrl_nopath_noslash_3") << base << u"path/to"_s << result; + + base.setUrl("http://xyz.io/"); + result.setUrl("http://xyz.io/path/to"); + QTest::newRow("baseUrl_nopath_withslash_1") << base << u""_s << base; + QTest::newRow("baseUrl_nopath_withslash_2") << base << u"/path/to"_s << result; + QTest::newRow("baseUrl_nopath_withslash_3") << base << u"path/to"_s << result; + + base.setUrl("http://xyz.io/v1"); + result.setUrl("http://xyz.io/v1/path/to"); + QTest::newRow("baseUrl_withpath_noslash_1") << base << u""_s << base; + QTest::newRow("baseUrl_withpath_noslash_2") << base << u"/path/to"_s << result; + QTest::newRow("baseUrl_withpath_noslash_3") << base << u"path/to"_s << result; + + base.setUrl("http://xyz.io/v1/"); + QTest::newRow("baseUrl_withpath_withslash_1") << base << u""_s << base; + QTest::newRow("baseUrl_withpath_withslash_2") << base << u"/path/to"_s << result; + QTest::newRow("baseUrl_withpath_withslash_3") << base << u"path/to"_s << result; + + // Currently we keep any double '//', but not sure if there is a use case for it, or could + // it be corrected to a single '/' + base.setUrl("http://xyz.io/v1//"); + result.setUrl("http://xyz.io/v1//path/to"); + QTest::newRow("baseUrl_withpath_doubleslash_1") << base << u""_s << base; + QTest::newRow("baseUrl_withpath_doubleslash_2") << base << u"/path/to"_s << result; + QTest::newRow("baseUrl_withpath_doubleslash_3") << base << u"path/to"_s << result; +} + +void tst_QNetworkRequestFactory::urlAndPath() +{ + QFETCH(QUrl, baseUrl); + QFETCH(QString, requestPath); + QFETCH(QUrl, expectedRequestUrl); + + // Set with constructor + QNetworkRequestFactory factory1{baseUrl}; + QCOMPARE(factory1.baseUrl(), baseUrl); + + // Set with setter calls + QNetworkRequestFactory factory2{}; + factory2.setBaseUrl(baseUrl); + QCOMPARE(factory2.baseUrl(), baseUrl); + + // Request path + QNetworkRequest request = factory1.createRequest(); + QCOMPARE(request.url(), baseUrl); // No path was provided for createRequest(), expect baseUrl + request = factory1.createRequest(requestPath); + QCOMPARE(request.url(), expectedRequestUrl); + + // Check the request path didn't change base url + QCOMPARE(factory1.baseUrl(), baseUrl); +} + +void tst_QNetworkRequestFactory::queryParameters() +{ + QNetworkRequestFactory factory({"http://example.com"}); + const QUrlQuery query1{{"q1k", "q1v"}}; + const QUrlQuery query2{{"q2k", "q2v"}}; + + // Set query parameters in createRequest() call + QCOMPARE(factory.createRequest(query1).url(), QUrl{"http://example.com?q1k=q1v"}); + QCOMPARE(factory.createRequest(query2).url(), QUrl{"http://example.com?q2k=q2v"}); + + // Set query parameters into the factory + factory.setQueryParameters(query1); + QUrlQuery resultQuery = factory.queryParameters(); + for (const auto &item: query1.queryItems()) { + QVERIFY(resultQuery.hasQueryItem(item.first)); + QCOMPARE(resultQuery.queryItemValue(item.first), item.second); + } + QCOMPARE(factory.createRequest().url(), QUrl{"http://example.com?q1k=q1v"}); + + // Set query parameters into both createRequest() and factory + QCOMPARE(factory.createRequest(query2).url(), QUrl{"http://example.com?q2k=q2v&q1k=q1v"}); + + // Clear query parameters + factory.clearQueryParameters(); + QVERIFY(factory.queryParameters().isEmpty()); + QCOMPARE(factory.createRequest().url(), QUrl{"http://example.com"}); + + const QString pathWithQuery{"content?raw=1"}; + // Set query parameters in per-request path + QCOMPARE(factory.createRequest(pathWithQuery).url(), + QUrl{"http://example.com/content?raw=1"}); + // Set query parameters in per-request path and the query parameter + QCOMPARE(factory.createRequest(pathWithQuery, query1).url(), + QUrl{"http://example.com/content?q1k=q1v&raw=1"}); + // Set query parameter in per-request path and into the factory + factory.setQueryParameters(query2); + QCOMPARE(factory.createRequest(pathWithQuery).url(), + QUrl{"http://example.com/content?raw=1&q2k=q2v"}); + // Set query parameters in per-request, as additional parameters, and into the factory + QCOMPARE(factory.createRequest(pathWithQuery, query1).url(), + QUrl{"http://example.com/content?q1k=q1v&raw=1&q2k=q2v"}); + + // Test that other than path and query items as part of path are ignored + factory.setQueryParameters(query1); + QRegularExpression re("The provided path*"); + QTest::ignoreMessage(QtMsgType::QtWarningMsg, re); + QCOMPARE(factory.createRequest("https://example2.com").url(), QUrl{"http://example.com?q1k=q1v"}); + QTest::ignoreMessage(QtMsgType::QtWarningMsg, re); + QCOMPARE(factory.createRequest("https://example2.com?q3k=q3v").url(), + QUrl{"http://example.com?q3k=q3v&q1k=q1v"}); +} + +void tst_QNetworkRequestFactory::sslConfiguration() +{ +#ifdef QT_NO_SSL + QSKIP("Skipping SSL tests, not supported by build"); +#else + // Two initially equal factories + QNetworkRequestFactory factory1{url1}; + QNetworkRequestFactory factory2{url1}; + + // Make two differing SSL configurations (for this test it's irrelevant how they differ) + QSslConfiguration config1; + config1.setProtocol(QSsl::TlsV1_2); + QSslConfiguration config2; + config2.setProtocol(QSsl::DtlsV1_2); + + // Set configuration and verify that the same config is returned + factory1.setSslConfiguration(config1); + QCOMPARE(factory1.sslConfiguration(), config1); + factory2.setSslConfiguration(config2); + QCOMPARE(factory2.sslConfiguration(), config2); + + // Verify requests are set with appropriate SSL configs + QNetworkRequest request1 = factory1.createRequest(); + QCOMPARE(request1.sslConfiguration(), config1); + QNetworkRequest request2 = factory2.createRequest(); + QCOMPARE(request2.sslConfiguration(), config2); +#endif +} + +void tst_QNetworkRequestFactory::headers() +{ + const QByteArray name1{"headername1"}; + const QByteArray name2{"headername2"}; + const QByteArray value1{"headervalue1"}; + const QByteArray value2{"headervalue2"}; + const QByteArray value3{"headervalue3"}; + + QNetworkRequestFactory factory{url1}; + // Initial state when no headers are set + QVERIFY(factory.commonHeaders().isEmpty()); + QVERIFY(factory.commonHeaders().values(name1).isEmpty()); + QVERIFY(!factory.commonHeaders().contains(name1)); + + // Set headers + QHttpHeaders h1; + h1.append(name1, value1); + factory.setCommonHeaders(h1); + QVERIFY(factory.commonHeaders().contains(name1)); + QCOMPARE(factory.commonHeaders().combinedValue(name1), value1); + QCOMPARE(factory.commonHeaders().size(), 1); + QVERIFY(factory.commonHeaders().values("nonexistent").isEmpty()); + QNetworkRequest request = factory.createRequest(); + QVERIFY(request.hasRawHeader(name1)); + QCOMPARE(request.rawHeader(name1), value1); + + // Check that empty header does not match + QVERIFY(!factory.commonHeaders().contains(""_ba)); + QVERIFY(factory.commonHeaders().values(""_ba).isEmpty()); + + // Clear headers + factory.clearCommonHeaders(); + QVERIFY(factory.commonHeaders().isEmpty()); + request = factory.createRequest(); + QVERIFY(!request.hasRawHeader(name1)); + + // Set headers with more entries + h1.clear(); + h1.append(name1, value1); + h1.append(name2, value2); + factory.setCommonHeaders(h1); + QVERIFY(factory.commonHeaders().contains(name1)); + QVERIFY(factory.commonHeaders().contains(name2)); + QCOMPARE(factory.commonHeaders().combinedValue(name1), value1); + QCOMPARE(factory.commonHeaders().combinedValue(name2), value2); + QCOMPARE(factory.commonHeaders().size(), 2); + request = factory.createRequest(); + QVERIFY(request.hasRawHeader(name1)); + QVERIFY(request.hasRawHeader(name2)); + QCOMPARE(request.rawHeader(name1), value1); + QCOMPARE(request.rawHeader(name2), value2); + // Append more values to pre-existing header name2 + h1.clear(); + h1.append(name1, value1); + h1.append(name1, value2); + h1.append(name1, value3); + factory.setCommonHeaders(h1); + QVERIFY(factory.commonHeaders().contains(name1)); + QCOMPARE(factory.commonHeaders().combinedValue(name1), value1 + ", " + value2 + ", " + value3); + request = factory.createRequest(); + QVERIFY(request.hasRawHeader(name1)); + QCOMPARE(request.rawHeader(name1), value1 + ", " + value2 + ", " + value3); +} + +void tst_QNetworkRequestFactory::bearerToken() +{ + const auto authHeader = "Authorization"_ba; + QNetworkRequestFactory factory{url1}; + QVERIFY(factory.bearerToken().isEmpty()); + + factory.setBearerToken(bearerToken1); + QCOMPARE(factory.bearerToken(), bearerToken1); + QNetworkRequest request = factory.createRequest(); + QVERIFY(request.hasRawHeader(authHeader)); + QCOMPARE(request.rawHeader(authHeader), "Bearer "_ba + bearerToken1); + + // Verify that bearerToken is not in debug output + QString debugOutput; + QDebug debug(&debugOutput); + debug << factory; + QVERIFY(debugOutput.contains("bearerToken = (is set)")); + QVERIFY(!debugOutput.contains(bearerToken1)); + + factory.setBearerToken(bearerToken2); + QCOMPARE(factory.bearerToken(), bearerToken2); + request = factory.createRequest(); + QVERIFY(request.hasRawHeader(authHeader)); + QCOMPARE(request.rawHeader(authHeader), "Bearer "_ba + bearerToken2); + + // Set authorization header manually + const auto value = "headervalue"_ba; + QHttpHeaders h1; + h1.append(authHeader, value); + factory.setCommonHeaders(h1); + request = factory.createRequest(); + QVERIFY(request.hasRawHeader(authHeader)); + // bearerToken has precedence over manually set header + QCOMPARE(request.rawHeader(authHeader), "Bearer "_ba + bearerToken2); + // clear bearer token, the manually set header is now used + factory.clearBearerToken(); + request = factory.createRequest(); + QVERIFY(request.hasRawHeader(authHeader)); + QCOMPARE(request.rawHeader(authHeader), value); +} + +void tst_QNetworkRequestFactory::operators() +{ + QNetworkRequestFactory factory1(url1); + + // Copy ctor + QNetworkRequestFactory factory2(factory1); + QCOMPARE(factory2.baseUrl(), factory1.baseUrl()); + + // Copy assignment + QNetworkRequestFactory factory3; + factory3 = factory2; + QCOMPARE(factory3.baseUrl(), factory2.baseUrl()); + + // Move assignment + QNetworkRequestFactory factory4; + factory4 = std::move(factory3); + QCOMPARE(factory4.baseUrl(), factory2.baseUrl()); + + // Verify implicit sharing + factory1.setBaseUrl(url2); + QCOMPARE(factory1.baseUrl(), url2); // changed + QCOMPARE(factory2.baseUrl(), url1); // remains + + // Move ctor + QNetworkRequestFactory factory5{std::move(factory4)}; + QCOMPARE(factory5.baseUrl(), factory2.baseUrl()); // the moved factory4 originates from factory2 + QCOMPARE(factory5.baseUrl(), url1); +} + +void tst_QNetworkRequestFactory::timeout() +{ + constexpr auto defaultTimeout = 0ms; + constexpr auto timeout = 150ms; + + QNetworkRequestFactory factory; + QNetworkRequest request = factory.createRequest(); + QCOMPARE(factory.transferTimeout(), defaultTimeout); + QCOMPARE(request.transferTimeoutAsDuration(), defaultTimeout); + + factory.setTransferTimeout(timeout); + request = factory.createRequest(); + QCOMPARE(factory.transferTimeout(), timeout); + QCOMPARE(request.transferTimeoutAsDuration(), timeout); +} + +void tst_QNetworkRequestFactory::userInfo() +{ + QNetworkRequestFactory factory; + QVERIFY(factory.userName().isEmpty()); + QVERIFY(factory.password().isEmpty()); + + const auto uname = u"a_username"_s; + const auto password = u"a_password"_s; + factory.setUserName(uname); + QCOMPARE(factory.userName(), uname); + factory.setPassword(password); + QCOMPARE(factory.password(), password); + + // Verify that debug output does not contain password + QString debugOutput; + QDebug debug(&debugOutput); + debug << factory; + QVERIFY(debugOutput.contains("password = (is set)")); + QVERIFY(!debugOutput.contains(password)); + + factory.clearUserName(); + factory.clearPassword(); + QVERIFY(factory.userName().isEmpty()); + QVERIFY(factory.password().isEmpty()); +} + +void tst_QNetworkRequestFactory::priority() +{ + QNetworkRequestFactory factory(u"http://example.com"_s); + QCOMPARE(factory.priority(), QNetworkRequest::NormalPriority); + auto request = factory.createRequest("/index.html"); + QCOMPARE(request.priority(), QNetworkRequest::NormalPriority); + + factory.setPriority(QNetworkRequest::HighPriority); + QCOMPARE(factory.priority(), QNetworkRequest::HighPriority); + request = factory.createRequest("/index.html"); + QCOMPARE(request.priority(), QNetworkRequest::HighPriority); +} + +void tst_QNetworkRequestFactory::attributes() +{ + const auto attribute1 = QNetworkRequest::Attribute::BackgroundRequestAttribute; + const auto attribute2 = QNetworkRequest::User; + QNetworkRequestFactory factory; + QNetworkRequest request; + + // Empty factory + QVERIFY(!factory.attribute(attribute1).isValid()); + request = factory.createRequest(); + QVERIFY(!request.attribute(attribute1).isValid()); + + // (Re-)set and clear individual attribute + factory.setAttribute(attribute1, true); + QVERIFY(factory.attribute(attribute1).isValid()); + QCOMPARE(factory.attribute(attribute1).toBool(), true); + request = factory.createRequest(); + QVERIFY(request.attribute(attribute1).isValid()); + QCOMPARE(request.attribute(attribute1).toBool(), true); + // Replace previous value + factory.setAttribute(attribute1, false); + QVERIFY(factory.attribute(attribute1).isValid()); + QCOMPARE(factory.attribute(attribute1).toBool(), false); + request = factory.createRequest(); + QVERIFY(request.attribute(attribute1).isValid()); + QCOMPARE(request.attribute(attribute1).toBool(), false); + // Clear individual attribute + factory.clearAttribute(attribute1); + QVERIFY(!factory.attribute(attribute1).isValid()); + + // Getter default value + QCOMPARE(factory.attribute(attribute2, 111).toInt(), 111); // default value returned + factory.setAttribute(attribute2, 222); + QCOMPARE(factory.attribute(attribute2, 111).toInt(), 222); // actual value returned + factory.clearAttribute(attribute2); + QCOMPARE(factory.attribute(attribute2, 111).toInt(), 111); // default value returned + + // Clear attributes + factory.setAttribute(attribute1, true); + factory.setAttribute(attribute2, 333); + QVERIFY(factory.attribute(attribute1).isValid()); + QVERIFY(factory.attribute(attribute2).isValid()); + factory.clearAttributes(); + QVERIFY(!factory.attribute(attribute1).isValid()); + QVERIFY(!factory.attribute(attribute2).isValid()); + request = factory.createRequest(); + QVERIFY(!request.attribute(attribute1).isValid()); + QVERIFY(!request.attribute(attribute2).isValid()); +} + +QTEST_MAIN(tst_QNetworkRequestFactory) +#include "tst_qnetworkrequestfactory.moc" diff --git a/tests/auto/network/access/qrestaccessmanager/CMakeLists.txt b/tests/auto/network/access/qrestaccessmanager/CMakeLists.txt new file mode 100644 index 0000000000..614248be28 --- /dev/null +++ b/tests/auto/network/access/qrestaccessmanager/CMakeLists.txt @@ -0,0 +1,17 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qrestaccessmanager LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qrestaccessmanager + SOURCES + tst_qrestaccessmanager.cpp + httptestserver.cpp httptestserver_p.h + LIBRARIES + Qt::Network + Qt::CorePrivate +) diff --git a/tests/auto/network/access/qrestaccessmanager/httptestserver.cpp b/tests/auto/network/access/qrestaccessmanager/httptestserver.cpp new file mode 100644 index 0000000000..25869eb46b --- /dev/null +++ b/tests/auto/network/access/qrestaccessmanager/httptestserver.cpp @@ -0,0 +1,268 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "httptestserver_p.h" + +#include <QtNetwork/qtcpsocket.h> + +#include <QtCore/qcoreapplication.h> + +#include <private/qlocale_p.h> + +using namespace Qt::StringLiterals; + +static constexpr char CRLF[] = "\r\n"; + +HttpTestServer::HttpTestServer(QObject *parent) : QTcpServer(parent) +{ + QObject::connect(this, &QTcpServer::newConnection, this, &HttpTestServer::handleConnected); + const auto ok = listen(QHostAddress::LocalHost); + Q_ASSERT(ok); +}; + +HttpTestServer::~HttpTestServer() +{ + if (isListening()) + close(); +} + +QUrl HttpTestServer::url() +{ + return QUrl(u"http://127.0.0.1:%1"_s.arg(serverPort())); +} + +void HttpTestServer::handleConnected() +{ + Q_ASSERT(!m_socket); // No socket must exist previously, this is a single-connection server + m_socket = nextPendingConnection(); + Q_ASSERT(m_socket); + QObject::connect(m_socket, &QTcpSocket::readyRead, + this, &HttpTestServer::handleDataAvailable); +} + +void HttpTestServer::handleDataAvailable() +{ + Q_ASSERT(m_socket); + bool ok = true; + + // Parse the incoming request data into the HttpData object + while (m_socket->bytesAvailable()) { + if (state == State::ReadingMethod && !(ok = readMethod(m_socket))) + qWarning("Invalid Method"); + if (ok && state == State::ReadingUrl && !(ok = readUrl(m_socket))) + qWarning("Invalid URL"); + if (ok && state == State::ReadingStatus && !(ok = readStatus(m_socket))) + qWarning("Invalid Status"); + if (ok && state == State::ReadingHeader && !(ok = readHeaders(m_socket))) + qWarning("Invalid Header"); + if (ok && state == State::ReadingBody && !(ok = readBody(m_socket))) + qWarning("Invalid Body"); + } // while bytes available + + Q_ASSERT(ok); + Q_ASSERT(m_handler); + Q_ASSERT(state == State::AllDone); + + if (auto values = m_request.headers.values( + QHttpHeaders::WellKnownHeader::Host); !values.empty()) { + const auto parts = values.first().split(':'); + m_request.url.setHost(parts.at(0)); + if (parts.size() == 2) + m_request.url.setPort(parts.at(1).toUInt()); + } + HttpData response; + ResponseControl control; + // Inform the testcase about request and ask for response data + m_handler(m_request, response, control); + + QByteArray responseMessage; + responseMessage += "HTTP/1.1 "; + responseMessage += QByteArray::number(response.status); + responseMessage += CRLF; + // Insert headers if any + for (const auto &[name,value] : response.headers.toListOfPairs()) { + responseMessage += name; + responseMessage += ": "; + responseMessage += value; + responseMessage += CRLF; + } + responseMessage += CRLF; + /* + qDebug() << "HTTPTestServer received request" + << "\nMethod:" << m_request.method + << "\nHeaders:" << m_request.headers + << "\nBody:" << m_request.body; + */ + if (control.respond) { + if (control.responseChunkSize <= 0) { + responseMessage += response.body; + // qDebug() << "HTTPTestServer response:" << responseMessage; + m_socket->write(responseMessage); + } else { + // Respond in chunks, first write the headers + // qDebug() << "HTTPTestServer response:" << responseMessage; + m_socket->write(responseMessage); + // Then write bodydata in chunks, while allowing the testcase to process as well + QByteArray chunk; + while (!response.body.isEmpty()) { + chunk = response.body.left(control.responseChunkSize); + response.body.remove(0, control.responseChunkSize); + // qDebug() << "SERVER writing chunk" << chunk; + m_socket->write(chunk); + m_socket->flush(); + m_socket->waitForBytesWritten(); + // Process events until testcase indicates it's ready for next chunk. + // This way we can control the bytes the testcase gets in each chunk + control.readyForNextChunk = false; + while (!control.readyForNextChunk) + QCoreApplication::processEvents(); + } + } + } + m_socket->disconnectFromHost(); + m_request = {}; + m_socket = nullptr; // deleted by QTcpServer during destruction + state = State::ReadingMethod; + fragment.clear(); +} + +bool HttpTestServer::readMethod(QTcpSocket *socket) +{ + bool finished = false; + while (socket->bytesAvailable() && !finished) { + const auto c = socket->read(1).at(0); + if (ascii_isspace(c)) + finished = true; + else if (std::isupper(c) && fragment.size() < 8) + fragment += c; + else + return false; + } + if (finished) { + if (fragment == "HEAD") + method = Method::Head; + else if (fragment == "GET") + method = Method::Get; + else if (fragment == "PUT") + method = Method::Put; + else if (fragment == "PATCH") + method = Method::Patch; + else if (fragment == "POST") + method = Method::Post; + else if (fragment == "DELETE") + method = Method::Delete; + else if (fragment == "FOOBAR") // used by custom verb/method tests + method = Method::Custom; + else + qWarning("Invalid operation %s", fragment.data()); + + state = State::ReadingUrl; + m_request.method = fragment; + fragment.clear(); + + return method != Method::Unknown; + } + return true; +} + +bool HttpTestServer::readUrl(QTcpSocket *socket) +{ + bool finished = false; + while (socket->bytesAvailable() && !finished) { + const auto c = socket->read(1).at(0); + if (std::isspace(c)) + finished = true; + else + fragment += c; + } + if (finished) { + if (!fragment.startsWith('/')) { + qWarning("Invalid URL path %s", fragment.constData()); + return false; + } + m_request.url = QStringLiteral("http://127.0.0.1:") + QString::number(m_request.port) + + QString::fromUtf8(fragment); + state = State::ReadingStatus; + if (!m_request.url.isValid()) { + qWarning("Invalid URL %s", fragment.constData()); + return false; + } + fragment.clear(); + } + return true; +} + +bool HttpTestServer::readStatus(QTcpSocket *socket) +{ + bool finished = false; + while (socket->bytesAvailable() && !finished) { + fragment += socket->read(1); + if (fragment.endsWith(CRLF)) { + finished = true; + fragment.resize(fragment.size() - 2); + } + } + if (finished) { + if (!std::isdigit(fragment.at(fragment.size() - 3)) || + fragment.at(fragment.size() - 2) != '.' || + !std::isdigit(fragment.at(fragment.size() - 1))) { + qWarning("Invalid version"); + return false; + } + m_request.version = std::pair(fragment.at(fragment.size() - 3) - '0', + fragment.at(fragment.size() - 1) - '0'); + state = State::ReadingHeader; + fragment.clear(); + } + return true; +} + +bool HttpTestServer::readHeaders(QTcpSocket *socket) +{ + while (socket->bytesAvailable()) { + fragment += socket->read(1); + if (fragment.endsWith(CRLF)) { + if (fragment == CRLF) { + state = State::ReadingBody; + fragment.clear(); + return true; + } else { + fragment.chop(2); + const int index = fragment.indexOf(':'); + if (index == -1) + return false; + + QByteArray key = fragment.sliced(0, index).trimmed(); + QByteArray value = fragment.sliced(index + 1).trimmed(); + m_request.headers.append(key, value); + fragment.clear(); + } + } + } + return true; +} + +bool HttpTestServer::readBody(QTcpSocket *socket) +{ + qint64 bytesLeft = 0; + if (auto values = m_request.headers.values( + QHttpHeaders::WellKnownHeader::ContentLength); !values.empty()) { + bool conversionResult; + bytesLeft = values.first().toInt(&conversionResult); + if (!conversionResult) + return false; + fragment.resize(bytesLeft); + } + while (bytesLeft) { + qint64 got = socket->read(&fragment.data()[fragment.size() - bytesLeft], bytesLeft); + if (got < 0) + return false; // error + bytesLeft -= got; + if (bytesLeft) + qApp->processEvents(); + } + fragment.swap(m_request.body); + state = State::AllDone; + return true; +} + diff --git a/tests/auto/network/access/qrestaccessmanager/httptestserver_p.h b/tests/auto/network/access/qrestaccessmanager/httptestserver_p.h new file mode 100644 index 0000000000..0a94b2c8a6 --- /dev/null +++ b/tests/auto/network/access/qrestaccessmanager/httptestserver_p.h @@ -0,0 +1,90 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#ifndef QRESTACCESSSMANAGER_HTTPTESTSERVER_P_H +#define QRESTACCESSSMANAGER_HTTPTESTSERVER_P_H + +#include <QtNetwork/qtcpserver.h> +#include <QtNetwork/qhttpheaders.h> + +#include <QtCore/qmap.h> +#include <QtCore/qurl.h> + +#include <functional> + +// This struct is used for parsing the incoming network request data into, as well +// as getting the response data from the testcase +struct HttpData { + QUrl url; + int status = 0; + QByteArray body; + QByteArray method; + quint16 port = 0; + QPair<quint8, quint8> version; + QHttpHeaders headers; +}; + +struct ResponseControl +{ + bool respond = true; + qsizetype responseChunkSize = -1; + bool readyForNextChunk = true; +}; + +// Simple HTTP server. Currently supports only one concurrent connection +class HttpTestServer : public QTcpServer +{ + Q_OBJECT + +public: + explicit HttpTestServer(QObject *parent = nullptr); + ~HttpTestServer() override; + + // Returns this server's URL for the testcase to send requests to + QUrl url(); + + enum class State { + ReadingMethod, + ReadingUrl, + ReadingStatus, + ReadingHeader, + ReadingBody, + AllDone + } state = State::ReadingMethod; + + enum class Method { + Unknown, + Head, + Get, + Put, + Patch, + Post, + Delete, + Custom, + } method = Method::Unknown; + + // Parsing helpers for incoming data => HttpData + bool readMethod(QTcpSocket *socket); + bool readUrl(QTcpSocket *socket); + bool readStatus(QTcpSocket *socket); + bool readHeaders(QTcpSocket *socket); + bool readBody(QTcpSocket *socket); + // Parsing-time buffer in case data is received a small chunk at a time (readyRead()) + QByteArray fragment; + + // Settable callback for testcase. Gives the received request data, and takes in response data + using Handler = std::function<void(const HttpData &request, HttpData &response, + ResponseControl &control)>; + void setHandler(Handler handler) { m_handler = std::move(handler); } + +private slots: + void handleConnected(); + void handleDataAvailable(); + +private: + QTcpSocket *m_socket = nullptr; + HttpData m_request; + Handler m_handler = nullptr; +}; + +#endif // QRESTACCESSSMANAGER_HTTPTESTSERVER_P_H diff --git a/tests/auto/network/access/qrestaccessmanager/tst_qrestaccessmanager.cpp b/tests/auto/network/access/qrestaccessmanager/tst_qrestaccessmanager.cpp new file mode 100644 index 0000000000..d6bdda76ca --- /dev/null +++ b/tests/auto/network/access/qrestaccessmanager/tst_qrestaccessmanager.cpp @@ -0,0 +1,876 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "httptestserver_p.h" + +#if QT_CONFIG(http) +#include <QtNetwork/qhttpmultipart.h> +#endif +#include <QtNetwork/qrestaccessmanager.h> +#include <QtNetwork/qauthenticator.h> +#include <QtNetwork/qnetworkreply.h> +#include <QtNetwork/qnetworkrequestfactory.h> +#include <QtNetwork/qrestreply.h> + +#include <QTest> +#include <QtTest/qsignalspy.h> + +#include <QtCore/private/qglobal_p.h> // for access to Qt's feature system +#include <QtCore/qbuffer.h> +#include <QtCore/qjsonobject.h> +#include <QtCore/qjsondocument.h> +#include <QtCore/qjsonarray.h> +#include <QtCore/qstringconverter.h> + +using namespace Qt::StringLiterals; +using namespace std::chrono_literals; + +using Header = QHttpHeaders::WellKnownHeader; + +class tst_QRestAccessManager : public QObject +{ + Q_OBJECT + +private slots: + void initialization(); + void destruction(); + void callbacks(); +#if QT_CONFIG(http) + void requests(); +#endif + void reply(); + void errors(); + void body(); + void json(); + void text(); + void textStreaming(); + +private: + void memberHandler(QRestReply &reply); + + friend class Transient; + QList<QNetworkReply*> m_expectedReplies; + QList<QNetworkReply*> m_actualReplies; +}; + +void tst_QRestAccessManager::initialization() +{ + QTest::ignoreMessage(QtMsgType::QtWarningMsg, "QRestAccessManager: QNetworkAccesManager is nullptr"); + QRestAccessManager manager1(nullptr); + QVERIFY(!manager1.networkAccessManager()); + + QNetworkAccessManager qnam; + QRestAccessManager manager2(&qnam); + QVERIFY(manager2.networkAccessManager()); +} + +void tst_QRestAccessManager::reply() +{ + QNetworkAccessManager qnam; + + QNetworkReply *nr = qnam.get(QNetworkRequest(QUrl{"someurl"})); + QRestReply rr1(nr); + QCOMPARE(rr1.networkReply(), nr); + + // Move-construct + QRestReply rr2(std::move(rr1)); + QCOMPARE(rr2.networkReply(), nr); + + // Move-assign + QTest::ignoreMessage(QtMsgType::QtWarningMsg, "QRestReply: QNetworkReply is nullptr"); + QRestReply rr3(nullptr); + rr3 = std::move(rr2); + QCOMPARE(rr3.networkReply(), nr); +} + +#define VERIFY_REPLY_OK(METHOD) \ +{ \ + QTRY_VERIFY(networkReply); \ + QRestReply restReply(networkReply); \ + QCOMPARE(serverSideRequest.method, METHOD); \ + QVERIFY(restReply.isSuccess()); \ + QVERIFY(!restReply.hasError()); \ + networkReply->deleteLater(); \ + networkReply = nullptr; \ +} + +#if QT_CONFIG(http) +void tst_QRestAccessManager::requests() +{ + // A basic test for each HTTP method against the local testserver. + QNetworkAccessManager qnam; + QRestAccessManager manager(&qnam); + HttpTestServer server; + QTRY_VERIFY(server.isListening()); + QNetworkRequest request(server.url()); + request.setRawHeader("Content-Type"_ba, "text/plain"); // To silence missing content-type warn + QNetworkReply *networkReply = nullptr; + std::unique_ptr<QHttpMultiPart> multiPart; + QHttpPart part; + part.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"text\"")); + part.setBody("multipart_text"); + QByteArray ioDeviceData{"io_device_data"_ba}; + QBuffer bufferIoDevice(&ioDeviceData); + + HttpData serverSideRequest; // The request data the server received + HttpData serverSideResponse; // The response data the server responds with + serverSideResponse.status = 200; + server.setHandler([&](const HttpData &request, HttpData &response, ResponseControl&) { + serverSideRequest = request; + response = serverSideResponse; + + }); + auto callback = [&](QRestReply &reply) { networkReply = reply.networkReply(); }; + const QByteArray byteArrayData{"some_data"_ba}; + const QJsonObject jsonObjectData{{"key1", "value1"}, {"key2", "value2"}}; + const QJsonArray jsonArrayData{{"arrvalue1", "arrvalue2", QJsonObject{{"key1", "value1"}}}}; + const QVariantMap variantMapData{{"key1", "value1"}, {"key2", "value2"}}; + const QByteArray methodDELETE{"DELETE"_ba}; + const QByteArray methodHEAD{"HEAD"_ba}; + const QByteArray methodPOST{"POST"_ba}; + const QByteArray methodGET{"GET"_ba}; + const QByteArray methodPUT{"PUT"_ba}; + const QByteArray methodPATCH{"PATCH"_ba}; + const QByteArray methodCUSTOM{"FOOBAR"_ba}; + + // DELETE + manager.deleteResource(request, this, callback); + VERIFY_REPLY_OK(methodDELETE); + QCOMPARE(serverSideRequest.body, ""_ba); + + // HEAD + manager.head(request, this, callback); + VERIFY_REPLY_OK(methodHEAD); + QCOMPARE(serverSideRequest.body, ""_ba); + + // GET + manager.get(request, this, callback); + VERIFY_REPLY_OK(methodGET); + QCOMPARE(serverSideRequest.body, ""_ba); + + manager.get(request, byteArrayData, this, callback); + VERIFY_REPLY_OK(methodGET); + QCOMPARE(serverSideRequest.body, byteArrayData); + + manager.get(request, QJsonDocument{jsonObjectData}, this, callback); + VERIFY_REPLY_OK(methodGET); + QCOMPARE(QJsonDocument::fromJson(serverSideRequest.body).object(), jsonObjectData); + + manager.get(request, &bufferIoDevice, this, callback); + VERIFY_REPLY_OK(methodGET); + QCOMPARE(serverSideRequest.body, ioDeviceData); + + // CUSTOM + manager.sendCustomRequest(request, methodCUSTOM, byteArrayData, this, callback); + VERIFY_REPLY_OK(methodCUSTOM); + QCOMPARE(serverSideRequest.body, byteArrayData); + + manager.sendCustomRequest(request, methodCUSTOM, &bufferIoDevice, this, callback); + VERIFY_REPLY_OK(methodCUSTOM); + QCOMPARE(serverSideRequest.body, ioDeviceData); + + multiPart.reset(new QHttpMultiPart(QHttpMultiPart::FormDataType)); + multiPart->append(part); + manager.sendCustomRequest(request, methodCUSTOM, multiPart.get(), this, callback); + VERIFY_REPLY_OK(methodCUSTOM); + QVERIFY(serverSideRequest.body.contains("--boundary"_ba)); + QVERIFY(serverSideRequest.body.contains("multipart_text"_ba)); + + // POST + manager.post(request, byteArrayData, this, callback); + VERIFY_REPLY_OK(methodPOST); + QCOMPARE(serverSideRequest.body, byteArrayData); + + manager.post(request, QJsonDocument{jsonObjectData}, this, callback); + VERIFY_REPLY_OK(methodPOST); + QCOMPARE(QJsonDocument::fromJson(serverSideRequest.body).object(), jsonObjectData); + + manager.post(request, QJsonDocument{jsonArrayData}, this, callback); + VERIFY_REPLY_OK(methodPOST); + QCOMPARE(QJsonDocument::fromJson(serverSideRequest.body).array(), jsonArrayData); + + manager.post(request, variantMapData, this, callback); + VERIFY_REPLY_OK(methodPOST); + QCOMPARE(QJsonDocument::fromJson(serverSideRequest.body).object(), jsonObjectData); + + multiPart = std::make_unique<QHttpMultiPart>(QHttpMultiPart::FormDataType); + multiPart->append(part); + manager.post(request, multiPart.get(), this, callback); + VERIFY_REPLY_OK(methodPOST); + QVERIFY(serverSideRequest.body.contains("--boundary"_ba)); + QVERIFY(serverSideRequest.body.contains("multipart_text"_ba)); + + manager.post(request, &bufferIoDevice, this, callback); + VERIFY_REPLY_OK(methodPOST); + QCOMPARE(serverSideRequest.body, ioDeviceData); + + // PUT + manager.put(request, byteArrayData, this, callback); + VERIFY_REPLY_OK(methodPUT); + QCOMPARE(serverSideRequest.body, byteArrayData); + + manager.put(request, QJsonDocument{jsonObjectData}, this, callback); + VERIFY_REPLY_OK(methodPUT); + QCOMPARE(QJsonDocument::fromJson(serverSideRequest.body).object(), jsonObjectData); + + manager.put(request, QJsonDocument{jsonArrayData}, this, callback); + VERIFY_REPLY_OK(methodPUT); + QCOMPARE(QJsonDocument::fromJson(serverSideRequest.body).array(), jsonArrayData); + + manager.put(request, variantMapData, this, callback); + VERIFY_REPLY_OK(methodPUT); + QCOMPARE(QJsonDocument::fromJson(serverSideRequest.body).object(), jsonObjectData); + + multiPart = std::make_unique<QHttpMultiPart>(QHttpMultiPart::FormDataType); + multiPart->append(part); + manager.put(request, multiPart.get(), this, callback); + VERIFY_REPLY_OK(methodPUT); + QVERIFY(serverSideRequest.body.contains("--boundary"_ba)); + QVERIFY(serverSideRequest.body.contains("multipart_text"_ba)); + + manager.put(request, &bufferIoDevice, this, callback); + VERIFY_REPLY_OK(methodPUT); + QCOMPARE(serverSideRequest.body, ioDeviceData); + + // PATCH + manager.patch(request, byteArrayData, this, callback); + VERIFY_REPLY_OK(methodPATCH); + QCOMPARE(serverSideRequest.body, byteArrayData); + + manager.patch(request, QJsonDocument{jsonObjectData}, this, callback); + VERIFY_REPLY_OK(methodPATCH); + QCOMPARE(QJsonDocument::fromJson(serverSideRequest.body).object(), jsonObjectData); + + manager.patch(request, QJsonDocument{jsonArrayData}, this, callback); + VERIFY_REPLY_OK(methodPATCH); + QCOMPARE(QJsonDocument::fromJson(serverSideRequest.body).array(), jsonArrayData); + + manager.patch(request, variantMapData, this, callback); + VERIFY_REPLY_OK(methodPATCH); + QCOMPARE(QJsonDocument::fromJson(serverSideRequest.body).object(), jsonObjectData); + + manager.patch(request, &bufferIoDevice, this, callback); + VERIFY_REPLY_OK(methodPATCH); + QCOMPARE(serverSideRequest.body, ioDeviceData); + + //These must NOT compile + //manager.get(request, [](){}); // callback without context object + //manager.get(request, ""_ba, [](){}); // callback without context object + //manager.get(request, QString()); // wrong datatype + //manager.get(request, 123); // wrong datatype + //manager.post(request, QString()); // wrong datatype + //manager.put(request, 123); // wrong datatype + //manager.post(request); // data is required + //manager.put(request, QString()); // wrong datatype + //manager.put(request); // data is required + //manager.patch(request, 123); // wrong datatype + //manager.patch(request, QString()); // wrong datatype + //manager.patch(request); // data is required + //manager.deleteResource(request, "f"_ba); // data not allowed + //manager.head(request, "f"_ba); // data not allowed + //manager.post(request, ""_ba, this, [](int param){}); // Wrong callback signature + //manager.get(request, this, [](int param){}); // Wrong callback signature + //manager.sendCustomRequest(request, this, [](){}); // No verb && no data + //manager.sendCustomRequest(request, "FOOBAR", this, [](){}); // No verb || no data +} +#endif + +void tst_QRestAccessManager::memberHandler(QRestReply &reply) +{ + m_actualReplies.append(reply.networkReply()); +} + +// Class that is destroyed during an active request. +// Used to test that the callbacks won't be called in these cases +class Transient : public QObject +{ + Q_OBJECT +public: + explicit Transient(tst_QRestAccessManager *test) : QObject(test), m_test(test) {} + + void memberHandler(QRestReply &reply) + { + m_test->m_actualReplies.append(reply.networkReply()); + } + +private: + tst_QRestAccessManager *m_test = nullptr; +}; + +template <typename Functor, std::enable_if_t< + QtPrivate::AreFunctionsCompatible<void(*)(QRestReply&), Functor>::value, bool> = true> +inline constexpr bool isCompatibleCallback(Functor &&) { return true; } + +template <typename Functor, std::enable_if_t< + !QtPrivate::AreFunctionsCompatible<void(*)(QRestReply&), Functor>::value, bool> = true, + typename = void> +inline constexpr bool isCompatibleCallback(Functor &&) { return false; } + +void tst_QRestAccessManager::callbacks() +{ + QNetworkAccessManager qnam; + QRestAccessManager manager(&qnam); + + QNetworkRequest request{u"i_dont_exist"_s}; // Will result in ProtocolUnknown error + + auto lambdaHandler = [this](QRestReply &reply) { m_actualReplies.append(reply.networkReply()); }; + Transient *transient = nullptr; + QByteArray data{"some_data"}; + + // Compile-time tests for callback signatures + static_assert(isCompatibleCallback([](QRestReply&){})); // Correct signature + static_assert(isCompatibleCallback(lambdaHandler)); + static_assert(isCompatibleCallback(&Transient::memberHandler)); + static_assert(isCompatibleCallback([](){})); // Less parameters are allowed + + static_assert(!isCompatibleCallback([](QString){})); // Wrong parameter type + static_assert(!isCompatibleCallback([](QRestReply*){})); // Wrong parameter type + static_assert(!isCompatibleCallback([](const QString &){})); // Wrong parameter type + static_assert(!isCompatibleCallback([](QRestReply&, QString){})); // Too many parameters + + // -- Test without data + // Without callback using signals and slot + QNetworkReply* reply = manager.get(request); + m_expectedReplies.append(reply); + QObject::connect(reply, &QNetworkReply::finished, this, + [this, reply](){m_actualReplies.append(reply);}); + + // With lambda callback, without context object + m_expectedReplies.append(manager.get(request, nullptr, lambdaHandler)); + m_expectedReplies.append(manager.get(request, nullptr, + [this](QRestReply &reply){m_actualReplies.append(reply.networkReply());})); + // With lambda callback and context object + m_expectedReplies.append(manager.get(request, this, lambdaHandler)); + m_expectedReplies.append(manager.get(request, this, + [this](QRestReply &reply){m_actualReplies.append(reply.networkReply());})); + // With member callback and context object + m_expectedReplies.append(manager.get(request, this, &tst_QRestAccessManager::memberHandler)); + // With context object that is destroyed, there should be no callback or eg. crash. + transient = new Transient(this); + manager.get(request, transient, &Transient::memberHandler); // Reply not added to expecteds + delete transient; + + // Let requests finish + QTRY_COMPARE(m_actualReplies.size(), m_expectedReplies.size()); + for (auto reply: m_actualReplies) { + QRestReply restReply(reply); + QVERIFY(!restReply.isSuccess()); + QVERIFY(restReply.hasError()); + QCOMPARE(restReply.error(), QNetworkReply::ProtocolUnknownError); + QCOMPARE(restReply.networkReply()->isFinished(), true); + restReply.networkReply()->deleteLater(); + } + m_actualReplies.clear(); + m_expectedReplies.clear(); + + // -- Test with data + // With lambda callback, without context object + m_expectedReplies.append(manager.post(request, data, nullptr, lambdaHandler)); + m_expectedReplies.append(manager.post(request, data, nullptr, + [this](QRestReply &reply){m_actualReplies.append(reply.networkReply());})); + // With lambda callback and context object + m_expectedReplies.append(manager.post(request, data, this, lambdaHandler)); + m_expectedReplies.append(manager.post(request, data, this, + [this](QRestReply &reply){m_actualReplies.append(reply.networkReply());})); + // With member callback and context object + m_expectedReplies.append(manager.post(request, data, + this, &tst_QRestAccessManager::memberHandler)); + // With context object that is destroyed, there should be no callback or eg. crash + transient = new Transient(this); + manager.post(request, data, transient, &Transient::memberHandler); // Note: reply not expected + delete transient; + + // Let requests finish + QTRY_COMPARE(m_actualReplies.size(), m_expectedReplies.size()); + for (auto reply: m_actualReplies) { + QRestReply restReply(reply); + QVERIFY(!restReply.isSuccess()); + QVERIFY(restReply.hasError()); + QCOMPARE(restReply.error(), QNetworkReply::ProtocolUnknownError); + QCOMPARE(restReply.networkReply()->isFinished(), true); + reply->deleteLater(); + } + m_actualReplies.clear(); + m_expectedReplies.clear(); + + // -- Test GET with data separately, as GET provides methods that are usable with and + // without data, and fairly easy to get the qrestaccessmanager.h template SFINAE subtly wrong. + // With lambda callback, without context object + m_expectedReplies.append(manager.get(request, data, nullptr, lambdaHandler)); + m_expectedReplies.append(manager.get(request, data, nullptr, + [this](QRestReply &reply){m_actualReplies.append(reply.networkReply());})); + // With lambda callback and context object + m_expectedReplies.append(manager.get(request, data, this, lambdaHandler)); + m_expectedReplies.append(manager.get(request, data, this, + [this](QRestReply &reply){m_actualReplies.append(reply.networkReply());})); + // With member callback and context object + m_expectedReplies.append(manager.get(request, data, + this, &tst_QRestAccessManager::memberHandler)); + // With context object that is destroyed, there should be no callback or eg. crash + transient = new Transient(this); + manager.get(request, data, transient, &Transient::memberHandler); // Reply not added + delete transient; + + // Let requests finish + QTRY_COMPARE(m_actualReplies.size(), m_expectedReplies.size()); + for (auto reply: m_actualReplies) { + QRestReply restReply(reply); + QVERIFY(!restReply.isSuccess()); + QVERIFY(restReply.hasError()); + QCOMPARE(restReply.error(), QNetworkReply::ProtocolUnknownError); + QCOMPARE(restReply.networkReply()->isFinished(), true); + restReply.networkReply()->deleteLater(); + } + m_actualReplies.clear(); + m_expectedReplies.clear(); +} + +void tst_QRestAccessManager::destruction() +{ + std::unique_ptr<QNetworkAccessManager> qnam = std::make_unique<QNetworkAccessManager>(); + std::unique_ptr<QRestAccessManager> manager = std::make_unique<QRestAccessManager>(qnam.get()); + QNetworkRequest request{u"i_dont_exist"_s}; // Will result in ProtocolUnknown error + m_expectedReplies.clear(); + m_actualReplies.clear(); + auto handler = [this](QRestReply &reply) { m_actualReplies.append(reply.networkReply()); }; + + // Delete reply immediately, make sure nothing bad happens and that there is no callback + QNetworkReply *networkReply = manager->get(request, this, handler); + delete networkReply; + QTest::qWait(20); // allow some time for the callback to arrive (it shouldn't) + QCOMPARE(m_actualReplies.size(), m_expectedReplies.size()); // Both should be 0 + + // Delete access manager immediately after request, make sure nothing bad happens + manager->get(request, this, handler); + manager->post(request, "data"_ba, this, handler); + QTest::ignoreMessage(QtWarningMsg, "Access manager destroyed while 2 requests were still" + " in progress"); + manager.reset(); + QTest::qWait(20); + QCOMPARE(m_actualReplies.size(), m_expectedReplies.size()); // Both should be 0 + + // Destroy the underlying QNAM while requests in progress + manager = std::make_unique<QRestAccessManager>(qnam.get()); + manager->get(request, this, handler); + manager->post(request, "data"_ba, this, handler); + qnam.reset(); + QTest::qWait(20); + QCOMPARE(m_actualReplies.size(), m_expectedReplies.size()); // Both should be 0 +} + +#define VERIFY_HTTP_ERROR_STATUS(STATUS) \ +{ \ + serverSideResponse.status = STATUS; \ + QRestReply restReply(manager.get(request)); \ + QTRY_VERIFY(restReply.networkReply()->isFinished()); \ + QVERIFY(!restReply.hasError()); \ + QCOMPARE(restReply.httpStatus(), serverSideResponse.status); \ + QCOMPARE(restReply.error(), QNetworkReply::NetworkError::NoError); \ + QVERIFY(!restReply.isSuccess()); \ + restReply.networkReply()->deleteLater(); \ +} \ + +void tst_QRestAccessManager::errors() +{ + // Tests the distinction between HTTP and other (network/protocol) errors + QNetworkAccessManager qnam; + QRestAccessManager manager(&qnam); + HttpTestServer server; + QTRY_VERIFY(server.isListening()); + QNetworkRequest request(server.url()); + + HttpData serverSideResponse; // The response data the server responds with + server.setHandler([&](const HttpData &, HttpData &response, ResponseControl &) { + response = serverSideResponse; + }); + + // Test few HTTP statuses in different categories + VERIFY_HTTP_ERROR_STATUS(301) // QNetworkReply::ProtocolUnknownError + VERIFY_HTTP_ERROR_STATUS(302) // QNetworkReply::ProtocolUnknownError + VERIFY_HTTP_ERROR_STATUS(400) // QNetworkReply::ProtocolInvalidOperationError + VERIFY_HTTP_ERROR_STATUS(401) // QNetworkReply::AuthenticationRequiredEror + VERIFY_HTTP_ERROR_STATUS(402) // QNetworkReply::UnknownContentError + VERIFY_HTTP_ERROR_STATUS(403) // QNetworkReply::ContentAccessDenied + VERIFY_HTTP_ERROR_STATUS(404) // QNetworkReply::ContentNotFoundError + VERIFY_HTTP_ERROR_STATUS(405) // QNetworkReply::ContentOperationNotPermittedError + VERIFY_HTTP_ERROR_STATUS(406) // QNetworkReply::UnknownContentError + VERIFY_HTTP_ERROR_STATUS(407) // QNetworkReply::ProxyAuthenticationRequiredError + VERIFY_HTTP_ERROR_STATUS(408) // QNetworkReply::UnknownContentError + VERIFY_HTTP_ERROR_STATUS(409) // QNetworkReply::ContentConflictError + VERIFY_HTTP_ERROR_STATUS(410) // QNetworkReply::ContentGoneError + VERIFY_HTTP_ERROR_STATUS(500) // QNetworkReply::InternalServerError + VERIFY_HTTP_ERROR_STATUS(501) // QNetworkReply::OperationNotImplementedError + VERIFY_HTTP_ERROR_STATUS(502) // QNetworkReply::UnknownServerError + VERIFY_HTTP_ERROR_STATUS(503) // QNetworkReply::ServiceUnavailableError + VERIFY_HTTP_ERROR_STATUS(504) // QNetworkReply::UnknownServerError + VERIFY_HTTP_ERROR_STATUS(505) // QNetworkReply::UnknownServerError + + { + // Test that actual network/protocol errors come through + QRestReply restReply(manager.get({})); // Empty url + QTRY_VERIFY(restReply.networkReply()->isFinished()); + QVERIFY(restReply.hasError()); + QVERIFY(!restReply.isSuccess()); + QCOMPARE(restReply.error(), QNetworkReply::ProtocolUnknownError); + restReply.networkReply()->deleteLater(); + } + + { + QRestReply restReply(manager.get(QNetworkRequest{{"http://non-existent.foo.bar.test"}})); + QTRY_VERIFY(restReply.networkReply()->isFinished()); + QVERIFY(restReply.hasError()); + QVERIFY(!restReply.isSuccess()); + QCOMPARE(restReply.error(), QNetworkReply::HostNotFoundError); + restReply.networkReply()->deleteLater(); + } + + { + QRestReply restReply(manager.get(request)); + restReply.networkReply()->abort(); + QTRY_VERIFY(restReply.networkReply()->isFinished()); + QVERIFY(restReply.hasError()); + QVERIFY(!restReply.isSuccess()); + QCOMPARE(restReply.error(), QNetworkReply::OperationCanceledError); + restReply.networkReply()->deleteLater(); + } +} + +void tst_QRestAccessManager::body() +{ + // Test using QRestReply::body() data accessor + QNetworkAccessManager qnam; + QRestAccessManager manager(&qnam); + HttpTestServer server; + QTRY_VERIFY(server.isListening()); + QNetworkRequest request(server.url()); + QNetworkReply *networkReply = nullptr; + + HttpData serverSideRequest; // The request data the server received + HttpData serverSideResponse; // The response data the server responds with + server.setHandler([&](const HttpData &request, HttpData &response, ResponseControl&) { + serverSideRequest = request; + response = serverSideResponse; + }); + + { + serverSideResponse.status = 200; + serverSideResponse.body = "some_data"_ba; + manager.get(request, this, [&](QRestReply &reply) { networkReply = reply.networkReply(); }); + QTRY_VERIFY(networkReply); + QRestReply restReply(networkReply); + QCOMPARE(restReply.readBody(), serverSideResponse.body); + QCOMPARE(restReply.httpStatus(), serverSideResponse.status); + QVERIFY(!restReply.hasError()); + QVERIFY(restReply.isSuccess()); + networkReply->deleteLater(); + networkReply = nullptr; + } + + { + serverSideResponse.status = 200; + serverSideResponse.body = ""_ba; // Empty + manager.get(request, this, [&](QRestReply &reply) { networkReply = reply.networkReply(); }); + QTRY_VERIFY(networkReply); + QRestReply restReply(networkReply); + QCOMPARE(restReply.readBody(), serverSideResponse.body); + networkReply->deleteLater(); + networkReply = nullptr; + } + + { + serverSideResponse.status = 500; + serverSideResponse.body = "some_other_data"_ba; + manager.get(request, this, [&](QRestReply &reply) { networkReply = reply.networkReply(); }); + QTRY_VERIFY(networkReply); + QRestReply restReply(networkReply); + QCOMPARE(restReply.readBody(), serverSideResponse.body); + QCOMPARE(restReply.httpStatus(), serverSideResponse.status); + QVERIFY(!restReply.hasError()); + QVERIFY(!restReply.isSuccess()); + networkReply->deleteLater(); + networkReply = nullptr; + } +} + +void tst_QRestAccessManager::json() +{ + // Tests using QRestReply::readJson() + QNetworkAccessManager qnam; + QRestAccessManager manager(&qnam); + HttpTestServer server; + QTRY_VERIFY(server.isListening()); + QNetworkRequest request(server.url()); + QNetworkReply *networkReply = nullptr; + QJsonDocument responseJsonDocument; + std::optional<QJsonDocument> json; + QJsonParseError parseError; + + HttpData serverSideRequest; // The request data the server received + HttpData serverSideResponse; // The response data the server responds with + serverSideResponse.status = 200; + server.setHandler([&](const HttpData &request, HttpData &response, ResponseControl&) { + serverSideRequest = request; + response = serverSideResponse; + }); + + { + // Test receiving valid json object + serverSideResponse.body = "{\"key1\":\"value1\",""\"key2\":\"value2\"}\n"_ba; + networkReply = manager.get(request); + // Read unfinished reply + QVERIFY(!networkReply->isFinished()); + QTest::ignoreMessage(QtWarningMsg, "readJson() called on an unfinished reply, ignoring"); + parseError.error = QJsonParseError::ParseError::DocumentTooLarge; // Reset to impossible value + QRestReply restReply(networkReply); + QVERIFY(!restReply.readJson(&parseError)); + QCOMPARE(parseError.error, QJsonParseError::ParseError::NoError); + // Read finished reply + QTRY_VERIFY(networkReply->isFinished()); + parseError.error = QJsonParseError::ParseError::DocumentTooLarge; + json = restReply.readJson(&parseError); + QVERIFY(json); + QCOMPARE(parseError.error, QJsonParseError::ParseError::NoError); + responseJsonDocument = *json; + QVERIFY(responseJsonDocument.isObject()); + QCOMPARE(responseJsonDocument["key1"], "value1"); + QCOMPARE(responseJsonDocument["key2"], "value2"); + networkReply->deleteLater(); + networkReply = nullptr; + } + + { + // Test receiving an invalid json object + serverSideResponse.body = "foobar"_ba; + manager.get(request, this, [&](QRestReply &reply) { networkReply = reply.networkReply(); }); + QTRY_VERIFY(networkReply); + QRestReply restReply(networkReply); + parseError.error = QJsonParseError::ParseError::DocumentTooLarge; + const auto json = restReply.readJson(&parseError); + networkReply->deleteLater(); + networkReply = nullptr; + QCOMPARE_EQ(json, std::nullopt); + QCOMPARE_NE(parseError.error, QJsonParseError::ParseError::NoError); + QCOMPARE_NE(parseError.error, QJsonParseError::ParseError::DocumentTooLarge); + QCOMPARE_GT(parseError.offset, 0); + } + + { + // Test receiving valid json array + serverSideResponse.body = "[\"foo\", \"bar\"]\n"_ba; + manager.get(request, this, [&](QRestReply &reply) { networkReply = reply.networkReply(); }); + QTRY_VERIFY(networkReply); + QRestReply restReply(networkReply); + parseError.error = QJsonParseError::ParseError::DocumentTooLarge; + json = restReply.readJson(&parseError); + networkReply->deleteLater(); + networkReply = nullptr; + QCOMPARE(parseError.error, QJsonParseError::ParseError::NoError); + QVERIFY(json); + responseJsonDocument = *json; + QVERIFY(responseJsonDocument.isArray()); + QCOMPARE(responseJsonDocument.array().size(), 2); + QCOMPARE(responseJsonDocument[0].toString(), "foo"_L1); + QCOMPARE(responseJsonDocument[1].toString(), "bar"_L1); + } +} + +#define VERIFY_TEXT_REPLY_OK \ +{ \ + manager.get(request, this, [&](QRestReply &reply) { networkReply = reply.networkReply(); }); \ + QTRY_VERIFY(networkReply); \ + QRestReply restReply(networkReply); \ + responseString = restReply.readText(); \ + networkReply->deleteLater(); \ + networkReply = nullptr; \ + QCOMPARE(responseString, sourceString); \ +} + +#define VERIFY_TEXT_REPLY_ERROR(WARNING_MESSAGE) \ +{ \ + manager.get(request, this, [&](QRestReply &reply) { networkReply = reply.networkReply(); }); \ + QTRY_VERIFY(networkReply); \ + QTest::ignoreMessage(QtWarningMsg, WARNING_MESSAGE); \ + QRestReply restReply(networkReply); \ + responseString = restReply.readText(); \ + networkReply->deleteLater(); \ + networkReply = nullptr; \ + QVERIFY(responseString.isEmpty()); \ +} + +void tst_QRestAccessManager::text() +{ + // Test using QRestReply::text() data accessor with various text encodings + QNetworkAccessManager qnam; + QRestAccessManager manager(&qnam); + HttpTestServer server; + QTRY_VERIFY(server.isListening()); + QNetworkRequest request(server.url()); + QNetworkReply *networkReply = nullptr; + QJsonObject responseJsonObject; + + QStringEncoder encUTF8("UTF-8"); + QStringEncoder encUTF16("UTF-16"); + QStringEncoder encUTF32("UTF-32"); + QString responseString; + + HttpData serverSideRequest; // The request data the server received + HttpData serverSideResponse; // The response data the server responds with + serverSideResponse.status = 200; + server.setHandler([&](const HttpData &request, HttpData &response, ResponseControl&) { + serverSideRequest = request; + response = serverSideResponse; + }); + + const QString sourceString("this is a string"_L1); + + // Charset parameter of Content-Type header may specify non-UTF-8 character encoding. + // + // QString is UTF-16, and in the tests below we encode the response data to various + // charset encodings (into byte arrays). When we get the response data, the text() + // should consider the indicated charset and convert it to an UTF-16 QString => the returned + // QString from text() should match with the original (UTF-16) QString. + + // Successful UTF-8 (explicit) + serverSideResponse.headers.append(Header::ContentType, "text/plain; charset=UTF-8"_ba); + serverSideResponse.body = encUTF8(sourceString); + VERIFY_TEXT_REPLY_OK; + + // Successful UTF-8 (obfuscated) + serverSideResponse.headers.removeAll(Header::ContentType); + serverSideResponse.headers.append(Header::ContentType, "text/plain; charset=\"UT\\F-8\""_ba); + serverSideResponse.body = encUTF8(sourceString); + VERIFY_TEXT_REPLY_OK; + + // Successful UTF-8 (empty charset) + serverSideResponse.headers.removeAll(Header::ContentType); + serverSideResponse.headers.append(Header::ContentType, "text/plain; charset=\"\""_ba); + serverSideResponse.body = encUTF8(sourceString); + VERIFY_TEXT_REPLY_OK; + + // Successful UTF-8 (implicit) + serverSideResponse.headers.removeAll(Header::ContentType); + serverSideResponse.headers.append(Header::ContentType, "text/plain"_ba); + serverSideResponse.body = encUTF8(sourceString); + VERIFY_TEXT_REPLY_OK; + + // Successful UTF-16 + serverSideResponse.headers.removeAll(Header::ContentType); + serverSideResponse.headers.append(Header::ContentType, "text/plain; charset=UTF-16"_ba); + serverSideResponse.body = encUTF16(sourceString); + VERIFY_TEXT_REPLY_OK; + + // Successful UTF-16, parameter case insensitivity + serverSideResponse.headers.removeAll(Header::ContentType); + serverSideResponse.headers.append(Header::ContentType, "text/plain; chARset=uTf-16"_ba); + serverSideResponse.body = encUTF16(sourceString); + VERIFY_TEXT_REPLY_OK; + + // Successful UTF-32 + serverSideResponse.headers.removeAll(Header::ContentType); + serverSideResponse.headers.append(Header::ContentType, "text/plain; charset=UTF-32"_ba); + serverSideResponse.body = encUTF32(sourceString); + VERIFY_TEXT_REPLY_OK; + + // Successful UTF-32 with spec-wise allowed extra trailing content in the Content-Type header value + serverSideResponse.headers.removeAll(Header::ContentType); + serverSideResponse.headers.append(Header::ContentType, + "text(this is a \\)comment)/ (this (too)) plain; charset = \"UTF-32\";extraparameter=bar"_ba); + serverSideResponse.body = encUTF32(sourceString); + VERIFY_TEXT_REPLY_OK; + + // Successful UTF-32 with spec-wise allowed extra leading content in the Content-Type header value + serverSideResponse.headers.removeAll(Header::ContentType); + serverSideResponse.headers.append(Header::ContentType, + "text/plain; extraparameter=bar;charset = \"UT\\F-32\""_ba); + serverSideResponse.body = encUTF32(sourceString); + VERIFY_TEXT_REPLY_OK; + + { + // Unsuccessful UTF-32, wrong encoding indicated (indicated UTF-32 but data is UTF-8) + serverSideResponse.headers.removeAll(Header::ContentType); + serverSideResponse.headers.append(Header::ContentType, "text/plain; charset=UTF-32"_ba); + serverSideResponse.body = encUTF8(sourceString); + manager.get(request, this, [&](QRestReply &reply) { networkReply = reply.networkReply(); }); + QTRY_VERIFY(networkReply); + QRestReply restReply(networkReply); + responseString = restReply.readText(); + QCOMPARE_NE(responseString, sourceString); + networkReply->deleteLater(); + networkReply = nullptr; + } + + // Unsupported encoding + serverSideResponse.headers.removeAll(Header::ContentType); + serverSideResponse.headers.append(Header::ContentType, "text/plain; charset=foo"_ba); + serverSideResponse.body = encUTF8(sourceString); + VERIFY_TEXT_REPLY_ERROR("readText(): Charset \"foo\" is not supported") + + // Broken UTF-8 + serverSideResponse.headers.removeAll(Header::ContentType); + serverSideResponse.headers.append(Header::ContentType, "text/plain; charset=UTF-8"_ba); + serverSideResponse.body = "\xF0\x28\x8C\x28\xA0\xB0\xC0\xD0"; // invalid characters + VERIFY_TEXT_REPLY_ERROR("readText(): Decoding error occurred"); +} + +void tst_QRestAccessManager::textStreaming() +{ + // Tests textual data received in chunks + QNetworkAccessManager qnam; + QRestAccessManager manager(&qnam); + HttpTestServer server; + QTRY_VERIFY(server.isListening()); + QNetworkRequest request(server.url()); + + // Create long text data + const QString expectedData = u"사랑abcd€fghiklmnΩpqrstuvwx愛사랑A사랑BCD€FGHIJKLMNΩPQRsTUVWXYZ愛"_s; + QString cumulativeReceivedText; + QStringEncoder encUTF8("UTF-8"); + ResponseControl *responseControl = nullptr; + + HttpData serverSideResponse; // The response data the server responds with + serverSideResponse.headers.removeAll(Header::ContentType); + serverSideResponse.headers.append(Header::ContentType, "text/plain; charset=UTF-8"_ba); + serverSideResponse.body = encUTF8(expectedData); + serverSideResponse.status = 200; + + server.setHandler([&](const HttpData &, HttpData &response, ResponseControl &control) { + response = serverSideResponse; + responseControl = &control; // store for later + control.responseChunkSize = 5; // tell testserver to send data in chunks of this size + }); + + { + QRestReply restReply(manager.get(request)); + QObject::connect(restReply.networkReply(), &QNetworkReply::readyRead, this, [&]() { + cumulativeReceivedText += restReply.readText(); + // Tell testserver that test is ready for next chunk + responseControl->readyForNextChunk = true; + }); + QTRY_VERIFY(restReply.networkReply()->isFinished()); + QCOMPARE(cumulativeReceivedText, expectedData); + restReply.networkReply()->deleteLater(); + } + + { + cumulativeReceivedText.clear(); + // Broken UTF-8 characters after first five ok characters + serverSideResponse.body = + "12345"_ba + "\xF0\x28\x8C\x28\xA0\xB0\xC0\xD0" + "abcde"_ba; + QRestReply restReply(manager.get(request)); + QObject::connect(restReply.networkReply(), &QNetworkReply::readyRead, this, [&]() { + static bool firstTime = true; + if (!firstTime) // First text part is without warnings + QTest::ignoreMessage(QtWarningMsg, "readText(): Decoding error occurred"); + firstTime = false; + cumulativeReceivedText += restReply.readText(); + // Tell testserver that test is ready for next chunk + responseControl->readyForNextChunk = true; + }); + QTRY_VERIFY(restReply.networkReply()->isFinished()); + QCOMPARE(cumulativeReceivedText, "12345"_ba); + restReply.networkReply()->deleteLater(); + } +} + +QTEST_MAIN(tst_QRestAccessManager) +#include "tst_qrestaccessmanager.moc" diff --git a/tests/auto/network/kernel/CMakeLists.txt b/tests/auto/network/kernel/CMakeLists.txt index 0b25020694..df87e9d58e 100644 --- a/tests/auto/network/kernel/CMakeLists.txt +++ b/tests/auto/network/kernel/CMakeLists.txt @@ -1,14 +1,27 @@ -add_subdirectory(qdnslookup) -add_subdirectory(qdnslookup_appless) -add_subdirectory(qnetworkinterface) -add_subdirectory(qnetworkdatagram) -add_subdirectory(qnetworkaddressentry) -add_subdirectory(qhostaddress) +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause +if(QT_FEATURE_dnslookup AND (QT_FEATURE_libresolv OR WIN32)) + add_subdirectory(qdnslookup) + add_subdirectory(qdnslookup_appless) +endif() +if(QT_FEATURE_networkinterface) + add_subdirectory(qnetworkaddressentry) + add_subdirectory(qnetworkproxyfactory) + add_subdirectory(qnetworkinterface) +endif() +if(QT_FEATURE_networkproxy) + add_subdirectory(qnetworkproxy) +endif() +if(QT_FEATURE_udpsocket) + add_subdirectory(qnetworkdatagram) +endif() +add_subdirectory(qhostaddress) +if(QT_FEATURE_private_tests AND NOT MACOS AND NOT INTEGRITY) + add_subdirectory(qhostinfo) +endif() if(QT_FEATURE_private_tests) add_subdirectory(qauthenticator) - - if(NOT MACOS) - add_subdirectory(qhostinfo) - endif() + add_subdirectory(qnetworkinformation) + add_subdirectory(qnetworkinformation_appless) endif() diff --git a/tests/auto/network/kernel/kernel.pro b/tests/auto/network/kernel/kernel.pro deleted file mode 100644 index c13378cc02..0000000000 --- a/tests/auto/network/kernel/kernel.pro +++ /dev/null @@ -1,20 +0,0 @@ -TEMPLATE=subdirs -SUBDIRS=\ - qdnslookup \ - qdnslookup_appless \ - qhostinfo \ - qnetworkproxyfactory \ - qauthenticator \ - qnetworkproxy \ - qnetworkinterface \ - qnetworkdatagram \ - qnetworkaddressentry \ - qhostaddress \ - -osx: SUBDIRS -= \ # QTBUG-41847 - qhostinfo \ - -!qtConfig(private_tests): SUBDIRS -= \ - qauthenticator \ - qhostinfo \ - diff --git a/tests/auto/network/kernel/qauthenticator/CMakeLists.txt b/tests/auto/network/kernel/qauthenticator/CMakeLists.txt index a4d5d7f277..552e9065ed 100644 --- a/tests/auto/network/kernel/qauthenticator/CMakeLists.txt +++ b/tests/auto/network/kernel/qauthenticator/CMakeLists.txt @@ -1,4 +1,11 @@ -# Generated from qauthenticator.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qauthenticator LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() if(NOT QT_FEATURE_private_tests) return() @@ -8,14 +15,9 @@ endif() ## tst_qauthenticator Test: ##################################################################### -qt_add_test(tst_qauthenticator +qt_internal_add_test(tst_qauthenticator SOURCES tst_qauthenticator.cpp - DEFINES - SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/\\\" - PUBLIC_LIBRARIES + LIBRARIES Qt::NetworkPrivate ) - -#### Keys ignored in scope 1:.:.:qauthenticator.pro:<TRUE>: -# _REQUIREMENTS = "qtConfig(private_tests)" diff --git a/tests/auto/network/kernel/qauthenticator/qauthenticator.pro b/tests/auto/network/kernel/qauthenticator/qauthenticator.pro deleted file mode 100644 index 5038eea9af..0000000000 --- a/tests/auto/network/kernel/qauthenticator/qauthenticator.pro +++ /dev/null @@ -1,6 +0,0 @@ -CONFIG += testcase -TARGET = tst_qauthenticator -requires(qtConfig(private_tests)) -QT = core network-private testlib -SOURCES += tst_qauthenticator.cpp -DEFINES += SRCDIR=\\\"$$PWD/\\\" diff --git a/tests/auto/network/kernel/qauthenticator/tst_qauthenticator.cpp b/tests/auto/network/kernel/qauthenticator/tst_qauthenticator.cpp index 7e56921606..1cd1b6a63b 100644 --- a/tests/auto/network/kernel/qauthenticator/tst_qauthenticator.cpp +++ b/tests/auto/network/kernel/qauthenticator/tst_qauthenticator.cpp @@ -1,36 +1,12 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the FOO 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtCore/QString> -#include <QtTest/QtTest> +#include <QTest> #include <QtCore/QCoreApplication> #include <QtNetwork/QAuthenticator> +#include <QtNetwork/QHttpHeaders> #include <private/qauthenticator_p.h> @@ -48,7 +24,11 @@ private Q_SLOTS: void ntlmAuth_data(); void ntlmAuth(); + void sha256AndMd5Digest(); + void equalityOperators(); + + void isMethodSupported(); }; tst_QAuthenticator::tst_QAuthenticator() @@ -81,8 +61,8 @@ void tst_QAuthenticator::basicAuth() QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(auth); QCOMPARE(priv->phase, QAuthenticatorPrivate::Start); - QList<QPair<QByteArray, QByteArray> > headers; - headers << qMakePair(QByteArray("WWW-Authenticate"), "Basic " + data.toUtf8()); + QHttpHeaders headers; + headers.append(QByteArray("WWW-Authenticate"), "Basic " + data.toUtf8()); priv->parseHttpResponse(headers, /*isProxy = */ false, {}); QCOMPARE(auth.realm(), realm); @@ -93,7 +73,7 @@ void tst_QAuthenticator::basicAuth() QCOMPARE(priv->phase, QAuthenticatorPrivate::Start); - QCOMPARE(priv->calculateResponse("GET", "/", "").constData(), QByteArray("Basic " + expectedReply).constData()); + QCOMPARE(priv->calculateResponse("GET", "/", u"").constData(), QByteArray("Basic " + expectedReply).constData()); } void tst_QAuthenticator::ntlmAuth_data() @@ -124,29 +104,58 @@ void tst_QAuthenticator::ntlmAuth() QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(auth); QCOMPARE(priv->phase, QAuthenticatorPrivate::Start); - QList<QPair<QByteArray, QByteArray> > headers; + QHttpHeaders headers; // NTLM phase 1: negotiate // This phase of NTLM contains no information, other than what we're willing to negotiate // Current implementation uses flags: // NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_REQUEST_TARGET - headers << qMakePair(QByteArrayLiteral("WWW-Authenticate"), QByteArrayLiteral("NTLM")); + headers.append(QByteArrayLiteral("WWW-Authenticate"), QByteArrayLiteral("NTLM")); priv->parseHttpResponse(headers, /*isProxy = */ false, {}); if (sso) - QVERIFY(priv->calculateResponse("GET", "/", "").startsWith("NTLM ")); + QVERIFY(priv->calculateResponse("GET", "/", u"").startsWith("NTLM ")); else - QCOMPARE(priv->calculateResponse("GET", "/", "").constData(), "NTLM TlRMTVNTUAABAAAABYIIAAAAAAAAAAAAAAAAAAAAAAA="); + QCOMPARE(priv->calculateResponse("GET", "/", u"").constData(), "NTLM TlRMTVNTUAABAAAABYIIAAAAAAAAAAAAAAAAAAAAAAA="); // NTLM phase 2: challenge headers.clear(); - headers << qMakePair(QByteArray("WWW-Authenticate"), "NTLM " + data.toUtf8()); + headers.append(QByteArray("WWW-Authenticate"), "NTLM " + data.toUtf8()); priv->parseHttpResponse(headers, /*isProxy = */ false, {}); QEXPECT_FAIL("with-realm", "NTLM authentication code doesn't extract the realm", Continue); QEXPECT_FAIL("with-realm-sso", "NTLM authentication code doesn't extract the realm", Continue); QCOMPARE(auth.realm(), realm); - QVERIFY(priv->calculateResponse("GET", "/", "").startsWith("NTLM ")); + QVERIFY(priv->calculateResponse("GET", "/", u"").startsWith("NTLM ")); +} + +// We don't (currently) support SHA256. So, when presented with the option of MD5 or SHA256, +// we should always pick MD5. +void tst_QAuthenticator::sha256AndMd5Digest() +{ + QByteArray md5 = "Digest realm=\"\", nonce=\"\", algorithm=MD5, qop=\"auth\""; + QByteArray sha256 = "Digest realm=\"\", nonce=\"\", algorithm=SHA-256, qop=\"auth\""; + + QAuthenticator auth; + auth.setUser("unimportant"); + auth.setPassword("unimportant"); + + QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(auth); + QVERIFY(priv->isMethodSupported("digest")); // sanity check + + QCOMPARE(priv->phase, QAuthenticatorPrivate::Start); + QHttpHeaders headers; + // Put sha256 first, so that its parsed first... + headers.append("WWW-Authenticate", sha256); + headers.append("WWW-Authenticate", md5); + priv->parseHttpResponse(headers, false, QString()); + + QByteArray response = priv->calculateResponse("GET", "/index", {}); + QCOMPARE(priv->phase, QAuthenticatorPrivate::Done); + + QVERIFY(!response.isEmpty()); + QVERIFY(!response.contains("algorithm=SHA-256")); + QVERIFY(response.contains("algorithm=MD5")); } void tst_QAuthenticator::equalityOperators() @@ -163,6 +172,22 @@ void tst_QAuthenticator::equalityOperators() QVERIFY(s2 != s1); } +void tst_QAuthenticator::isMethodSupported() +{ + QVERIFY(QAuthenticatorPrivate::isMethodSupported("basic")); + QVERIFY(QAuthenticatorPrivate::isMethodSupported("Basic realm=\"Shadow\"")); + QVERIFY(QAuthenticatorPrivate::isMethodSupported("DIgesT")); + QVERIFY(QAuthenticatorPrivate::isMethodSupported("NTLM")); + QVERIFY(QAuthenticatorPrivate::isMethodSupported("ntlm")); +#if QT_CONFIG(sspi) || QT_CONFIG(gssapi) + QVERIFY(QAuthenticatorPrivate::isMethodSupported("negotiate")); +#else + QVERIFY(!QAuthenticatorPrivate::isMethodSupported("negotiate")); +#endif + + QVERIFY(!QAuthenticatorPrivate::isMethodSupported("Bearer")); +} + QTEST_MAIN(tst_QAuthenticator); #include "tst_qauthenticator.moc" diff --git a/tests/auto/network/kernel/qdnslookup/BLACKLIST b/tests/auto/network/kernel/qdnslookup/BLACKLIST deleted file mode 100644 index f07a8ce9a3..0000000000 --- a/tests/auto/network/kernel/qdnslookup/BLACKLIST +++ /dev/null @@ -1,2 +0,0 @@ -[lookup] -* diff --git a/tests/auto/network/kernel/qdnslookup/CMakeLists.txt b/tests/auto/network/kernel/qdnslookup/CMakeLists.txt index 6736b480b2..ea539ecbe0 100644 --- a/tests/auto/network/kernel/qdnslookup/CMakeLists.txt +++ b/tests/auto/network/kernel/qdnslookup/CMakeLists.txt @@ -1,12 +1,25 @@ -# Generated from qdnslookup.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qdnslookup Test: ##################################################################### -qt_add_test(tst_qdnslookup +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qdnslookup LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qdnslookup SOURCES tst_qdnslookup.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Network + Qt::TestPrivate +) + +qt_internal_extend_target(tst_qdnslookup CONDITION WIN32 + LIBRARIES + iphlpapi ) diff --git a/tests/auto/network/kernel/qdnslookup/qdnslookup.pro b/tests/auto/network/kernel/qdnslookup/qdnslookup.pro deleted file mode 100644 index f14ffd003e..0000000000 --- a/tests/auto/network/kernel/qdnslookup/qdnslookup.pro +++ /dev/null @@ -1,7 +0,0 @@ -CONFIG += testcase - -TARGET = tst_qdnslookup - -SOURCES += tst_qdnslookup.cpp - -QT = core network testlib diff --git a/tests/auto/network/kernel/qdnslookup/tst_qdnslookup.cpp b/tests/auto/network/kernel/qdnslookup/tst_qdnslookup.cpp index d72e92b859..af3a74a498 100644 --- a/tests/auto/network/kernel/qdnslookup/tst_qdnslookup.cpp +++ b/tests/auto/network/kernel/qdnslookup/tst_qdnslookup.cpp @@ -1,61 +1,250 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org> -** Copyright (C) 2016 Intel Corporation. -** 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> +// Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org> +// Copyright (C) 2016 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QTest> +#include <QSignalSpy> +#include <QtTest/private/qpropertytesthelper_p.h> + #include <QtNetwork/QDnsLookup> + +#include <QtCore/QRandomGenerator> #include <QtNetwork/QHostAddress> +#include <QtNetwork/QNetworkDatagram> +#include <QtNetwork/QUdpSocket> + +#if QT_CONFIG(networkproxy) +# include <QtNetwork/QNetworkProxyFactory> +#endif +#if QT_CONFIG(ssl) +# include <QtNetwork/QSslSocket> +#endif + +#ifdef Q_OS_UNIX +# include <QtCore/QFile> +#else +# include <winsock2.h> +# include <iphlpapi.h> +#endif +using namespace Qt::StringLiterals; static const int Timeout = 15000; // 15s class tst_QDnsLookup: public QObject { Q_OBJECT + const QString normalDomain = u".test.qt-project.org"_s; + const QString idnDomain = u".alqualondë.test.qt-project.org"_s; + bool usingIdnDomain = false; + bool dnsServersMustWork = false; + QString domainName(const QString &input); QString domainNameList(const QString &input); QStringList domainNameListAlternatives(const QString &input); + + std::unique_ptr<QDnsLookup> lookupCommon(QDnsLookup::Type type, const QString &domain, + const QHostAddress &server = {}, quint16 port = 0, + QDnsLookup::Protocol protocol = QDnsLookup::Standard); + QStringList formatReply(const QDnsLookup *lookup) const; + + void setNameserver_helper(QDnsLookup::Protocol protocol); public slots: void initTestCase(); private slots: + void lookupLocalhost(); + void lookupRoot(); + void lookupNxDomain_data(); + void lookupNxDomain(); void lookup_data(); void lookup(); + void lookupIdn_data() { lookup_data(); } + void lookupIdn(); + void lookupReuse(); void lookupAbortRetry(); + void setNameserverLoopback(); + void setNameserver_data(); + void setNameserver(); + void dnsOverTls_data(); + void dnsOverTls(); + void bindingsAndProperties(); + void automatedBindings(); }; +static constexpr qsizetype HeaderSize = 6 * sizeof(quint16); +static const char preparedDnsQuery[] = + // header + "\x00\x00" // transaction ID, we'll replace + "\x01\x20" // flags + "\x00\x01" // qdcount + "\x00\x00" // ancount + "\x00\x00" // nscount + "\x00\x00" // arcount + // query: + "\x00\x00\x06\x00\x01" // <root domain> IN SOA + ; + +static QList<QHostAddress> systemNameservers(QDnsLookup::Protocol protocol) +{ + QList<QHostAddress> result; + if (protocol != QDnsLookup::Standard) + return result; + +#ifdef Q_OS_WIN + ULONG infosize = 0; + DWORD r = GetNetworkParams(nullptr, &infosize); + auto buffer = std::make_unique<uchar[]>(infosize); + auto info = new (buffer.get()) FIXED_INFO; + r = GetNetworkParams(info, &infosize); + if (r == NO_ERROR) { + for (PIP_ADDR_STRING ptr = &info->DnsServerList; ptr; ptr = ptr->Next) { + QLatin1StringView addr(ptr->IpAddress.String); + result.emplaceBack(addr); + } + } +#else + auto parseFile = [&](QLatin1StringView path) { + QFile f(path); + if (!f.open(QIODevice::ReadOnly)) + return; + + while (!f.atEnd()) { + static const char command[] = "nameserver"; + QByteArray line = f.readLine().simplified(); + if (!line.startsWith(command)) + continue; + + QString addr = QLatin1StringView(line).mid(sizeof(command)); + result.emplaceBack(addr); + } + }; + parseFile("/etc/resolv.conf"_L1); + parseFile("/run/systemd/resolve/resolv.conf"_L1); +#endif + + return result; +} + +static QList<QHostAddress> globalPublicNameservers(QDnsLookup::Protocol proto) +{ + const char *const candidates[] = { + // Google's dns.google + "8.8.8.8", "2001:4860:4860::8888", + //"8.8.4.4", "2001:4860:4860::8844", + + // CloudFare's one.one.one.one + "1.1.1.1", "2606:4700:4700::1111", + //"1.0.0.1", "2606:4700:4700::1001", + + // Quad9's dns9 + //"9.9.9.9", "2620:fe::9", + }; + + auto udpSendAndReceive = [](const QHostAddress &addr, QByteArray &data) { + QUdpSocket socket; + socket.connectToHost(addr, 53); + if (socket.waitForConnected(1)) + socket.write(data); + + if (!socket.waitForReadyRead(1000)) + return socket.errorString(); + + QNetworkDatagram dgram = socket.receiveDatagram(); + if (!dgram.isValid()) + return socket.errorString(); + + data = dgram.data(); + return QString(); + }; + + auto tlsSendAndReceive = [](const QHostAddress &addr, QByteArray &data) { +#if QT_CONFIG(ssl) + QSslSocket socket; + QDeadlineTimer timeout(2000); + socket.connectToHostEncrypted(addr.toString(), 853); + if (!socket.waitForEncrypted(2000)) + return socket.errorString(); + + quint16 size = qToBigEndian<quint16>(data.size()); + socket.write(reinterpret_cast<char *>(&size), sizeof(size)); + socket.write(data); + + if (!socket.waitForReadyRead(timeout.remainingTime())) + return socket.errorString(); + if (socket.bytesAvailable() < 2) + return u"protocol error"_s; + + socket.read(reinterpret_cast<char *>(&size), sizeof(size)); + size = qFromBigEndian(size); + + while (socket.bytesAvailable() < size) { + int remaining = timeout.remainingTime(); + if (remaining < 0 || !socket.waitForReadyRead(remaining)) + return socket.errorString(); + } + + data = socket.readAll(); + return QString(); +#else + return u"SSL/TLS support not compiled in"_s; +#endif + }; + + QList<QHostAddress> result; + QRandomGenerator &rng = *QRandomGenerator::system(); + for (auto name : candidates) { + // check the candidates for reachability + QHostAddress addr{QLatin1StringView(name)}; + quint16 id = quint16(rng()); + QByteArray data(preparedDnsQuery, sizeof(preparedDnsQuery)); + char *ptr = data.data(); + qToBigEndian(id, ptr); + + QString errorString = [&] { + switch (proto) { + case QDnsLookup::Standard: return udpSendAndReceive(addr, data); + case QDnsLookup::DnsOverTls: return tlsSendAndReceive(addr, data); + } + Q_UNREACHABLE(); + }(); + if (!errorString.isEmpty()) { + qDebug() << addr << "discarded:" << errorString; + continue; + } + + ptr = data.data(); + if (data.size() < HeaderSize) { + qDebug() << addr << "discarded: reply too small"; + continue; + } + + bool ok = qFromBigEndian<quint16>(ptr) == id + && (ptr[2] & 0x80) // is a reply + && (ptr[3] & 0xf) == 0 // rcode NOERROR + && qFromBigEndian<quint16>(ptr + 4) == 1 // qdcount + && qFromBigEndian<quint16>(ptr + 6) >= 1; // ancount + if (!ok) { + qDebug() << addr << "discarded: invalid reply"; + continue; + } + + result.emplaceBack(std::move(addr)); + } + + return result; +} + void tst_QDnsLookup::initTestCase() { - QTest::addColumn<QString>("tld"); - QTest::newRow("normal") << ".test.qt-project.org"; - QTest::newRow("idn") << ".alqualond\xc3\xab.test.qt-project.org"; + if (qgetenv("QTEST_ENVIRONMENT") == "ci") + dnsServersMustWork = true; + +#if QT_CONFIG(networkproxy) + // for DNS-over-TLS + QNetworkProxyFactory::setUseSystemConfiguration(true); +#endif } QString tst_QDnsLookup::domainName(const QString &input) @@ -69,15 +258,16 @@ QString tst_QDnsLookup::domainName(const QString &input) return nodot; } - QFETCH_GLOBAL(QString, tld); - return input + tld; + if (usingIdnDomain) + return input + idnDomain; + return input + normalDomain; } QString tst_QDnsLookup::domainNameList(const QString &input) { - QStringList list = input.split(QLatin1Char(';')); + const QStringList list = input.split(QLatin1Char(';')); QString result; - foreach (const QString &s, list) { + for (const QString &s : list) { if (!result.isEmpty()) result += ';'; result += domainName(s); @@ -88,229 +278,289 @@ QString tst_QDnsLookup::domainNameList(const QString &input) QStringList tst_QDnsLookup::domainNameListAlternatives(const QString &input) { QStringList alternatives = input.split('|'); - for (int i = 0; i < alternatives.length(); ++i) + for (int i = 0; i < alternatives.size(); ++i) alternatives[i] = domainNameList(alternatives[i]); return alternatives; } +std::unique_ptr<QDnsLookup> +tst_QDnsLookup::lookupCommon(QDnsLookup::Type type, const QString &domain, + const QHostAddress &server, quint16 port, + QDnsLookup::Protocol protocol) +{ + auto lookup = std::make_unique<QDnsLookup>(type, domainName(domain), protocol, server, port); + QObject::connect(lookup.get(), &QDnsLookup::finished, + &QTestEventLoop::instance(), &QTestEventLoop::exitLoop); + lookup->lookup(); + QTestEventLoop::instance().enterLoopMSecs(Timeout); + + QDnsLookup::Error error = lookup->error(); + if (QTestEventLoop::instance().timeout()) + error = QDnsLookup::TimeoutError; + + if (!dnsServersMustWork && (error == QDnsLookup::ServerFailureError + || error == QDnsLookup::ServerRefusedError + || error == QDnsLookup::TimeoutError)) { + // It's not a QDnsLookup problem if the server refuses to answer the query. + // This happens for queries of type ANY through Dnsmasq, for example. + [&] { + auto me = QMetaEnum::fromType<QDnsLookup::Type>(); + QString msg = u"Server refused or was unable to answer query; %1 type %3: %2"_s + .arg(domain, lookup->errorString(), QString(me.valueToKey(int(type)))); + QSKIP(msg.toLocal8Bit()); + }(); + return {}; + } + + return lookup; +} + +QStringList tst_QDnsLookup::formatReply(const QDnsLookup *lookup) const +{ + QStringList result; + QString domain = lookup->name(); + + auto shorter = [this](QString value) { + const QString &ending = usingIdnDomain ? idnDomain : normalDomain; + if (value.endsWith(ending)) + value.chop(ending.size()); + else + value += u'.'; + return value; + }; + + for (const QDnsMailExchangeRecord &rr : lookup->mailExchangeRecords()) { + QString entry = u"MX %1 %2"_s.arg(rr.preference(), 5).arg(shorter(rr.exchange())); + if (rr.name() != domain) + entry = "MX unexpected label to "_L1 + rr.name(); + result.append(std::move(entry)); + } + + for (const QDnsServiceRecord &rr : lookup->serviceRecords()) { + QString entry = u"SRV %1 %2 %3 %4"_s.arg(rr.priority(), 5).arg(rr.weight()) + .arg(rr.port()).arg(shorter(rr.target())); + if (rr.name() != domain) + entry = "SRV unexpected label to "_L1 + rr.name(); + result.append(std::move(entry)); + } + + auto addNameRecords = [&](QLatin1StringView rrtype, const QList<QDnsDomainNameRecord> &rrset) { + for (const QDnsDomainNameRecord &rr : rrset) { + QString entry = u"%1 %2"_s.arg(rrtype, shorter(rr.value())); + if (rr.name() != domain) + entry = rrtype + " unexpected label to "_L1 + rr.name(); + result.append(std::move(entry)); + } + }; + addNameRecords("NS"_L1, lookup->nameServerRecords()); + addNameRecords("PTR"_L1, lookup->pointerRecords()); + addNameRecords("CNAME"_L1, lookup->canonicalNameRecords()); + + for (const QDnsHostAddressRecord &rr : lookup->hostAddressRecords()) { + if (rr.name() != domain) + continue; // A and AAAA may appear as extra records in the answer section + QHostAddress addr = rr.value(); + result.append(u"%1 %2"_s + .arg(addr.protocol() == QHostAddress::IPv6Protocol ? "AAAA" : "A", + addr.toString())); + } + + for (const QDnsTextRecord &rr : lookup->textRecords()) { + QString entry = "TXT"_L1; + for (const QByteArray &data : rr.values()) { + entry += u' '; + entry += QDebug::toString(data); + } + result.append(std::move(entry)); + } + + for (const QDnsTlsAssociationRecord &rr : lookup->tlsAssociationRecords()) { + QString entry = u"TLSA %1 %2 %3 %4"_s.arg(int(rr.usage())).arg(int(rr.selector())) + .arg(int(rr.matchType())).arg(rr.value().toHex().toUpper()); + if (rr.name() != domain) + entry = "TLSA unexpected label to "_L1 + rr.name(); + result.append(std::move(entry)); + } + + result.sort(); + return result; +} + +void tst_QDnsLookup::lookupLocalhost() +{ + auto lookup = lookupCommon(QDnsLookup::Type::A, u"localhost."_s); + QVERIFY(lookup); + QCOMPARE(lookup->error(), QDnsLookup::NoError); + + QList<QDnsHostAddressRecord> hosts = lookup->hostAddressRecords(); + QCOMPARE(hosts.size(), 1); + QCOMPARE(hosts.at(0).value(), QHostAddress::LocalHost); + QVERIFY2(hosts.at(0).name().startsWith(lookup->name()), + qPrintable(hosts.at(0).name())); +} + +void tst_QDnsLookup::lookupRoot() +{ +#ifdef Q_OS_WIN + QSKIP("This test fails on Windows as it seems to treat the lookup as a local one."); +#else + auto lookup = lookupCommon(QDnsLookup::Type::NS, u""_s); + if (!lookup) + return; + QCOMPARE(lookup->error(), QDnsLookup::NoError); + + const QList<QDnsDomainNameRecord> servers = lookup->nameServerRecords(); + QVERIFY(!servers.isEmpty()); + for (const QDnsDomainNameRecord &ns : servers) { + QCOMPARE(ns.name(), QString()); + QVERIFY(ns.value().endsWith(".root-servers.net")); + } +#endif +} + +void tst_QDnsLookup::lookupNxDomain_data() +{ + QTest::addColumn<QDnsLookup::Type>("type"); + QTest::addColumn<QString>("domain"); + + QTest::newRow("a") << QDnsLookup::A << "invalid.invalid"; + QTest::newRow("aaaa") << QDnsLookup::AAAA << "invalid.invalid"; + QTest::newRow("any") << QDnsLookup::ANY << "invalid.invalid"; + QTest::newRow("mx") << QDnsLookup::MX << "invalid.invalid"; + QTest::newRow("ns") << QDnsLookup::NS << "invalid.invalid"; + QTest::newRow("ptr") << QDnsLookup::PTR << "invalid.invalid"; + QTest::newRow("srv") << QDnsLookup::SRV << "invalid.invalid"; + QTest::newRow("txt") << QDnsLookup::TXT << "invalid.invalid"; +} + +void tst_QDnsLookup::lookupNxDomain() +{ + QFETCH(QDnsLookup::Type, type); + QFETCH(QString, domain); + + auto lookup = lookupCommon(type, domain); + if (!lookup) + return; + QCOMPARE(lookup->name(), domainName(domain)); + QCOMPARE(lookup->type(), type); + QCOMPARE(lookup->error(), QDnsLookup::NotFoundError); +} + void tst_QDnsLookup::lookup_data() { - QTest::addColumn<int>("type"); + QTest::addColumn<QDnsLookup::Type>("type"); QTest::addColumn<QString>("domain"); - QTest::addColumn<int>("error"); - QTest::addColumn<QString>("cname"); - QTest::addColumn<QString>("host"); - QTest::addColumn<QString>("mx"); - QTest::addColumn<QString>("ns"); - QTest::addColumn<QString>("ptr"); - QTest::addColumn<QString>("srv"); - QTest::addColumn<QString>("txt"); - - QTest::newRow("a-empty") << int(QDnsLookup::A) << "" << int(QDnsLookup::InvalidRequestError) << "" << "" << "" << "" << ""<< "" << ""; - QTest::newRow("a-notfound") << int(QDnsLookup::A) << "invalid.invalid" << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << ""; - QTest::newRow("a-single") << int(QDnsLookup::A) << "a-single" << int(QDnsLookup::NoError) << "" << "192.0.2.1" << "" << "" << "" << "" << ""; - QTest::newRow("a-multi") << int(QDnsLookup::A) << "a-multi" << int(QDnsLookup::NoError) << "" << "192.0.2.1;192.0.2.2;192.0.2.3" << "" << "" << "" << "" << ""; - QTest::newRow("aaaa-empty") << int(QDnsLookup::AAAA) << "" << int(QDnsLookup::InvalidRequestError) << "" << "" << "" << "" << "" << "" << ""; - QTest::newRow("aaaa-notfound") << int(QDnsLookup::AAAA) << "invalid.invalid" << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << ""; - QTest::newRow("aaaa-single") << int(QDnsLookup::AAAA) << "aaaa-single" << int(QDnsLookup::NoError) << "" << "2001:db8::1" << "" << "" << "" << "" << ""; - QTest::newRow("aaaa-multi") << int(QDnsLookup::AAAA) << "aaaa-multi" << int(QDnsLookup::NoError) << "" << "2001:db8::1;2001:db8::2;2001:db8::3" << "" << "" << "" << "" << ""; - - QTest::newRow("any-empty") << int(QDnsLookup::ANY) << "" << int(QDnsLookup::InvalidRequestError) << "" << "" << "" << "" << "" << "" << ""; - QTest::newRow("any-notfound") << int(QDnsLookup::ANY) << "invalid.invalid" << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << ""; - QTest::newRow("any-a-single") << int(QDnsLookup::ANY) << "a-single" << int(QDnsLookup::NoError) << "" << "192.0.2.1" << "" << "" << "" << "" << ""; - QTest::newRow("any-a-plus-aaaa") << int(QDnsLookup::ANY) << "a-plus-aaaa" << int(QDnsLookup::NoError) << "" << "198.51.100.1;2001:db8::1:1" << "" << "" << "" << "" << ""; - QTest::newRow("any-multi") << int(QDnsLookup::ANY) << "multi" << int(QDnsLookup::NoError) << "" << "198.51.100.1;198.51.100.2;198.51.100.3;2001:db8::1:1;2001:db8::1:2" << "" << "" << "" << "" << ""; - - QTest::newRow("mx-empty") << int(QDnsLookup::MX) << "" << int(QDnsLookup::InvalidRequestError) << "" << "" << "" << "" << "" << "" << ""; - QTest::newRow("mx-notfound") << int(QDnsLookup::MX) << "invalid.invalid" << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << ""; - QTest::newRow("mx-single") << int(QDnsLookup::MX) << "mx-single" << int(QDnsLookup::NoError) << "" << "" << "10 multi" << "" << "" << "" << ""; - QTest::newRow("mx-single-cname") << int(QDnsLookup::MX) << "mx-single-cname" << int(QDnsLookup::NoError) << "" << "" << "10 cname" << "" << "" << "" << ""; - QTest::newRow("mx-multi") << int(QDnsLookup::MX) << "mx-multi" << int(QDnsLookup::NoError) << "" << "" << "10 multi;20 a-single" << "" << "" << "" << ""; - QTest::newRow("mx-multi-sameprio") << int(QDnsLookup::MX) << "mx-multi-sameprio" << int(QDnsLookup::NoError) << "" << "" - << "10 multi;10 a-single|" - "10 a-single;10 multi" << "" << "" << "" << ""; - - QTest::newRow("ns-empty") << int(QDnsLookup::NS) << "" << int(QDnsLookup::InvalidRequestError) << "" << "" << "" << "" << "" << "" << ""; - QTest::newRow("ns-notfound") << int(QDnsLookup::NS) << "invalid.invalid" << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << ""; - QTest::newRow("ns-single") << int(QDnsLookup::NS) << "ns-single" << int(QDnsLookup::NoError) << "" << "" << "" << "ns11.cloudns.net." << "" << "" << ""; - QTest::newRow("ns-multi") << int(QDnsLookup::NS) << "ns-multi" << int(QDnsLookup::NoError) << "" << "" << "" << "ns11.cloudns.net.;ns12.cloudns.net." << "" << "" << ""; - - QTest::newRow("ptr-empty") << int(QDnsLookup::PTR) << "" << int(QDnsLookup::InvalidRequestError) << "" << "" << "" << "" << "" << "" << ""; - QTest::newRow("ptr-notfound") << int(QDnsLookup::PTR) << "invalid.invalid" << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << ""; + QTest::addColumn<QString>("expected"); + + QTest::newRow("a-single") << QDnsLookup::A << "a-single" + << "A 192.0.2.1"; + QTest::newRow("a-multi") << QDnsLookup::A << "a-multi" + << "A 192.0.2.1;A 192.0.2.2;A 192.0.2.3"; + QTest::newRow("aaaa-single") << QDnsLookup::AAAA << "aaaa-single" + << "AAAA 2001:db8::1"; + QTest::newRow("aaaa-multi") << QDnsLookup::AAAA << "aaaa-multi" + << "AAAA 2001:db8::1;AAAA 2001:db8::2;AAAA 2001:db8::3"; + + QTest::newRow("any-a-single") << QDnsLookup::ANY << "a-single" + << "A 192.0.2.1"; + QTest::newRow("any-a-plus-aaaa") << QDnsLookup::ANY << "a-plus-aaaa" + << "A 198.51.100.1;AAAA 2001:db8::1:1"; + QTest::newRow("any-multi") << QDnsLookup::ANY << "multi" + << "A 198.51.100.1;A 198.51.100.2;A 198.51.100.3;" + "AAAA 2001:db8::1:1;AAAA 2001:db8::1:2" ; + + QTest::newRow("mx-single") << QDnsLookup::MX << "mx-single" + << "MX 10 multi"; + QTest::newRow("mx-single-cname") << QDnsLookup::MX << "mx-single-cname" + << "MX 10 cname"; + QTest::newRow("mx-multi") << QDnsLookup::MX << "mx-multi" + << "MX 10 multi;MX 20 a-single"; + QTest::newRow("mx-multi-sameprio") << QDnsLookup::MX << "mx-multi-sameprio" + << "MX 10 a-single;MX 10 multi"; + + QTest::newRow("ns-single") << QDnsLookup::NS << "ns-single" + << "NS ns11.cloudns.net."; + QTest::newRow("ns-multi") << QDnsLookup::NS << "ns-multi" + << "NS ns11.cloudns.net.;NS ns12.cloudns.net."; + #if 0 // temporarily disabled since the new hosting provider can't insert // PTR records outside of the in-addr.arpa zone - QTest::newRow("ptr-single") << int(QDnsLookup::PTR) << "ptr-single" << int(QDnsLookup::NoError) << "" << "" << "" << "" << "a-single" << "" << ""; + QTest::newRow("ptr-single") << QDnsLookup::PTR << "ptr-single" + << "PTR a-single"; #endif - - QTest::newRow("srv-empty") << int(QDnsLookup::SRV) << "" << int(QDnsLookup::InvalidRequestError) << "" << "" << "" << "" << "" << "" << ""; - QTest::newRow("srv-notfound") << int(QDnsLookup::SRV) << "invalid.invalid" << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << ""; - QTest::newRow("srv-single") << int(QDnsLookup::SRV) << "_echo._tcp.srv-single" << int(QDnsLookup::NoError) << "" << "" << "" << "" << "" << "5 0 7 multi" << ""; - QTest::newRow("srv-prio") << int(QDnsLookup::SRV) << "_echo._tcp.srv-prio" << int(QDnsLookup::NoError) << "" << "" << "" << "" << "" << "1 0 7 multi;2 0 7 a-plus-aaaa" << ""; - QTest::newRow("srv-weighted") << int(QDnsLookup::SRV) << "_echo._tcp.srv-weighted" << int(QDnsLookup::NoError) << "" << "" << "" << "" << "" - << "5 75 7 multi;5 25 7 a-plus-aaaa|" - "5 25 7 a-plus-aaaa;5 75 7 multi" << ""; - QTest::newRow("srv-multi") << int(QDnsLookup::SRV) << "_echo._tcp.srv-multi" << int(QDnsLookup::NoError) << "" << "" << "" << "" << "" - << "1 50 7 multi;2 50 7 a-single;2 50 7 aaaa-single;3 50 7 a-multi|" - "1 50 7 multi;2 50 7 aaaa-single;2 50 7 a-single;3 50 7 a-multi" << ""; - - QTest::newRow("txt-empty") << int(QDnsLookup::TXT) << "" << int(QDnsLookup::InvalidRequestError) << "" << "" << "" << "" << "" << "" << ""; - QTest::newRow("txt-notfound") << int(QDnsLookup::TXT) << "invalid.invalid" << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << ""; - QTest::newRow("txt-single") << int(QDnsLookup::TXT) << "txt-single" << int(QDnsLookup::NoError) << "" << "" << "" << "" << "" << "" << "Hello"; - QTest::newRow("txt-multi-onerr") << int(QDnsLookup::TXT) << "txt-multi-onerr" << int(QDnsLookup::NoError) << "" << "" << "" << "" << "" << "" - << QString::fromLatin1("Hello\0World", sizeof("Hello\0World") - 1); - QTest::newRow("txt-multi-multirr") << int(QDnsLookup::TXT) << "txt-multi-multirr" << int(QDnsLookup::NoError) << "" << "" << "" << "" << "" << "" << "Hello;World"; -} - -static QByteArray msgDnsLookup(QDnsLookup::Error actualError, - int expectedError, - const QString &domain, - const QString &cname, - const QString &host, - const QString &srv, - const QString &mx, - const QString &ns, - const QString &ptr, - const QString &errorString) -{ - QString result; - QTextStream str(&result); - str << "Actual error: " << actualError; - if (!errorString.isEmpty()) - str << " (" << errorString << ')'; - str << ", expected: " << expectedError; - str << ", domain: " << domain; - if (!cname.isEmpty()) - str << ", cname: " << cname; - str << ", host: " << host; - if (!srv.isEmpty()) - str << " server: " << srv; - if (!mx.isEmpty()) - str << " mx: " << mx; - if (!ns.isEmpty()) - str << " ns: " << ns; - if (!ptr.isEmpty()) - str << " ptr: " << ptr; - return result.toLocal8Bit(); + QTest::newRow("ptr-1.1.1.1") << QDnsLookup::PTR << "1.1.1.1.in-addr.arpa." + << "PTR one.one.one.one."; + QTest::newRow("ptr-8.8.8.8") << QDnsLookup::PTR << "8.8.8.8.in-addr.arpa." + << "PTR dns.google."; + QTest::newRow("ptr-2001:4860:4860::8888") + << QDnsLookup::PTR << "8.8.8.8.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.6.8.4.0.6.8.4.1.0.0.2.ip6.arpa." + << "PTR dns.google."; + QTest::newRow("ptr-2606:4700:4700::1111") + << QDnsLookup::PTR << "1.1.1.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.7.4.0.0.7.4.6.0.6.2.ip6.arpa." + << "PTR one.one.one.one."; + + QTest::newRow("srv-single") << QDnsLookup::SRV << "_echo._tcp.srv-single" + << "SRV 5 0 7 multi"; + QTest::newRow("srv-prio") << QDnsLookup::SRV << "_echo._tcp.srv-prio" + << "SRV 1 0 7 multi;SRV 2 0 7 a-plus-aaaa"; + QTest::newRow("srv-weighted") << QDnsLookup::SRV << "_echo._tcp.srv-weighted" + << "SRV 5 25 7 a-plus-aaaa;SRV 5 75 7 multi"; + QTest::newRow("srv-multi") << QDnsLookup::SRV << "_echo._tcp.srv-multi" + << "SRV 1 50 7 multi;" + "SRV 2 50 7 a-single;" + "SRV 2 50 7 aaaa-single;" + "SRV 3 50 7 a-multi"; + + QTest::newRow("tlsa") << QDnsLookup::Type::TLSA << "_25._tcp.multi" + << "TLSA 3 1 1 0123456789ABCDEFFEDCBA9876543210" + "0123456789ABCDEFFEDCBA9876543210"; + + QTest::newRow("txt-single") << QDnsLookup::TXT << "txt-single" + << "TXT \"Hello\""; + QTest::newRow("txt-multi-onerr") << QDnsLookup::TXT << "txt-multi-onerr" + << "TXT \"Hello\" \"World\""; + QTest::newRow("txt-multi-multirr") << QDnsLookup::TXT << "txt-multi-multirr" + << "TXT \"Hello\";TXT \"World\""; } void tst_QDnsLookup::lookup() { - QFETCH(int, type); + QFETCH(QDnsLookup::Type, type); QFETCH(QString, domain); - QFETCH(int, error); - QFETCH(QString, cname); - QFETCH(QString, host); - QFETCH(QString, mx); - QFETCH(QString, ns); - QFETCH(QString, ptr); - QFETCH(QString, srv); - QFETCH(QString, txt); - - // transform the inputs - domain = domainName(domain); - cname = domainName(cname); - ns = domainNameList(ns); - ptr = domainNameList(ptr); - - // SRV and MX have reply entries that can change order - // and we can't sort - QStringList mx_alternatives = domainNameListAlternatives(mx); - QStringList srv_alternatives = domainNameListAlternatives(srv); + QFETCH(QString, expected); - QDnsLookup lookup; - lookup.setType(static_cast<QDnsLookup::Type>(type)); - lookup.setName(domain); - lookup.lookup(); - QTRY_VERIFY_WITH_TIMEOUT(lookup.isFinished(), Timeout); + std::unique_ptr<QDnsLookup> lookup = lookupCommon(type, domain); + if (!lookup) + return; -#if defined(Q_OS_ANDROID) - if (lookup.errorString() == QStringLiteral("Not yet supported on Android")) - QEXPECT_FAIL("", "Not yet supported on Android", Abort); +#ifdef Q_OS_WIN + if (QTest::currentDataTag() == "tlsa"_L1) + QSKIP("WinDNS doesn't work properly with TLSA records and we don't know why"); #endif + QCOMPARE(lookup->errorString(), QString()); + QCOMPARE(lookup->error(), QDnsLookup::NoError); + QCOMPARE(lookup->type(), type); + QCOMPARE(lookup->name(), domainName(domain)); + + QString result = formatReply(lookup.get()).join(u';'); + QCOMPARE(result, expected); + + // confirm that MX and SRV records are properly sorted + const QList<QDnsMailExchangeRecord> mx = lookup->mailExchangeRecords(); + for (qsizetype i = 1; i < mx.size(); ++i) + QCOMPARE_GE(mx[i].preference(), mx[i - 1].preference()); + + const QList<QDnsServiceRecord> srv = lookup->serviceRecords(); + for (qsizetype i = 1; i < srv.size(); ++i) + QCOMPARE_GE(srv[i].priority(), srv[i - 1].priority()); +} - QVERIFY2(int(lookup.error()) == error, - msgDnsLookup(lookup.error(), error, domain, cname, host, srv, mx, ns, ptr, lookup.errorString())); - if (error == QDnsLookup::NoError) - QVERIFY(lookup.errorString().isEmpty()); - QCOMPARE(int(lookup.type()), type); - QCOMPARE(lookup.name(), domain); - - // canonical names - if (!cname.isEmpty()) { - QVERIFY(!lookup.canonicalNameRecords().isEmpty()); - const QDnsDomainNameRecord cnameRecord = lookup.canonicalNameRecords().first(); - QCOMPARE(cnameRecord.name(), domain); - QCOMPARE(cnameRecord.value(), cname); - } else { - QVERIFY(lookup.canonicalNameRecords().isEmpty()); - } - - // host addresses - const QString hostName = cname.isEmpty() ? domain : cname; - QStringList addresses; - foreach (const QDnsHostAddressRecord &record, lookup.hostAddressRecords()) { - //reply may include A & AAAA records for nameservers, ignore them and only look at records matching the query - if (record.name() == hostName) - addresses << record.value().toString().toLower(); - } - addresses.sort(); - QCOMPARE(addresses.join(';'), host); - - // mail exchanges - QStringList mailExchanges; - foreach (const QDnsMailExchangeRecord &record, lookup.mailExchangeRecords()) { - QCOMPARE(record.name(), domain); - mailExchanges << QString::number(record.preference()) + QLatin1Char(' ') + record.exchange(); - } - QVERIFY2(mx_alternatives.contains(mailExchanges.join(';')), - qPrintable("Actual: " + mailExchanges.join(';') + "\nExpected one of:\n" + mx_alternatives.join('\n'))); - - // name servers - QStringList nameServers; - foreach (const QDnsDomainNameRecord &record, lookup.nameServerRecords()) { - //reply may include NS records for authoritative nameservers, ignore them and only look at records matching the query - if (record.name() == domain) - nameServers << record.value(); - } - nameServers.sort(); - QCOMPARE(nameServers.join(';'), ns); - - // pointers - if (!ptr.isEmpty()) { - QVERIFY(!lookup.pointerRecords().isEmpty()); - const QDnsDomainNameRecord ptrRecord = lookup.pointerRecords().first(); - QCOMPARE(ptrRecord.name(), domain); - QCOMPARE(ptrRecord.value(), ptr); - } else { - QVERIFY(lookup.pointerRecords().isEmpty()); - } - - // services - QStringList services; - foreach (const QDnsServiceRecord &record, lookup.serviceRecords()) { - QCOMPARE(record.name(), domain); - services << (QString::number(record.priority()) + QLatin1Char(' ') - + QString::number(record.weight()) + QLatin1Char(' ') - + QString::number(record.port()) + QLatin1Char(' ') + record.target()); - } - QVERIFY2(srv_alternatives.contains(services.join(';')), - qPrintable("Actual: " + services.join(';') + "\nExpected one of:\n" + srv_alternatives.join('\n'))); - - // text - QStringList texts; - foreach (const QDnsTextRecord &record, lookup.textRecords()) { - QCOMPARE(record.name(), domain); - QString text; - foreach (const QByteArray &ba, record.values()) { - if (!text.isEmpty()) - text += '\0'; - text += QString::fromLatin1(ba); - } - texts << text; - } - texts.sort(); - QCOMPARE(texts.join(';'), txt); +void tst_QDnsLookup::lookupIdn() +{ + usingIdnDomain = true; + lookup(); + usingIdnDomain = false; } void tst_QDnsLookup::lookupReuse() @@ -323,11 +573,6 @@ void tst_QDnsLookup::lookupReuse() lookup.lookup(); QTRY_VERIFY_WITH_TIMEOUT(lookup.isFinished(), Timeout); -#if defined(Q_OS_ANDROID) - if (lookup.errorString() == QStringLiteral("Not yet supported on Android")) - QEXPECT_FAIL("", "Not yet supported on Android", Abort); -#endif - QCOMPARE(int(lookup.error()), int(QDnsLookup::NoError)); QVERIFY(!lookup.hostAddressRecords().isEmpty()); QCOMPARE(lookup.hostAddressRecords().first().name(), domainName("a-single")); @@ -364,16 +609,204 @@ void tst_QDnsLookup::lookupAbortRetry() lookup.lookup(); QTRY_VERIFY_WITH_TIMEOUT(lookup.isFinished(), Timeout); -#if defined(Q_OS_ANDROID) - if (lookup.errorString() == QStringLiteral("Not yet supported on Android")) - QEXPECT_FAIL("", "Not yet supported on Android", Abort); -#endif - QCOMPARE(int(lookup.error()), int(QDnsLookup::NoError)); QVERIFY(!lookup.hostAddressRecords().isEmpty()); QCOMPARE(lookup.hostAddressRecords().first().name(), domainName("aaaa-single")); QCOMPARE(lookup.hostAddressRecords().first().value(), QHostAddress("2001:db8::1")); } +void tst_QDnsLookup::setNameserverLoopback() +{ +#ifdef Q_OS_WIN + // Windows doesn't like sending DNS requests to ports other than 53, so + // let's try it first. + constexpr quint16 DesiredPort = 53; +#else + // Trying to bind to port 53 will fail on Unix systems unless this test is + // run as root, so we try mDNS's port (to help decoding in a packet capture). + constexpr quint16 DesiredPort = 5353; // mDNS +#endif + // random loopback address so multiple copies of this test can run + QHostAddress desiredAddress(0x7f000000 | QRandomGenerator::system()->bounded(0xffffff)); + + QUdpSocket server; + if (!server.bind(desiredAddress, DesiredPort)) { + // port in use, try a random one + server.bind(QHostAddress::LocalHost, 0); + } + QCOMPARE(server.state(), QUdpSocket::BoundState); + + QDnsLookup lookup(QDnsLookup::Type::A, u"somelabel.somedomain"_s); + QSignalSpy spy(&lookup, SIGNAL(finished())); + lookup.setNameserver(server.localAddress(), server.localPort()); + + // QDnsLookup is threaded, so we can answer on the main thread + QObject::connect(&server, &QUdpSocket::readyRead, + &QTestEventLoop::instance(), &QTestEventLoop::exitLoop); + QObject::connect(&lookup, &QDnsLookup::finished, + &QTestEventLoop::instance(), &QTestEventLoop::exitLoop); + lookup.lookup(); + QTestEventLoop::instance().enterLoop(5); + QVERIFY(!QTestEventLoop::instance().timeout()); + QVERIFY2(spy.isEmpty(), qPrintable(lookup.errorString())); + + QNetworkDatagram dgram = server.receiveDatagram(); + QByteArray data = dgram.data(); + QCOMPARE_GT(data.size(), HeaderSize); + + quint8 opcode = (quint8(data.at(2)) >> 3) & 0xF; + QCOMPARE(opcode, 0); // standard query + + // send an NXDOMAIN reply to release the lookup thread + QByteArray reply = data; + reply[2] = 0x80U; // header->qr = true; + reply[3] = 3; // header->rcode = NXDOMAIN; + server.writeDatagram(reply.constData(), reply.size(), dgram.senderAddress(), + dgram.senderPort()); + server.close(); + + // now check that the QDnsLookup finished + QTestEventLoop::instance().enterLoop(5); + QVERIFY(!QTestEventLoop::instance().timeout()); + QCOMPARE(spy.size(), 1); + QCOMPARE(lookup.error(), QDnsLookup::NotFoundError); +} + +template <QDnsLookup::Protocol Protocol> +static void setNameserver_data_helper(const QByteArray &protoName) +{ + if (!QDnsLookup::isProtocolSupported(Protocol)) + QSKIP(protoName + " not supported"); + + static QList<QHostAddress> servers = systemNameservers(Protocol) + + globalPublicNameservers(Protocol); + QTest::addColumn<QHostAddress>("server"); + + if (servers.isEmpty()) { + QSKIP("No reachable " + protoName + " servers were found"); + } else { + for (const QHostAddress &h : std::as_const(servers)) + QTest::addRow("%s", qUtf8Printable(h.toString())) << h; + } +} + +void tst_QDnsLookup::setNameserver_data() +{ + setNameserver_data_helper<QDnsLookup::Standard>("DNS"); +} + +void tst_QDnsLookup::setNameserver_helper(QDnsLookup::Protocol protocol) +{ + QFETCH(QHostAddress, server); + QElapsedTimer timer; + timer.start(); + std::unique_ptr<QDnsLookup> lookup = + lookupCommon(QDnsLookup::Type::A, "a-single", server, 0, protocol); + if (!lookup) + return; + qDebug() << "Lookup took" << timer.elapsed() << "ms"; + QCOMPARE(lookup->error(), QDnsLookup::NoError); + QString result = formatReply(lookup.get()).join(';'); + QCOMPARE(result, "A 192.0.2.1"); +} + +void tst_QDnsLookup::setNameserver() +{ + setNameserver_helper(QDnsLookup::Standard); +} + +void tst_QDnsLookup::dnsOverTls_data() +{ + setNameserver_data_helper<QDnsLookup::DnsOverTls>("DNS-over-TLS"); +} + +void tst_QDnsLookup::dnsOverTls() +{ + setNameserver_helper(QDnsLookup::DnsOverTls); +} + +void tst_QDnsLookup::bindingsAndProperties() +{ + QDnsLookup lookup; + + lookup.setType(QDnsLookup::A); + QProperty<QDnsLookup::Type> dnsTypeProp; + lookup.bindableType().setBinding(Qt::makePropertyBinding(dnsTypeProp)); + const QSignalSpy typeChangeSpy(&lookup, &QDnsLookup::typeChanged); + + dnsTypeProp = QDnsLookup::AAAA; + QCOMPARE(typeChangeSpy.size(), 1); + QCOMPARE(lookup.type(), QDnsLookup::AAAA); + + dnsTypeProp.setBinding(lookup.bindableType().makeBinding()); + lookup.setType(QDnsLookup::A); + QCOMPARE(dnsTypeProp.value(), QDnsLookup::A); + + QProperty<QString> nameProp; + lookup.bindableName().setBinding(Qt::makePropertyBinding(nameProp)); + const QSignalSpy nameChangeSpy(&lookup, &QDnsLookup::nameChanged); + + nameProp = QStringLiteral("a-plus-aaaa"); + QCOMPARE(nameChangeSpy.size(), 1); + QCOMPARE(lookup.name(), QStringLiteral("a-plus-aaaa")); + + nameProp.setBinding(lookup.bindableName().makeBinding()); + lookup.setName(QStringLiteral("a-single")); + QCOMPARE(nameProp.value(), QStringLiteral("a-single")); + + QProperty<QHostAddress> nameserverProp; + lookup.bindableNameserver().setBinding(Qt::makePropertyBinding(nameserverProp)); + const QSignalSpy nameserverChangeSpy(&lookup, &QDnsLookup::nameserverChanged); + const QSignalSpy nameserverPortChangeSpy(&lookup, &QDnsLookup::nameserverPortChanged); + + nameserverProp = QHostAddress::LocalHost; + QCOMPARE(nameserverChangeSpy.size(), 1); + QCOMPARE(nameserverPortChangeSpy.size(), 0); + QCOMPARE(lookup.nameserver(), QHostAddress::LocalHost); + + nameserverProp.setBinding(lookup.bindableNameserver().makeBinding()); + lookup.setNameserver(QHostAddress::Any); + QCOMPARE(nameserverProp.value(), QHostAddress::Any); + QCOMPARE(nameserverChangeSpy.size(), 2); + QCOMPARE(nameserverPortChangeSpy.size(), 0); + + lookup.setNameserver(QHostAddress::LocalHostIPv6, 10053); + QCOMPARE(nameserverProp.value(), QHostAddress::LocalHostIPv6); + QCOMPARE(nameserverChangeSpy.size(), 3); + QCOMPARE(nameserverPortChangeSpy.size(), 1); +} + +void tst_QDnsLookup::automatedBindings() +{ + QDnsLookup lookup; + + QTestPrivate::testReadWritePropertyBasics(lookup, u"aaaa"_s, u"txt"_s, "name"); + if (QTest::currentTestFailed()) { + qDebug("Failed property test for QDnsLookup::name"); + return; + } + + QTestPrivate::testReadWritePropertyBasics(lookup, QDnsLookup::AAAA, QDnsLookup::TXT, "type"); + if (QTest::currentTestFailed()) { + qDebug("Failed property test for QDnsLookup::type"); + return; + } + + QTestPrivate::testReadWritePropertyBasics(lookup, QHostAddress{QHostAddress::Any}, + QHostAddress{QHostAddress::LocalHost}, + "nameserver"); + if (QTest::currentTestFailed()) { + qDebug("Failed property test for QDnsLookup::nameserver"); + return; + } + + QTestPrivate::testReadWritePropertyBasics(lookup, quint16(123), quint16(456), + "nameserverPort"); + if (QTest::currentTestFailed()) { + qDebug("Failed property test for QDnsLookup::nameserverPort"); + return; + } +} + QTEST_MAIN(tst_QDnsLookup) #include "tst_qdnslookup.moc" diff --git a/tests/auto/network/kernel/qdnslookup_appless/CMakeLists.txt b/tests/auto/network/kernel/qdnslookup_appless/CMakeLists.txt index 1730879bd2..41cf19753f 100644 --- a/tests/auto/network/kernel/qdnslookup_appless/CMakeLists.txt +++ b/tests/auto/network/kernel/qdnslookup_appless/CMakeLists.txt @@ -1,12 +1,19 @@ -# Generated from qdnslookup_appless.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qdnslookup_appless Test: ##################################################################### -qt_add_test(tst_qdnslookup_appless +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qdnslookup_appless LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qdnslookup_appless SOURCES tst_qdnslookup_appless.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Network ) diff --git a/tests/auto/network/kernel/qdnslookup_appless/qdnslookup_appless.pro b/tests/auto/network/kernel/qdnslookup_appless/qdnslookup_appless.pro deleted file mode 100644 index 25d76b5739..0000000000 --- a/tests/auto/network/kernel/qdnslookup_appless/qdnslookup_appless.pro +++ /dev/null @@ -1,7 +0,0 @@ -CONFIG += testcase - -TARGET = tst_qdnslookup_appless - -SOURCES += tst_qdnslookup_appless.cpp - -QT = core network testlib diff --git a/tests/auto/network/kernel/qdnslookup_appless/tst_qdnslookup_appless.cpp b/tests/auto/network/kernel/qdnslookup_appless/tst_qdnslookup_appless.cpp index e302fe8c74..21393ee628 100644 --- a/tests/auto/network/kernel/qdnslookup_appless/tst_qdnslookup_appless.cpp +++ b/tests/auto/network/kernel/qdnslookup_appless/tst_qdnslookup_appless.cpp @@ -1,34 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org> -** 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$ -** -****************************************************************************/ +// Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtCore/QCoreApplication> #include <QtNetwork/QDnsLookup> -#include <QtTest/QtTest> +#include <QTest> +#include <QTestEventLoop> class tst_QDnsLookup_Appless : public QObject { diff --git a/tests/auto/network/kernel/qhostaddress/CMakeLists.txt b/tests/auto/network/kernel/qhostaddress/CMakeLists.txt index c1999c8db2..e11a600b60 100644 --- a/tests/auto/network/kernel/qhostaddress/CMakeLists.txt +++ b/tests/auto/network/kernel/qhostaddress/CMakeLists.txt @@ -1,20 +1,27 @@ -# Generated from qhostaddress.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qhostaddress Test: ##################################################################### -qt_add_test(tst_qhostaddress +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qhostaddress LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qhostaddress SOURCES tst_qhostaddress.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::NetworkPrivate ) ## Scopes: ##################################################################### -qt_extend_target(tst_qhostaddress CONDITION WIN32 - PUBLIC_LIBRARIES +qt_internal_extend_target(tst_qhostaddress CONDITION WIN32 + LIBRARIES ws2_32 ) diff --git a/tests/auto/network/kernel/qhostaddress/qhostaddress.pro b/tests/auto/network/kernel/qhostaddress/qhostaddress.pro deleted file mode 100644 index d170d879e6..0000000000 --- a/tests/auto/network/kernel/qhostaddress/qhostaddress.pro +++ /dev/null @@ -1,7 +0,0 @@ -CONFIG += testcase -TARGET = tst_qhostaddress -SOURCES += tst_qhostaddress.cpp - -QT = core network-private testlib - -win32: QMAKE_USE += ws2_32 diff --git a/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp b/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp index 6bfd40a580..18d1c04a85 100644 --- a/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp +++ b/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp @@ -1,36 +1,11 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2016 Intel Corporation. -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2016 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <qhostaddress.h> #include <private/qhostaddress_p.h> #include <qcoreapplication.h> -#include <QtTest/QtTest> +#include <QTest> #include <qplatformdefs.h> #include <qdebug.h> #include <qhash.h> @@ -40,7 +15,7 @@ # include <qt_windows.h> #endif -#ifdef Q_OS_ANDROID +#if defined(Q_OS_ANDROID) || defined(Q_OS_WASM) || defined(Q_OS_VXWORKS) # include <netinet/in.h> #endif @@ -110,14 +85,14 @@ void tst_QHostAddress::constructor_QString() QTEST(hostAddr.toString(), "resAddr"); if ( protocol == 4 ) { - QVERIFY( hostAddr.protocol() == QAbstractSocket::IPv4Protocol || hostAddr.protocol() == QAbstractSocket::UnknownNetworkLayerProtocol ); - QVERIFY( hostAddr.protocol() != QAbstractSocket::IPv6Protocol ); + QVERIFY( hostAddr.protocol() == QHostAddress::IPv4Protocol || hostAddr.protocol() == QHostAddress::UnknownNetworkLayerProtocol ); + QVERIFY( hostAddr.protocol() != QHostAddress::IPv6Protocol ); } else if ( protocol == 6 ) { - QVERIFY( hostAddr.protocol() != QAbstractSocket::IPv4Protocol && hostAddr.protocol() != QAbstractSocket::UnknownNetworkLayerProtocol ); - QVERIFY( hostAddr.protocol() == QAbstractSocket::IPv6Protocol ); + QVERIFY( hostAddr.protocol() != QHostAddress::IPv4Protocol && hostAddr.protocol() != QHostAddress::UnknownNetworkLayerProtocol ); + QVERIFY( hostAddr.protocol() == QHostAddress::IPv6Protocol ); } else { QVERIFY( hostAddr.isNull() ); - QVERIFY( hostAddr.protocol() == QAbstractSocket::UnknownNetworkLayerProtocol ); + QVERIFY( hostAddr.protocol() == QHostAddress::UnknownNetworkLayerProtocol ); } } @@ -217,14 +192,14 @@ void tst_QHostAddress::setAddress_QString() QTEST(hostAddr.toString(), "resAddr"); if ( protocol == 4 ) { - QVERIFY( hostAddr.protocol() == QAbstractSocket::IPv4Protocol || hostAddr.protocol() == QAbstractSocket::UnknownNetworkLayerProtocol ); - QVERIFY( hostAddr.protocol() != QAbstractSocket::IPv6Protocol ); + QVERIFY( hostAddr.protocol() == QHostAddress::IPv4Protocol || hostAddr.protocol() == QHostAddress::UnknownNetworkLayerProtocol ); + QVERIFY( hostAddr.protocol() != QHostAddress::IPv6Protocol ); } else if ( protocol == 6 ) { - QVERIFY( hostAddr.protocol() != QAbstractSocket::IPv4Protocol && hostAddr.protocol() != QAbstractSocket::UnknownNetworkLayerProtocol ); - QVERIFY( hostAddr.protocol() == QAbstractSocket::IPv6Protocol ); + QVERIFY( hostAddr.protocol() != QHostAddress::IPv4Protocol && hostAddr.protocol() != QHostAddress::UnknownNetworkLayerProtocol ); + QVERIFY( hostAddr.protocol() == QHostAddress::IPv6Protocol ); } else { QVERIFY( hostAddr.isNull() ); - QVERIFY( hostAddr.protocol() == QAbstractSocket::UnknownNetworkLayerProtocol ); + QVERIFY( hostAddr.protocol() == QHostAddress::UnknownNetworkLayerProtocol ); } } @@ -351,6 +326,12 @@ void tst_QHostAddress::isEqual_data() 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; + QTest::newRow("localhostv6-any-tolerant") << QHostAddress(QHostAddress::LocalHostIPv6) << QHostAddress(QHostAddress::Any) << (int)QHostAddress::TolerantConversion << false; + QTest::newRow("localhostv4-any-tolerant") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::Any) << (int)QHostAddress::TolerantConversion << false; + QTest::newRow("localhostv6-anyv6-tolerant") << QHostAddress(QHostAddress::LocalHostIPv6) << QHostAddress(QHostAddress::AnyIPv6) << (int)QHostAddress::TolerantConversion << false; + QTest::newRow("localhostv4-anyv6-tolerant") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::AnyIPv6) << (int)QHostAddress::TolerantConversion << false; + QTest::newRow("localhostv6-anyv4-tolerant") << QHostAddress(QHostAddress::LocalHostIPv6) << QHostAddress(QHostAddress::AnyIPv4) << (int)QHostAddress::TolerantConversion << false; + QTest::newRow("localhostv4-anyv4-tolerant") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::AnyIPv4) << (int)QHostAddress::TolerantConversion << false; } void tst_QHostAddress::isEqual() @@ -722,6 +703,7 @@ void tst_QHostAddress::classification() bool isUniqueLocalAddress = (result == UniqueLocalAddress); bool isMulticast = (result == MulticastAddress); bool isBroadcast = (result == BroadcastAddress); + bool isPrivateUse = (result == PrivateNetworkAddress || result == UniqueLocalAddress); QCOMPARE(address.isLoopback(), isLoopback); QCOMPARE(address.isGlobal(), isGlobal); @@ -730,6 +712,7 @@ void tst_QHostAddress::classification() QCOMPARE(address.isUniqueLocalUnicast(), isUniqueLocalAddress); QCOMPARE(address.isMulticast(), isMulticast); QCOMPARE(address.isBroadcast(), isBroadcast); + QCOMPARE(address.isPrivateUse(), isPrivateUse); } void tst_QHostAddress::convertv4v6_data() @@ -770,7 +753,7 @@ void tst_QHostAddress::convertv4v6() if (protocol == 4) { bool ok; quint32 v4 = source.toIPv4Address(&ok); - QCOMPARE(ok, result.protocol() == QAbstractSocket::IPv4Protocol); + QCOMPARE(ok, result.protocol() == QHostAddress::IPv4Protocol); if (ok) QCOMPARE(QHostAddress(v4), result); } else if (protocol == 6) { diff --git a/tests/auto/network/kernel/qhostinfo/CMakeLists.txt b/tests/auto/network/kernel/qhostinfo/CMakeLists.txt index b571718d25..dc7ab3b221 100644 --- a/tests/auto/network/kernel/qhostinfo/CMakeLists.txt +++ b/tests/auto/network/kernel/qhostinfo/CMakeLists.txt @@ -1,4 +1,11 @@ -# Generated from qhostinfo.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qhostinfo LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() if(NOT QT_FEATURE_private_tests) return() @@ -8,21 +15,18 @@ endif() ## tst_qhostinfo Test: ##################################################################### -qt_add_test(tst_qhostinfo +qt_internal_add_test(tst_qhostinfo SOURCES tst_qhostinfo.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::NetworkPrivate ) -#### Keys ignored in scope 1:.:.:qhostinfo.pro:<TRUE>: -# _REQUIREMENTS = "qtConfig(private_tests)" - ## Scopes: ##################################################################### -qt_extend_target(tst_qhostinfo CONDITION WIN32 - PUBLIC_LIBRARIES +qt_internal_extend_target(tst_qhostinfo CONDITION WIN32 + LIBRARIES ws2_32 ) diff --git a/tests/auto/network/kernel/qhostinfo/qhostinfo.pro b/tests/auto/network/kernel/qhostinfo/qhostinfo.pro deleted file mode 100644 index e084f28229..0000000000 --- a/tests/auto/network/kernel/qhostinfo/qhostinfo.pro +++ /dev/null @@ -1,9 +0,0 @@ -CONFIG += testcase -TARGET = tst_qhostinfo - -SOURCES += tst_qhostinfo.cpp - -requires(qtConfig(private_tests)) -QT = core-private network-private testlib - -win32: QMAKE_USE += ws2_32 diff --git a/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp b/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp index 539043377f..bd4bb7ef81 100644 --- a/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp +++ b/tests/auto/network/kernel/qhostinfo/tst_qhostinfo.cpp @@ -1,73 +1,52 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2016 Intel Corporation. -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2016 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only // When using WinSock2 on Windows, it's the first thing that can be included // (except qglobal.h), or else you'll get tons of compile errors #include <qglobal.h> -// To prevent windows system header files from re-defining min/max -#define NOMINMAX 1 - #if defined(Q_OS_WIN) # include <winsock2.h> # include <ws2tcpip.h> #endif -#include <QtTest/QtTest> -#include <qcoreapplication.h> +#include <qhostinfo.h> +#include "private/qhostinfo_p.h" +#include "private/qnativesocketengine_p.h" + +#include <QCoreApplication> #include <QDebug> +#include <QTcpServer> #include <QTcpSocket> +#include <QTest> +#include <QTestEventLoop> + #include <private/qthread_p.h> -#include <QTcpServer> -#include <time.h> +#include <sys/types.h> + #if defined(Q_OS_WIN) -#include <windows.h> +# include <qt_windows.h> +# ifdef gai_strerror +# undef gai_strerror +# define gai_strerror gai_strerrorA +# endif #else -#include <unistd.h> -#include <signal.h> -#endif - -#include <qhostinfo.h> -#include "private/qhostinfo_p.h" - -#include <sys/types.h> -#if defined(Q_OS_UNIX) -# include <sys/socket.h> # include <netdb.h> +# include <sys/socket.h> +# include <unistd.h> +#endif +#ifndef NI_MAXHOST +# define NI_MAXHOST 1025 #endif #include "../../../network-settings.h" #define TEST_DOMAIN ".test.qt-project.org" +using namespace std::chrono_literals; class tst_QHostInfo : public QObject { @@ -106,15 +85,55 @@ private slots: void cache(); void abortHostLookup(); -protected slots: - void resultsReady(const QHostInfo &); private: bool ipv6LookupsAvailable; bool ipv6Available; - bool lookupDone; - int lookupsDoneCounter; +}; + +class tst_QHostInfo_Helper : public QObject +{ + Q_OBJECT +protected slots: + void resultsReady(const QHostInfo &); +public: + tst_QHostInfo_Helper(const QString &hostname) + : hostname(hostname) + {} + + QString hostname; + bool lookupDone = false; + int lookupsDoneCounter = 0; QHostInfo lookupResults; + + void blockingLookup() + { + lookupResults = QHostInfo::fromName(hostname); + lookupDone = true; + ++lookupsDoneCounter; + } + void lookupHostOldStyle() + { + QHostInfo::lookupHost(hostname, this, SLOT(resultsReady(QHostInfo))); + } + void lookupHostNewStyle() + { + QHostInfo::lookupHost(hostname, this, &tst_QHostInfo_Helper::resultsReady); + } + void lookupHostLambda() + { + QHostInfo::lookupHost(hostname, this, [this](const QHostInfo &hostInfo) { + resultsReady(hostInfo); + }); + } + + bool waitForResults(std::chrono::milliseconds timeout = 15s) + { + QTestEventLoop::instance().enterLoop(timeout); + return !QTestEventLoop::instance().timeout() && lookupDone; + } + + void checkResults(QHostInfo::HostInfoError err, const QString &addresses); }; void tst_QHostInfo::swapFunction() @@ -230,26 +249,15 @@ void tst_QHostInfo::lookupIPv4_data() QTest::newRow("idn-unicode") << QString::fromLatin1("a-single.alqualond\353" TEST_DOMAIN) << "192.0.2.1" << int(QHostInfo::NoError); } -void tst_QHostInfo::lookupIPv4() +void tst_QHostInfo_Helper::checkResults(QHostInfo::HostInfoError err, const QString &addresses) { - QFETCH(QString, hostname); - QFETCH(int, err); - QFETCH(QString, addresses); - - lookupDone = false; - QHostInfo::lookupHost(hostname, this, SLOT(resultsReady(QHostInfo))); - - QTestEventLoop::instance().enterLoop(10); - QVERIFY(!QTestEventLoop::instance().timeout()); - QVERIFY(lookupDone); - if ((int)lookupResults.error() != (int)err) { qWarning() << hostname << "=>" << lookupResults.errorString(); } - QCOMPARE((int)lookupResults.error(), (int)err); + QCOMPARE(lookupResults.error(), err); QStringList tmp; - for (int i = 0; i < lookupResults.addresses().count(); ++i) + for (int i = 0; i < lookupResults.addresses().size(); ++i) tmp.append(lookupResults.addresses().at(i).toString()); tmp.sort(); @@ -259,6 +267,18 @@ void tst_QHostInfo::lookupIPv4() QCOMPARE(tmp.join(' '), expected.join(' ')); } +void tst_QHostInfo::lookupIPv4() +{ + QFETCH(QString, hostname); + QFETCH(int, err); + QFETCH(QString, addresses); + + tst_QHostInfo_Helper helper(hostname); + helper.lookupHostOldStyle(); + QVERIFY(helper.waitForResults()); + helper.checkResults(QHostInfo::HostInfoError(err), addresses); +} + void tst_QHostInfo::lookupIPv6_data() { QTest::addColumn<QString>("hostname"); @@ -284,24 +304,10 @@ void tst_QHostInfo::lookupIPv6() if (!ipv6LookupsAvailable) QSKIP("This platform does not support IPv6 lookups"); - lookupDone = false; - QHostInfo::lookupHost(hostname, this, SLOT(resultsReady(QHostInfo))); - - QTestEventLoop::instance().enterLoop(10); - QVERIFY(!QTestEventLoop::instance().timeout()); - QVERIFY(lookupDone); - - QCOMPARE((int)lookupResults.error(), (int)err); - - QStringList tmp; - for (int i = 0; i < lookupResults.addresses().count(); ++i) - tmp.append(lookupResults.addresses().at(i).toString()); - tmp.sort(); - - QStringList expected = addresses.split(' '); - expected.sort(); - - QCOMPARE(tmp.join(' ').toLower(), expected.join(' ').toLower()); + tst_QHostInfo_Helper helper(hostname); + helper.lookupHostOldStyle(); + QVERIFY(helper.waitForResults()); + helper.checkResults(QHostInfo::HostInfoError(err), addresses); } void tst_QHostInfo::lookupConnectToFunctionPointer_data() @@ -315,26 +321,10 @@ void tst_QHostInfo::lookupConnectToFunctionPointer() QFETCH(int, err); QFETCH(QString, addresses); - lookupDone = false; - QHostInfo::lookupHost(hostname, this, &tst_QHostInfo::resultsReady); - - QTestEventLoop::instance().enterLoop(10); - QVERIFY(!QTestEventLoop::instance().timeout()); - QVERIFY(lookupDone); - - if (int(lookupResults.error()) != int(err)) - qWarning() << hostname << "=>" << lookupResults.errorString(); - QCOMPARE(int(lookupResults.error()), int(err)); - - QStringList tmp; - for (const auto &result : lookupResults.addresses()) - tmp.append(result.toString()); - tmp.sort(); - - QStringList expected = addresses.split(' '); - expected.sort(); - - QCOMPARE(tmp.join(' '), expected.join(' ')); + tst_QHostInfo_Helper helper(hostname); + helper.lookupHostNewStyle(); + QVERIFY(helper.waitForResults()); + helper.checkResults(QHostInfo::HostInfoError(err), addresses); } void tst_QHostInfo::lookupConnectToFunctionPointerDeleted() @@ -359,89 +349,38 @@ void tst_QHostInfo::lookupConnectToLambda() QFETCH(int, err); QFETCH(QString, addresses); - lookupDone = false; - QHostInfo::lookupHost(hostname, [=](const QHostInfo &hostInfo) { - resultsReady(hostInfo); - }); - - QTestEventLoop::instance().enterLoop(10); - QVERIFY(!QTestEventLoop::instance().timeout()); - QVERIFY(lookupDone); - - if (int(lookupResults.error()) != int(err)) - qWarning() << hostname << "=>" << lookupResults.errorString(); - QCOMPARE(int(lookupResults.error()), int(err)); - - QStringList tmp; - for (int i = 0; i < lookupResults.addresses().count(); ++i) - tmp.append(lookupResults.addresses().at(i).toString()); - tmp.sort(); - - QStringList expected = addresses.split(' '); - expected.sort(); - - QCOMPARE(tmp.join(' '), expected.join(' ')); + tst_QHostInfo_Helper helper(hostname); + helper.lookupHostLambda(); + QVERIFY(helper.waitForResults()); + helper.checkResults(QHostInfo::HostInfoError(err), addresses); } static QStringList reverseLookupHelper(const QString &ip) { QStringList results; - - const QString pythonCode = - "import socket;" - "import sys;" - "print (socket.getnameinfo((sys.argv[1], 0), 0)[0]);"; - - QList<QByteArray> lines; - QProcess python; - python.setProcessChannelMode(QProcess::ForwardedErrorChannel); - python.start("python", QStringList() << QString("-c") << pythonCode << ip); - if (python.waitForFinished()) { - if (python.exitStatus() == QProcess::NormalExit && python.exitCode() == 0) - lines = python.readAllStandardOutput().split('\n'); - for (QByteArray line : lines) { - if (!line.isEmpty()) - results << line.trimmed(); - } - if (!results.isEmpty()) - return results; - } - - qDebug() << "Python failed, falling back to nslookup"; - QProcess lookup; - lookup.setProcessChannelMode(QProcess::ForwardedErrorChannel); - lookup.start("nslookup", QStringList(ip)); - if (!lookup.waitForFinished()) { - results << "nslookup failure"; - qDebug() << "nslookup failure"; + union qt_sockaddr { + sockaddr a; + sockaddr_in a4; + sockaddr_in6 a6; + } sa = {}; + + QHostAddress addr(ip); + if (addr.isNull()) { + qWarning("Could not parse IP address: %ls", qUtf16Printable(ip)); return results; } - lines = lookup.readAllStandardOutput().split('\n'); - - QByteArray name; - - const QByteArray nameMarkerNix("name ="); - const QByteArray nameMarkerWin("Name:"); - const QByteArray addressMarkerWin("Address:"); - - for (QByteArray line : lines) { - int index = -1; - if ((index = line.indexOf(nameMarkerNix)) != -1) { // Linux and macOS - name = line.mid(index + nameMarkerNix.length()).chopped(1).trimmed(); - results << name; - } else if (line.startsWith(nameMarkerWin)) { // Windows formatting - name = line.mid(line.lastIndexOf(" ")).trimmed(); - } else if (line.startsWith(addressMarkerWin)) { - QByteArray address = line.mid(addressMarkerWin.length()).trimmed(); - if (address == ip.toUtf8()) { - results << name; - } - } - } - if (results.isEmpty()) { - qDebug() << "Failure to parse nslookup output: " << lines; + // from qnativesocketengine_p.h: + QT_SOCKLEN_T len = setSockaddr(&sa.a, addr, /*port = */ 0); + + QByteArray name(NI_MAXHOST, Qt::Uninitialized); + int ni_flags = NI_NAMEREQD | NI_NUMERICSERV; + if (int r = getnameinfo(&sa.a, len, name.data(), name.size(), nullptr, 0, ni_flags)) { + qWarning("Failed to reverse look up '%ls': %s", qUtf16Printable(ip), gai_strerror(r)); + } else { + results << QString::fromLatin1(name, qstrnlen(name, name.size())); } + return results; } @@ -454,8 +393,10 @@ void tst_QHostInfo::reverseLookup_data() QTest::newRow("dns.google") << QString("8.8.8.8") << reverseLookupHelper("8.8.8.8") << 0 << false; QTest::newRow("one.one.one.one") << QString("1.1.1.1") << reverseLookupHelper("1.1.1.1") << 0 << false; - QTest::newRow("dns.google IPv6") << QString("2001:4860:4860::8888") << reverseLookupHelper("2001:4860:4860::8888") << 0 << true; - QTest::newRow("cloudflare IPv6") << QString("2606:4700:4700::1111") << reverseLookupHelper("2606:4700:4700::1111") << 0 << true; + if (QStringList hostNames = reverseLookupHelper("2001:4860:4860::8888"); !hostNames.isEmpty()) + QTest::newRow("dns.google IPv6") << QString("2001:4860:4860::8888") << std::move(hostNames) << 0 << true; + if (QStringList hostNames = reverseLookupHelper("2606:4700:4700::1111"); !hostNames.isEmpty()) + QTest::newRow("cloudflare IPv6") << QString("2606:4700:4700::1111") << std::move(hostNames) << 0 << true; QTest::newRow("bogus-name IPv6") << QString("1::2::3::4") << QStringList() << 1 << true; } @@ -464,11 +405,6 @@ void tst_QHostInfo::reverseLookup() QFETCH(QString, address); QFETCH(QStringList, hostNames); QFETCH(int, err); - QFETCH(bool, ipv6); - - if (ipv6 && !ipv6LookupsAvailable) { - QSKIP("IPv6 reverse lookups are not supported on this platform"); - } QHostInfo info = QHostInfo::fromName(address); @@ -476,7 +412,7 @@ void tst_QHostInfo::reverseLookup() if (!hostNames.contains(info.hostName())) qDebug() << "Failure: expecting" << hostNames << ",got " << info.hostName(); QVERIFY(hostNames.contains(info.hostName())); - QCOMPARE(info.addresses().first(), QHostAddress(address)); + QCOMPARE(info.addresses().constFirst(), QHostAddress(address)); } else { QCOMPARE(info.hostName(), address); QCOMPARE(info.error(), QHostInfo::HostNotFound); @@ -497,21 +433,9 @@ void tst_QHostInfo::blockingLookup() QFETCH(int, err); QFETCH(QString, addresses); - QHostInfo hostInfo = QHostInfo::fromName(hostname); - QStringList tmp; - for (int i = 0; i < hostInfo.addresses().count(); ++i) - tmp.append(hostInfo.addresses().at(i).toString()); - tmp.sort(); - - if ((int)hostInfo.error() != (int)err) { - qWarning() << hostname << "=>" << lookupResults.errorString(); - } - QCOMPARE((int)hostInfo.error(), (int)err); - - QStringList expected = addresses.split(' '); - expected.sort(); - - QCOMPARE(tmp.join(' ').toUpper(), expected.join(' ').toUpper()); + tst_QHostInfo_Helper helper(hostname); + helper.blockingLookup(); + helper.checkResults(QHostInfo::HostInfoError(err), addresses); } void tst_QHostInfo::raceCondition() @@ -528,8 +452,9 @@ protected: inline void run() override { QHostInfo info = QHostInfo::fromName("a-single" TEST_DOMAIN); + QCOMPARE(info.errorString(), "Unknown error"); // no error QCOMPARE(info.error(), QHostInfo::NoError); - QVERIFY(info.addresses().count() > 0); + QVERIFY(info.addresses().size() > 0); QCOMPARE(info.addresses().at(0).toString(), QString("192.0.2.1")); } }; @@ -576,24 +501,22 @@ void tst_QHostInfo::threadSafetyAsynchronousAPI() { const int nattempts = 10; const int lookupsperthread = 10; - QList<QThread*> threads; - QList<LookupReceiver*> receivers; + QThread threads[nattempts]; + LookupReceiver receivers[nattempts]; for (int i = 0; i < nattempts; ++i) { - QThread* thread = new QThread; - LookupReceiver* receiver = new LookupReceiver; + QThread *thread = &threads[i]; + LookupReceiver *receiver = &receivers[i]; receiver->numrequests = lookupsperthread; - receivers.append(receiver); receiver->moveToThread(thread); connect(thread, SIGNAL(started()), receiver, SLOT(start())); thread->start(); - threads.append(thread); } - for (int k = threads.count() - 1; k >= 0; --k) - QVERIFY(threads.at(k)->wait(60000)); - foreach (LookupReceiver* receiver, receivers) { - QCOMPARE(receiver->result.error(), QHostInfo::NoError); - QCOMPARE(receiver->result.addresses().at(0).toString(), QString("192.0.2.1")); - QCOMPARE(receiver->numrequests, 0); + for (int k = nattempts - 1; k >= 0; --k) + QVERIFY(threads[k].wait(60000)); + for (LookupReceiver &receiver : receivers) { + QCOMPARE(receiver.result.error(), QHostInfo::NoError); + QCOMPARE(receiver.result.addresses().at(0).toString(), QString("192.0.2.1")); + QCOMPARE(receiver.numrequests, 0); } } @@ -602,17 +525,11 @@ void tst_QHostInfo::threadSafetyAsynchronousAPI() void tst_QHostInfo::multipleSameLookups() { const int COUNT = 10; - lookupsDoneCounter = 0; - + tst_QHostInfo_Helper helper("localhost"); for (int i = 0; i < COUNT; i++) - QHostInfo::lookupHost("localhost", this, SLOT(resultsReady(QHostInfo))); + helper.lookupHostOldStyle(); - QElapsedTimer timer; - timer.start(); - while (timer.elapsed() < 10000 && lookupsDoneCounter < COUNT) { - QTestEventLoop::instance().enterLoop(2); - } - QCOMPARE(lookupsDoneCounter, COUNT); + QTRY_COMPARE_WITH_TIMEOUT(helper.lookupsDoneCounter, COUNT, 10s); } // this test is for the multi-threaded QHostInfo rewrite. It is about getting results at all, @@ -641,19 +558,15 @@ void tst_QHostInfo::multipleDifferentLookups() QFETCH(int, repeats); const int COUNT = hostnameList.size(); - lookupsDoneCounter = 0; + tst_QHostInfo_Helper helper(QString{}); for (int i = 0; i < hostnameList.size(); i++) - for (int j = 0; j < repeats; ++j) - QHostInfo::lookupHost(hostnameList.at(i), this, SLOT(resultsReady(QHostInfo))); - - QElapsedTimer timer; - timer.start(); - while (timer.elapsed() < 60000 && lookupsDoneCounter < repeats*COUNT) { - QTestEventLoop::instance().enterLoop(2); - //qDebug() << "t:" << timer.elapsed(); - } - QCOMPARE(lookupsDoneCounter, repeats*COUNT); + for (int j = 0; j < repeats; ++j) { + helper.hostname = hostnameList.at(i); + helper.lookupHostOldStyle(); + } + + QTRY_COMPARE_WITH_TIMEOUT(helper.lookupsDoneCounter, repeats*COUNT, 60s); } void tst_QHostInfo::cache() @@ -662,13 +575,12 @@ void tst_QHostInfo::cache() if (!cache) return; // test makes only sense when cache enabled - // reset slot counter - lookupsDoneCounter = 0; + tst_QHostInfo_Helper helper("localhost"); // lookup once, wait in event loop, result should not come directly. bool valid = true; int id = -1; - QHostInfo result = qt_qhostinfo_lookup("localhost", this, SLOT(resultsReady(QHostInfo)), &valid, &id); + QHostInfo result = qt_qhostinfo_lookup(helper.hostname, &helper, SLOT(resultsReady(QHostInfo)), &valid, &id); QTestEventLoop::instance().enterLoop(5); QVERIFY(!QTestEventLoop::instance().timeout()); QVERIFY(!valid); @@ -676,7 +588,7 @@ void tst_QHostInfo::cache() // loopkup second time, result should come directly valid = false; - result = qt_qhostinfo_lookup("localhost", this, SLOT(resultsReady(QHostInfo)), &valid, &id); + result = qt_qhostinfo_lookup(helper.hostname, &helper, SLOT(resultsReady(QHostInfo)), &valid, &id); QVERIFY(valid); QVERIFY(!result.addresses().isEmpty()); @@ -685,17 +597,17 @@ void tst_QHostInfo::cache() // lookup third time, result should not come directly. valid = true; - result = qt_qhostinfo_lookup("localhost", this, SLOT(resultsReady(QHostInfo)), &valid, &id); + result = qt_qhostinfo_lookup(helper.hostname, &helper, SLOT(resultsReady(QHostInfo)), &valid, &id); QTestEventLoop::instance().enterLoop(5); QVERIFY(!QTestEventLoop::instance().timeout()); QVERIFY(!valid); QVERIFY(result.addresses().isEmpty()); // the slot should have been called 2 times. - QCOMPARE(lookupsDoneCounter, 2); + QCOMPARE(helper.lookupsDoneCounter, 2); } -void tst_QHostInfo::resultsReady(const QHostInfo &hi) +void tst_QHostInfo_Helper::resultsReady(const QHostInfo &hi) { QVERIFY(QThread::currentThread() == thread()); lookupDone = true; @@ -706,16 +618,15 @@ void tst_QHostInfo::resultsReady(const QHostInfo &hi) void tst_QHostInfo::abortHostLookup() { - //reset counter - lookupsDoneCounter = 0; + tst_QHostInfo_Helper helper("a-single" TEST_DOMAIN); bool valid = false; int id = -1; - QHostInfo result = qt_qhostinfo_lookup("a-single" TEST_DOMAIN, this, SLOT(resultsReady(QHostInfo)), &valid, &id); + QHostInfo result = qt_qhostinfo_lookup(helper.hostname, &helper, SLOT(resultsReady(QHostInfo)), &valid, &id); QVERIFY(!valid); //it is assumed that the DNS request/response in the backend is slower than it takes to call abort QHostInfo::abortHostLookup(id); QTestEventLoop::instance().enterLoop(5); - QCOMPARE(lookupsDoneCounter, 0); + QCOMPARE(helper.lookupsDoneCounter, 0); } class LookupAborter : public QObject diff --git a/tests/auto/network/kernel/qnetworkaddressentry/CMakeLists.txt b/tests/auto/network/kernel/qnetworkaddressentry/CMakeLists.txt index 3dcfd2ac9b..02bf37880a 100644 --- a/tests/auto/network/kernel/qnetworkaddressentry/CMakeLists.txt +++ b/tests/auto/network/kernel/qnetworkaddressentry/CMakeLists.txt @@ -1,12 +1,19 @@ -# Generated from qnetworkaddressentry.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qnetworkaddressentry Test: ##################################################################### -qt_add_test(tst_qnetworkaddressentry +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qnetworkaddressentry LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qnetworkaddressentry SOURCES tst_qnetworkaddressentry.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Network ) diff --git a/tests/auto/network/kernel/qnetworkaddressentry/qnetworkaddressentry.pro b/tests/auto/network/kernel/qnetworkaddressentry/qnetworkaddressentry.pro deleted file mode 100644 index 427f2e0f19..0000000000 --- a/tests/auto/network/kernel/qnetworkaddressentry/qnetworkaddressentry.pro +++ /dev/null @@ -1,5 +0,0 @@ -CONFIG += testcase -TARGET = tst_qnetworkaddressentry -SOURCES += tst_qnetworkaddressentry.cpp - -QT = core network testlib diff --git a/tests/auto/network/kernel/qnetworkaddressentry/tst_qnetworkaddressentry.cpp b/tests/auto/network/kernel/qnetworkaddressentry/tst_qnetworkaddressentry.cpp index f8583d0aba..801eb58931 100644 --- a/tests/auto/network/kernel/qnetworkaddressentry/tst_qnetworkaddressentry.cpp +++ b/tests/auto/network/kernel/qnetworkaddressentry/tst_qnetworkaddressentry.cpp @@ -1,33 +1,8 @@ -/**************************************************************************** -** -** 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> +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + + +#include <QTest> #include <qcoreapplication.h> #include <qnetworkinterface.h> diff --git a/tests/auto/network/kernel/qnetworkdatagram/CMakeLists.txt b/tests/auto/network/kernel/qnetworkdatagram/CMakeLists.txt index 4ae11ab146..5bfc2edc6a 100644 --- a/tests/auto/network/kernel/qnetworkdatagram/CMakeLists.txt +++ b/tests/auto/network/kernel/qnetworkdatagram/CMakeLists.txt @@ -1,12 +1,19 @@ -# Generated from qnetworkdatagram.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qnetworkdatagram Test: ##################################################################### -qt_add_test(tst_qnetworkdatagram +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qnetworkdatagram LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qnetworkdatagram SOURCES tst_qnetworkdatagram.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Network ) diff --git a/tests/auto/network/kernel/qnetworkdatagram/qnetworkdatagram.pro b/tests/auto/network/kernel/qnetworkdatagram/qnetworkdatagram.pro deleted file mode 100644 index 23d57f3fbf..0000000000 --- a/tests/auto/network/kernel/qnetworkdatagram/qnetworkdatagram.pro +++ /dev/null @@ -1,4 +0,0 @@ -CONFIG += testcase console -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 index cd6019090f..df473133a6 100644 --- a/tests/auto/network/kernel/qnetworkdatagram/tst_qnetworkdatagram.cpp +++ b/tests/auto/network/kernel/qnetworkdatagram/tst_qnetworkdatagram.cpp @@ -1,33 +1,8 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Intel Corporation. -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QNetworkDatagram> -#include <QtTest> +#include <QTest> #include <QCoreApplication> class tst_QNetworkDatagram : public QObject @@ -83,6 +58,17 @@ void tst_QNetworkDatagram::getSetCheck() dg.setDestination(QHostAddress::Broadcast, 137); QCOMPARE(dg.destinationAddress(), QHostAddress(QHostAddress::Broadcast)); QCOMPARE(dg.destinationPort(), 137); + + auto dg2 = dg; + QCOMPARE(dg2.hopLimit(), dg.hopLimit()); + QCOMPARE(dg2.interfaceIndex(), dg.interfaceIndex()); + QCOMPARE(dg2.senderAddress(), dg.senderAddress()); + QCOMPARE(dg2.senderPort(), dg.senderPort()); + QCOMPARE(dg2.destinationAddress(), dg.destinationAddress()); + QCOMPARE(dg2.destinationPort(), dg.destinationPort()); + + dg.clear(); + QVERIFY(dg.isNull()); } void tst_QNetworkDatagram::makeReply_data() diff --git a/tests/auto/network/kernel/qnetworkinformation/CMakeLists.txt b/tests/auto/network/kernel/qnetworkinformation/CMakeLists.txt new file mode 100644 index 0000000000..354cefc993 --- /dev/null +++ b/tests/auto/network/kernel/qnetworkinformation/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qnetworkinformation LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qnetworkinformation + SOURCES + tst_qnetworkinformation.cpp + LIBRARIES + Qt::NetworkPrivate +) diff --git a/tests/auto/network/kernel/qnetworkinformation/tst_qnetworkinformation.cpp b/tests/auto/network/kernel/qnetworkinformation/tst_qnetworkinformation.cpp new file mode 100644 index 0000000000..daf81823e8 --- /dev/null +++ b/tests/auto/network/kernel/qnetworkinformation/tst_qnetworkinformation.cpp @@ -0,0 +1,255 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QtNetwork/private/qnetworkinformation_p.h> +#include <QtNetwork/qnetworkinformation.h> +#include <QtTest/qtest.h> +#include <QtTest/qsignalspy.h> + +#include <limits> +#include <memory> + +class MockFactory; +class tst_QNetworkInformation : public QObject +{ + Q_OBJECT +private slots: + void initTestCase(); + void supportedFeatures(); + void reachability(); + void behindCaptivePortal(); + void transportMedium(); + void isMetered(); + void cleanupTestCase(); + +private: + std::unique_ptr<MockFactory> mockFactory; +}; + +static const QString mockName = QStringLiteral("mock"); +class MockBackend : public QNetworkInformationBackend +{ + Q_OBJECT +public: + MockBackend() + { + Q_ASSERT(!instance); + instance = this; + setReachability(QNetworkInformation::Reachability::Online); + setNewBehindCaptivePortal(false); + } + ~MockBackend() { instance = nullptr; } + + QString name() const override { return mockName; } + + QNetworkInformation::Features featuresSupported() const override + { + return featuresSupportedStatic(); + } + + static void setNewReachability(QNetworkInformation::Reachability value) + { + Q_ASSERT(instance); + instance->setReachability(value); + } + + static void setNewBehindCaptivePortal(bool value) + { + Q_ASSERT(instance); + instance->setBehindCaptivePortal(value); + } + + static void setNewTransportMedium(QNetworkInformation::TransportMedium medium) + { + Q_ASSERT(instance); + instance->setTransportMedium(medium); + } + + static void setNewMetered(bool metered) + { + Q_ASSERT(instance); + instance->setMetered(metered); + } + + static QNetworkInformation::Features featuresSupportedStatic() + { + return { QNetworkInformation::Feature::Reachability + | QNetworkInformation::Feature::CaptivePortal + | QNetworkInformation::Feature::TransportMedium + | QNetworkInformation::Feature::Metered }; + } + +private: + static inline MockBackend *instance = nullptr; +}; + +class MockFactory : public QNetworkInformationBackendFactory +{ + Q_OBJECT +public: + QString name() const override { return mockName; } + QNetworkInformationBackend * + create(QNetworkInformation::Features requiredFeatures) const override + { + if ((requiredFeatures & featuresSupported()) != requiredFeatures) + return nullptr; + return new MockBackend(); + } + QNetworkInformation::Features featuresSupported() const override + { + return MockBackend::featuresSupportedStatic(); + } +}; + +void tst_QNetworkInformation::initTestCase() +{ + auto prevBackends = QNetworkInformation::availableBackends(); + qDebug() << "available backends:" << prevBackends; + // Creating the factory registers it as a backend + mockFactory = std::make_unique<MockFactory>(); + auto backends = QNetworkInformation::availableBackends(); + QVERIFY(backends.size() > prevBackends.size()); + QVERIFY(backends.contains(u"mock")); + QVERIFY(QNetworkInformation::loadBackendByName(u"mock")); + QVERIFY(QNetworkInformation::loadBackendByName(u"mock")); + QVERIFY(QNetworkInformation::loadBackendByName(u"mOcK")); + QVERIFY(!QNetworkInformation::loadBackendByName(u"mocks")); +} + +void tst_QNetworkInformation::cleanupTestCase() +{ + // Make sure the factory gets unregistered on destruction: + mockFactory.reset(); + auto backends = QNetworkInformation::availableBackends(); + QVERIFY(!backends.contains(u"mock")); +} + +void tst_QNetworkInformation::supportedFeatures() +{ + auto info = QNetworkInformation::instance(); + + auto allFeatures = QNetworkInformation::Features(QNetworkInformation::Feature::CaptivePortal + | QNetworkInformation::Feature::Reachability + | QNetworkInformation::Feature::TransportMedium + | QNetworkInformation::Feature::Metered); + + QCOMPARE(info->supportedFeatures(), allFeatures); + + QVERIFY(info->supports(allFeatures)); + QVERIFY(info->supports(QNetworkInformation::Feature::CaptivePortal)); + QVERIFY(info->supports(QNetworkInformation::Feature::Reachability)); + QVERIFY(info->supports(QNetworkInformation::Feature::TransportMedium)); + QVERIFY(info->supports(QNetworkInformation::Feature::Metered)); +} + +void tst_QNetworkInformation::reachability() +{ + auto info = QNetworkInformation::instance(); + QNetworkInformation::Reachability boundIsOnline = QNetworkInformation::Reachability::Unknown; + bool signalEmitted = false; + + connect(info, &QNetworkInformation::reachabilityChanged, this, [&, info]() { + signalEmitted = true; + boundIsOnline = info->reachability(); + }); + QCOMPARE(info->reachability(), QNetworkInformation::Reachability::Online); + MockBackend::setNewReachability(QNetworkInformation::Reachability::Disconnected); + QCoreApplication::processEvents(); + QVERIFY(signalEmitted); + QCOMPARE(info->reachability(), QNetworkInformation::Reachability::Disconnected); + QCOMPARE(boundIsOnline, QNetworkInformation::Reachability::Disconnected); + + // Set the same value again, signal should not be emitted again + signalEmitted = false; + MockBackend::setNewReachability(QNetworkInformation::Reachability::Disconnected); + QCoreApplication::processEvents(); + QVERIFY(!signalEmitted); + + MockBackend::setNewReachability(QNetworkInformation::Reachability::Local); + QCOMPARE(info->reachability(), QNetworkInformation::Reachability::Local); + QCOMPARE(boundIsOnline, QNetworkInformation::Reachability::Local); + MockBackend::setNewReachability(QNetworkInformation::Reachability::Site); + QCOMPARE(info->reachability(), QNetworkInformation::Reachability::Site); + QCOMPARE(boundIsOnline, QNetworkInformation::Reachability::Site); +} + +void tst_QNetworkInformation::behindCaptivePortal() +{ + auto info = QNetworkInformation::instance(); + bool behindPortal = false; + bool signalEmitted = false; + + connect(info, &QNetworkInformation::isBehindCaptivePortalChanged, this, + [&, info](bool state) { + signalEmitted = true; + QCOMPARE(state, info->isBehindCaptivePortal()); + behindPortal = info->isBehindCaptivePortal(); + }); + QVERIFY(!info->isBehindCaptivePortal()); + MockBackend::setNewBehindCaptivePortal(true); + QCoreApplication::processEvents(); + QVERIFY(signalEmitted); + QVERIFY(info->isBehindCaptivePortal()); + QVERIFY(behindPortal); + + // Set the same value again, signal should not be emitted again + signalEmitted = false; + MockBackend::setNewBehindCaptivePortal(true); + QCoreApplication::processEvents(); + QVERIFY(!signalEmitted); +} + +void tst_QNetworkInformation::transportMedium() +{ + auto info = QNetworkInformation::instance(); + using TransportMedium = QNetworkInformation::TransportMedium; + TransportMedium medium = TransportMedium::Unknown; + bool signalEmitted = false; + + connect(info, &QNetworkInformation::transportMediumChanged, this, [&, info](TransportMedium tm) { + signalEmitted = true; + QCOMPARE(tm, info->transportMedium()); + medium = info->transportMedium(); + }); + QCOMPARE(info->transportMedium(), TransportMedium::Unknown); // Default is unknown + + auto transportMediumEnum = QMetaEnum::fromType<TransportMedium>(); + auto mediumCount = transportMediumEnum.keyCount(); + // Verify index 0 is Unknown and skip it in the loop, it's the default. + QCOMPARE(TransportMedium(transportMediumEnum.value(0)), TransportMedium::Unknown); + for (int i = 1; i < mediumCount; ++i) { + signalEmitted = false; + TransportMedium m = TransportMedium(transportMediumEnum.value(i)); + MockBackend::setNewTransportMedium(m); + QCoreApplication::processEvents(); + QVERIFY(signalEmitted); + QCOMPARE(info->transportMedium(), m); + QCOMPARE(medium, m); + } + + // Set the current value again, signal should not be emitted again + signalEmitted = false; + MockBackend::setNewTransportMedium(medium); + QCoreApplication::processEvents(); + QVERIFY(!signalEmitted); +} + +void tst_QNetworkInformation::isMetered() +{ + auto info = QNetworkInformation::instance(); + + QSignalSpy spy(info, &QNetworkInformation::isMeteredChanged); + QVERIFY(!info->isMetered()); + MockBackend::setNewMetered(true); + QCOMPARE(spy.size(), 1); + QVERIFY(info->isMetered()); + QVERIFY(spy[0][0].toBool()); + spy.clear(); + + // Set the same value again, signal should not be emitted again + MockBackend::setNewMetered(true); + QCOMPARE(spy.size(), 0); +} + +QTEST_MAIN(tst_QNetworkInformation); +#include "tst_qnetworkinformation.moc" diff --git a/tests/auto/network/kernel/qnetworkinformation_appless/CMakeLists.txt b/tests/auto/network/kernel/qnetworkinformation_appless/CMakeLists.txt new file mode 100644 index 0000000000..d4a2e486bd --- /dev/null +++ b/tests/auto/network/kernel/qnetworkinformation_appless/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qnetworkinformation_appless LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qnetworkinformation_appless + SOURCES + tst_qnetworkinformation_appless.cpp + LIBRARIES + Qt::Network +) diff --git a/tests/auto/network/kernel/qnetworkinformation_appless/tst_qnetworkinformation_appless.cpp b/tests/auto/network/kernel/qnetworkinformation_appless/tst_qnetworkinformation_appless.cpp new file mode 100644 index 0000000000..b08843314a --- /dev/null +++ b/tests/auto/network/kernel/qnetworkinformation_appless/tst_qnetworkinformation_appless.cpp @@ -0,0 +1,42 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QtCore/qcoreapplication.h> +#include <QtNetwork/qnetworkinformation.h> +#include <QtTest/qtest.h> + +class tst_QNetworkInformation_appless : public QObject +{ + Q_OBJECT +private slots: + void reinit(); +}; + +void tst_QNetworkInformation_appless::reinit() +{ + int argc = 1; + char name[] = "./test"; + char *argv[] = { name, nullptr }; + + { + QCoreApplication app(argc, argv); + if (QNetworkInformation::availableBackends().isEmpty()) + QSKIP("No backends available!"); + + QVERIFY(QNetworkInformation::loadDefaultBackend()); + auto info = QNetworkInformation::instance(); + QVERIFY(info); + } + + QVERIFY(!QNetworkInformation::instance()); + + { + QCoreApplication app(argc, argv); + QVERIFY(QNetworkInformation::loadDefaultBackend()); + auto info = QNetworkInformation::instance(); + QVERIFY(info); + } +} + +QTEST_APPLESS_MAIN(tst_QNetworkInformation_appless); +#include "tst_qnetworkinformation_appless.moc" diff --git a/tests/auto/network/kernel/qnetworkinterface/CMakeLists.txt b/tests/auto/network/kernel/qnetworkinterface/CMakeLists.txt index 7bf840881a..3e5dab63e0 100644 --- a/tests/auto/network/kernel/qnetworkinterface/CMakeLists.txt +++ b/tests/auto/network/kernel/qnetworkinterface/CMakeLists.txt @@ -1,15 +1,20 @@ -# Generated from qnetworkinterface.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qnetworkinterface Test: ##################################################################### -qt_add_test(tst_qnetworkinterface +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qnetworkinterface LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qnetworkinterface SOURCES - ../../../../shared/emulationdetector.h tst_qnetworkinterface.cpp - INCLUDE_DIRECTORIES - ../../../../shared - PUBLIC_LIBRARIES - Qt::Network + LIBRARIES + Qt::NetworkPrivate + QT_TEST_SERVER_LIST "apache2" ) diff --git a/tests/auto/network/kernel/qnetworkinterface/qnetworkinterface.pro b/tests/auto/network/kernel/qnetworkinterface/qnetworkinterface.pro deleted file mode 100644 index bbcf60b828..0000000000 --- a/tests/auto/network/kernel/qnetworkinterface/qnetworkinterface.pro +++ /dev/null @@ -1,7 +0,0 @@ -CONFIG += testcase -TARGET = tst_qnetworkinterface -SOURCES += tst_qnetworkinterface.cpp -INCLUDEPATH += ../../../../shared/ -HEADERS += ../../../../shared/emulationdetector.h - -QT = core network testlib diff --git a/tests/auto/network/kernel/qnetworkinterface/tst_qnetworkinterface.cpp b/tests/auto/network/kernel/qnetworkinterface/tst_qnetworkinterface.cpp index 35d593ff9b..e5bbf3467c 100644 --- a/tests/auto/network/kernel/qnetworkinterface/tst_qnetworkinterface.cpp +++ b/tests/auto/network/kernel/qnetworkinterface/tst_qnetworkinterface.cpp @@ -1,40 +1,17 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2016 Intel Corporation. -** 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> +// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2016 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QTest> +#include <QtEndian> +#include <QSet> #include <qcoreapplication.h> #include <qnetworkinterface.h> #include <qudpsocket.h> #include "../../../network-settings.h" -#include "emulationdetector.h" + +#include <private/qtnetwork-config_p.h> Q_DECLARE_METATYPE(QHostAddress) @@ -59,6 +36,8 @@ private slots: void interfaceFromXXX_data(); void interfaceFromXXX(); void copyInvalidInterface(); +private: + bool hasNetworkServer = false; }; tst_QNetworkInterface::tst_QNetworkInterface() @@ -71,22 +50,29 @@ tst_QNetworkInterface::~tst_QNetworkInterface() bool tst_QNetworkInterface::isIPv6Working() { - QUdpSocket socket; - socket.connectToHost(QHostAddress::LocalHostIPv6, 1234); - return socket.state() == QAbstractSocket::ConnectedState || socket.waitForConnected(100); + // QNetworkInterface may be unable to detect IPv6 addresses even if they + // are there, due to limitations of the implementation. + if (QOperatingSystemVersion::currentType() == QOperatingSystemVersion::Windows || + QT_CONFIG(linux_netlink) || (QT_CONFIG(getifaddrs) && QT_CONFIG(ipv6ifname))) { + return QtNetworkSettings::hasIPv6(); + } + return false; } void tst_QNetworkInterface::initTestCase() { - if (!QtNetworkSettings::verifyTestNetworkSettings()) - QSKIP("No network test server available"); +#ifdef QT_TEST_SERVER + hasNetworkServer = QtNetworkSettings::verifyConnection(QtNetworkSettings::httpServerName(), 80); +#else + hasNetworkServer = QtNetworkSettings::verifyTestNetworkSettings(); +#endif } void tst_QNetworkInterface::dump() { // This is for manual testing: - QList<QNetworkInterface> allInterfaces = QNetworkInterface::allInterfaces(); - foreach (const QNetworkInterface &i, allInterfaces) { + const QList<QNetworkInterface> allInterfaces = QNetworkInterface::allInterfaces(); + for (const QNetworkInterface &i : allInterfaces) { QString flags; if (i.flags() & QNetworkInterface::IsUp) flags += "Up,"; if (i.flags() & QNetworkInterface::IsRunning) flags += "Running,"; @@ -113,7 +99,8 @@ void tst_QNetworkInterface::dump() qDebug() << " MTU: " << i.maximumTransmissionUnit(); int count = 0; - foreach (const QNetworkAddressEntry &e, i.addressEntries()) { + const auto entries = i.addressEntries(); + for (const QNetworkAddressEntry &e : entries) { QDebug s = qDebug(); s.nospace() << " address " << qSetFieldWidth(2) << count++ << qSetFieldWidth(0); @@ -139,11 +126,11 @@ void tst_QNetworkInterface::dump() void tst_QNetworkInterface::consistencyCheck() { - QList<QNetworkInterface> ifaces = QNetworkInterface::allInterfaces(); + const QList<QNetworkInterface> ifaces = QNetworkInterface::allInterfaces(); QSet<QString> interfaceNames; QList<int> interfaceIndexes; - foreach (const QNetworkInterface &iface, ifaces) { + for (const QNetworkInterface &iface : ifaces) { QVERIFY(iface.isValid()); QVERIFY2(!interfaceNames.contains(iface.name()), "duplicate name = " + iface.name().toLocal8Bit()); @@ -189,7 +176,8 @@ void tst_QNetworkInterface::localAddress_data() if (ipv6) QTest::newRow("localhost-ipv6") << QHostAddress(QHostAddress::LocalHostIPv6); - QTest::newRow("test-server") << QtNetworkSettings::serverIP(); + if (hasNetworkServer) + QTest::newRow("test-server") << QtNetworkSettings::httpServerIp(); QSet<QHostAddress> added; const QList<QNetworkInterface> ifaces = QNetworkInterface::allInterfaces(); @@ -209,6 +197,14 @@ void tst_QNetworkInterface::localAddress_data() } else if (!ipv6 || entry.prefixLength() != 64) { continue; } else { +#ifdef Q_OS_ANDROID + // Android seem to not allow IPv6 connection from interfaces other than wlan, + // if it's connected, and wlan is connected by default on Android emulators, + // so prefer selecting wlan in this test. + const QString scopeId = addr.scopeId(); + if (!scopeId.isEmpty() && !scopeId.startsWith("wlan")) + continue; +#endif // add a random node in this IPv6 network quint64 randomid = qFromBigEndian(Q_UINT64_C(0x8f41f072e5733caa)); QIPv6Address ip6 = addr.toIPv6Address(); @@ -263,10 +259,10 @@ void tst_QNetworkInterface::interfaceFromXXX_data() { QTest::addColumn<QNetworkInterface>("iface"); - QList<QNetworkInterface> allInterfaces = QNetworkInterface::allInterfaces(); - if (allInterfaces.count() == 0) + const QList<QNetworkInterface> allInterfaces = QNetworkInterface::allInterfaces(); + if (allInterfaces.size() == 0) QSKIP("No interfaces to test!"); - foreach (QNetworkInterface iface, allInterfaces) + for (const QNetworkInterface &iface : allInterfaces) QTest::newRow(iface.name().toLocal8Bit()) << iface; } @@ -277,12 +273,11 @@ void tst_QNetworkInterface::interfaceFromXXX() QVERIFY(QNetworkInterface::interfaceFromName(iface.name()).isValid()); if (int idx = iface.index()) { QVERIFY(QNetworkInterface::interfaceFromIndex(idx).isValid()); - if (EmulationDetector::isRunningArmOnX86()) - QEXPECT_FAIL("", "SIOCGIFNAME fails on QEMU", Continue); QCOMPARE(QNetworkInterface::interfaceNameFromIndex(idx), iface.name()); QCOMPARE(QNetworkInterface::interfaceIndexFromName(iface.name()), idx); } - foreach (QNetworkAddressEntry entry, iface.addressEntries()) { + const auto entries = iface.addressEntries(); + for (const QNetworkAddressEntry &entry : entries) { QVERIFY(!entry.ip().isNull()); if (!entry.netmask().isNull()) { diff --git a/tests/auto/network/kernel/qnetworkproxy/CMakeLists.txt b/tests/auto/network/kernel/qnetworkproxy/CMakeLists.txt index 4402ba4a72..629bfb0a8a 100644 --- a/tests/auto/network/kernel/qnetworkproxy/CMakeLists.txt +++ b/tests/auto/network/kernel/qnetworkproxy/CMakeLists.txt @@ -1,12 +1,19 @@ -# Generated from qnetworkproxy.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qnetworkproxy Test: ##################################################################### -qt_add_test(tst_qnetworkproxy +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qnetworkproxy LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qnetworkproxy SOURCES tst_qnetworkproxy.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Network ) diff --git a/tests/auto/network/kernel/qnetworkproxy/qnetworkproxy.pro b/tests/auto/network/kernel/qnetworkproxy/qnetworkproxy.pro deleted file mode 100644 index 996f9e3691..0000000000 --- a/tests/auto/network/kernel/qnetworkproxy/qnetworkproxy.pro +++ /dev/null @@ -1,9 +0,0 @@ -############################################################ -# Project file for autotest for file qnetworkproxy.h -############################################################ - -CONFIG += testcase -TARGET = tst_qnetworkproxy -QT = core network testlib - -SOURCES += tst_qnetworkproxy.cpp diff --git a/tests/auto/network/kernel/qnetworkproxy/tst_qnetworkproxy.cpp b/tests/auto/network/kernel/qnetworkproxy/tst_qnetworkproxy.cpp index b3e3568321..1f00f8d054 100644 --- a/tests/auto/network/kernel/qnetworkproxy/tst_qnetworkproxy.cpp +++ b/tests/auto/network/kernel/qnetworkproxy/tst_qnetworkproxy.cpp @@ -1,33 +1,8 @@ -/**************************************************************************** -** -** 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> +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + + +#include <QTest> #include <qcoreapplication.h> #include <qdebug.h> diff --git a/tests/auto/network/kernel/qnetworkproxyfactory/CMakeLists.txt b/tests/auto/network/kernel/qnetworkproxyfactory/CMakeLists.txt index e8bc9beefb..41dae6a02a 100644 --- a/tests/auto/network/kernel/qnetworkproxyfactory/CMakeLists.txt +++ b/tests/auto/network/kernel/qnetworkproxyfactory/CMakeLists.txt @@ -1,12 +1,19 @@ -# Generated from qnetworkproxyfactory.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qnetworkproxyfactory Test: ##################################################################### -qt_add_test(tst_qnetworkproxyfactory +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qnetworkproxyfactory LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qnetworkproxyfactory SOURCES tst_qnetworkproxyfactory.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::NetworkPrivate ) diff --git a/tests/auto/network/kernel/qnetworkproxyfactory/qnetworkproxyfactory.pro b/tests/auto/network/kernel/qnetworkproxyfactory/qnetworkproxyfactory.pro deleted file mode 100644 index a7fa43015f..0000000000 --- a/tests/auto/network/kernel/qnetworkproxyfactory/qnetworkproxyfactory.pro +++ /dev/null @@ -1,9 +0,0 @@ -############################################################ -# Project file for autotest for file qnetworkproxy.h (proxy factory part) -############################################################ - -CONFIG += testcase -TARGET = tst_qnetworkproxyfactory -QT = core network-private testlib - -SOURCES += tst_qnetworkproxyfactory.cpp diff --git a/tests/auto/network/kernel/qnetworkproxyfactory/tst_qnetworkproxyfactory.cpp b/tests/auto/network/kernel/qnetworkproxyfactory/tst_qnetworkproxyfactory.cpp index c84120a6e5..c38a480766 100644 --- a/tests/auto/network/kernel/qnetworkproxyfactory/tst_qnetworkproxyfactory.cpp +++ b/tests/auto/network/kernel/qnetworkproxyfactory/tst_qnetworkproxyfactory.cpp @@ -1,31 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtTest/QTest> #include <QtTest/QTestEventLoop> @@ -53,7 +27,7 @@ public: class QDebugProxyFactory : public QNetworkProxyFactory { public: - virtual QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query = QNetworkProxyQuery()) + QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query = QNetworkProxyQuery()) override { returnedList = QNetworkProxyFactory::systemProxyForQuery(query); requestCounter++; @@ -119,7 +93,8 @@ void tst_QNetworkProxyFactory::systemProxyForQuery_data() QTest::newRow("autobind-server") << (int)QNetworkProxyQuery::TcpServer << QUrl() << QString() << QString() << 0 << (int)QNetworkProxy::ListeningCapability; QTest::newRow("web-server") << (int)QNetworkProxyQuery::TcpServer << QUrl() << QString() << QString() << 80 << (int)QNetworkProxy::ListeningCapability; //windows: these should be bypassed if "bypass proxy server for local addresses" is ticked - foreach (QHostAddress address, QNetworkInterface::allAddresses()) { + const auto addresses = QNetworkInterface::allAddresses(); + for (const QHostAddress &address : addresses) { QTest::newRow(qPrintable(address.toString())) << (int)QNetworkProxyQuery::TcpSocket << QUrl() << QString() << address.toString() << 0 << 0; } @@ -172,16 +147,15 @@ void tst_QNetworkProxyFactory::systemProxyForQuery() const QElapsedTimer sw; sw.start(); - QList<QNetworkProxy> systemProxyList = QNetworkProxyFactory::systemProxyForQuery(query); + const QList<QNetworkProxy> systemProxyList = QNetworkProxyFactory::systemProxyForQuery(query); qDebug() << sw.elapsed() << "ms"; QVERIFY(!systemProxyList.isEmpty()); // for manual comparison with system qDebug() << systemProxyList; - foreach (const QNetworkProxy &proxy, systemProxyList) { + for (const QNetworkProxy &proxy : systemProxyList) QVERIFY((requiredCapabilities == 0) || (proxy.capabilities() & requiredCapabilities)); - } } void tst_QNetworkProxyFactory::systemProxyForQuery_local() @@ -256,8 +230,6 @@ void tst_QNetworkProxyFactory::genericSystemProxy() QFETCH(QString, hostName); QFETCH(int, port); -// We can only use the generic system proxy where available: -#if !defined(Q_OS_WIN) && !defined(Q_OS_MACOS) && !QT_CONFIG(libproxy) qputenv(envVar, url); const QList<QNetworkProxy> systemProxy = QNetworkProxyFactory::systemProxyForQuery(); QCOMPARE(systemProxy.size(), 1); @@ -265,18 +237,14 @@ void tst_QNetworkProxyFactory::genericSystemProxy() QCOMPARE(systemProxy.first().hostName(), hostName); QCOMPARE(systemProxy.first().port(), static_cast<quint16>(port)); qunsetenv(envVar); -#else - Q_UNUSED(envVar); - Q_UNUSED(url); - Q_UNUSED(proxyType); - Q_UNUSED(hostName); - Q_UNUSED(port); - QSKIP("Generic system proxy not available on this platform."); -#endif } void tst_QNetworkProxyFactory::genericSystemProxy_data() { + // We can only use the generic system proxy where available: +#if defined(Q_OS_WIN) || defined(Q_OS_MACOS) || defined(Q_OS_ANDROID) || QT_CONFIG(libproxy) + QSKIP("Generic system proxy not available on this platform."); +#else QTest::addColumn<QByteArray>("envVar"); QTest::addColumn<QByteArray>("url"); QTest::addColumn<QNetworkProxy::ProxyType>("proxyType"); @@ -289,12 +257,13 @@ void tst_QNetworkProxyFactory::genericSystemProxy_data() << QNetworkProxy::Socks5Proxy << QString("127.0.0.1") << 4242; QTest::newRow("http") << QByteArray("http_proxy") << QByteArray("http://example.com:666") << QNetworkProxy::HttpProxy << QString("example.com") << 666; +#endif } class QSPFQThread : public QThread { protected: - virtual void run() + void run() override { proxies = QNetworkProxyFactory::systemProxyForQuery(query); } diff --git a/tests/auto/network/network.pro b/tests/auto/network/network.pro deleted file mode 100644 index 2572bb235f..0000000000 --- a/tests/auto/network/network.pro +++ /dev/null @@ -1,9 +0,0 @@ -TEMPLATE=subdirs -SUBDIRS=\ - selftest \ - access \ - kernel \ - ssl \ - socket \ - -win32: socket.CONFIG += no_check_target # QTBUG-24451 - all socket tests require waitForX diff --git a/tests/auto/network/selftest/selftest.pro b/tests/auto/network/selftest/selftest.pro deleted file mode 100644 index e8312032c3..0000000000 --- a/tests/auto/network/selftest/selftest.pro +++ /dev/null @@ -1,6 +0,0 @@ -CONFIG += testcase -TARGET = tst_networkselftest -SOURCES += tst_networkselftest.cpp - -requires(qtConfig(private_tests)) -QT = core network network-private testlib diff --git a/tests/auto/network/selftest/tst_networkselftest.cpp b/tests/auto/network/selftest/tst_networkselftest.cpp index a00c5e9770..4288a65a37 100644 --- a/tests/auto/network/selftest/tst_networkselftest.cpp +++ b/tests/auto/network/selftest/tst_networkselftest.cpp @@ -1,33 +1,8 @@ -/**************************************************************************** -** -** Copyright (C) 2020 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> +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + + +#include <QTest> #include "../../network-settings.h" diff --git a/tests/auto/network/socket/.prev_CMakeLists.txt b/tests/auto/network/socket/.prev_CMakeLists.txt deleted file mode 100644 index 7e72b4be29..0000000000 --- a/tests/auto/network/socket/.prev_CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -# Generated from socket.pro. - -if(QT_FEATURE_private_tests) - add_subdirectory(qhttpsocketengine) - add_subdirectory(qtcpsocket) - add_subdirectory(qsocks5socketengine) - add_subdirectory(platformsocketengine) -endif() -add_subdirectory(qudpsocket) -add_subdirectory(qlocalsocket) -add_subdirectory(qtcpserver) -add_subdirectory(qabstractsocket) -if(QT_FEATURE_sctp) - add_subdirectory(qsctpsocket) -endif() diff --git a/tests/auto/network/socket/CMakeLists.txt b/tests/auto/network/socket/CMakeLists.txt index a4b19ac1d6..7136017f39 100644 --- a/tests/auto/network/socket/CMakeLists.txt +++ b/tests/auto/network/socket/CMakeLists.txt @@ -1,4 +1,5 @@ -# Generated from socket.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause if(QT_FEATURE_private_tests) add_subdirectory(qhttpsocketengine) @@ -6,10 +7,20 @@ if(QT_FEATURE_private_tests) add_subdirectory(qsocks5socketengine) add_subdirectory(platformsocketengine) endif() -add_subdirectory(qudpsocket) -### add_subdirectory(qlocalsocket) # special case -add_subdirectory(qtcpserver) +if(QT_FEATURE_udpsocket) + add_subdirectory(qudpsocket) +endif() add_subdirectory(qabstractsocket) +if(QT_FEATURE_localserver AND NOT ANDROID) + # QTBUG-87387 + add_subdirectory(qlocalsocket) +endif() + +if(QT_FEATURE_networkinterface AND NOT ANDROID) + # QTBUG-87388 + add_subdirectory(qtcpserver) +endif() + if(QT_FEATURE_sctp) add_subdirectory(qsctpsocket) endif() diff --git a/tests/auto/network/socket/platformsocketengine/BLACKLIST b/tests/auto/network/socket/platformsocketengine/BLACKLIST index f1f88d26d1..796f81a02a 100644 --- a/tests/auto/network/socket/platformsocketengine/BLACKLIST +++ b/tests/auto/network/socket/platformsocketengine/BLACKLIST @@ -1,11 +1,2 @@ [tcpLoopbackPerformance] -windows-10 msvc-2015 -windows-7sp1 -[receiveUrgentData] -windows-10 msvc-2015 -windows-7sp1 -[serverTest] -windows-10 msvc-2015 -windows-7sp1 -[tcpLoopbackPerformance] windows diff --git a/tests/auto/network/socket/platformsocketengine/CMakeLists.txt b/tests/auto/network/socket/platformsocketengine/CMakeLists.txt index 780826f211..891041df04 100644 --- a/tests/auto/network/socket/platformsocketengine/CMakeLists.txt +++ b/tests/auto/network/socket/platformsocketengine/CMakeLists.txt @@ -1,4 +1,11 @@ -# Generated from platformsocketengine.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_platformsocketengine LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() if(NOT QT_FEATURE_private_tests) return() @@ -8,24 +15,19 @@ endif() ## tst_platformsocketengine Test: ##################################################################### -qt_add_test(tst_platformsocketengine +qt_internal_add_test(tst_platformsocketengine SOURCES tst_platformsocketengine.cpp - INCLUDE_DIRECTORIES - ${QT_SOURCE_TREE}/src/network - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::NetworkPrivate + QT_TEST_SERVER_LIST "cyrus" ) -#### Keys ignored in scope 1:.:.:platformsocketengine.pro:<TRUE>: -# MOC_DIR = "tmp" -# _REQUIREMENTS = "qtConfig(private_tests)" - ## Scopes: ##################################################################### -qt_extend_target(tst_platformsocketengine CONDITION WIN32 - PUBLIC_LIBRARIES +qt_internal_extend_target(tst_platformsocketengine CONDITION WIN32 + LIBRARIES ws2_32 ) diff --git a/tests/auto/network/socket/platformsocketengine/platformsocketengine.pri b/tests/auto/network/socket/platformsocketengine/platformsocketengine.pri deleted file mode 100644 index 1b304bfc69..0000000000 --- a/tests/auto/network/socket/platformsocketengine/platformsocketengine.pri +++ /dev/null @@ -1,8 +0,0 @@ -QT += network - -QNETWORK_SRC = $$QT_SOURCE_TREE/src/network - -INCLUDEPATH += $$QNETWORK_SRC - -win32: QMAKE_USE += ws2_32 - diff --git a/tests/auto/network/socket/platformsocketengine/platformsocketengine.pro b/tests/auto/network/socket/platformsocketengine/platformsocketengine.pro deleted file mode 100644 index ab96bb444e..0000000000 --- a/tests/auto/network/socket/platformsocketengine/platformsocketengine.pro +++ /dev/null @@ -1,11 +0,0 @@ -CONFIG += testcase -TARGET = tst_platformsocketengine -SOURCES += tst_platformsocketengine.cpp - -include(../platformsocketengine/platformsocketengine.pri) - -requires(qtConfig(private_tests)) - -MOC_DIR=tmp - -QT = core-private network-private testlib diff --git a/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp b/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp index 88a39eea93..1f6ecf9200 100644 --- a/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp +++ b/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp @@ -1,31 +1,6 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2016 Intel Corporation. -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2016 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtTest/QTest> @@ -48,7 +23,7 @@ #define PLATFORMSOCKETENGINE QNativeSocketEngine #define PLATFORMSOCKETENGINESTRING "QNativeSocketEngine" -#include <private/qnativesocketengine_p.h> +#include <private/qnativesocketengine_p_p.h> #include <qstringlist.h> @@ -81,8 +56,12 @@ private slots: void tst_PlatformSocketEngine::initTestCase() { +#ifdef QT_TEST_SERVER + QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::imapServerName(), 143)); +#else if (!QtNetworkSettings::verifyTestNetworkSettings()) QSKIP("No network test server available"); +#endif } //--------------------------------------------------------------------------- @@ -122,14 +101,14 @@ void tst_PlatformSocketEngine::simpleConnectToIMAP() QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState); - const bool isConnected = socketDevice.connectToHost(QtNetworkSettings::serverIP(), 143); + const bool isConnected = socketDevice.connectToHost(QtNetworkSettings::imapServerIp(), 143); if (!isConnected) { QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectingState); QVERIFY(socketDevice.waitForWrite()); QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectedState); } QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectedState); - QCOMPARE(socketDevice.peerAddress(), QtNetworkSettings::serverIP()); + QCOMPARE(socketDevice.peerAddress(), QtNetworkSettings::imapServerIp()); // Wait for the greeting QVERIFY(socketDevice.waitForRead()); @@ -276,7 +255,7 @@ void tst_PlatformSocketEngine::broadcastTest() PLATFORMSOCKETENGINE broadcastSocket; // Initialize a regular Udp socket - QVERIFY(broadcastSocket.initialize(QAbstractSocket::UdpSocket, QAbstractSocket::AnyIPProtocol)); + QVERIFY(broadcastSocket.initialize(QAbstractSocket::UdpSocket, QAbstractSocket::IPv4Protocol)); // Bind to any port on all interfaces QVERIFY(broadcastSocket.bind(QHostAddress::Any, 0)); @@ -324,7 +303,7 @@ void tst_PlatformSocketEngine::serverTest() quint16 port = server.localPort(); // Listen for incoming connections - QVERIFY(server.listen()); + QVERIFY(server.listen(50)); QCOMPARE(server.state(), QAbstractSocket::ListeningState); // Initialize a Tcp socket @@ -429,7 +408,7 @@ void tst_PlatformSocketEngine::tcpLoopbackPerformance() quint16 port = server.localPort(); // Listen for incoming connections - QVERIFY(server.listen()); + QVERIFY(server.listen(50)); QCOMPARE(server.state(), QAbstractSocket::ListeningState); // Initialize a Tcp socket @@ -567,7 +546,7 @@ void tst_PlatformSocketEngine::networkError() QVERIFY(client.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); - const bool isConnected = client.connectToHost(QtNetworkSettings::serverIP(), 143); + const bool isConnected = client.connectToHost(QtNetworkSettings::imapServerIp(), 143); if (!isConnected) { QCOMPARE(client.state(), QAbstractSocket::ConnectingState); QVERIFY(client.waitForWrite()); @@ -620,7 +599,7 @@ void tst_PlatformSocketEngine::receiveUrgentData() QCOMPARE(server.state(), QAbstractSocket::BoundState); quint16 port = server.localPort(); - QVERIFY(server.listen()); + QVERIFY(server.listen(50)); QCOMPARE(server.state(), QAbstractSocket::ListeningState); PLATFORMSOCKETENGINE client; diff --git a/tests/auto/network/socket/qabstractsocket/CMakeLists.txt b/tests/auto/network/socket/qabstractsocket/CMakeLists.txt index b5de9360c3..3ca18aceef 100644 --- a/tests/auto/network/socket/qabstractsocket/CMakeLists.txt +++ b/tests/auto/network/socket/qabstractsocket/CMakeLists.txt @@ -1,12 +1,19 @@ -# Generated from qabstractsocket.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qabstractsocket Test: ##################################################################### -qt_add_test(tst_qabstractsocket +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qabstractsocket LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qabstractsocket SOURCES tst_qabstractsocket.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Network ) diff --git a/tests/auto/network/socket/qabstractsocket/qabstractsocket.pro b/tests/auto/network/socket/qabstractsocket/qabstractsocket.pro deleted file mode 100644 index 00e604972f..0000000000 --- a/tests/auto/network/socket/qabstractsocket/qabstractsocket.pro +++ /dev/null @@ -1,10 +0,0 @@ -############################################################ -# Project file for autotest for file qabstractsocket.h -############################################################ - -CONFIG += testcase -TARGET = tst_qabstractsocket -QT = core network testlib - -SOURCES += tst_qabstractsocket.cpp - diff --git a/tests/auto/network/socket/qabstractsocket/tst_qabstractsocket.cpp b/tests/auto/network/socket/qabstractsocket/tst_qabstractsocket.cpp index c306308b76..6b038acdfa 100644 --- a/tests/auto/network/socket/qabstractsocket/tst_qabstractsocket.cpp +++ b/tests/auto/network/socket/qabstractsocket/tst_qabstractsocket.cpp @@ -1,33 +1,8 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only -#include <QtTest/QtTest> +#include <QTest> #include <qcoreapplication.h> #include <qdebug.h> diff --git a/tests/auto/network/socket/qhttpsocketengine/BLACKLIST b/tests/auto/network/socket/qhttpsocketengine/BLACKLIST index ceb3b7862e..e0cd701636 100644 --- a/tests/auto/network/socket/qhttpsocketengine/BLACKLIST +++ b/tests/auto/network/socket/qhttpsocketengine/BLACKLIST @@ -1,5 +1,2 @@ -[downloadBigFile] -windows-10 msvc-2015 -windows-7sp1 [ensureEofTriggersNotification] windows diff --git a/tests/auto/network/socket/qhttpsocketengine/CMakeLists.txt b/tests/auto/network/socket/qhttpsocketengine/CMakeLists.txt index 5b4a9d0195..6b4f904725 100644 --- a/tests/auto/network/socket/qhttpsocketengine/CMakeLists.txt +++ b/tests/auto/network/socket/qhttpsocketengine/CMakeLists.txt @@ -1,4 +1,11 @@ -# Generated from qhttpsocketengine.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qhttpsocketengine LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() if(NOT QT_FEATURE_private_tests) return() @@ -8,28 +15,21 @@ endif() ## tst_qhttpsocketengine Test: ##################################################################### -qt_add_test(tst_qhttpsocketengine +qt_internal_add_test(tst_qhttpsocketengine SOURCES tst_qhttpsocketengine.cpp - INCLUDE_DIRECTORIES - ${QT_SOURCE_TREE}/src/network - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::NetworkPrivate - QT_TEST_SERVER_LIST "squid" "danted" "cyrus" "apache2" # special case + QT_TEST_SERVER_LIST "squid" "danted" "cyrus" "apache2" ) -#### Keys ignored in scope 1:.:.:qhttpsocketengine.pro:<TRUE>: -# MOC_DIR = "tmp" -# _REQUIREMENTS = "qtConfig(private_tests)" - ## Scopes: ##################################################################### -#### Keys ignored in scope 2:.:.:qhttpsocketengine.pro:LINUX: # QT_TEST_SERVER_LIST = "squid" "danted" "cyrus" "apache2" -qt_extend_target(tst_qhttpsocketengine CONDITION WIN32 - PUBLIC_LIBRARIES +qt_internal_extend_target(tst_qhttpsocketengine CONDITION WIN32 + LIBRARIES ws2_32 ) diff --git a/tests/auto/network/socket/qhttpsocketengine/qhttpsocketengine.pro b/tests/auto/network/socket/qhttpsocketengine/qhttpsocketengine.pro deleted file mode 100644 index 63f41f4eb7..0000000000 --- a/tests/auto/network/socket/qhttpsocketengine/qhttpsocketengine.pro +++ /dev/null @@ -1,17 +0,0 @@ -CONFIG += testcase -TARGET = tst_qhttpsocketengine -SOURCES += tst_qhttpsocketengine.cpp - - -include(../platformsocketengine/platformsocketengine.pri) - -MOC_DIR=tmp - -requires(qtConfig(private_tests)) -QT = core-private network-private testlib - -# TODO: For now linux-only, because cyrus is linux-only atm ... -linux { - CONFIG += unsupported/testserver - QT_TEST_SERVER_LIST = squid danted cyrus apache2 -} diff --git a/tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp b/tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp index 2d0d9f5ffc..a52099b5b4 100644 --- a/tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp +++ b/tests/auto/network/socket/qhttpsocketengine/tst_qhttpsocketengine.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtTest/QTest> @@ -43,6 +18,8 @@ #include "../../../network-settings.h" +using namespace std::chrono_literals; + class tst_QHttpSocketEngine : public QObject { Q_OBJECT @@ -108,9 +85,9 @@ public slots: int idx = client->property("dataTransmitionIdx").toInt(); if (receivedData.contains("\r\n\r\n") || receivedData.contains("\n\n")) { - if (idx < dataToTransmit.length()) + if (idx < dataToTransmit.size()) client->write(dataToTransmit.at(idx++)); - if (idx == dataToTransmit.length()) { + if (idx == dataToTransmit.size()) { client->disconnectFromHost(); disconnect(client, 0, this, 0); client = 0; @@ -348,7 +325,7 @@ void tst_QHttpSocketEngine::simpleErrorsAndStates() QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState); QVERIFY(!socketDevice.connectToHost(QHostAddress(QtNetworkSettings::socksProxyServerName()), 8088)); QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectingState); - if (socketDevice.waitForWrite(30000)) { + if (socketDevice.waitForWrite(30s)) { QVERIFY(socketDevice.state() == QAbstractSocket::ConnectedState || socketDevice.state() == QAbstractSocket::UnconnectedState); } else { diff --git a/tests/auto/network/socket/qlocalsocket/BLACKLIST b/tests/auto/network/socket/qlocalsocket/BLACKLIST new file mode 100644 index 0000000000..730b7e6d2f --- /dev/null +++ b/tests/auto/network/socket/qlocalsocket/BLACKLIST @@ -0,0 +1,10 @@ +# QTBUG-87387 +[fullPath] +android +[processConnection] +android +windows +[verifySocketOptions] +android +[threadedConnection] +windows diff --git a/tests/auto/network/socket/qlocalsocket/CMakeLists.txt b/tests/auto/network/socket/qlocalsocket/CMakeLists.txt index 97466174f9..4b886a02ee 100644 --- a/tests/auto/network/socket/qlocalsocket/CMakeLists.txt +++ b/tests/auto/network/socket/qlocalsocket/CMakeLists.txt @@ -1,4 +1,22 @@ -# Generated from qlocalsocket.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qlocalsocket LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() -add_subdirectory(test) add_subdirectory(socketprocess) + +qt_internal_add_test(tst_qlocalsocket + SOURCES + tst_qlocalsocket.cpp + DEFINES + QLOCALSERVER_DEBUG + QLOCALSOCKET_DEBUG + LIBRARIES + Qt::Network + Qt::TestPrivate +) +add_dependencies(tst_qlocalsocket socketprocess) diff --git a/tests/auto/network/socket/qlocalsocket/qlocalsocket.pro b/tests/auto/network/socket/qlocalsocket/qlocalsocket.pro deleted file mode 100644 index cbf5d160d9..0000000000 --- a/tests/auto/network/socket/qlocalsocket/qlocalsocket.pro +++ /dev/null @@ -1,2 +0,0 @@ -TEMPLATE = subdirs -SUBDIRS = test socketprocess diff --git a/tests/auto/network/socket/qlocalsocket/socketprocess/CMakeLists.txt b/tests/auto/network/socket/qlocalsocket/socketprocess/CMakeLists.txt index 5f382b114a..3e0476d2b6 100644 --- a/tests/auto/network/socket/qlocalsocket/socketprocess/CMakeLists.txt +++ b/tests/auto/network/socket/qlocalsocket/socketprocess/CMakeLists.txt @@ -1,14 +1,15 @@ -# Generated from socketprocess.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## socketprocess Binary: ##################################################################### -qt_add_executable(socketprocess +qt_internal_add_executable(socketprocess OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/" SOURCES main.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Network Qt::Test ) diff --git a/tests/auto/network/socket/qlocalsocket/socketprocess/main.cpp b/tests/auto/network/socket/qlocalsocket/socketprocess/main.cpp index 272e837ac5..d254253aca 100644 --- a/tests/auto/network/socket/qlocalsocket/socketprocess/main.cpp +++ b/tests/auto/network/socket/qlocalsocket/socketprocess/main.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <qcoreapplication.h> diff --git a/tests/auto/network/socket/qlocalsocket/socketprocess/socketprocess.pro b/tests/auto/network/socket/qlocalsocket/socketprocess/socketprocess.pro deleted file mode 100644 index e11ed5644b..0000000000 --- a/tests/auto/network/socket/qlocalsocket/socketprocess/socketprocess.pro +++ /dev/null @@ -1,8 +0,0 @@ -QT = core network testlib - -DESTDIR = ./ -TARGET = socketprocess - -CONFIG += cmdline - -SOURCES += main.cpp diff --git a/tests/auto/network/socket/qlocalsocket/test/CMakeLists.txt b/tests/auto/network/socket/qlocalsocket/test/CMakeLists.txt deleted file mode 100644 index 02017adbca..0000000000 --- a/tests/auto/network/socket/qlocalsocket/test/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -# Generated from test.pro. - -##################################################################### -## tst_qlocalsocket Test: -##################################################################### - -qt_add_test(tst_qlocalsocket - SOURCES - ../tst_qlocalsocket.cpp - DEFINES - QLOCALSERVER_DEBUG - QLOCALSOCKET_DEBUG - SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/../\\\" - PUBLIC_LIBRARIES - Qt::Network -) - -## Scopes: -##################################################################### - -#### Keys ignored in scope 3:.:.:test.pro:(CMAKE_BUILD_TYPE STREQUAL Debug): -# DESTDIR = "../debug" - -#### Keys ignored in scope 4:.:.:test.pro:else: -# DESTDIR = "../release" - -#### Keys ignored in scope 5:.:.:test.pro:else: -# DESTDIR = ".." diff --git a/tests/auto/network/socket/qlocalsocket/test/test.pro b/tests/auto/network/socket/qlocalsocket/test/test.pro deleted file mode 100644 index ab9ed90b1d..0000000000 --- a/tests/auto/network/socket/qlocalsocket/test/test.pro +++ /dev/null @@ -1,21 +0,0 @@ -CONFIG += testcase - -DEFINES += QLOCALSERVER_DEBUG -DEFINES += QLOCALSOCKET_DEBUG -DEFINES += SRCDIR=\\\"$$PWD/../\\\" - -QT = core network testlib - -SOURCES += ../tst_qlocalsocket.cpp - -TARGET = tst_qlocalsocket -CONFIG(debug_and_release) { - CONFIG(debug, debug|release) { - DESTDIR = ../debug - } else { - DESTDIR = ../release - } -} else { - DESTDIR = .. -} - diff --git a/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp b/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp index e172c255a7..30ffb50d23 100644 --- a/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp +++ b/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp @@ -1,38 +1,23 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2016 Intel Corporation. -** 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> +// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2016 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + + +#include <QTest> +#include <QSignalSpy> +#include <QtTest/private/qpropertytesthelper_p.h> +#if QT_CONFIG(process) +#include <QProcess> +#endif +#include <QWaitCondition> +#include <QLoggingCategory> +#include <QMutex> +#include <QList> #include <qtextstream.h> #include <qdatastream.h> #include <qelapsedtimer.h> +#include <qproperty.h> #include <QtNetwork/qlocalsocket.h> #include <QtNetwork/qlocalserver.h> @@ -50,6 +35,7 @@ Q_DECLARE_METATYPE(QLocalSocket::LocalSocketError) Q_DECLARE_METATYPE(QLocalSocket::LocalSocketState) Q_DECLARE_METATYPE(QLocalServer::SocketOption) +Q_DECLARE_METATYPE(QLocalSocket::SocketOption) Q_DECLARE_METATYPE(QFile::Permissions) class tst_QLocalSocket : public QObject @@ -57,6 +43,7 @@ class tst_QLocalSocket : public QObject Q_OBJECT public: + using ByteArrayList = QList<QByteArray>; tst_QLocalSocket(); private slots: @@ -71,12 +58,24 @@ private slots: void listenAndConnect_data(); void listenAndConnect(); + void listenAndConnectAbstractNamespace_data(); + void listenAndConnectAbstractNamespace(); + + void listenAndConnectAbstractNamespaceTrailingZeros_data(); + void listenAndConnectAbstractNamespaceTrailingZeros(); + void connectWithOpen(); void connectWithOldOpen(); void sendData_data(); void sendData(); + void readLine_data(); + void readLine(); + + void skip_data(); + void skip(); + void readBufferOverflow(); void simpleCommandProtocol1(); @@ -98,6 +97,8 @@ private slots: void longPath(); void waitForDisconnect(); void waitForDisconnectByServer(); + void waitForReadyReadOnDisconnected(); + void delayedDisconnect(); void removeServer(); @@ -109,6 +110,7 @@ private slots: void writeToClientAndDisconnect_data(); void writeToClientAndDisconnect(); + void writeToDisconnected(); void debug(); void bytesWrittenSignal(); @@ -121,6 +123,11 @@ private slots: void verifyListenWithDescriptor(); void verifyListenWithDescriptor_data(); + void serverBindingsAndProperties(); + void socketBindings(); + +protected slots: + void socketClosedSlot(); }; tst_QLocalSocket::tst_QLocalSocket() @@ -128,17 +135,17 @@ tst_QLocalSocket::tst_QLocalSocket() qRegisterMetaType<QLocalSocket::LocalSocketState>("QLocalSocket::LocalSocketState"); qRegisterMetaType<QLocalSocket::LocalSocketError>("QLocalSocket::LocalSocketError"); qRegisterMetaType<QLocalServer::SocketOption>("QLocalServer::SocketOption"); + qRegisterMetaType<QLocalServer::SocketOption>("QLocalSocket::SocketOption"); qRegisterMetaType<QFile::Permissions>("QFile::Permissions"); } -class LocalServer : public QLocalServer +class CrashSafeLocalServer : public QLocalServer { Q_OBJECT public: - LocalServer() : QLocalServer() + CrashSafeLocalServer() : QLocalServer() { - connect(this, SIGNAL(newConnection()), this, SLOT(slotNewConnection())); } bool listen(const QString &name) @@ -147,10 +154,23 @@ public: return QLocalServer::listen(name); } + bool listen(qintptr socketDescriptor) { return QLocalServer::listen(socketDescriptor); } +}; + +class LocalServer : public CrashSafeLocalServer +{ + Q_OBJECT + +public: + LocalServer() : CrashSafeLocalServer() + { + connect(this, SIGNAL(newConnection()), this, SLOT(slotNewConnection())); + } + QList<int> hits; protected: - void incomingConnection(quintptr socketDescriptor) + void incomingConnection(quintptr socketDescriptor) override { hits.append(socketDescriptor); QLocalServer::incomingConnection(socketDescriptor); @@ -168,7 +188,7 @@ class LocalSocket : public QLocalSocket Q_OBJECT public: - LocalSocket(QObject *parent = 0) : QLocalSocket(parent) + LocalSocket(QObject *parent = nullptr) : QLocalSocket(parent) { connect(this, SIGNAL(connected()), this, SLOT(slotConnected())); @@ -227,8 +247,8 @@ void tst_QLocalSocket::server_basic() QVERIFY(!timedOut); QCOMPARE(server.listen(QString()), false); - QCOMPARE(server.hits.count(), 0); - QCOMPARE(spyNewConnection.count(), 0); + QCOMPARE(server.hits.size(), 0); + QCOMPARE(spyNewConnection.size(), 0); } void tst_QLocalSocket::server_connectionsCount() @@ -269,11 +289,11 @@ void tst_QLocalSocket::socket_basic() QCOMPARE(socket.waitForDisconnected(0), false); QCOMPARE(socket.waitForReadyRead(0), false); - QCOMPARE(spyConnected.count(), 0); - QCOMPARE(spyDisconnected.count(), 0); - QCOMPARE(spyError.count(), 0); - QCOMPARE(spyStateChanged.count(), 0); - QCOMPARE(spyReadyRead.count(), 0); + QCOMPARE(spyConnected.size(), 0); + QCOMPARE(spyDisconnected.size(), 0); + QCOMPARE(spyError.size(), 0); + QCOMPARE(spyStateChanged.size(), 0); + QCOMPARE(spyReadyRead.size(), 0); } void tst_QLocalSocket::listen_data() @@ -282,8 +302,8 @@ void tst_QLocalSocket::listen_data() QTest::addColumn<bool>("canListen"); QTest::addColumn<bool>("close"); QTest::newRow("null") << QString() << false << false; - QTest::newRow("tst_localsocket") << "tst_localsocket" << true << true; - QTest::newRow("tst_localsocket") << "tst_localsocket" << true << false; + QTest::newRow("tst_localsocket,close") << "tst_localsocket" << true << true; + QTest::newRow("tst_localsocket,no-close") << "tst_localsocket" << true << false; } // start a server that listens, but don't connect a socket, make sure everything is in order @@ -295,7 +315,7 @@ void tst_QLocalSocket::listen() QFETCH(QString, name); QFETCH(bool, canListen); QFETCH(bool, close); - QVERIFY2((server.listen(name) == canListen), server.errorString().toLatin1().constData()); + QVERIFY2((server.listen(name) == canListen), qUtf8Printable(server.errorString())); // test listening QCOMPARE(server.serverName(), name); @@ -303,8 +323,8 @@ void tst_QLocalSocket::listen() QCOMPARE(server.isListening(), canListen); QCOMPARE(server.hasPendingConnections(), false); QCOMPARE(server.nextPendingConnection(), (QLocalSocket*)0); - QCOMPARE(server.hits.count(), 0); - QCOMPARE(spyNewConnection.count(), 0); + QCOMPARE(server.hits.size(), 0); + QCOMPARE(spyNewConnection.size(), 0); if (canListen) { QVERIFY(server.errorString().isEmpty()); QCOMPARE(server.serverError(), QAbstractSocket::UnknownSocketError); @@ -378,7 +398,7 @@ void tst_QLocalSocket::listenAndConnect() QCOMPARE(socket->error(), QLocalSocket::UnknownSocketError); QCOMPARE(socket->state(), QLocalSocket::ConnectedState); //QVERIFY(socket->socketDescriptor() != -1); - QCOMPARE(spyError.count(), 0); + QCOMPARE(spyError.size(), 0); } else { QVERIFY(!socket->errorString().isEmpty()); QVERIFY(socket->error() != QLocalSocket::UnknownSocketError); @@ -397,13 +417,13 @@ void tst_QLocalSocket::listenAndConnect() QCOMPARE(socket->waitForConnected(0), canListen); QCOMPARE(socket->waitForReadyRead(0), false); - QTRY_COMPARE(spyConnected.count(), canListen ? 1 : 0); - QCOMPARE(spyDisconnected.count(), 0); + QTRY_COMPARE(spyConnected.size(), canListen ? 1 : 0); + QCOMPARE(spyDisconnected.size(), 0); // error signals - QVERIFY(spyError.count() >= 0); + QVERIFY(spyError.size() >= 0); if (canListen) { - if (spyError.count() > 0) + if (spyError.size() > 0) QCOMPARE(qvariant_cast<QLocalSocket::LocalSocketError>(spyError.first()[0]), QLocalSocket::SocketTimeoutError); } else { @@ -418,8 +438,8 @@ void tst_QLocalSocket::listenAndConnect() if (canListen) QCOMPARE(qvariant_cast<QLocalSocket::LocalSocketState>(spyStateChanged.last()[0]), QLocalSocket::ConnectedState); - QCOMPARE(spyStateChanged.count(), 2); - QCOMPARE(spyReadyRead.count(), 0); + QCOMPARE(spyStateChanged.size(), 2); + QCOMPARE(spyReadyRead.size(), 0); bool timedOut = true; QCOMPARE(server.waitForNewConnection(3000, &timedOut), canListen); @@ -433,16 +453,16 @@ void tst_QLocalSocket::listenAndConnect() QCOMPARE(server.serverName(), name); QVERIFY(server.fullServerName().contains(name)); QVERIFY(server.nextPendingConnection() != (QLocalSocket*)0); - QTRY_COMPARE(server.hits.count(), i + 1); - QCOMPARE(spyNewConnection.count(), i + 1); + QTRY_COMPARE(server.hits.size(), i + 1); + QCOMPARE(spyNewConnection.size(), i + 1); QVERIFY(server.errorString().isEmpty()); QCOMPARE(server.serverError(), QAbstractSocket::UnknownSocketError); } else { QVERIFY(server.serverName().isEmpty()); QVERIFY(server.fullServerName().isEmpty()); QCOMPARE(server.nextPendingConnection(), (QLocalSocket*)0); - QCOMPARE(spyNewConnection.count(), 0); - QCOMPARE(server.hits.count(), 0); + QCOMPARE(spyNewConnection.size(), 0); + QCOMPARE(server.hits.size(), 0); QVERIFY(!server.errorString().isEmpty()); QCOMPARE(server.serverError(), QAbstractSocket::HostNotFoundError); } @@ -451,16 +471,17 @@ void tst_QLocalSocket::listenAndConnect() server.close(); - QCOMPARE(server.hits.count(), (canListen ? connections : 0)); - QCOMPARE(spyNewConnection.count(), (canListen ? connections : 0)); + QCOMPARE(server.hits.size(), (canListen ? connections : 0)); + QCOMPARE(spyNewConnection.size(), (canListen ? connections : 0)); } void tst_QLocalSocket::connectWithOpen() { LocalServer server; - QVERIFY(server.listen("tst_qlocalsocket")); + QVERIFY2(server.listen("tst_qlocalsocket"), qUtf8Printable(server.errorString())); LocalSocket socket; + QSignalSpy spyAboutToClose(&socket, SIGNAL(aboutToClose())); socket.setServerName("tst_qlocalsocket"); QVERIFY(socket.open()); @@ -474,6 +495,107 @@ void tst_QLocalSocket::connectWithOpen() socket.close(); server.close(); + + QCOMPARE(spyAboutToClose.size(), 1); +} + +void tst_QLocalSocket::listenAndConnectAbstractNamespaceTrailingZeros_data() +{ +#ifdef Q_OS_LINUX + QTest::addColumn<bool>("server_0"); + QTest::addColumn<bool>("client_0"); + QTest::addColumn<bool>("success"); + QTest::newRow("srv0_cli0") << true << true << true; + QTest::newRow("srv_cli0") << false << true << false; + QTest::newRow("srv0_cli") << true << false << false; + QTest::newRow("srv_cli") << false << false << true; +#else + return; +#endif +} + +void tst_QLocalSocket::listenAndConnectAbstractNamespaceTrailingZeros() +{ +#ifdef Q_OS_LINUX + QFETCH(bool, server_0); + QFETCH(bool, client_0); + QFETCH(bool, success); + bool expectedTimeOut = !success; + QString server_path("tst_qlocalsocket"); + QString client_path("tst_qlocalsocket"); + + if (server_0) + server_path.append(QChar('\0')); + if (client_0) + client_path.append(QChar('\0')); + LocalServer server; + server.setSocketOptions(QLocalServer::AbstractNamespaceOption); + QVERIFY2(server.listen(server_path), qUtf8Printable(server.errorString())); + QCOMPARE(server.fullServerName(), server_path); + + LocalSocket socket; + socket.setSocketOptions(QLocalSocket::AbstractNamespaceOption); + socket.setServerName(client_path); + QCOMPARE(socket.open(), success); + if (success) + QCOMPARE(socket.fullServerName(), client_path); + else + QVERIFY(socket.fullServerName().isEmpty()); + + bool timedOut = true; + QCOMPARE(server.waitForNewConnection(3000, &timedOut), success); + +#if defined(QT_LOCALSOCKET_TCP) + QTest::qWait(250); +#endif + QCOMPARE(timedOut, expectedTimeOut); + + socket.close(); + server.close(); +#else + return; +#endif +} + +void tst_QLocalSocket::listenAndConnectAbstractNamespace_data() +{ + QTest::addColumn<QLocalServer::SocketOption>("serverOption"); + QTest::addColumn<QLocalSocket::SocketOption>("socketOption"); + QTest::addColumn<bool>("success"); + QTest::newRow("abs_abs") << QLocalServer::AbstractNamespaceOption << QLocalSocket::AbstractNamespaceOption << true; + QTest::newRow("reg_reg") << QLocalServer::NoOptions << QLocalSocket::NoOptions << true; +#ifdef Q_OS_LINUX + QTest::newRow("reg_abs") << QLocalServer::UserAccessOption << QLocalSocket::AbstractNamespaceOption << false; + QTest::newRow("abs_reg") << QLocalServer::AbstractNamespaceOption << QLocalSocket::NoOptions << false; +#endif +} + +void tst_QLocalSocket::listenAndConnectAbstractNamespace() +{ + QFETCH(QLocalServer::SocketOption, serverOption); + QFETCH(QLocalSocket::SocketOption, socketOption); + QFETCH(bool, success); + bool expectedTimeOut = !success; + + LocalServer server; + server.setSocketOptions(serverOption); + QVERIFY2(server.listen("tst_qlocalsocket"), qUtf8Printable(server.errorString())); + + LocalSocket socket; + socket.setSocketOptions(socketOption); + socket.setServerName("tst_qlocalsocket"); + QCOMPARE(socket.open(), success); + + bool timedOut = true; + QCOMPARE(server.waitForNewConnection(3000, &timedOut), success); + +#if defined(QT_LOCALSOCKET_TCP) + QTest::qWait(250); +#endif + QCOMPARE(timedOut, expectedTimeOut); + + socket.close(); + server.close(); } void tst_QLocalSocket::connectWithOldOpen() @@ -540,7 +662,7 @@ void tst_QLocalSocket::sendData() QTest::qWait(250); #endif QVERIFY(!timedOut); - QCOMPARE(spyConnected.count(), canListen ? 1 : 0); + QCOMPARE(spyConnected.size(), canListen ? 1 : 0); QCOMPARE(socket.state(), canListen ? QLocalSocket::ConnectedState : QLocalSocket::UnconnectedState); // test sending/receiving data @@ -566,7 +688,7 @@ void tst_QLocalSocket::sendData() QCOMPARE(socket.flush(), false); QCOMPARE(socket.isValid(), canListen); QCOMPARE(socket.readBufferSize(), (qint64)0); - QCOMPARE(spyReadyRead.count(), expectedReadyReadSignals); + QCOMPARE(spyReadyRead.size(), expectedReadyReadSignals); QVERIFY(testLine.startsWith(in.readLine())); @@ -577,16 +699,165 @@ void tst_QLocalSocket::sendData() } socket.disconnectFromServer(); - QCOMPARE(spyConnected.count(), canListen ? 1 : 0); - QCOMPARE(spyDisconnected.count(), canListen ? 1 : 0); - QCOMPARE(spyError.count(), canListen ? 0 : 1); - QCOMPARE(spyStateChanged.count(), canListen ? 4 : 2); - QCOMPARE(spyReadyRead.count(), canListen ? expectedReadyReadSignals : 0); + QCOMPARE(spyConnected.size(), canListen ? 1 : 0); + QCOMPARE(spyDisconnected.size(), canListen ? 1 : 0); + QCOMPARE(spyError.size(), canListen ? 0 : 1); + QCOMPARE(spyStateChanged.size(), canListen ? 4 : 2); + QCOMPARE(spyReadyRead.size(), canListen ? expectedReadyReadSignals : 0); server.close(); - QCOMPARE(server.hits.count(), (canListen ? 1 : 0)); - QCOMPARE(spy.count(), (canListen ? 1 : 0)); + QCOMPARE(server.hits.size(), (canListen ? 1 : 0)); + QCOMPARE(spy.size(), (canListen ? 1 : 0)); +} + +void tst_QLocalSocket::readLine_data() +{ + QTest::addColumn<ByteArrayList>("input"); + QTest::addColumn<ByteArrayList>("output"); + QTest::addColumn<int>("maxSize"); + QTest::addColumn<bool>("wholeLinesOnly"); + + QTest::newRow("0") << ByteArrayList{ "\n", "A", "\n", "B", "B", "A", "\n" } + << ByteArrayList{ "\n", "", "", "A\n", "", "", "", "", + "BBA\n", "", "" } + << 80 << true; + QTest::newRow("1") << ByteArrayList{ "A", "\n", "\n", "B", "B", "\n", "A", "A" } + << ByteArrayList{ "", "A\n", "", "\n", "", "", "", "BB\n", + "", "", "", "AA", "" } + << 80 << true; + + QTest::newRow("2") << ByteArrayList{ "\nA\nA\n" } + << ByteArrayList{ "\n", "A", "\n", "A", "\n", "", "" } + << 1 << false; + QTest::newRow("3") << ByteArrayList{ "A\n\n\nA", "A" } + << ByteArrayList{ "A\n", "\n", "\n", "A", "", "A", "", "" } + << 2 << false; + + QTest::newRow("4") << ByteArrayList{ "He", "ll", "o\n", " \n", "wo", "rl", "d", "!\n" } + << ByteArrayList{ "", "Hel", "", "lo\n", "", " \n", "", "", "wor", + "", "", "ld!", "\n", "", "" } + << 3 << true; + QTest::newRow("5") << ByteArrayList{ "Hello\n world!" } + << ByteArrayList{ "Hello\n", "", " world!", "" } + << 80 << true; + + QTest::newRow("6") << ByteArrayList{ "\nHello", " \n", " wor", "ld!\n" } + << ByteArrayList{ "\n", "Hell", "o", "", " \n", "", " wor", "", + "ld!\n", "", "" } + << 4 << false; + QTest::newRow("7") << ByteArrayList{ "Hello\n world", "!" } + << ByteArrayList{ "Hello\n", " world", "", "!", "", "" } + << 80 << false; +} + +void tst_QLocalSocket::readLine() +{ + QFETCH(ByteArrayList, input); + QFETCH(ByteArrayList, output); + QFETCH(int, maxSize); + QFETCH(bool, wholeLinesOnly); + + const QString serverName = QLatin1String("tst_localsocket"); + LocalServer server; + QVERIFY2(server.listen(serverName), qUtf8Printable(server.errorString())); + + LocalSocket client; + client.connectToServer(serverName); + QVERIFY(server.waitForNewConnection()); + QLocalSocket *serverSocket = server.nextPendingConnection(); + QVERIFY(serverSocket); + QCOMPARE(client.state(), QLocalSocket::ConnectedState); + + ByteArrayList result; + qsizetype pos = 0; + do { + // This test assumes that such small chunks of data are synchronously + // delivered to the receiver on all supported platforms. + if (pos < input.size()) { + const QByteArray &chunk = input.at(pos); + QCOMPARE(serverSocket->write(chunk), qint64(chunk.size())); + QVERIFY(serverSocket->waitForBytesWritten()); + QCOMPARE(serverSocket->bytesToWrite(), qint64(0)); + QVERIFY(client.waitForReadyRead()); + } else { + serverSocket->close(); + QVERIFY(!client.waitForReadyRead()); + } + + while (!wholeLinesOnly || (client.bytesAvailable() >= qint64(maxSize)) + || client.canReadLine() || (pos == input.size())) { + const bool chunkEmptied = (client.bytesAvailable() == 0); + QByteArray line(maxSize, Qt::Uninitialized); + + const qint64 readResult = client.readLine(line.data(), maxSize + 1); + if (chunkEmptied) { + if (pos == input.size()) + QCOMPARE(readResult, qint64(-1)); + else + QCOMPARE(readResult, qint64(0)); + break; + } + QVERIFY((readResult > 0) && (readResult <= maxSize)); + line.resize(readResult); + result.append(line); + } + result.append(QByteArray()); + } while (++pos <= input.size()); + QCOMPARE(client.state(), QLocalSocket::UnconnectedState); + QCOMPARE(result, output); +} + +void tst_QLocalSocket::skip_data() +{ + QTest::addColumn<QByteArray>("data"); + QTest::addColumn<int>("read"); + QTest::addColumn<int>("skip"); + QTest::addColumn<int>("skipped"); + QTest::addColumn<char>("expect"); + + QByteArray bigData; + bigData.fill('a', 20000); + bigData[10001] = 'x'; + + QTest::newRow("small_data") << QByteArray("abcdefghij") << 3 << 6 << 6 << 'j'; + QTest::newRow("big_data") << bigData << 1 << 10000 << 10000 << 'x'; + QTest::newRow("beyond_the_end") << bigData << 1 << 20000 << 19999 << '\0'; +} + +void tst_QLocalSocket::skip() +{ + QFETCH(QByteArray, data); + QFETCH(int, read); + QFETCH(int, skip); + QFETCH(int, skipped); + QFETCH(char, expect); + char lastChar = '\0'; + + const QString serverName = QLatin1String("tst_localsocket"); + LocalServer server; + QVERIFY2(server.listen(serverName), qUtf8Printable(server.errorString())); + + LocalSocket client; + client.connectToServer(serverName); + QVERIFY(server.waitForNewConnection()); + QLocalSocket *serverSocket = server.nextPendingConnection(); + QVERIFY(serverSocket); + QCOMPARE(client.state(), QLocalSocket::ConnectedState); + + QCOMPARE(serverSocket->write(data), data.size()); + while (serverSocket->waitForBytesWritten()) + QVERIFY(client.waitForReadyRead()); + QCOMPARE(serverSocket->bytesToWrite(), qint64(0)); + serverSocket->close(); + QVERIFY(client.waitForDisconnected()); + + for (int i = 0; i < read; ++i) + client.getChar(nullptr); + + QCOMPARE(client.skip(skip), skipped); + client.getChar(&lastChar); + QCOMPARE(lastChar, expect); } void tst_QLocalSocket::readBufferOverflow() @@ -632,26 +903,6 @@ void tst_QLocalSocket::readBufferOverflow() QCOMPARE(client.read(buffer, readBufferSize), qint64(readBufferSize)); // no more bytes available QCOMPARE(client.bytesAvailable(), 0); - -#ifdef Q_OS_WIN - serverSocket->write(buffer, readBufferSize); - QVERIFY(serverSocket->waitForBytesWritten()); - - // ensure the read completion routine is called - SleepEx(100, true); - QVERIFY(client.waitForReadyRead()); - QCOMPARE(client.read(buffer, readBufferSize), qint64(readBufferSize)); - - // Test overflow caused by an asynchronous pipe operation. - client.setReadBufferSize(1); - serverSocket->write(buffer, 2); - - QVERIFY(client.waitForReadyRead()); - // socket disconnects, if there any error on pipe - QCOMPARE(client.state(), QLocalSocket::ConnectedState); - QCOMPARE(client.bytesAvailable(), qint64(2)); - QCOMPARE(client.read(buffer, 2), qint64(2)); -#endif } static qint64 writeCommand(const QVariant &command, QIODevice *device, int commandCounter) @@ -684,7 +935,7 @@ static QVariant readCommand(QIODevice *ioDevice, int *readCommandCounter, bool r void tst_QLocalSocket::simpleCommandProtocol1() { - QLocalServer server; + CrashSafeLocalServer server; server.listen(QStringLiteral("simpleProtocol")); QLocalSocket localSocketWrite; @@ -710,10 +961,11 @@ void tst_QLocalSocket::simpleCommandProtocol1() void tst_QLocalSocket::simpleCommandProtocol2() { - QLocalServer server; + CrashSafeLocalServer server; server.listen(QStringLiteral("simpleProtocol")); QLocalSocket localSocketWrite; + QSignalSpy spyDisconnected(&localSocketWrite, SIGNAL(disconnected())); localSocketWrite.connectToServer(server.serverName()); QVERIFY(server.waitForNewConnection()); QLocalSocket* localSocketRead = server.nextPendingConnection(); @@ -755,13 +1007,18 @@ void tst_QLocalSocket::simpleCommandProtocol2() } localSocketWrite.abort(); + QCOMPARE(localSocketWrite.state(), QLocalSocket::UnconnectedState); + QCOMPARE(spyDisconnected.size(), 1); + QCOMPARE(localSocketWrite.bytesToWrite(), 0); + QVERIFY(!localSocketWrite.isOpen()); + QVERIFY(localSocketRead->waitForDisconnected(1000)); } // QLocalSocket/Server can take a name or path, check that it works as expected void tst_QLocalSocket::fullPath() { - QLocalServer server; + CrashSafeLocalServer server; QString name = "qlocalsocket_pathtest"; #if defined(QT_LOCALSOCKET_TCP) QString path = "QLocalServer"; @@ -771,7 +1028,7 @@ void tst_QLocalSocket::fullPath() QString path = "/tmp"; #endif QString serverName = path + '/' + name; - QVERIFY2(server.listen(serverName), server.errorString().toLatin1().constData()); + QVERIFY2(server.listen(serverName), qUtf8Printable(server.errorString())); QCOMPARE(server.serverName(), serverName); QCOMPARE(server.fullServerName(), serverName); @@ -802,7 +1059,7 @@ void tst_QLocalSocket::hitMaximumConnections() LocalServer server; QString name = "tst_localsocket"; server.setMaxPendingConnections(max); - QVERIFY2(server.listen(name), server.errorString().toLatin1().constData()); + QVERIFY2(server.listen(name), qUtf8Printable(server.errorString())); int connections = server.maxPendingConnections() + 1; QList<QLocalSocket*> sockets; for (int i = 0; i < connections; ++i) { @@ -813,7 +1070,7 @@ void tst_QLocalSocket::hitMaximumConnections() bool timedOut = true; QVERIFY(server.waitForNewConnection(3000, &timedOut)); QVERIFY(!timedOut); - QVERIFY(server.hits.count() > 0); + QVERIFY(server.hits.size() > 0); qDeleteAll(sockets.begin(), sockets.end()); } @@ -832,7 +1089,7 @@ class Client : public QThread { public: - void run() + void run() override { QString testLine = "test"; LocalSocket socket; @@ -841,9 +1098,9 @@ public: QVERIFY(socket.waitForConnected(1000)); // We should *not* have this signal yet! - QCOMPARE(spyReadyRead.count(), 0); + QCOMPARE(spyReadyRead.size(), 0); socket.waitForReadyRead(); - QCOMPARE(spyReadyRead.count(), 1); + QCOMPARE(spyReadyRead.size(), 1); QTextStream in(&socket); QCOMPARE(in.readLine(), testLine); socket.close(); @@ -857,13 +1114,13 @@ public: int clients; QMutex mutex; QWaitCondition wc; - void run() + void run() override { QString testLine = "test"; LocalServer server; server.setMaxPendingConnections(10); QVERIFY2(server.listen("qlocalsocket_threadtest"), - server.errorString().toLatin1().constData()); + qUtf8Printable(server.errorString())); mutex.lock(); wc.wakeAll(); mutex.unlock(); @@ -885,7 +1142,7 @@ public: --done; delete serverSocket; } - QCOMPARE(server.hits.count(), clients); + QCOMPARE(server.hits.size(), clients); } }; @@ -935,7 +1192,7 @@ void tst_QLocalSocket::processConnection_data() class ProcessOutputDumper { public: - ProcessOutputDumper(QProcess *p = 0) + ProcessOutputDumper(QProcess *p = nullptr) : process(p) {} @@ -947,7 +1204,7 @@ public: void clear() { - process = 0; + process = nullptr; } private: @@ -1024,7 +1281,7 @@ void tst_QLocalSocket::waitForDisconnect() { QString name = "tst_localsocket"; LocalServer server; - QVERIFY(server.listen(name)); + QVERIFY2(server.listen(name), qUtf8Printable(server.errorString())); LocalSocket socket; socket.connectToServer(name); QVERIFY(socket.waitForConnected(3000)); @@ -1042,7 +1299,7 @@ void tst_QLocalSocket::waitForDisconnectByServer() { QString name = "tst_localsocket"; LocalServer server; - QVERIFY(server.listen(name)); + QVERIFY2(server.listen(name), qUtf8Printable(server.errorString())); LocalSocket socket; QSignalSpy spy(&socket, SIGNAL(disconnected())); QVERIFY(spy.isValid()); @@ -1054,15 +1311,81 @@ void tst_QLocalSocket::waitForDisconnectByServer() serverSocket->close(); QCOMPARE(serverSocket->state(), QLocalSocket::UnconnectedState); QVERIFY(socket.waitForDisconnected(3000)); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); +} + +void tst_QLocalSocket::waitForReadyReadOnDisconnected() +{ + QString name = "tst_localsocket"; + LocalServer server; + QVERIFY2(server.listen(name), qUtf8Printable(server.errorString())); + LocalSocket socket; + connect(&socket, &QLocalSocket::readyRead, [&socket]() { + QVERIFY(socket.getChar(nullptr)); + // The next call should not block because the socket was closed + // by the peer. + QVERIFY(!socket.waitForReadyRead(3000)); + }); + + socket.connectToServer(name); + QVERIFY(socket.waitForConnected(3000)); + QVERIFY(server.waitForNewConnection(3000)); + QLocalSocket *serverSocket = server.nextPendingConnection(); + QVERIFY(serverSocket); + QVERIFY(serverSocket->putChar(0)); + QVERIFY(serverSocket->waitForBytesWritten(3000)); + serverSocket->close(); + +#ifdef Q_OS_WIN + // Ensure that the asynchronously delivered close notification is + // already queued up before we consume the data. + QTest::qSleep(250); +#endif + + QElapsedTimer timer; + timer.start(); + QVERIFY(socket.waitForReadyRead(5000)); + QVERIFY(timer.elapsed() < 2000); +} + +void tst_QLocalSocket::delayedDisconnect() +{ + QString name = "tst_localsocket"; + LocalServer server; + QVERIFY2(server.listen(name), qUtf8Printable(server.errorString())); + LocalSocket socket; + socket.connectToServer(name); + QVERIFY(socket.waitForConnected(3000)); + QVERIFY(server.waitForNewConnection(3000)); + QLocalSocket *serverSocket = server.nextPendingConnection(); + QVERIFY(serverSocket); + connect(serverSocket, &QLocalSocket::aboutToClose, [serverSocket]() { + QVERIFY(serverSocket->isOpen()); + QCOMPARE(serverSocket->bytesAvailable(), qint64(1)); + }); + + QVERIFY(socket.putChar(0)); + socket.disconnectFromServer(); + QCOMPARE(socket.state(), QLocalSocket::ClosingState); + QVERIFY(socket.waitForDisconnected(3000)); + QCOMPARE(socket.state(), QLocalSocket::UnconnectedState); + QVERIFY(socket.isOpen()); + + QVERIFY(serverSocket->waitForReadyRead(3000)); + serverSocket->close(); + QCOMPARE(serverSocket->state(), QLocalSocket::UnconnectedState); + QVERIFY(!serverSocket->isOpen()); + QCOMPARE(serverSocket->bytesAvailable(), qint64(0)); } void tst_QLocalSocket::removeServer() { // this is a hostile takeover, but recovering from a crash results in the same + // Note: Explicitly not a CrashSafeLocalServer QLocalServer server, server2; + QVERIFY(QLocalServer::removeServer("cleanuptest")); - QVERIFY(server.listen("cleanuptest")); + QVERIFY2(server.listen("cleanuptest"), qUtf8Printable(server.errorString())); #ifndef Q_OS_WIN // on Windows, there can be several sockets listening on the same pipe // on Unix, there can only be one socket instance @@ -1074,10 +1397,10 @@ void tst_QLocalSocket::removeServer() void tst_QLocalSocket::recycleServer() { - QLocalServer server; + CrashSafeLocalServer server; QLocalSocket client; - QVERIFY(server.listen("recycletest1")); + QVERIFY2(server.listen("recycletest1"), qUtf8Printable(server.errorString())); client.connectToServer("recycletest1"); QVERIFY(client.waitForConnected(201)); QVERIFY(server.waitForNewConnection(201)); @@ -1087,7 +1410,7 @@ void tst_QLocalSocket::recycleServer() client.disconnectFromServer(); qApp->processEvents(); - QVERIFY(server.listen("recycletest2")); + QVERIFY2(server.listen("recycletest2"), qUtf8Printable(server.errorString())); client.connectToServer("recycletest2"); QVERIFY(client.waitForConnected(202)); QVERIFY(server.waitForNewConnection(202)); @@ -1099,13 +1422,13 @@ void tst_QLocalSocket::recycleClientSocket() const QByteArrayList lines = QByteArrayList() << "Have you heard of that new band" << "\"1023 Megabytes\"?" << "They haven't made it to a gig yet."; - QLocalServer server; + CrashSafeLocalServer server; const QString serverName = QStringLiteral("recycleClientSocket"); - QVERIFY(server.listen(serverName)); + QVERIFY2(server.listen(serverName), qUtf8Printable(server.errorString())); QLocalSocket client; QSignalSpy clientReadyReadSpy(&client, SIGNAL(readyRead())); QSignalSpy clientErrorSpy(&client, SIGNAL(errorOccurred(QLocalSocket::LocalSocketError))); - for (int i = 0; i < lines.count(); ++i) { + for (int i = 0; i < lines.size(); ++i) { client.abort(); clientReadyReadSpy.clear(); client.connectToServer(serverName); @@ -1124,12 +1447,12 @@ void tst_QLocalSocket::recycleClientSocket() void tst_QLocalSocket::multiConnect() { - QLocalServer server; + CrashSafeLocalServer server; QLocalSocket client1; QLocalSocket client2; QLocalSocket client3; - QVERIFY(server.listen("multiconnect")); + QVERIFY2(server.listen("multiconnect"), qUtf8Printable(server.errorString())); client1.connectToServer("multiconnect"); client2.connectToServer("multiconnect"); @@ -1149,8 +1472,8 @@ void tst_QLocalSocket::multiConnect() void tst_QLocalSocket::writeOnlySocket() { - QLocalServer server; - QVERIFY(server.listen("writeOnlySocket")); + CrashSafeLocalServer server; + QVERIFY2(server.listen("writeOnlySocket"), qUtf8Printable(server.errorString())); QLocalSocket client; client.connectToServer("writeOnlySocket", QIODevice::WriteOnly); @@ -1161,6 +1484,13 @@ void tst_QLocalSocket::writeOnlySocket() QCOMPARE(client.bytesAvailable(), qint64(0)); QCOMPARE(client.state(), QLocalSocket::ConnectedState); + + serverSocket->abort(); + // On Windows, we need to test that the socket state is periodically + // checked in a loop, even if no timeout value is specified (i.e. + // waitForDisconnected(-1) does not fail immediately). + QVERIFY(client.waitForDisconnected(-1)); + QCOMPARE(client.state(), QLocalSocket::UnconnectedState); } void tst_QLocalSocket::writeToClientAndDisconnect_data() @@ -1173,33 +1503,60 @@ void tst_QLocalSocket::writeToClientAndDisconnect_data() void tst_QLocalSocket::writeToClientAndDisconnect() { QFETCH(int, chunks); - QLocalServer server; + CrashSafeLocalServer server; QLocalSocket client; QSignalSpy readChannelFinishedSpy(&client, SIGNAL(readChannelFinished())); - QVERIFY(server.listen("writeAndDisconnectServer")); + QVERIFY2(server.listen("writeAndDisconnectServer"), qUtf8Printable(server.errorString())); client.connectToServer("writeAndDisconnectServer"); QVERIFY(client.waitForConnected(200)); QVERIFY(server.waitForNewConnection(200)); QLocalSocket* clientSocket = server.nextPendingConnection(); QVERIFY(clientSocket); + server.close(); char buffer[100]; memset(buffer, 0, sizeof(buffer)); for (int i = 0; i < chunks; ++i) QCOMPARE(clientSocket->write(buffer, sizeof(buffer)), qint64(sizeof(buffer))); - while (clientSocket->bytesToWrite()) - QVERIFY(clientSocket->waitForBytesWritten()); clientSocket->close(); - server.close(); + QVERIFY(clientSocket->waitForDisconnected()); - client.waitForDisconnected(); - QCOMPARE(readChannelFinishedSpy.count(), 1); + QVERIFY(client.waitForDisconnected()); + QCOMPARE(readChannelFinishedSpy.size(), 1); const QByteArray received = client.readAll(); QCOMPARE(received.size(), qint64(sizeof(buffer) * chunks)); QCOMPARE(client.state(), QLocalSocket::UnconnectedState); } +void tst_QLocalSocket::writeToDisconnected() +{ + CrashSafeLocalServer server; + QVERIFY2(server.listen("writeToDisconnected"), qUtf8Printable(server.errorString())); + + QLocalSocket client; + QSignalSpy spyError(&client, SIGNAL(errorOccurred(QLocalSocket::LocalSocketError))); + client.connectToServer("writeToDisconnected"); + QVERIFY(client.waitForConnected(3000)); + QVERIFY(server.waitForNewConnection(3000)); + QLocalSocket *serverSocket = server.nextPendingConnection(); + QVERIFY(serverSocket); + serverSocket->abort(); + + QCOMPARE(client.state(), QLocalSocket::ConnectedState); + QVERIFY(client.putChar(0)); + +#ifdef Q_OS_WIN + // Ensure the asynchronous write operation is finished. + QTest::qSleep(250); +#endif + + QCOMPARE(client.bytesToWrite(), qint64(1)); + QVERIFY(!client.waitForBytesWritten()); + QCOMPARE(spyError.size(), 1); + QCOMPARE(client.state(), QLocalSocket::UnconnectedState); +} + void tst_QLocalSocket::debug() { // Make sure this compiles @@ -1212,7 +1569,8 @@ class WriteThread : public QThread { Q_OBJECT public: - void run() { + void run() override + { QLocalSocket socket; socket.connectToServer("qlocalsocket_readyread"); @@ -1244,8 +1602,8 @@ public slots: */ void tst_QLocalSocket::bytesWrittenSignal() { - QLocalServer server; - QVERIFY(server.listen("qlocalsocket_readyread")); + CrashSafeLocalServer server; + QVERIFY2(server.listen("qlocalsocket_readyread"), qUtf8Printable(server.errorString())); WriteThread writeThread; QSignalSpy receivedSpy(&writeThread, &WriteThread::bytesWrittenReceived); writeThread.start(); @@ -1256,36 +1614,59 @@ void tst_QLocalSocket::bytesWrittenSignal() QVERIFY(writeThread.wait(2000)); } +void tst_QLocalSocket::socketClosedSlot() +{ + QLocalSocket *socket = qobject_cast<QLocalSocket *>(sender()); + + QCOMPARE(socket->state(), QLocalSocket::UnconnectedState); +} + void tst_QLocalSocket::syncDisconnectNotify() { - QLocalServer server; - QVERIFY(server.listen("syncDisconnectNotify")); + CrashSafeLocalServer server; + QVERIFY2(server.listen("syncDisconnectNotify"), qUtf8Printable(server.errorString())); QLocalSocket client; + connect(&client, &QLocalSocket::disconnected, + this, &tst_QLocalSocket::socketClosedSlot); + connect(&client, &QIODevice::readChannelFinished, + this, &tst_QLocalSocket::socketClosedSlot); + client.connectToServer("syncDisconnectNotify"); QVERIFY(server.waitForNewConnection()); QLocalSocket* serverSocket = server.nextPendingConnection(); QVERIFY(serverSocket); delete serverSocket; QCOMPARE(client.waitForReadyRead(), false); + QVERIFY(!client.putChar(0)); } void tst_QLocalSocket::asyncDisconnectNotify() { - QLocalServer server; - QVERIFY(server.listen("asyncDisconnectNotify")); + CrashSafeLocalServer server; + QVERIFY2(server.listen("asyncDisconnectNotify"), qUtf8Printable(server.errorString())); QLocalSocket client; QSignalSpy disconnectedSpy(&client, SIGNAL(disconnected())); + QSignalSpy readChannelFinishedSpy(&client, SIGNAL(readChannelFinished())); + connect(&client, &QLocalSocket::disconnected, + this, &tst_QLocalSocket::socketClosedSlot); + connect(&client, &QIODevice::readChannelFinished, + this, &tst_QLocalSocket::socketClosedSlot); + client.connectToServer("asyncDisconnectNotify"); QVERIFY(server.waitForNewConnection()); QLocalSocket* serverSocket = server.nextPendingConnection(); QVERIFY(serverSocket); delete serverSocket; QTRY_VERIFY(!disconnectedSpy.isEmpty()); + QCOMPARE(readChannelFinishedSpy.size(), 1); } void tst_QLocalSocket::verifySocketOptions_data() { #ifdef Q_OS_LINUX + if (::geteuid() == 0) + QSKIP("Running this test as root doesn't make sense"); + QTest::addColumn<QString>("service"); QTest::addColumn<QLocalServer::SocketOption>("opts"); QTest::addColumn<QFile::Permissions>("perms"); @@ -1311,16 +1692,14 @@ void tst_QLocalSocket::verifySocketOptions_data() void tst_QLocalSocket::verifySocketOptions() { // These are only guaranteed to be useful on linux at this time -#ifdef Q_OS_LINUX +#if defined(Q_OS_LINUX) && !defined(Q_OS_WEBOS) QFETCH(QString, service); QFETCH(QLocalServer::SocketOption, opts); QFETCH(QFile::Permissions, perms); - - QLocalServer::removeServer(service); - QLocalServer server; + CrashSafeLocalServer server; server.setSocketOptions(opts); - QVERIFY2(server.listen(service), "service failed to start listening"); + QVERIFY2(server.listen(service), qUtf8Printable(server.errorString())); // find the socket QString fullServerPath = QDir::cleanPath(QDir::tempPath()); @@ -1333,7 +1712,7 @@ void tst_QLocalSocket::verifySocketOptions() void tst_QLocalSocket::verifyListenWithDescriptor() { -#ifdef Q_OS_UNIX +#if defined(Q_OS_UNIX) && !defined(Q_OS_VXWORKS) QFETCH(QString, path); QFETCH(bool, abstract); QFETCH(bool, bound); @@ -1342,15 +1721,15 @@ void tst_QLocalSocket::verifyListenWithDescriptor() int listenSocket; + // Construct the unix address + struct ::sockaddr_un addr; + addr.sun_family = PF_UNIX; + if (bound) { // create the unix socket listenSocket = ::socket(PF_UNIX, SOCK_STREAM, 0); QVERIFY2(listenSocket != -1, "failed to create test socket"); - // Construct the unix address - struct ::sockaddr_un addr; - addr.sun_family = PF_UNIX; - QVERIFY2(sizeof(addr.sun_path) > ((uint)path.size() + 1), "path to large to create socket"); ::memset(addr.sun_path, 0, sizeof(addr.sun_path)); @@ -1375,16 +1754,16 @@ void tst_QLocalSocket::verifyListenWithDescriptor() close(fds[1]); } - QLocalServer server; - QVERIFY2(server.listen(listenSocket), "failed to start create QLocalServer with local socket"); + CrashSafeLocalServer server; + QVERIFY2(server.listen(listenSocket), qUtf8Printable(server.errorString())); -#ifdef Q_OS_LINUX - const QChar at(QLatin1Char('@')); +#if defined(Q_OS_LINUX) || defined(Q_OS_QNX) if (!bound) { - QCOMPARE(server.serverName().at(0), at); - QCOMPARE(server.fullServerName().at(0), at); + QCOMPARE(server.serverName().isEmpty(), true); + QCOMPARE(server.fullServerName().isEmpty(), true); } else if (abstract) { - QVERIFY2(server.fullServerName().at(0) == at, "abstract sockets should start with a '@'"); + QVERIFY2(server.fullServerName().at(0) == addr.sun_path[1], + "abstract sockets should match server path without leading null"); } else { QCOMPARE(server.fullServerName(), path); if (path.contains(QLatin1Char('/'))) { @@ -1394,8 +1773,17 @@ void tst_QLocalSocket::verifyListenWithDescriptor() } } #else - QVERIFY(server.serverName().isEmpty()); - QVERIFY(server.fullServerName().isEmpty()); + if (bound) { + QCOMPARE(server.fullServerName(), path); + if (path.contains(QLatin1Char('/'))) { + QVERIFY2(server.serverName() == path.mid(path.lastIndexOf(QLatin1Char('/'))+1), "server name invalid short name"); + } else { + QVERIFY2(server.serverName() == path, "server name doesn't match the path provided"); + } + } else { + QVERIFY(server.serverName().isEmpty()); + QVERIFY(server.fullServerName().isEmpty()); + } #endif @@ -1410,7 +1798,7 @@ void tst_QLocalSocket::verifyListenWithDescriptor_data() QTest::addColumn<bool>("bound"); QTest::newRow("normal") << QDir::tempPath() + QLatin1String("/testsocket") << false << true; -#ifdef Q_OS_LINUX +#if defined(Q_OS_LINUX) || defined(Q_OS_QNX) QTest::newRow("abstract") << QString::fromLatin1("abstractsocketname") << true << true; QTest::newRow("abstractwithslash") << QString::fromLatin1("abstractsocketwitha/inthename") << true << true; #endif @@ -1420,6 +1808,24 @@ void tst_QLocalSocket::verifyListenWithDescriptor_data() } +void tst_QLocalSocket::serverBindingsAndProperties() +{ + CrashSafeLocalServer server; + + QTestPrivate::testReadWritePropertyBasics( + server, QLocalServer::SocketOptions{QLocalServer::GroupAccessOption}, + QLocalServer::SocketOptions{QLocalServer::OtherAccessOption}, "socketOptions"); +} + +void tst_QLocalSocket::socketBindings() +{ + QLocalSocket socket; + + QTestPrivate::testReadWritePropertyBasics( + socket, QLocalSocket::SocketOptions{QLocalSocket::AbstractNamespaceOption}, + QLocalSocket::SocketOptions{QLocalSocket::NoOptions}, "socketOptions"); +} + QTEST_MAIN(tst_QLocalSocket) #include "tst_qlocalsocket.moc" diff --git a/tests/auto/network/socket/qsctpsocket/CMakeLists.txt b/tests/auto/network/socket/qsctpsocket/CMakeLists.txt index d2d849aa05..4bf5438841 100644 --- a/tests/auto/network/socket/qsctpsocket/CMakeLists.txt +++ b/tests/auto/network/socket/qsctpsocket/CMakeLists.txt @@ -1,12 +1,19 @@ -# Generated from qsctpsocket.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qsctpsocket Test: ##################################################################### -qt_add_test(tst_qsctpsocket +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qsctpsocket LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qsctpsocket SOURCES tst_qsctpsocket.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Network ) diff --git a/tests/auto/network/socket/qsctpsocket/qsctpsocket.pro b/tests/auto/network/socket/qsctpsocket/qsctpsocket.pro deleted file mode 100644 index 49a40ce9b5..0000000000 --- a/tests/auto/network/socket/qsctpsocket/qsctpsocket.pro +++ /dev/null @@ -1,6 +0,0 @@ -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 index 89a1430948..2893053158 100644 --- a/tests/auto/network/socket/qsctpsocket/tst_qsctpsocket.cpp +++ b/tests/auto/network/socket/qsctpsocket/tst_qsctpsocket.cpp @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com> -** 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> +// Copyright (C) 2016 Alex Trotsenko <alex1973tr@gmail.com> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QTest> #include <QDebug> -#include <QEventLoop> +#include <QTestEventLoop> #include <QByteArray> #include <QString> #include <QHostAddress> @@ -152,12 +127,13 @@ void tst_QSctpSocket::bind_data() // 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) { + const QString knownBad[] = { + "198.51.100.1", + "2001:0DB8::1", + }; + + for (const QString &badAddress : knownBad) QTest::newRow(badAddress.toLatin1().constData()) << badAddress << false << QString(); - } } // Testing bind function diff --git a/tests/auto/network/socket/qsocks5socketengine/BLACKLIST b/tests/auto/network/socket/qsocks5socketengine/BLACKLIST index 405d03f990..6b3a39ab5e 100644 --- a/tests/auto/network/socket/qsocks5socketengine/BLACKLIST +++ b/tests/auto/network/socket/qsocks5socketengine/BLACKLIST @@ -1,12 +1,10 @@ [udpTest] * [passwordAuth] -ubuntu-18.04 -ubuntu-20.04 +ubuntu +# QTBUG-101274 +qnx ci # QTBUG-74162 [passwordAuth2] ubuntu -[downloadBigFile] -windows-10 msvc-2015 -windows-7sp1 diff --git a/tests/auto/network/socket/qsocks5socketengine/CMakeLists.txt b/tests/auto/network/socket/qsocks5socketengine/CMakeLists.txt index e46257c123..dc0b87cd94 100644 --- a/tests/auto/network/socket/qsocks5socketengine/CMakeLists.txt +++ b/tests/auto/network/socket/qsocks5socketengine/CMakeLists.txt @@ -1,4 +1,11 @@ -# Generated from qsocks5socketengine.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qsocks5socketengine LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() if(NOT QT_FEATURE_private_tests) return() @@ -8,28 +15,21 @@ endif() ## tst_qsocks5socketengine Test: ##################################################################### -qt_add_test(tst_qsocks5socketengine +qt_internal_add_test(tst_qsocks5socketengine SOURCES tst_qsocks5socketengine.cpp - INCLUDE_DIRECTORIES - ${QT_SOURCE_TREE}/src/network - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::NetworkPrivate - QT_TEST_SERVER_LIST "danted" "apache2" "cyrus" # special case + QT_TEST_SERVER_LIST "danted" "apache2" "cyrus" ) -#### Keys ignored in scope 1:.:.:qsocks5socketengine.pro:<TRUE>: -# MOC_DIR = "tmp" -# _REQUIREMENTS = "qtConfig(private_tests)" - ## Scopes: ##################################################################### -#### Keys ignored in scope 2:.:.:qsocks5socketengine.pro:LINUX: # QT_TEST_SERVER_LIST = "danted" "apache2" "cyrus" -qt_extend_target(tst_qsocks5socketengine CONDITION WIN32 - PUBLIC_LIBRARIES +qt_internal_extend_target(tst_qsocks5socketengine CONDITION WIN32 + LIBRARIES ws2_32 ) diff --git a/tests/auto/network/socket/qsocks5socketengine/qsocks5socketengine.pro b/tests/auto/network/socket/qsocks5socketengine/qsocks5socketengine.pro deleted file mode 100644 index 243eab9480..0000000000 --- a/tests/auto/network/socket/qsocks5socketengine/qsocks5socketengine.pro +++ /dev/null @@ -1,19 +0,0 @@ -CONFIG += testcase -TARGET = tst_qsocks5socketengine -SOURCES += tst_qsocks5socketengine.cpp - - -include(../platformsocketengine/platformsocketengine.pri) - - -MOC_DIR=tmp - -QT = core-private network-private testlib - -requires(qtConfig(private_tests)) - -# Only on Linux until cyrus has been added to docker-compose-for-{windows,macOS}.yml and tested -linux { - CONFIG += unsupported/testserver - QT_TEST_SERVER_LIST = danted apache2 cyrus -} diff --git a/tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp b/tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp index f0cff5da3e..cc77ba2da3 100644 --- a/tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp +++ b/tests/auto/network/socket/qsocks5socketengine/tst_qsocks5socketengine.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtTest/QTest> @@ -48,6 +23,8 @@ #include "../../../network-settings.h" +using namespace std::chrono_literals; + class tst_QSocks5SocketEngine : public QObject, public QAbstractSocketEngineReceiver { Q_OBJECT @@ -312,12 +289,15 @@ void tst_QSocks5SocketEngine::simpleConnectToIMAP() QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectedState); QCOMPARE(socketDevice.peerAddress(), QtNetworkSettings::imapServerIp()); - // Wait for the greeting - QVERIFY2(socketDevice.waitForRead(), qPrintable("Socket error:" + socketDevice.errorString())); - - // Read the greeting + // Wait for the greeting, if it hasn't arrived yet qint64 available = socketDevice.bytesAvailable(); + if (available == 0) { + QVERIFY2(socketDevice.waitForRead(), qPrintable("Socket error:" + socketDevice.errorString())); + available = socketDevice.bytesAvailable(); + } QVERIFY(available > 0); + + // Read the greeting QByteArray array; array.resize(available); QVERIFY(socketDevice.read(array.data(), array.size()) == available); @@ -363,7 +343,7 @@ void tst_QSocks5SocketEngine::simpleErrorsAndStates() QCOMPARE(socketDevice.state(), QAbstractSocket::UnconnectedState); QVERIFY(!socketDevice.connectToHost(QHostInfo::fromName(QtNetworkSettings::socksProxyServerName()).addresses().first(), 8088)); QCOMPARE(socketDevice.state(), QAbstractSocket::ConnectingState); - if (socketDevice.waitForWrite(15000)) { + if (socketDevice.waitForWrite(15s)) { QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState || socketDevice.state() == QAbstractSocket::ConnectedState); } else { @@ -453,7 +433,7 @@ void tst_QSocks5SocketEngine::serverTest() QCOMPARE(server.state(), QAbstractSocket::BoundState); // Listen for incoming connections - QVERIFY(server.listen()); + QVERIFY(server.listen(50)); QCOMPARE(server.state(), QAbstractSocket::ListeningState); // Initialize a Tcp socket @@ -937,13 +917,13 @@ void tst_QSocks5SocketEngine::fragmentation_data() responses << authMethodBasic << authSuccess.left(1) << authSuccess.mid(1) << connectResponseIPv4; QTest::newRow("auth-response") << responses; - for (int i = 1; i < connectResponseIPv4.length() - 1; i++) { + for (int i = 1; i < connectResponseIPv4.size() - 1; i++) { responses.clear(); responses << authMethodNone << connectResponseIPv4.left(i) << connectResponseIPv4.mid(i); QTest::newRow(qPrintable(QString("connect-response-ipv4-") + QString::number(i))) << responses; } - for (int i = 1; i < connectResponseIPv6.length() - 1; i++) { + for (int i = 1; i < connectResponseIPv6.size() - 1; i++) { responses.clear(); responses << authMethodNone << connectResponseIPv6.left(i) << connectResponseIPv6.mid(i); QTest::newRow(qPrintable(QString("connect-response-ipv6-") + QString::number(i))) << responses; @@ -986,13 +966,13 @@ void tst_QSocks5SocketEngine::incomplete_data() responses << authMethodBasic << authSuccess.left(1); QTest::newRow("auth-response") << responses; - for (int i = 1; i < connectResponseIPv4.length() - 1; i++) { + for (int i = 1; i < connectResponseIPv4.size() - 1; i++) { responses.clear(); responses << authMethodNone << connectResponseIPv4.left(i); QTest::newRow(qPrintable(QString("connect-response-ipv4-") + QString::number(i))) << responses; } - for (int i = 1; i < connectResponseIPv6.length() - 1; i++) { + for (int i = 1; i < connectResponseIPv6.size() - 1; i++) { responses.clear(); responses << authMethodNone << connectResponseIPv6.left(i); QTest::newRow(qPrintable(QString("connect-response-ipv6-") + QString::number(i))) << responses; diff --git a/tests/auto/network/socket/qtcpserver/BLACKLIST b/tests/auto/network/socket/qtcpserver/BLACKLIST index e268468bdb..a8b5f5d137 100644 --- a/tests/auto/network/socket/qtcpserver/BLACKLIST +++ b/tests/auto/network/socket/qtcpserver/BLACKLIST @@ -1,16 +1,13 @@ [listenWhileListening:WithSocks5Proxy] linux windows -[ipv6Server] -windows-7sp1 -windows-10 msvc-2017 [ipv6Server:WithoutProxy] windows osx -[eagainBlockingAccept] -windows-7sp1 -windows-10 [serverAddress] -windows-7sp1 +# QTBUG-103056 +qnx windows-10 +[linkLocal] +macos arm diff --git a/tests/auto/network/socket/qtcpserver/CMakeLists.txt b/tests/auto/network/socket/qtcpserver/CMakeLists.txt index 01f6c8b672..b01a164302 100644 --- a/tests/auto/network/socket/qtcpserver/CMakeLists.txt +++ b/tests/auto/network/socket/qtcpserver/CMakeLists.txt @@ -1,4 +1,11 @@ -# Generated from qtcpserver.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qtcpserver LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() -add_subdirectory(test) add_subdirectory(crashingServer) +add_subdirectory(test) diff --git a/tests/auto/network/socket/qtcpserver/crashingServer/CMakeLists.txt b/tests/auto/network/socket/qtcpserver/crashingServer/CMakeLists.txt index fab02435a6..bb1feb0237 100644 --- a/tests/auto/network/socket/qtcpserver/crashingServer/CMakeLists.txt +++ b/tests/auto/network/socket/qtcpserver/crashingServer/CMakeLists.txt @@ -1,14 +1,15 @@ -# Generated from crashingServer.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## crashingServer Binary: ##################################################################### -qt_add_executable(crashingServer +qt_internal_add_executable(crashingServer OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/" SOURCES main.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Network ) diff --git a/tests/auto/network/socket/qtcpserver/crashingServer/crashingServer.pro b/tests/auto/network/socket/qtcpserver/crashingServer/crashingServer.pro deleted file mode 100644 index 487b9014d0..0000000000 --- a/tests/auto/network/socket/qtcpserver/crashingServer/crashingServer.pro +++ /dev/null @@ -1,8 +0,0 @@ -SOURCES += main.cpp -QT = core network -CONFIG -= app_bundle -DESTDIR = ./ - -# This means the auto test works on some machines for MinGW. No dialog stalls -# the application. -mingw:CONFIG += console diff --git a/tests/auto/network/socket/qtcpserver/crashingServer/main.cpp b/tests/auto/network/socket/qtcpserver/crashingServer/main.cpp index 7cb65cd1a3..1c41552eb5 100644 --- a/tests/auto/network/socket/qtcpserver/crashingServer/main.cpp +++ b/tests/auto/network/socket/qtcpserver/crashingServer/main.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtCore> @@ -32,18 +7,45 @@ #if defined(Q_OS_WIN) && defined(Q_CC_MSVC) # include <crtdbg.h> #endif +#ifdef Q_OS_UNIX +# include <sys/resource.h> +# include <unistd.h> +#endif int main(int argc, char *argv[]) { - // Windows: Suppress crash notification dialog. #if defined(Q_OS_WIN) && defined(Q_CC_MSVC) + // Windows: Suppress crash notification dialog. _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG); +#elif defined(RLIMIT_CORE) + // Unix: set our core dump limit to zero to request no dialogs. + if (struct rlimit rlim; getrlimit(RLIMIT_CORE, &rlim) == 0) { + rlim.rlim_cur = 0; + setrlimit(RLIMIT_CORE, &rlim); + } #endif + QCoreApplication app(argc, argv); + if (argc < 1) { + fprintf(stderr, "Need a port number\n"); + return 1; + } + int port = QByteArrayView(argv[1]).toInt(); QTcpServer server; - if (!server.listen(QHostAddress::LocalHost, 49199)) { - qDebug("Failed to listen: %s", server.errorString().toLatin1().constData()); + if (!server.listen(QHostAddress::LocalHost, port)) { + fprintf(stderr, "Failed to listen: %s\n", server.errorString().toLatin1().constData()); + if (server.serverError() == QTcpSocket::AddressInUseError) { + // let's see if we can find the process that would be holding this + // still open +#ifdef Q_OS_LINUX + static const char *ss_args[] = { + "ss", "-nap", "sport", "=", argv[1], nullptr + }; + dup2(STDERR_FILENO, STDOUT_FILENO); + execvp(ss_args[0], const_cast<char **>(ss_args)); +#endif + } return 1; } diff --git a/tests/auto/network/socket/qtcpserver/qtcpserver.pro b/tests/auto/network/socket/qtcpserver/qtcpserver.pro deleted file mode 100644 index e123cfe73b..0000000000 --- a/tests/auto/network/socket/qtcpserver/qtcpserver.pro +++ /dev/null @@ -1,4 +0,0 @@ -TEMPLATE = subdirs -SUBDIRS = test crashingServer - - diff --git a/tests/auto/network/socket/qtcpserver/test/.prev_CMakeLists.txt b/tests/auto/network/socket/qtcpserver/test/.prev_CMakeLists.txt deleted file mode 100644 index f80fdedcac..0000000000 --- a/tests/auto/network/socket/qtcpserver/test/.prev_CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -# Generated from test.pro. - -##################################################################### -## tst_qtcpserver Test: -##################################################################### - -qt_add_test(tst_qtcpserver - SOURCES - ../tst_qtcpserver.cpp - PUBLIC_LIBRARIES - Qt::Network -) - -#### Keys ignored in scope 1:.:.:test.pro:<TRUE>: -# MOC_DIR = "tmp" - -## Scopes: -##################################################################### - -qt_extend_target(tst_qtcpserver CONDITION WIN32 - PUBLIC_LIBRARIES - ws2_32 -) - -#### Keys ignored in scope 6:.:.:test.pro:LINUX: -# QT_TEST_SERVER_LIST = "danted" "cyrus" "squid" "ftp-proxy" diff --git a/tests/auto/network/socket/qtcpserver/test/CMakeLists.txt b/tests/auto/network/socket/qtcpserver/test/CMakeLists.txt index 4d328ebddb..55615bbae1 100644 --- a/tests/auto/network/socket/qtcpserver/test/CMakeLists.txt +++ b/tests/auto/network/socket/qtcpserver/test/CMakeLists.txt @@ -1,28 +1,27 @@ -# Generated from test.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qtcpserver Test: ##################################################################### -qt_add_test(tst_qtcpserver - OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../" # special case +qt_internal_add_test(tst_qtcpserver + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../" SOURCES ../tst_qtcpserver.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Network - QT_TEST_SERVER_LIST "danted" "cyrus" "squid" "ftp-proxy" # special case + QT_TEST_SERVER_LIST "danted" "cyrus" "squid" "ftp-proxy" ) -#### Keys ignored in scope 1:.:.:test.pro:<TRUE>: -# MOC_DIR = "tmp" +add_dependencies(tst_qtcpserver + crashingServer +) ## Scopes: ##################################################################### -qt_extend_target(tst_qtcpserver CONDITION WIN32 - PUBLIC_LIBRARIES +qt_internal_extend_target(tst_qtcpserver CONDITION WIN32 + LIBRARIES ws2_32 ) - -#### Keys ignored in scope 6:.:.:test.pro:LINUX: -# QT_TEST_SERVER_LIST = "danted" "cyrus" "squid" "ftp-proxy" diff --git a/tests/auto/network/socket/qtcpserver/test/test.pro b/tests/auto/network/socket/qtcpserver/test/test.pro deleted file mode 100644 index 491ff28cdc..0000000000 --- a/tests/auto/network/socket/qtcpserver/test/test.pro +++ /dev/null @@ -1,24 +0,0 @@ -CONFIG += testcase -SOURCES += ../tst_qtcpserver.cpp - -win32: QMAKE_USE += ws2_32 - -TARGET = tst_qtcpserver - -win32 { - CONFIG(debug, debug|release) { - TARGET = ../debug/tst_qtcpserver -} else { - TARGET = ../release/tst_qtcpserver - } -} - -QT = core network testlib - -MOC_DIR=tmp - -# Only on Linux until cyrus has been added to docker-compose-for-{windows,macOS}.yml and tested -linux { - CONFIG += unsupported/testserver - QT_TEST_SERVER_LIST = danted cyrus squid ftp-proxy -} diff --git a/tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp b/tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp index 1bf6777040..c03076d98e 100644 --- a/tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp +++ b/tests/auto/network/socket/qtcpserver/tst_qtcpserver.cpp @@ -1,34 +1,7 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <qglobal.h> -// To prevent windows system header files from re-defining min/max -#define NOMINMAX 1 #if defined(_WIN32) #include <winsock2.h> #else @@ -38,7 +11,9 @@ #define INVALID_SOCKET -1 #endif -#include <QtTest/QtTest> +#include <QTest> +#include <QSignalSpy> +#include <QTimer> #ifndef Q_OS_WIN #include <unistd.h> @@ -58,6 +33,8 @@ #include <qnetworkinterface.h> #include <QNetworkProxy> +#include <QSet> +#include <QList> #include "../../../network-settings.h" @@ -113,6 +90,11 @@ private slots: void canAccessPendingConnectionsWhileNotListening(); + void pauseAccepting(); + + void pendingConnectionAvailable_data(); + void pendingConnectionAvailable(); + private: bool shouldSkipIpv6TestsForBrokenGetsockopt(); #ifdef SHOULD_CHECK_SYSCALL_SUPPORT @@ -156,7 +138,8 @@ void tst_QTcpServer::initTestCase() #ifdef QT_TEST_SERVER QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::socksProxyServerName(), 1080)); QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::httpProxyServerName(), 3128)); - QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpProxyServerName(), 2121)); + // FTP currently not supported: + // QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpProxyServerName(), 2121)); QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::imapServerName(), 143)); #else if (!QtNetworkSettings::verifyTestNetworkSettings()) @@ -264,7 +247,7 @@ void tst_QTcpServer::clientServerLoop() QVERIFY(server.waitForNewConnection(5000)); QVERIFY(server.hasPendingConnections()); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QTcpSocket *serverSocket = server.nextPendingConnection(); QVERIFY(serverSocket != 0); @@ -425,9 +408,9 @@ void tst_QTcpServer::maxPendingConnections() // two connections have been made. The second compare makes sure no // more are accepted. Creating connections happens multithreaded so // qWait must be used for that. - QTRY_COMPARE(spy.count(), 2); + QTRY_COMPARE(spy.size(), 2); QTest::qWait(100); - QCOMPARE(spy.count(), 2); + QCOMPARE(spy.size(), 2); QVERIFY(server.hasPendingConnections()); QVERIFY(server.nextPendingConnection()); @@ -476,7 +459,7 @@ public: protected: void run() override { - sleep(2); + sleep(std::chrono::seconds{2}); QTcpSocket socket; socket.connectToHost(host, port); @@ -594,9 +577,6 @@ void tst_QTcpServer::addressReusable() #if !QT_CONFIG(process) QSKIP("No qprocess support", SkipAll); #else -#ifdef Q_OS_LINUX - QSKIP("The addressReusable test is unstable on Linux. See QTBUG-39985."); -#endif QFETCH_GLOBAL(bool, setProxy); if (setProxy) { #ifndef QT_NO_NETWORKPROXY @@ -607,16 +587,25 @@ void tst_QTcpServer::addressReusable() QSKIP("No proxy support"); #endif // QT_NO_NETWORKPROXY } + + QTcpServer server; + QVERIFY(server.listen(QHostAddress::LocalHost, 0)); + quint16 serverPort = server.serverPort(); + qDebug() << "Got port" << serverPort; + server.close(); // cleanly close + + QTest::qSleep(10); + // The crashingServer process will crash once it gets a connection. QProcess process; QString processExe = crashingServerDir + "/crashingServer"; - process.start(processExe); + process.start(processExe, { QString::number(serverPort) }); QVERIFY2(process.waitForStarted(), qPrintable( QString::fromLatin1("Could not start %1: %2").arg(processExe, process.errorString()))); - QVERIFY(process.waitForReadyRead(5000)); + QVERIFY2(process.waitForReadyRead(5000), qPrintable(process.readAllStandardError())); QTcpSocket socket; - socket.connectToHost(QHostAddress::LocalHost, 49199); + socket.connectToHost(QHostAddress::LocalHost, serverPort); QVERIFY(socket.waitForConnected(5000)); QVERIFY(process.waitForFinished(30000)); @@ -624,8 +613,9 @@ void tst_QTcpServer::addressReusable() // Give the system some time. QTest::qSleep(10); - QTcpServer server; - QVERIFY(server.listen(QHostAddress::LocalHost, 49199)); + // listen again + QVERIFY2(server.listen(QHostAddress::LocalHost, serverPort), + qPrintable(server.errorString())); #endif } @@ -744,6 +734,7 @@ void tst_QTcpServer::proxyFactory_data() << proxyList << proxyList.at(1) << false << int(QAbstractSocket::UnknownSocketError); +#if 0 // ftp not currently supported proxyList.clear(); proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121) << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3128) @@ -751,6 +742,7 @@ void tst_QTcpServer::proxyFactory_data() QTest::newRow("ftp+cachinghttp+socks5") << proxyList << proxyList.at(2) << false << int(QAbstractSocket::UnknownSocketError); +#endif // tests that fail to listen proxyList.clear(); @@ -765,6 +757,7 @@ void tst_QTcpServer::proxyFactory_data() << proxyList << QNetworkProxy() << true << int(QAbstractSocket::UnsupportedSocketOperationError); +#if 0 // ftp not currently supported proxyList.clear(); proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121); QTest::newRow("ftp") @@ -777,6 +770,7 @@ void tst_QTcpServer::proxyFactory_data() QTest::newRow("ftp+cachinghttp") << proxyList << QNetworkProxy() << true << int(QAbstractSocket::UnsupportedSocketOperationError); +#endif } void tst_QTcpServer::proxyFactory() @@ -871,10 +865,12 @@ void tst_QTcpServer::serverAddress_data() QTest::newRow("AnyIPv4") << QHostAddress(QHostAddress::AnyIPv4) << QHostAddress(QHostAddress::AnyIPv4); if (QtNetworkSettings::hasIPv6()) QTest::newRow("AnyIPv6") << QHostAddress(QHostAddress::AnyIPv6) << QHostAddress(QHostAddress::AnyIPv6); - foreach (const QNetworkInterface &iface, QNetworkInterface::allInterfaces()) { + const auto ifaces = QNetworkInterface::allInterfaces(); + for (const QNetworkInterface &iface : ifaces) { if ((iface.flags() & QNetworkInterface::IsUp) == 0) continue; - foreach (const QNetworkAddressEntry &entry, iface.addressEntries()) { + const auto entries = iface.addressEntries(); + for (const QNetworkAddressEntry &entry : entries) { QTest::newRow(qPrintable(entry.ip().toString())) << entry.ip() << entry.ip(); } } @@ -928,7 +924,8 @@ void tst_QTcpServer::linkLocal() QSet <QString> scopes; QHostAddress localMaskv4("169.254.0.0"); QHostAddress localMaskv6("fe80::"); - foreach (const QNetworkInterface& iface, QNetworkInterface::allInterfaces()) { + const auto ifaces = QNetworkInterface::allInterfaces(); + for (const QNetworkInterface &iface : ifaces) { //Windows preallocates link local addresses to interfaces that are down. //These may or may not work depending on network driver (they do not work for the Bluetooth PAN driver) if (iface.flags() & QNetworkInterface::IsUp) { @@ -941,8 +938,15 @@ void tst_QTcpServer::linkLocal() // (we don't know why) if (iface.name().startsWith("utun")) continue; + // Do not use the iBridge interfae + if (iface.hardwareAddress() == "AC:DE:48:00:11:22") + continue; + // Do no use the Apple Wireless Direct Link interfaces + if (iface.name().startsWith("awdl")) + continue; #endif - foreach (QNetworkAddressEntry addressEntry, iface.addressEntries()) { + const auto entries = iface.addressEntries(); + for (const QNetworkAddressEntry &addressEntry : entries) { QHostAddress addr = addressEntry.ip(); if (addr.isInSubnet(localMaskv4, 16)) { addresses << addr; @@ -961,7 +965,7 @@ void tst_QTcpServer::linkLocal() QList<QTcpServer*> servers; quint16 port = 0; - foreach (const QHostAddress& addr, addresses) { + for (const QHostAddress &addr : std::as_const(addresses)) { QTcpServer *server = new QTcpServer; QVERIFY(server->listen(addr, port)); port = server->serverPort(); //listen to same port on different interfaces @@ -969,7 +973,7 @@ void tst_QTcpServer::linkLocal() } QList<QTcpSocket*> clients; - foreach (const QHostAddress& addr, addresses) { + for (const QHostAddress &addr : std::as_const(addresses)) { //unbound socket QTcpSocket *socket = new QTcpSocket; socket->connectToHost(addr, port); @@ -984,7 +988,7 @@ void tst_QTcpServer::linkLocal() } //each server should have two connections - foreach (QTcpServer* server, servers) { + for (QTcpServer *server : std::as_const(servers)) { //qDebug() << "checking for connections" << server->serverAddress() << ":" << server->serverPort(); QVERIFY(server->waitForNewConnection(5000)); QTcpSocket* remote = server->nextPendingConnection(); @@ -1019,12 +1023,12 @@ void tst_QTcpServer::eagainBlockingAccept() QTcpSocket s; s.connectToHost(QHostAddress::LocalHost, 7896); QSignalSpy spy(&server, SIGNAL(newConnection())); - QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 500); + QTRY_COMPARE_WITH_TIMEOUT(spy.size(), 1, 500); s.close(); // To test try again, should connect just fine. s.connectToHost(QHostAddress::LocalHost, 7896); - QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 2, 500); + QTRY_COMPARE_WITH_TIMEOUT(spy.size(), 2, 500); s.close(); server.close(); } @@ -1046,5 +1050,104 @@ void tst_QTcpServer::canAccessPendingConnectionsWhileNotListening() QCOMPARE(&socket, server.nextPendingConnection()); } +void tst_QTcpServer::pauseAccepting() +{ + QTcpServer server; + QSignalSpy spy(&server, &QTcpServer::newConnection); + QVERIFY(server.listen()); + + QFETCH_GLOBAL(bool, setProxy); + const auto address = QHostAddress(setProxy ? QtNetworkSettings::socksProxyServerIp() + : QHostAddress::LocalHost); + + const int NumSockets = 6; + QTcpSocket sockets[NumSockets]; + sockets[0].connectToHost(address, server.serverPort()); + QVERIFY(spy.wait()); + QCOMPARE(spy.size(), 1); + + server.pauseAccepting(); + for (int i = 1; i < NumSockets; ++i) + sockets[i].connectToHost(address, server.serverPort()); + QVERIFY(!spy.wait(400)); + QCOMPARE(spy.size(), 1); + + server.resumeAccepting(); + if (setProxy) { + QEXPECT_FAIL("", "The socks proxy does weird things after accepting the first connection", + Abort); + } + QVERIFY(spy.wait()); + QCOMPARE(spy.size(), 6); +} + + +// Only adds the socket to the pending connections list after emitNextSocket is +// called. It's very artificial, but it allows us to test the behavior of +// the pendingConnectionAvailable signal when a server doesn't add the socket +// during the incomingConnection virtual function. +class DerivedServer : public QTcpServer +{ +public: + explicit DerivedServer(QObject *parent = nullptr) + : QTcpServer(parent) + { + } + + void emitNextSocket() + { + if (m_socketDescriptors.isEmpty()) + return; + auto *socket = new QTcpSocket(this); + socket->setSocketDescriptor(m_socketDescriptors.back()); + m_socketDescriptors.pop_back(); + addPendingConnection(socket); + } +protected: + void incomingConnection(qintptr socketDescriptor) override + { + m_socketDescriptors.push_back(socketDescriptor); + } +private: + QList<qintptr> m_socketDescriptors; +}; + +void tst_QTcpServer::pendingConnectionAvailable_data() +{ + QTest::addColumn<bool>("useDerivedServer"); + QTest::newRow("QTcpServer") << false; + QTest::newRow("DerivedServer") << true; +} + +void tst_QTcpServer::pendingConnectionAvailable() +{ + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + QSKIP("This feature does not differentiate with or without proxy"); + QFETCH(bool, useDerivedServer); + + QTcpServer *server = useDerivedServer ? new DerivedServer : new QTcpServer; + if (!server->listen(QHostAddress::LocalHost, 0)) { + qWarning() << "Server failed to listen:" << server->errorString(); + QSKIP("Server failed to listen"); + } + QSignalSpy newConnectionSpy(server, &QTcpServer::newConnection); + QSignalSpy pendingConnectionSpy(server, &QTcpServer::pendingConnectionAvailable); + + QTcpSocket socket; + socket.connectToHost(QHostAddress::LocalHost, server->serverPort()); + + QVERIFY(newConnectionSpy.wait()); + QVERIFY(socket.waitForConnected()); + QCOMPARE(socket.state(), QTcpSocket::ConnectedState); + + int expectedPendingConnections = useDerivedServer ? 0 : 1; + QCOMPARE(pendingConnectionSpy.size(), expectedPendingConnections); + + if (useDerivedServer) + static_cast<DerivedServer *>(server)->emitNextSocket(); + QCOMPARE(pendingConnectionSpy.size(), 1); +} + QTEST_MAIN(tst_QTcpServer) #include "tst_qtcpserver.moc" diff --git a/tests/auto/network/socket/qtcpsocket/BLACKLIST b/tests/auto/network/socket/qtcpsocket/BLACKLIST index 129e9f0b4e..6261c85a09 100644 --- a/tests/auto/network/socket/qtcpsocket/BLACKLIST +++ b/tests/auto/network/socket/qtcpsocket/BLACKLIST @@ -1,4 +1,77 @@ [timeoutConnect:ip] windows +# QTBUG-101274 +[timeoutConnect:WithSocks5Proxy:ip] +qnx ci +[timeoutConnect:WithSocks5ProxyAuth:ip] +qnx ci +[timeoutConnect:WithHttpProxy:ip] +qnx ci +[timeoutConnect:WithHttpProxyBasicAuth:ip] +qnx ci +[timeoutConnect:WithSocks5Proxy SSL:ip] +qnx ci +[timeoutConnect:WithSocks5AuthProxy SSL:ip] +qnx ci +[timeoutConnect:WithHttpProxy SSL:ip] +qnx ci +[timeoutConnect:WithHttpProxyBasicAuth SSL:ip] +qnx ci +[suddenRemoteDisconnect:WithoutProxy:Qt4 Client <-> Qt4 Server] +qnx ci # QTBUG-66247 - +[delayedClose:WithSocks5Proxy] +windows-10 gcc developer-build +[delayedClose:WithSocks5Proxy SSL] +windows-10 gcc developer-build +[partialRead:WithSocks5Proxy] +windows-10 gcc developer-build +[partialRead:WithSocks5Proxy SSL] +windows-10 gcc developer-build +[unget:WithSocks5Proxy] +windows-10 gcc developer-build +[unget:WithSocks5Proxy SSL] +windows-10 gcc developer-build +[readAllAfterClose:WithSocks5Proxy] +windows-10 gcc developer-build +[readAllAfterClose:WithSocks5Proxy SSL] +windows-10 gcc developer-build +[openCloseOpenClose:WithSocks5Proxy] +windows-10 gcc developer-build +[openCloseOpenClose:WithSocks5Proxy SSL] +windows-10 gcc developer-build +[connectDisconnectConnectDisconnect:WithSocks5Proxy] +windows-10 gcc developer-build +[connectDisconnectConnectDisconnect:WithSocks5Proxy SSL] +windows-10 gcc developer-build +[downloadBigFile:WithSocks5Proxy] +windows-10 gcc developer-build +[downloadBigFile:WithSocks5Proxy SSL] +windows-10 gcc developer-build +[connectToHostError:WithoutProxy:localhost no service] +windows-10 gcc developer-build +[connectToHostError:WithSocks5Proxy:localhost no service] +windows-10 gcc developer-build +[connectToHostError:WithSocks5ProxyAuth:localhost no service] +windows-10 gcc developer-build +[connectToHostError:WithHttpProxy:localhost no service] +windows-10 gcc developer-build +[connectToHostError:WithHttpProxyBasicAuth:localhost no service] +windows-10 gcc developer-build +[connectToHostError:WithoutProxy SSL:localhost no service] +windows-10 gcc developer-build +[connectToHostError:WithSocks5Proxy SSL:localhost no service] +windows-10 gcc developer-build +[connectToHostError:WithSocks5AuthProxy SSL:localhost no service] +windows-10 gcc developer-build +[connectToHostError:WithHttpProxy SSL:localhost no service] +windows-10 gcc developer-build +[connectToHostError:WithHttpProxyBasicAuth SSL:localhost no service] +windows-10 gcc developer-build +[bind] +macos arm +# QTBUG-101274 +[bindThenResolveHost:WithoutProxy:first-fail] +qnx ci +[bindThenResolveHost:WithoutProxy SSL:first-fail] +qnx ci diff --git a/tests/auto/network/socket/qtcpsocket/CMakeLists.txt b/tests/auto/network/socket/qtcpsocket/CMakeLists.txt index 645c65671a..7b6bb4d881 100644 --- a/tests/auto/network/socket/qtcpsocket/CMakeLists.txt +++ b/tests/auto/network/socket/qtcpsocket/CMakeLists.txt @@ -1,4 +1,11 @@ -# Generated from qtcpsocket.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qtcpsocket LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() if(NOT QT_FEATURE_private_tests) return() diff --git a/tests/auto/network/socket/qtcpsocket/qtcpsocket.pro b/tests/auto/network/socket/qtcpsocket/qtcpsocket.pro deleted file mode 100644 index 1f13a396dd..0000000000 --- a/tests/auto/network/socket/qtcpsocket/qtcpsocket.pro +++ /dev/null @@ -1,8 +0,0 @@ -TEMPLATE = subdirs - -SUBDIRS = test -!vxworks{ -SUBDIRS += stressTest -test.depends = stressTest -} -requires(qtConfig(private_tests)) diff --git a/tests/auto/network/socket/qtcpsocket/stressTest/CMakeLists.txt b/tests/auto/network/socket/qtcpsocket/stressTest/CMakeLists.txt index 784cee453d..3ea6c55895 100644 --- a/tests/auto/network/socket/qtcpsocket/stressTest/CMakeLists.txt +++ b/tests/auto/network/socket/qtcpsocket/stressTest/CMakeLists.txt @@ -1,19 +1,16 @@ -# Generated from stressTest.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## stressTest Binary: ##################################################################### -qt_add_executable(stressTest +qt_internal_add_executable(stressTest OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/" SOURCES Test.cpp Test.h main.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Network Qt::Test ) - -#### Keys ignored in scope 1:.:.:stressTest.pro:<TRUE>: -# MOC_DIR = ".moc/" -# TMP_DIR = ".tmp/" diff --git a/tests/auto/network/socket/qtcpsocket/stressTest/Test.cpp b/tests/auto/network/socket/qtcpsocket/stressTest/Test.cpp index ed61db1a13..8d6e470220 100644 --- a/tests/auto/network/socket/qtcpsocket/stressTest/Test.cpp +++ b/tests/auto/network/socket/qtcpsocket/stressTest/Test.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only // Qt #include <QByteArray> #include <QCoreApplication> diff --git a/tests/auto/network/socket/qtcpsocket/stressTest/Test.h b/tests/auto/network/socket/qtcpsocket/stressTest/Test.h index 3e61456f75..495b90d733 100644 --- a/tests/auto/network/socket/qtcpsocket/stressTest/Test.h +++ b/tests/auto/network/socket/qtcpsocket/stressTest/Test.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef TEST_H #define TEST_H @@ -53,7 +28,7 @@ class My4Server : public QTcpServer { Q_OBJECT public: - My4Server(QObject *parent = 0); + My4Server(QObject *parent = nullptr); protected: void incomingConnection(qintptr socket) override; diff --git a/tests/auto/network/socket/qtcpsocket/stressTest/main.cpp b/tests/auto/network/socket/qtcpsocket/stressTest/main.cpp index 1948389e37..f989a4de34 100644 --- a/tests/auto/network/socket/qtcpsocket/stressTest/main.cpp +++ b/tests/auto/network/socket/qtcpsocket/stressTest/main.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include "Test.h" #include <QCoreApplication> diff --git a/tests/auto/network/socket/qtcpsocket/stressTest/stressTest.pro b/tests/auto/network/socket/qtcpsocket/stressTest/stressTest.pro deleted file mode 100644 index 6afc008e7d..0000000000 --- a/tests/auto/network/socket/qtcpsocket/stressTest/stressTest.pro +++ /dev/null @@ -1,8 +0,0 @@ -HEADERS += Test.h -SOURCES += main.cpp Test.cpp -QT = core network testlib - -CONFIG += cmdline -DESTDIR = ./ -MOC_DIR = .moc/ -TMP_DIR = .tmp/ diff --git a/tests/auto/network/socket/qtcpsocket/test/.prev_CMakeLists.txt b/tests/auto/network/socket/qtcpsocket/test/.prev_CMakeLists.txt deleted file mode 100644 index 22a105887d..0000000000 --- a/tests/auto/network/socket/qtcpsocket/test/.prev_CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -# Generated from test.pro. - -##################################################################### -## tst_qtcpsocket Test: -##################################################################### - -qt_add_test(tst_qtcpsocket - SOURCES - ../tst_qtcpsocket.cpp - PUBLIC_LIBRARIES - Qt::CorePrivate - Qt::NetworkPrivate -) - -## Scopes: -##################################################################### - -qt_extend_target(tst_qtcpsocket CONDITION WIN32 - PUBLIC_LIBRARIES - ws2_32 -) - -#### Keys ignored in scope 4:.:.:test.pro:(CMAKE_BUILD_TYPE STREQUAL Debug): -# DESTDIR = "../debug" - -#### Keys ignored in scope 5:.:.:test.pro:else: -# DESTDIR = "../release" - -#### Keys ignored in scope 6:.:.:test.pro:else: -# DESTDIR = "../" - -#### Keys ignored in scope 7:.:.:test.pro:LINUX: -# QT_TEST_SERVER_LIST = "danted" "squid" "apache2" "ftp-proxy" "vsftpd" "iptables" "cyrus" diff --git a/tests/auto/network/socket/qtcpsocket/test/CMakeLists.txt b/tests/auto/network/socket/qtcpsocket/test/CMakeLists.txt index 3b4bd856a3..c3258f8a95 100644 --- a/tests/auto/network/socket/qtcpsocket/test/CMakeLists.txt +++ b/tests/auto/network/socket/qtcpsocket/test/CMakeLists.txt @@ -1,35 +1,24 @@ -# Generated from test.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qtcpsocket Test: ##################################################################### -qt_add_test(tst_qtcpsocket - OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../" # special case +qt_internal_add_test(tst_qtcpsocket + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../" SOURCES ../tst_qtcpsocket.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::NetworkPrivate - QT_TEST_SERVER_LIST "danted" "squid" "apache2" "ftp-proxy" "vsftpd" "iptables" "cyrus" # special case + QT_TEST_SERVER_LIST "danted" "squid" "apache2" "ftp-proxy" "vsftpd" "iptables" "cyrus" ) ## Scopes: ##################################################################### -qt_extend_target(tst_qtcpsocket CONDITION WIN32 - PUBLIC_LIBRARIES +qt_internal_extend_target(tst_qtcpsocket CONDITION WIN32 + LIBRARIES ws2_32 ) - -#### Keys ignored in scope 4:.:.:test.pro:(CMAKE_BUILD_TYPE STREQUAL Debug): -# DESTDIR = "../debug" - -#### Keys ignored in scope 5:.:.:test.pro:else: -# DESTDIR = "../release" - -#### Keys ignored in scope 6:.:.:test.pro:else: -# DESTDIR = "../" - -#### Keys ignored in scope 7:.:.:test.pro:LINUX: -# QT_TEST_SERVER_LIST = "danted" "squid" "apache2" "ftp-proxy" "vsftpd" "iptables" "cyrus" diff --git a/tests/auto/network/socket/qtcpsocket/test/test.pro b/tests/auto/network/socket/qtcpsocket/test/test.pro deleted file mode 100644 index 4c07b1ec66..0000000000 --- a/tests/auto/network/socket/qtcpsocket/test/test.pro +++ /dev/null @@ -1,23 +0,0 @@ -CONFIG += testcase - -QT = core-private network-private testlib -SOURCES += ../tst_qtcpsocket.cpp - -win32: QMAKE_USE += ws2_32 -TARGET = tst_qtcpsocket - -win32 { - CONFIG(debug, debug|release) { - DESTDIR = ../debug -} else { - DESTDIR = ../release - } -} else { - DESTDIR = ../ -} - -# Only on Linux until cyrus has been added to docker-compose-for-{windows,macOS}.yml and tested -linux { - CONFIG += unsupported/testserver - QT_TEST_SERVER_LIST = danted squid apache2 ftp-proxy vsftpd iptables cyrus -} diff --git a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp index b9108932f7..4ec01a9d94 100644 --- a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp +++ b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp @@ -1,36 +1,9 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2017 Intel Corporation. -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2017 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <qglobal.h> -// To prevent windows system header files from re-defining min/max -#define NOMINMAX 1 #if defined(_WIN32) #include <winsock2.h> #else @@ -44,8 +17,8 @@ #include <qplatformdefs.h> -#include <QtTest/QtTest> - +#include <QTest> +#include <QSignalSpy> #include <QAuthenticator> #include <QCoreApplication> #include <QEventLoop> @@ -81,10 +54,14 @@ #include <unistd.h> #endif +#include <memory> + #include "private/qhostinfo_p.h" #include "../../../network-settings.h" +using namespace Qt::StringLiterals; + QT_FORWARD_DECLARE_CLASS(QTcpSocket) class SocketPair; @@ -271,7 +248,7 @@ class SocketPair: public QObject public: QTcpSocket *endPoints[2]; - SocketPair(QObject *parent = 0) + SocketPair(QObject *parent = nullptr) : QObject(parent) { endPoints[0] = endPoints[1] = 0; @@ -306,7 +283,7 @@ tst_QTcpSocket::tst_QTcpSocket() tmpSocket = 0; //This code relates to the socketsConstructedBeforeEventLoop test case - earlyConstructedSockets = new SocketPair; + earlyConstructedSockets = new SocketPair(this); QVERIFY(earlyConstructedSockets->create()); earlyBytesWrittenCount = 0; earlyReadyReadCount = 0; @@ -355,7 +332,8 @@ void tst_QTcpSocket::initTestCase() //QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::firewallServerName(), 1357)); QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::socksProxyServerName(), 1080)); QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpServerName(), 21)); - QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpProxyServerName(), 2121)); + // FTP currently not supported: + // QVERIFY(QtNetworkSettings::verifyConnection(QtNetworkSettings::ftpProxyServerName(), 2121)); #else if (!QtNetworkSettings::verifyTestNetworkSettings()) QSKIP("No network test server available"); @@ -370,8 +348,8 @@ void tst_QTcpSocket::init() QFETCH_GLOBAL(int, proxyType); QList<QHostAddress> socks5Addresses = QHostInfo::fromName(QtNetworkSettings::socksProxyServerName()).addresses(); QList<QHostAddress> httpProxyAddresses = QHostInfo::fromName(QtNetworkSettings::httpProxyServerName()).addresses(); - QVERIFY2(socks5Addresses.count() > 0, "failed to get ip address for SOCKS5 proxy server"); - QVERIFY2(httpProxyAddresses.count() > 0, "failed to get ip address for HTTP proxy server"); + QVERIFY2(socks5Addresses.size() > 0, "failed to get ip address for SOCKS5 proxy server"); + QVERIFY2(httpProxyAddresses.size() > 0, "failed to get ip address for HTTP proxy server"); QString socks5Address = socks5Addresses.first().toString(); QString httpProxyAddress = httpProxyAddresses.first().toString(); QNetworkProxy proxy; @@ -511,12 +489,13 @@ void tst_QTcpSocket::bind_data() bool testIpv6 = false; // iterate all interfaces, add all addresses on them as test data - QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces(); - foreach (const QNetworkInterface &netinterface, interfaces) { + const QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces(); + for (const QNetworkInterface &netinterface : interfaces) { if (!netinterface.isValid()) continue; - foreach (const QNetworkAddressEntry &entry, netinterface.addressEntries()) { + const auto entries = netinterface.addressEntries(); + for (const QNetworkAddressEntry &entry : entries) { 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. @@ -546,12 +525,12 @@ void tst_QTcpSocket::bind_data() // 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) { + const QString knownBad[] = { + u"198.51.100.1"_s, + u"2001:0DB8::1"_s + }; + for (const QString &badAddress : knownBad) QTest::addRow("%s:0", badAddress.toLatin1().constData()) << badAddress << 0 << false << QString(); - } // try to bind to a privileged ports // we should fail if we're not root (unless the ports are in use!) @@ -586,7 +565,7 @@ void tst_QTcpSocket::bind() std::unique_ptr<QTcpSocket> socket(newSocket()); quint16 boundPort; - qintptr fd; + qintptr fd = 0; if (successExpected) { bool randomPort = port == -1; @@ -1804,7 +1783,7 @@ void tst_QTcpSocket::recursiveReadyRead() QVERIFY2(!timeout(), "Timed out when waiting for the readyRead() signal."); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); delete testSocket; } @@ -1846,7 +1825,7 @@ void tst_QTcpSocket::atEnd() QVERIFY2(greeting.startsWith("220 (vsFTPd 3."), qPrintable(greeting)); #else // Test server must use some vsFTPd 2.x.x version - QVERIFY2(greeting.length() == sizeof("220 (vsFTPd 2.x.x)")-1, qPrintable(greeting)); + QVERIFY2(greeting.size() == sizeof("220 (vsFTPd 2.x.x)")-1, qPrintable(greeting)); QVERIFY2(greeting.startsWith("220 (vsFTPd 2."), qPrintable(greeting)); #endif QVERIFY2(greeting.endsWith(QLatin1Char(')')), qPrintable(greeting)); @@ -2029,8 +2008,8 @@ void tst_QTcpSocket::remoteCloseError() enterLoop(30); QVERIFY(!timeout()); - QCOMPARE(disconnectedSpy.count(), 1); - QCOMPARE(errorSpy.count(), 1); + QCOMPARE(disconnectedSpy.size(), 1); + QCOMPARE(errorSpy.size(), 1); QCOMPARE(clientSocket->error(), QAbstractSocket::RemoteHostClosedError); delete serverSocket; @@ -2088,33 +2067,51 @@ void tst_QTcpSocket::nestedEventLoopInErrorSlot() void tst_QTcpSocket::connectToHostError_data() { QTest::addColumn<QString>("host"); - QTest::addColumn<int>("port"); + QTest::addColumn<quint16>("port"); QTest::addColumn<QAbstractSocket::SocketError>("expectedError"); - QTest::newRow("localhost no service") << QStringLiteral("localhost") << 31415 << QAbstractSocket::ConnectionRefusedError; - QTest::newRow("unreachable") << QStringLiteral("0.0.0.1") << 65000 << QAbstractSocket::NetworkError; + QTest::newRow("localhost no service") << QStringLiteral("localhost") << quint16(31415) << QAbstractSocket::ConnectionRefusedError; + QTest::newRow("unreachable") << QStringLiteral("0.0.0.1") << quint16(65000) << QAbstractSocket::NetworkError; } void tst_QTcpSocket::connectToHostError() { - QTcpSocket *socket = newSocket(); + // We are aware of at least one OS in our CI, that would fail + // the test due to timeout - it's Ubuntu 20.04 and 'connect' + // to 0.0.0.1 there return EINPROGRESS, with no other error + // ever received, so only our own internal 30 s. timer can + // detect a connection timeout. + + std::unique_ptr<QTcpSocket> socket(newSocket()); QAbstractSocket::SocketError error = QAbstractSocket::UnknownSocketError; - QFETCH(QString, host); - QFETCH(int, port); + QFETCH(const QString, host); + QFETCH(const quint16, port); QFETCH(QAbstractSocket::SocketError, expectedError); - connect(socket, &QAbstractSocket::errorOccurred, [&](QAbstractSocket::SocketError socketError){ + QTestEventLoop eventLoop; + connect(socket.get(), &QAbstractSocket::errorOccurred, socket.get(), + [&](QAbstractSocket::SocketError socketError) { error = socketError; + QTimer::singleShot(0, &eventLoop, [&]{eventLoop.exitLoop();}); }); - socket->connectToHost(host, port); // no service running here, one suspects - QTRY_COMPARE(socket->state(), QTcpSocket::UnconnectedState); + + socket->connectToHost(host, port); + eventLoop.enterLoopMSecs(10'000); + if (eventLoop.timeout()) { + // Let's at least verify it's not in connected state: + QVERIFY(socket->state() != QAbstractSocket::ConnectedState); + QSKIP("Connection to unreachable host timed out, skipping the rest of the test"); + } + + QCOMPARE(socket->state(), QTcpSocket::UnconnectedState); + if (error != expectedError && error == QAbstractSocket::ConnectionRefusedError) QEXPECT_FAIL("unreachable", "CI firewall interfers with this test", Continue); + QCOMPARE(error, expectedError); - delete socket; } //---------------------------------------------------------------------------------- @@ -2143,7 +2140,7 @@ void tst_QTcpSocket::waitForConnectedInHostLookupSlot() if (tmpSocket->state() != QAbstractSocket::ConnectedState) loop.exec(); - QCOMPARE(timerSpy.count(), 0); + QCOMPARE(timerSpy.size(), 0); delete tmpSocket; } @@ -2163,7 +2160,7 @@ public: bool networkTimeout; int count; - inline Foo(QObject *parent = 0) : QObject(parent) + inline Foo(QObject *parent = nullptr) : QObject(parent) { attemptedToConnect = false; networkTimeout = false; @@ -2197,7 +2194,7 @@ public slots: #if defined(Q_OS_MAC) pthread_yield_np(); #elif defined Q_OS_LINUX && !defined Q_OS_ANDROID - pthread_yield(); + sched_yield(); #endif if (!sock->waitForConnected()) { networkTimeout = true; @@ -2248,7 +2245,7 @@ void tst_QTcpSocket::readyReadSignalsAfterWaitForReadyRead() // Wait for the read QVERIFY(socket->waitForReadyRead(10000)); - QCOMPARE(readyReadSpy.count(), 1); + QCOMPARE(readyReadSpy.size(), 1); QString s = socket->readLine(); QVERIFY2(QtNetworkSettings::compareReplyIMAP(s.toLatin1()), s.toLatin1().constData()); @@ -2256,7 +2253,7 @@ void tst_QTcpSocket::readyReadSignalsAfterWaitForReadyRead() QCoreApplication::instance()->processEvents(); QCOMPARE(socket->bytesAvailable(), qint64(0)); - QCOMPARE(readyReadSpy.count(), 1); + QCOMPARE(readyReadSpy.size(), 1); delete socket; } @@ -2330,8 +2327,8 @@ void tst_QTcpSocket::abortiveClose() enterLoop(5); - QCOMPARE(readyReadSpy.count(), 0); - QCOMPARE(errorSpy.count(), 1); + QCOMPARE(readyReadSpy.size(), 0); + QCOMPARE(errorSpy.size(), 1); QCOMPARE(*static_cast<const int *>(errorSpy.at(0).at(0).constData()), int(QAbstractSocket::RemoteHostClosedError)); @@ -2450,11 +2447,11 @@ void tst_QTcpSocket::connectionRefused() QCOMPARE(socket->state(), QAbstractSocket::UnconnectedState); QCOMPARE(socket->error(), QAbstractSocket::ConnectionRefusedError); - QCOMPARE(stateSpy.count(), 3); + QCOMPARE(stateSpy.size(), 3); QCOMPARE(qvariant_cast<QAbstractSocket::SocketState>(stateSpy.at(0).at(0)), QAbstractSocket::HostLookupState); QCOMPARE(qvariant_cast<QAbstractSocket::SocketState>(stateSpy.at(1).at(0)), QAbstractSocket::ConnectingState); QCOMPARE(qvariant_cast<QAbstractSocket::SocketState>(stateSpy.at(2).at(0)), QAbstractSocket::UnconnectedState); - QCOMPARE(errorSpy.count(), 1); + QCOMPARE(errorSpy.size(), 1); delete socket; } @@ -2586,7 +2583,7 @@ void tst_QTcpSocket::moveToThread0() { // Case 1: Moved after connecting, before waiting for connection. - QTcpSocket *socket = newSocket();; + QTcpSocket *socket = newSocket(); socket->connectToHost(QtNetworkSettings::imapServerName(), 143); socket->moveToThread(0); QVERIFY(socket->waitForConnected(5000)); @@ -2917,6 +2914,7 @@ void tst_QTcpSocket::proxyFactory_data() << proxyList << proxyList.at(1) << false << int(QAbstractSocket::UnknownSocketError); +#if 0 // FTP not currently supported proxyList.clear(); proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121) << QNetworkProxy(QNetworkProxy::HttpCachingProxy, QtNetworkSettings::httpProxyServerName(), 3129) @@ -2924,6 +2922,7 @@ void tst_QTcpSocket::proxyFactory_data() QTest::newRow("ftp+cachinghttp+socks5") << proxyList << proxyList.at(2) << false << int(QAbstractSocket::UnknownSocketError); +#endif // tests that fail to connect proxyList.clear(); @@ -2932,6 +2931,7 @@ void tst_QTcpSocket::proxyFactory_data() << proxyList << QNetworkProxy() << true << int(QAbstractSocket::UnsupportedSocketOperationError); +#if 0 // FTP not currently supported proxyList.clear(); proxyList << QNetworkProxy(QNetworkProxy::FtpCachingProxy, QtNetworkSettings::ftpProxyServerName(), 2121); QTest::newRow("ftp") @@ -2944,6 +2944,7 @@ void tst_QTcpSocket::proxyFactory_data() QTest::newRow("ftp+cachinghttp") << proxyList << QNetworkProxy() << true << int(QAbstractSocket::UnsupportedSocketOperationError); +#endif } void tst_QTcpSocket::proxyFactory() @@ -3123,8 +3124,8 @@ void tst_QTcpSocket::serverDisconnectWithBuffered() QCOMPARE(socket->state(), QAbstractSocket::UnconnectedState); } // Test signal emitting - QCOMPARE(spyDisconnected.count(), 1); - QVERIFY(spyStateChanged.count() > 0); + QCOMPARE(spyDisconnected.size(), 1); + QVERIFY(spyStateChanged.size() > 0); QVERIFY(qvariant_cast<QAbstractSocket::SocketState>(spyStateChanged.last().first()) == QAbstractSocket::UnconnectedState); @@ -3213,7 +3214,7 @@ void tst_QTcpSocket::readNotificationsAfterBind() QTestEventLoop::instance().enterLoop(10); QVERIFY2(!QTestEventLoop::instance().timeout(), "Connection to closed port timed out instead of refusing, something is wrong"); QVERIFY2(socket.state() == QAbstractSocket::UnconnectedState, "Socket connected unexpectedly!"); - QCOMPARE(spyReadyRead.count(), 0); + QCOMPARE(spyReadyRead.size(), 0); } QTEST_MAIN(tst_QTcpSocket) diff --git a/tests/auto/network/socket/qudpsocket/BLACKLIST b/tests/auto/network/socket/qudpsocket/BLACKLIST index 8ac9dad80b..f5f6a8e156 100644 --- a/tests/auto/network/socket/qudpsocket/BLACKLIST +++ b/tests/auto/network/socket/qudpsocket/BLACKLIST @@ -1,13 +1,9 @@ [writeDatagramToNonExistingPeer] -windows-10 msvc-2019 -windows-10 msvc-2017 -windows-10 msvc-2015 -windows-7sp1 -# QTBUG-85364 -windows-10 gcc cmake +windows [readyReadForEmptyDatagram] opensuse-leap -[echo] -opensuse-42.3 -[readyReadForEmptyDatagram] -linux +[multicast] +centos +macos arm +[linkLocalIPv6] +macos arm diff --git a/tests/auto/network/socket/qudpsocket/CMakeLists.txt b/tests/auto/network/socket/qudpsocket/CMakeLists.txt index b9d0646e58..a7a2659340 100644 --- a/tests/auto/network/socket/qudpsocket/CMakeLists.txt +++ b/tests/auto/network/socket/qudpsocket/CMakeLists.txt @@ -1,4 +1,11 @@ -# Generated from qudpsocket.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qudpsocket LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() -add_subdirectory(test) add_subdirectory(clientserver) +add_subdirectory(test) diff --git a/tests/auto/network/socket/qudpsocket/clientserver/CMakeLists.txt b/tests/auto/network/socket/qudpsocket/clientserver/CMakeLists.txt index 12fe8a453a..4644d0d96f 100644 --- a/tests/auto/network/socket/qudpsocket/clientserver/CMakeLists.txt +++ b/tests/auto/network/socket/qudpsocket/clientserver/CMakeLists.txt @@ -1,13 +1,14 @@ -# Generated from clientserver.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## clientserver Binary: ##################################################################### -qt_add_executable(clientserver +qt_internal_add_executable(clientserver OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/" SOURCES main.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Network ) diff --git a/tests/auto/network/socket/qudpsocket/clientserver/clientserver.pro b/tests/auto/network/socket/qudpsocket/clientserver/clientserver.pro deleted file mode 100644 index 83a31b11e9..0000000000 --- a/tests/auto/network/socket/qudpsocket/clientserver/clientserver.pro +++ /dev/null @@ -1,5 +0,0 @@ -QT = core network -SOURCES += main.cpp -CONFIG += cmdline -TARGET = clientserver -DESTDIR = ./ diff --git a/tests/auto/network/socket/qudpsocket/clientserver/main.cpp b/tests/auto/network/socket/qudpsocket/clientserver/main.cpp index 705abf87e3..76bdf3aada 100644 --- a/tests/auto/network/socket/qudpsocket/clientserver/main.cpp +++ b/tests/auto/network/socket/qudpsocket/clientserver/main.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtNetwork> class ClientServer : public QUdpSocket diff --git a/tests/auto/network/socket/qudpsocket/qudpsocket.pro b/tests/auto/network/socket/qudpsocket/qudpsocket.pro deleted file mode 100644 index b267d5f249..0000000000 --- a/tests/auto/network/socket/qudpsocket/qudpsocket.pro +++ /dev/null @@ -1,3 +0,0 @@ -TEMPLATE = subdirs -SUBDIRS = test clientserver -test.depends = clientserver diff --git a/tests/auto/network/socket/qudpsocket/test/.prev_CMakeLists.txt b/tests/auto/network/socket/qudpsocket/test/.prev_CMakeLists.txt deleted file mode 100644 index 4c393d67a8..0000000000 --- a/tests/auto/network/socket/qudpsocket/test/.prev_CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -# Generated from test.pro. - -##################################################################### -## tst_qudpsocket Test: -##################################################################### - -qt_add_test(tst_qudpsocket - SOURCES - ../tst_qudpsocket.cpp - INCLUDE_DIRECTORIES - ../../../../../shared - PUBLIC_LIBRARIES - Qt::Network -) - -#### Keys ignored in scope 1:.:.:test.pro:<TRUE>: -# MOC_DIR = "tmp" -# testcase.timeout = "800" - -## Scopes: -##################################################################### - -#### Keys ignored in scope 3:.:.:test.pro:(CMAKE_BUILD_TYPE STREQUAL Debug): -# DESTDIR = "../debug" - -#### Keys ignored in scope 4:.:.:test.pro:else: -# DESTDIR = "../release" - -#### Keys ignored in scope 5:.:.:test.pro:else: -# DESTDIR = "../" - -#### Keys ignored in scope 6:.:.:test.pro:LINUX: -# QT_TEST_SERVER_LIST = "danted" "echo" diff --git a/tests/auto/network/socket/qudpsocket/test/CMakeLists.txt b/tests/auto/network/socket/qudpsocket/test/CMakeLists.txt index 3da08a0e72..69b62c2f9f 100644 --- a/tests/auto/network/socket/qudpsocket/test/CMakeLists.txt +++ b/tests/auto/network/socket/qudpsocket/test/CMakeLists.txt @@ -1,35 +1,20 @@ -# Generated from test.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qudpsocket Test: ##################################################################### -qt_add_test(tst_qudpsocket - OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../" # special case +qt_internal_add_test(tst_qudpsocket + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../" SOURCES ../tst_qudpsocket.cpp - INCLUDE_DIRECTORIES - ../../../../../shared - PUBLIC_LIBRARIES + LIBRARIES Qt::Network - QT_TEST_SERVER_LIST "danted" "echo" # special case + Qt::TestPrivate + QT_TEST_SERVER_LIST "danted" "echo" ) -#### Keys ignored in scope 1:.:.:test.pro:<TRUE>: -# MOC_DIR = "tmp" -# testcase.timeout = "800" - -## Scopes: -##################################################################### - -#### Keys ignored in scope 3:.:.:test.pro:(CMAKE_BUILD_TYPE STREQUAL Debug): -# DESTDIR = "../debug" - -#### Keys ignored in scope 4:.:.:test.pro:else: -# DESTDIR = "../release" - -#### Keys ignored in scope 5:.:.:test.pro:else: -# DESTDIR = "../" - -#### Keys ignored in scope 6:.:.:test.pro:LINUX: -# QT_TEST_SERVER_LIST = "danted" "echo" +if(QT_FEATURE_process) + add_dependencies(tst_qudpsocket clientserver) +endif() diff --git a/tests/auto/network/socket/qudpsocket/test/test.pro b/tests/auto/network/socket/qudpsocket/test/test.pro deleted file mode 100644 index 994b360370..0000000000 --- a/tests/auto/network/socket/qudpsocket/test/test.pro +++ /dev/null @@ -1,25 +0,0 @@ -CONFIG += testcase -testcase.timeout = 800 # this test is slow -SOURCES += ../tst_qudpsocket.cpp -INCLUDEPATH += ../../../../../shared/ -QT = core network testlib - -MOC_DIR=tmp - -win32:debug_and_release { - CONFIG(debug, debug|release) { - DESTDIR = ../debug -} else { - DESTDIR = ../release - } -} else { - DESTDIR = ../ -} - -TARGET = tst_qudpsocket - -# Only on Linux until 'echo' has been added to docker-compose-for-{windows,macOS}.yml and tested -linux { - CONFIG += unsupported/testserver - QT_TEST_SERVER_LIST = danted echo -} diff --git a/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp b/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp index fe7822718f..689ff452f9 100644 --- a/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp +++ b/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp @@ -1,34 +1,16 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2017 Intel Corporation. -** 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> +// Copyright (C) 2021 The Qt Company Ltd. +// Copyright (C) 2017 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QTest> +#include <QSignalSpy> +#include <QtEndian> +#if QT_CONFIG(process) +#include <QProcess> +#endif +#include <QScopeGuard> +#include <QVersionNumber> +#include <QSemaphore> #include <qcoreapplication.h> #include <qfileinfo.h> @@ -46,8 +28,9 @@ #include <QNetworkInterface> #include <qstringlist.h> +#include <QSet> #include "../../../network-settings.h" -#include "emulationdetector.h" +#include <QtTest/private/qemulationdetector_p.h> #if defined(Q_OS_LINUX) #define SHOULD_CHECK_SYSCALL_SUPPORT @@ -63,6 +46,8 @@ # define RELIABLE_BYTES_AVAILABLE #endif +using namespace Qt::StringLiterals; + Q_DECLARE_METATYPE(QHostAddress) QT_FORWARD_DECLARE_CLASS(QUdpSocket) @@ -120,6 +105,8 @@ private slots: void asyncReadDatagram(); void writeInHostLookupState(); + void readyReadConnectionThrottling(); + protected slots: void empty_readyReadSlot(); void empty_connectedSlot(); @@ -138,6 +125,7 @@ private: QList<QHostAddress> allAddresses; QHostAddress multicastGroup4, multicastGroup6; QList<QHostAddress> linklocalMulticastGroups; + QNetworkInterface ifaceWithIPv6; QUdpSocket *m_asyncSender; QUdpSocket *m_asyncReceiver; }; @@ -188,26 +176,7 @@ QNetworkInterface tst_QUdpSocket::interfaceForGroup(const QHostAddress &multicas if (!scope.isEmpty()) return QNetworkInterface::interfaceFromName(scope); - static QNetworkInterface ipv6if = [=]() { - // find any link local address in the allAddress list - for (const QHostAddress &addr: qAsConst(allAddresses)) { - if (addr.isLoopback()) - continue; - - QString scope = addr.scopeId(); - if (!scope.isEmpty()) { - QNetworkInterface iface = QNetworkInterface::interfaceFromName(scope); - qDebug() << "Will bind IPv6 sockets to" << iface; - return iface; - } - } - - qWarning("interfaceForGroup(%s) could not find any link-local IPv6 address! " - "Make sure this test is behind a check of QtNetworkSettings::hasIPv6().", - qUtf8Printable(multicastGroup.toString())); - return QNetworkInterface(); - }(); - return ipv6if; + return ifaceWithIPv6; } bool tst_QUdpSocket::shouldWorkaroundLinuxKernelBug() @@ -286,18 +255,25 @@ void tst_QUdpSocket::initTestCase() // ff12:: is temporary, not prefix-based, link-local r[0] = qToBigEndian(Q_UINT64_C(0xff12) << 48); QHostAddress llbase(*reinterpret_cast<Q_IPV6ADDR *>(&r)); - for (const QHostAddress &a : qAsConst(allAddresses)) { + for (const QHostAddress &a : std::as_const(allAddresses)) { QString scope = a.scopeId(); if (scope.isEmpty()) continue; llbase.setScopeId(scope); linklocalMulticastGroups << llbase; + if (!ifaceWithIPv6.isValid()) { + // Remember the first interface we've found that has IPv6 so we can + // bind non-link-local sockets to it (the first is least likely to + // be some weird virtual interface). + ifaceWithIPv6 = QNetworkInterface::interfaceFromName(scope); + } } qDebug() << "Will use multicast groups" << multicastGroup4 << multicastGroup6 << linklocalMulticastGroups; + qDebug() << "Will bind IPv6 sockets to" << ifaceWithIPv6; m_workaroundLinuxKernelBug = shouldWorkaroundLinuxKernelBug(); - if (EmulationDetector::isRunningArmOnX86()) + if (QTestPrivate::isRunningArmOnX86()) QSKIP("This test is unreliable due to QEMU emulation shortcomings."); } @@ -351,7 +327,7 @@ void tst_QUdpSocket::unconnectedServerAndClientTest() QSignalSpy stateChangedSpy(&serverSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState))); QVERIFY2(serverSocket.bind(), serverSocket.errorString().toLatin1().constData()); - QCOMPARE(stateChangedSpy.count(), 1); + QCOMPARE(stateChangedSpy.size(), 1); const char *message[] = {"Yo mista", "Yo", "Wassap"}; @@ -400,10 +376,11 @@ void tst_QUdpSocket::broadcasting() const char *message[] = {"Yo mista", "", "Yo", "Wassap"}; QList<QHostAddress> broadcastAddresses; - foreach (QNetworkInterface iface, QNetworkInterface::allInterfaces()) { + const auto ifaces = QNetworkInterface::allInterfaces(); + for (const QNetworkInterface &iface : ifaces) { if ((iface.flags() & QNetworkInterface::CanBroadcast) && iface.flags() & QNetworkInterface::IsUp) { - for (int i=0;i<iface.addressEntries().count();i++) { + for (int i=0;i<iface.addressEntries().size();i++) { QHostAddress broadcast = iface.addressEntries().at(i).broadcast(); if (broadcast.protocol() == QAbstractSocket::IPv4Protocol) broadcastAddresses.append(broadcast); @@ -428,7 +405,7 @@ void tst_QUdpSocket::broadcasting() for (int k = 0; k < 4; k++) { broadcastSocket.writeDatagram(message[i], strlen(message[i]), QHostAddress::Broadcast, serverPort); - foreach (QHostAddress addr, broadcastAddresses) + for (const QHostAddress &addr : std::as_const(broadcastAddresses)) broadcastSocket.writeDatagram(message[i], strlen(message[i]), addr, serverPort); } QTestEventLoop::instance().enterLoop(15); @@ -437,7 +414,6 @@ void tst_QUdpSocket::broadcasting() QEXPECT_FAIL("", "Broadcasting to 255.255.255.255 does not work on FreeBSD", Abort); - QVERIFY(false); // seems that QFAIL() doesn't respect the QEXPECT_FAIL() :/ #endif QFAIL("Network operation timed out"); } @@ -449,7 +425,7 @@ void tst_QUdpSocket::broadcasting() QVERIFY(dgram.isValid()); QByteArray arr = dgram.data(); - QCOMPARE(arr.length(), messageLength); + QCOMPARE(arr.size(), messageLength); arr.resize(messageLength); QCOMPARE(arr, QByteArray(message[i])); @@ -509,27 +485,27 @@ void tst_QUdpSocket::loop() QHostAddress peterAddress = makeNonAny(peter.localAddress()); QHostAddress paulAddress = makeNonAny(paul.localAddress()); - QCOMPARE(peter.writeDatagram(peterMessage.data(), peterMessage.length(), - paulAddress, paul.localPort()), qint64(peterMessage.length())); - QCOMPARE(paul.writeDatagram(paulMessage.data(), paulMessage.length(), - peterAddress, peter.localPort()), qint64(paulMessage.length())); + QCOMPARE(peter.writeDatagram(peterMessage.data(), peterMessage.size(), + paulAddress, paul.localPort()), qint64(peterMessage.size())); + QCOMPARE(paul.writeDatagram(paulMessage.data(), paulMessage.size(), + peterAddress, peter.localPort()), qint64(paulMessage.size())); QVERIFY2(peter.waitForReadyRead(9000), QtNetworkSettings::msgSocketError(peter).constData()); QVERIFY2(paul.waitForReadyRead(9000), QtNetworkSettings::msgSocketError(paul).constData()); - QNetworkDatagram peterDatagram = peter.receiveDatagram(paulMessage.length() * 2); - QNetworkDatagram paulDatagram = paul.receiveDatagram(peterMessage.length() * 2); + QNetworkDatagram peterDatagram = peter.receiveDatagram(paulMessage.size() * 2); + QNetworkDatagram paulDatagram = paul.receiveDatagram(peterMessage.size() * 2); if (success) { - QCOMPARE(peterDatagram.data().length(), qint64(paulMessage.length())); - QCOMPARE(paulDatagram.data().length(), qint64(peterMessage.length())); + QCOMPARE(peterDatagram.data().size(), qint64(paulMessage.size())); + QCOMPARE(paulDatagram.data().size(), qint64(peterMessage.size())); } else { // this code path seems to never be executed - QVERIFY(peterDatagram.data().length() != paulMessage.length()); - QVERIFY(paulDatagram.data().length() != peterMessage.length()); + QVERIFY(peterDatagram.data().size() != paulMessage.size()); + QVERIFY(paulDatagram.data().size() != peterMessage.size()); } - QCOMPARE(peterDatagram.data().left(paulMessage.length()), paulMessage); - QCOMPARE(paulDatagram.data().left(peterMessage.length()), peterMessage); + QCOMPARE(peterDatagram.data().left(paulMessage.size()), paulMessage); + QCOMPARE(paulDatagram.data().left(peterMessage.size()), peterMessage); QCOMPARE(peterDatagram.senderAddress(), paulAddress); QCOMPARE(paulDatagram.senderAddress(), peterAddress); @@ -586,27 +562,27 @@ void tst_QUdpSocket::ipv6Loop() peterPort = peter.localPort(); paulPort = paul.localPort(); - QCOMPARE(peter.writeDatagram(peterMessage.data(), peterMessage.length(), QHostAddress("::1"), - paulPort), qint64(peterMessage.length())); - QCOMPARE(paul.writeDatagram(paulMessage.data(), paulMessage.length(), - QHostAddress("::1"), peterPort), qint64(paulMessage.length())); + QCOMPARE(peter.writeDatagram(peterMessage.data(), peterMessage.size(), QHostAddress("::1"), + paulPort), qint64(peterMessage.size())); + QCOMPARE(paul.writeDatagram(paulMessage.data(), paulMessage.size(), + QHostAddress("::1"), peterPort), qint64(paulMessage.size())); QVERIFY(peter.waitForReadyRead(5000)); QVERIFY(paul.waitForReadyRead(5000)); - QNetworkDatagram peterDatagram = peter.receiveDatagram(paulMessage.length() * 2); - QNetworkDatagram paulDatagram = paul.receiveDatagram(peterMessage.length() * 2); + QNetworkDatagram peterDatagram = peter.receiveDatagram(paulMessage.size() * 2); + QNetworkDatagram paulDatagram = paul.receiveDatagram(peterMessage.size() * 2); if (success) { - QCOMPARE(peterDatagram.data().length(), qint64(paulMessage.length())); - QCOMPARE(paulDatagram.data().length(), qint64(peterMessage.length())); + QCOMPARE(peterDatagram.data().size(), qint64(paulMessage.size())); + QCOMPARE(paulDatagram.data().size(), qint64(peterMessage.size())); } else { // this code path seems to never be executed - QVERIFY(peterDatagram.data().length() != paulMessage.length()); - QVERIFY(paulDatagram.data().length() != peterMessage.length()); + QVERIFY(peterDatagram.data().size() != paulMessage.size()); + QVERIFY(paulDatagram.data().size() != peterMessage.size()); } - QCOMPARE(peterDatagram.data().left(paulMessage.length()), paulMessage); - QCOMPARE(paulDatagram.data().left(peterMessage.length()), peterMessage); + QCOMPARE(peterDatagram.data().left(paulMessage.size()), paulMessage); + QCOMPARE(paulDatagram.data().left(peterMessage.size()), peterMessage); QCOMPARE(peterDatagram.senderAddress(), paulAddress); QCOMPARE(paulDatagram.senderAddress(), peterAddress); @@ -634,7 +610,7 @@ void tst_QUdpSocket::dualStack() QVERIFY(v4Sock.bind(QHostAddress(QHostAddress::AnyIPv4), 0)); //test v4 -> dual - QCOMPARE((int)v4Sock.writeDatagram(v4Data.constData(), v4Data.length(), QHostAddress(QHostAddress::LocalHost), dualSock.localPort()), v4Data.length()); + QCOMPARE((int)v4Sock.writeDatagram(v4Data.constData(), v4Data.size(), QHostAddress(QHostAddress::LocalHost), dualSock.localPort()), v4Data.size()); QVERIFY2(dualSock.waitForReadyRead(5000), QtNetworkSettings::msgSocketError(dualSock).constData()); QNetworkDatagram dgram = dualSock.receiveDatagram(100); QVERIFY(dgram.isValid()); @@ -646,7 +622,7 @@ void tst_QUdpSocket::dualStack() QCOMPARE(dgram.senderAddress(), makeNonAny(v4Sock.localAddress(), QHostAddress::Null)); if (dgram.destinationPort() != -1) { QCOMPARE(dgram.destinationPort(), int(dualSock.localPort())); - QVERIFY(dgram.destinationAddress().isEqual(dualSock.localAddress())); + QVERIFY(dgram.destinationAddress().isEqual(makeNonAny(dualSock.localAddress(), QHostAddress::LocalHost))); } else { qInfo("Getting IPv4 destination address failed."); } @@ -657,7 +633,7 @@ void tst_QUdpSocket::dualStack() QVERIFY(v6Sock.bind(QHostAddress(QHostAddress::AnyIPv6), 0)); //test v6 -> dual - QCOMPARE((int)v6Sock.writeDatagram(v6Data.constData(), v6Data.length(), QHostAddress(QHostAddress::LocalHostIPv6), dualSock.localPort()), v6Data.length()); + QCOMPARE((int)v6Sock.writeDatagram(v6Data.constData(), v6Data.size(), QHostAddress(QHostAddress::LocalHostIPv6), dualSock.localPort()), v6Data.size()); QVERIFY2(dualSock.waitForReadyRead(5000), QtNetworkSettings::msgSocketError(dualSock).constData()); dgram = dualSock.receiveDatagram(100); QVERIFY(dgram.isValid()); @@ -668,7 +644,7 @@ void tst_QUdpSocket::dualStack() QCOMPARE(dgram.destinationAddress(), makeNonAny(dualSock.localAddress(), QHostAddress::LocalHostIPv6)); //test dual -> v6 - QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.length(), QHostAddress(QHostAddress::LocalHostIPv6), v6Sock.localPort()), dualData.length()); + QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.size(), QHostAddress(QHostAddress::LocalHostIPv6), v6Sock.localPort()), dualData.size()); QVERIFY2(v6Sock.waitForReadyRead(5000), QtNetworkSettings::msgSocketError(v6Sock).constData()); dgram = v6Sock.receiveDatagram(100); QVERIFY(dgram.isValid()); @@ -680,7 +656,7 @@ void tst_QUdpSocket::dualStack() } //test dual -> v4 - QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.length(), QHostAddress(QHostAddress::LocalHost), v4Sock.localPort()), dualData.length()); + QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.size(), QHostAddress(QHostAddress::LocalHost), v4Sock.localPort()), dualData.size()); QVERIFY2(v4Sock.waitForReadyRead(5000), QtNetworkSettings::msgSocketError(v4Sock).constData()); dgram = v4Sock.receiveDatagram(100); QVERIFY(dgram.isValid()); @@ -719,19 +695,19 @@ void tst_QUdpSocket::dualStackAutoBinding() //test an autobound socket can send to both v4 and v6 addresses (v4 first) QUdpSocket dualSock; - QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.length(), QHostAddress(QHostAddress::LocalHost), v4Sock.localPort()), dualData.length()); + QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.size(), QHostAddress(QHostAddress::LocalHost), v4Sock.localPort()), dualData.size()); QVERIFY2(v4Sock.waitForReadyRead(5000), QtNetworkSettings::msgSocketError(v4Sock).constData()); buffer.reserve(100); size = v4Sock.readDatagram(buffer.data(), 100, &from, &port); - QCOMPARE((int)size, dualData.length()); + QCOMPARE((int)size, dualData.size()); buffer.resize(size); QCOMPARE(buffer, dualData); - QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.length(), QHostAddress(QHostAddress::LocalHostIPv6), v6Sock.localPort()), dualData.length()); + QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.size(), QHostAddress(QHostAddress::LocalHostIPv6), v6Sock.localPort()), dualData.size()); QVERIFY2(v6Sock.waitForReadyRead(5000), QtNetworkSettings::msgSocketError(v6Sock).constData()); buffer.reserve(100); size = v6Sock.readDatagram(buffer.data(), 100, &from, &port); - QCOMPARE((int)size, dualData.length()); + QCOMPARE((int)size, dualData.size()); buffer.resize(size); QCOMPARE(buffer, dualData); } @@ -740,19 +716,19 @@ void tst_QUdpSocket::dualStackAutoBinding() //test an autobound socket can send to both v4 and v6 addresses (v6 first) QUdpSocket dualSock; - QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.length(), QHostAddress(QHostAddress::LocalHostIPv6), v6Sock.localPort()), dualData.length()); + QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.size(), QHostAddress(QHostAddress::LocalHostIPv6), v6Sock.localPort()), dualData.size()); QVERIFY2(v6Sock.waitForReadyRead(5000), QtNetworkSettings::msgSocketError(v6Sock).constData()); buffer.reserve(100); size = v6Sock.readDatagram(buffer.data(), 100, &from, &port); - QCOMPARE((int)size, dualData.length()); + QCOMPARE((int)size, dualData.size()); buffer.resize(size); QCOMPARE(buffer, dualData); - QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.length(), QHostAddress(QHostAddress::LocalHost), v4Sock.localPort()), dualData.length()); + QCOMPARE((int)dualSock.writeDatagram(dualData.constData(), dualData.size(), QHostAddress(QHostAddress::LocalHost), v4Sock.localPort()), dualData.size()); QVERIFY2(v4Sock.waitForReadyRead(5000), QtNetworkSettings::msgSocketError(v4Sock).constData()); buffer.reserve(100); size = v4Sock.readDatagram(buffer.data(), 100, &from, &port); - QCOMPARE((int)size, dualData.length()); + QCOMPARE((int)size, dualData.size()); buffer.resize(size); QCOMPARE(buffer, dualData); } @@ -773,7 +749,7 @@ void tst_QUdpSocket::dualStackNoIPv4onV6only() QVERIFY(v6Sock.bind(QHostAddress(QHostAddress::AnyIPv6), 0)); //test v4 -> v6 (should not be received as this is a v6 only socket) - QCOMPARE((int)v4Sock.writeDatagram(v4Data.constData(), v4Data.length(), QHostAddress(QHostAddress::LocalHost), v6Sock.localPort()), v4Data.length()); + QCOMPARE((int)v4Sock.writeDatagram(v4Data.constData(), v4Data.size(), QHostAddress(QHostAddress::LocalHost), v6Sock.localPort()), v4Data.size()); QVERIFY(!v6Sock.waitForReadyRead(1000)); } @@ -893,17 +869,17 @@ void tst_QUdpSocket::writeDatagram() #if defined (Q_OS_HPUX) QSKIP("HP-UX 11.11 on hai (PA-RISC 64) truncates too long datagrams."); #endif - QCOMPARE(bytesspy.count(), 0); - QCOMPARE(errorspy.count(), 1); + QCOMPARE(bytesspy.size(), 0); + QCOMPARE(errorspy.size(), 1); QCOMPARE(*static_cast<const int *>(errorspy.at(0).at(0).constData()), int(QUdpSocket::DatagramTooLargeError)); QCOMPARE(client.error(), QUdpSocket::DatagramTooLargeError); break; } - QCOMPARE(bytesspy.count(), 1); + QCOMPARE(bytesspy.size(), 1); QCOMPARE(*static_cast<const qint64 *>(bytesspy.at(0).at(0).constData()), qint64(i * 1024)); - QCOMPARE(errorspy.count(), 0); + QCOMPARE(errorspy.size(), 0); if (!server.waitForReadyRead(5000)) QSKIP(QString("UDP packet lost at size %1, unable to complete the test.").arg(i * 1024).toLatin1().data()); QCOMPARE(server.pendingDatagramSize(), qint64(i * 1024)); @@ -1016,7 +992,7 @@ void tst_QUdpSocket::writeDatagramToNonExistingPeer() QVERIFY(sUdp.bind()); QCOMPARE(sUdp.writeDatagram("", 1, peerAddress, peerPort), qint64(1)); QTestEventLoop::instance().enterLoop(1); - QCOMPARE(sReadyReadSpy.count(), 0); + QCOMPARE(sReadyReadSpy.size(), 0); } void tst_QUdpSocket::writeToNonExistingPeer_data() @@ -1059,8 +1035,8 @@ void tst_QUdpSocket::writeToNonExistingPeer() // the third one will succeed... QCOMPARE(sConnected.write("", 1), qint64(1)); QTestEventLoop::instance().enterLoop(1); - QCOMPARE(sConnectedReadyReadSpy.count(), 0); - QCOMPARE(sConnectedErrorSpy.count(), 1); + QCOMPARE(sConnectedReadyReadSpy.size(), 0); + QCOMPARE(sConnectedErrorSpy.size(), 1); QCOMPARE(int(sConnected.error()), int(QUdpSocket::ConnectionRefusedError)); // we should now get a read error @@ -1259,11 +1235,12 @@ void tst_QUdpSocket::multicastTtlOption_data() QTest::addColumn<int>("ttl"); QTest::addColumn<int>("expected"); - QList<QHostAddress> addresses; - addresses += QHostAddress(QHostAddress::AnyIPv4); - addresses += QHostAddress(QHostAddress::AnyIPv6); + const QHostAddress addresses[] = { + QHostAddress(QHostAddress::AnyIPv4), + QHostAddress(QHostAddress::AnyIPv6), + }; - foreach (const QHostAddress &address, addresses) { + for (const QHostAddress &address : addresses) { const QByteArray addressB = address.toString().toLatin1(); QTest::newRow((addressB + " 0").constData()) << address << 0 << 0; QTest::newRow((addressB + " 1").constData()) << address << 1 << 1; @@ -1305,11 +1282,12 @@ void tst_QUdpSocket::multicastLoopbackOption_data() QTest::addColumn<int>("loopback"); QTest::addColumn<int>("expected"); - QList<QHostAddress> addresses; - addresses += QHostAddress(QHostAddress::AnyIPv4); - addresses += QHostAddress(QHostAddress::AnyIPv6); + const QHostAddress addresses[] = { + QHostAddress(QHostAddress::AnyIPv4), + QHostAddress(QHostAddress::AnyIPv6), + }; - foreach (const QHostAddress &address, addresses) { + for (const QHostAddress &address : addresses) { const QByteArray addressB = address.toString().toLatin1(); QTest::newRow((addressB + " 0").constData()) << address << 0 << 0; QTest::newRow((addressB + " 1").constData()) << address << 1 << 1; @@ -1352,7 +1330,7 @@ void tst_QUdpSocket::multicastJoinBeforeBind_data() QTest::newRow("valid ipv4 group address") << multicastGroup4; QTest::newRow("invalid ipv4 group address") << QHostAddress(QHostAddress::Broadcast); QTest::newRow("valid ipv6 group address") << multicastGroup6; - for (const QHostAddress &a : qAsConst(linklocalMulticastGroups)) + for (const QHostAddress &a : std::as_const(linklocalMulticastGroups)) QTest::addRow("valid ipv6 %s-link group address", a.scopeId().toLatin1().constData()) << a; QTest::newRow("invalid ipv6 group address") << QHostAddress(QHostAddress::AnyIPv6); } @@ -1372,7 +1350,7 @@ void tst_QUdpSocket::multicastLeaveAfterClose_data() QTest::addColumn<QHostAddress>("groupAddress"); QTest::newRow("ipv4") << multicastGroup4; QTest::newRow("ipv6") << multicastGroup6; - for (const QHostAddress &a : qAsConst(linklocalMulticastGroups)) + for (const QHostAddress &a : std::as_const(linklocalMulticastGroups)) QTest::addRow("ipv6-link-%s", a.scopeId().toLatin1().constData()) << a; } @@ -1409,11 +1387,12 @@ void tst_QUdpSocket::setMulticastInterface_data() { QTest::addColumn<QNetworkInterface>("iface"); QTest::addColumn<QHostAddress>("address"); - QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces(); - foreach (const QNetworkInterface &iface, interfaces) { + const QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces(); + for (const QNetworkInterface &iface : interfaces) { if ((iface.flags() & QNetworkInterface::IsUp) == 0) continue; - foreach (const QNetworkAddressEntry &entry, iface.addressEntries()) { + const auto entries = iface.addressEntries(); + for (const QNetworkAddressEntry &entry : entries) { const QByteArray testName = iface.name().toLatin1() + ':' + entry.ip().toString().toLatin1(); QTest::newRow(testName.constData()) << iface << entry.ip(); } @@ -1466,13 +1445,13 @@ void tst_QUdpSocket::multicast_data() QTest::newRow("valid bind, group ipv4 address") << anyAddress << true << groupAddress << true; QTest::newRow("valid bind, invalid group ipv4 address") << anyAddress << true << anyAddress << false; QTest::newRow("valid bind, group ipv6 address") << any6Address << true << group6Address << true; - for (const QHostAddress &a : qAsConst(linklocalMulticastGroups)) + for (const QHostAddress &a : std::as_const(linklocalMulticastGroups)) QTest::addRow("valid bind, %s-link group ipv6 address", a.scopeId().toLatin1().constData()) << any6Address << true << a << true; QTest::newRow("valid bind, invalid group ipv6 address") << any6Address << true << any6Address << false; QTest::newRow("dual bind, group ipv4 address") << dualAddress << true << groupAddress << false; QTest::newRow("dual bind, group ipv6 address") << dualAddress << true << group6Address << true; - for (const QHostAddress &a : qAsConst(linklocalMulticastGroups)) + for (const QHostAddress &a : std::as_const(linklocalMulticastGroups)) QTest::addRow("dual bind, %s-link group ipv6 address", a.scopeId().toLatin1().constData()) << dualAddress << true << a << true; } @@ -1517,15 +1496,16 @@ void tst_QUdpSocket::multicast() if (!joinResult) return; - QList<QByteArray> datagrams = QList<QByteArray>() - << QByteArray("0123") - << QByteArray("4567") - << QByteArray("89ab") - << QByteArray("cdef"); + const QByteArray datagrams[] = { + "0123"_ba, + "4567"_ba, + "89ab"_ba, + "cdef"_ba, + }; QUdpSocket sender; sender.bind(); - foreach (const QByteArray &datagram, datagrams) { + for (const QByteArray &datagram : datagrams) { QNetworkDatagram dgram(datagram, groupAddress, receiver.localPort()); dgram.setInterfaceIndex(interfaceForGroup(groupAddress).index()); QCOMPARE(int(sender.writeDatagram(dgram)), @@ -1568,7 +1548,7 @@ void tst_QUdpSocket::echo() { QFETCH(bool, connect); QHostInfo info = QHostInfo::fromName(QtNetworkSettings::echoServerName()); - QVERIFY(info.addresses().count()); + QVERIFY(info.addresses().size()); QHostAddress remote = info.addresses().first(); QUdpSocket sock; @@ -1595,7 +1575,7 @@ void tst_QUdpSocket::echo() in = sock.read(sock.pendingDatagramSize()); } else { in.resize(sock.pendingDatagramSize()); - sock.readDatagram(in.data(), in.length(), &from, &port); + sock.readDatagram(in.data(), in.size(), &from, &port); } if (in==out) successes++; @@ -1618,7 +1598,8 @@ void tst_QUdpSocket::linkLocalIPv6() QList <QHostAddress> addresses; QSet <QString> scopes; QHostAddress localMask("fe80::"); - foreach (const QNetworkInterface& iface, QNetworkInterface::allInterfaces()) { + const auto ifaces = QNetworkInterface::allInterfaces(); + for (const QNetworkInterface &iface : ifaces) { //Windows preallocates link local addresses to interfaces that are down. //These may or may not work depending on network driver if (iface.flags() & QNetworkInterface::IsUp) { @@ -1633,7 +1614,8 @@ void tst_QUdpSocket::linkLocalIPv6() continue; #endif - foreach (QNetworkAddressEntry addressEntry, iface.addressEntries()) { + const auto entries = iface.addressEntries(); + for (const QNetworkAddressEntry &addressEntry : entries) { QHostAddress addr(addressEntry.ip()); if (!addr.scopeId().isEmpty() && addr.isInSubnet(localMask, 64)) { scopes << addr.scopeId(); @@ -1648,7 +1630,7 @@ void tst_QUdpSocket::linkLocalIPv6() QList <QUdpSocket*> sockets; quint16 port = 0; - foreach (const QHostAddress& addr, addresses) { + for (const QHostAddress &addr : std::as_const(addresses)) { QUdpSocket *s = new QUdpSocket; QVERIFY2(s->bind(addr, port), addr.toString().toLatin1() + '/' + QByteArray::number(port) + ": " + qPrintable(s->errorString())); @@ -1657,7 +1639,7 @@ void tst_QUdpSocket::linkLocalIPv6() } QByteArray testData("hello"); - foreach (QUdpSocket *s, sockets) { + for (QUdpSocket *s : std::as_const(sockets)) { QUdpSocket neutral; QVERIFY(neutral.bind(QHostAddress(QHostAddress::AnyIPv6))); QSignalSpy neutralReadSpy(&neutral, SIGNAL(readyRead())); @@ -1665,27 +1647,26 @@ void tst_QUdpSocket::linkLocalIPv6() QSignalSpy spy(s, SIGNAL(readyRead())); QVERIFY(s->writeDatagram(testData, s->localAddress(), neutral.localPort())); - QTRY_VERIFY(neutralReadSpy.count() > 0); //note may need to accept a firewall prompt + QTRY_VERIFY(neutralReadSpy.size() > 0); //note may need to accept a firewall prompt - QNetworkDatagram dgram = neutral.receiveDatagram(testData.length() * 2); + QNetworkDatagram dgram = neutral.receiveDatagram(testData.size() * 2); QVERIFY(dgram.isValid()); QCOMPARE(dgram.senderAddress(), s->localAddress()); QCOMPARE(dgram.senderPort(), int(s->localPort())); QCOMPARE(dgram.destinationAddress(), s->localAddress()); QCOMPARE(dgram.destinationPort(), int(neutral.localPort())); - QCOMPARE(dgram.data().length(), testData.length()); + QCOMPARE(dgram.data().size(), testData.size()); QCOMPARE(dgram.data(), testData); QVERIFY(neutral.writeDatagram(dgram.makeReply(testData))); - QTRY_VERIFY(spy.count() > 0); //note may need to accept a firewall prompt + QTRY_VERIFY(spy.size() > 0); //note may need to accept a firewall prompt - dgram = s->receiveDatagram(testData.length() * 2); + dgram = s->receiveDatagram(testData.size() * 2); QCOMPARE(dgram.data(), testData); //sockets bound to other interfaces shouldn't have received anything - foreach (QUdpSocket *s2, sockets) { + for (QUdpSocket *s2 : std::as_const(sockets)) QCOMPARE((int)s2->bytesAvailable(), 0); - } //Sending to the same address with different scope should normally fail //However it will pass if there is a route between two interfaces, @@ -1704,7 +1685,8 @@ void tst_QUdpSocket::linkLocalIPv4() QList <QHostAddress> addresses; QHostAddress localMask("169.254.0.0"); - foreach (const QNetworkInterface& iface, QNetworkInterface::allInterfaces()) { + const auto ifaces = QNetworkInterface::allInterfaces(); + for (const QNetworkInterface &iface : ifaces) { //Windows preallocates link local addresses to interfaces that are down. //These may or may not work depending on network driver (they do not work for the Bluetooth PAN driver) if (iface.flags() & QNetworkInterface::IsUp) { @@ -1718,7 +1700,8 @@ void tst_QUdpSocket::linkLocalIPv4() if (iface.name().startsWith("utun")) continue; #endif - foreach (QNetworkAddressEntry addr, iface.addressEntries()) { + const auto entries = iface.addressEntries(); + for (const QNetworkAddressEntry &addr : entries) { if (addr.ip().isInSubnet(localMask, 16)) { addresses << addr.ip(); qDebug() << "Found IPv4 link local address" << addr.ip(); @@ -1731,7 +1714,7 @@ void tst_QUdpSocket::linkLocalIPv4() QList <QUdpSocket*> sockets; quint16 port = 0; - foreach (const QHostAddress& addr, addresses) { + for (const QHostAddress &addr : std::as_const(addresses)) { QUdpSocket *s = new QUdpSocket; QVERIFY2(s->bind(addr, port), qPrintable(s->errorString())); port = s->localPort(); //bind same port, different networks @@ -1742,15 +1725,15 @@ void tst_QUdpSocket::linkLocalIPv4() QVERIFY(neutral.bind(QHostAddress(QHostAddress::AnyIPv4))); QByteArray testData("hello"); - foreach (QUdpSocket *s, sockets) { + for (QUdpSocket *s : std::as_const(sockets)) { QVERIFY(s->writeDatagram(testData, s->localAddress(), neutral.localPort())); QVERIFY2(neutral.waitForReadyRead(10000), QtNetworkSettings::msgSocketError(neutral).constData()); - QNetworkDatagram dgram = neutral.receiveDatagram(testData.length() * 2); + QNetworkDatagram dgram = neutral.receiveDatagram(testData.size() * 2); QVERIFY(dgram.isValid()); QCOMPARE(dgram.senderAddress(), s->localAddress()); QCOMPARE(dgram.senderPort(), int(s->localPort())); - QCOMPARE(dgram.data().length(), testData.length()); + QCOMPARE(dgram.data().size(), testData.size()); QCOMPARE(dgram.data(), testData); // Unlike for IPv6 with IPV6_PKTINFO, IPv4 has no standardized way of @@ -1769,14 +1752,13 @@ void tst_QUdpSocket::linkLocalIPv4() QVERIFY(neutral.writeDatagram(dgram.makeReply(testData))); QVERIFY2(s->waitForReadyRead(10000), QtNetworkSettings::msgSocketError(*s).constData()); - dgram = s->receiveDatagram(testData.length() * 2); + dgram = s->receiveDatagram(testData.size() * 2); QVERIFY(dgram.isValid()); QCOMPARE(dgram.data(), testData); //sockets bound to other interfaces shouldn't have received anything - foreach (QUdpSocket *s2, sockets) { + for (QUdpSocket *s2 : std::as_const(sockets)) QCOMPARE((int)s2->bytesAvailable(), 0); - } } qDeleteAll(sockets); } @@ -1804,7 +1786,7 @@ void tst_QUdpSocket::readyRead() QTest::qWait(100); // make sure only one signal was emitted - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QVERIFY(receiver.hasPendingDatagrams()); #ifdef RELIABLE_BYTES_AVAILABLE QCOMPARE(receiver.bytesAvailable(), qint64(2)); @@ -1816,7 +1798,7 @@ void tst_QUdpSocket::readyRead() // no new signal should be emitted because we haven't read the first datagram yet QTest::qWait(100); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QVERIFY(receiver.hasPendingDatagrams()); QVERIFY(receiver.bytesAvailable() >= 1); // most likely is 1, but it could be 1 + 2 in the future QCOMPARE(receiver.pendingDatagramSize(), qint64(2)); @@ -1828,7 +1810,7 @@ void tst_QUdpSocket::readyRead() // write a new datagram and ensure the signal is emitted now sender.writeDatagram("abc", makeNonAny(receiver.localAddress()), port); QTest::qWait(100); - QCOMPARE(spy.count(), 2); + QCOMPARE(spy.size(), 2); QVERIFY(receiver.hasPendingDatagrams()); #ifdef RELIABLE_BYTES_AVAILABLE QCOMPARE(receiver.bytesAvailable(), qint64(3)); @@ -1908,7 +1890,7 @@ void tst_QUdpSocket::asyncReadDatagram() QTestEventLoop::instance().enterLoop(1); QVERIFY(!QTestEventLoop::instance().timeout()); - QCOMPARE(spy.count(), 2); + QCOMPARE(spy.size(), 2); delete m_asyncSender; delete m_asyncReceiver; @@ -1926,5 +1908,78 @@ void tst_QUdpSocket::writeInHostLookupState() QVERIFY(!socket.putChar('0')); } +void tst_QUdpSocket::readyReadConnectionThrottling() +{ + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; + using namespace std::chrono_literals; + + // QTBUG-105871: + // We have some signal/slot connection throttling in QAbstractSocket, but it + // was caring about the bytes, not about the datagrams. + // Test that we don't disable read notifications until we have at least one + // datagram available. Otherwise our good users who use the datagram APIs + // can get into scenarios where they no longer get the readyRead signal + // unless they call a read function once in a while. + + QUdpSocket receiver; + QVERIFY(receiver.bind(QHostAddress(QHostAddress::LocalHost), 0)); + + QSemaphore semaphore; + + // Repro-ing deterministically eludes me, so we are bruteforcing it: + // The thread acts as a remote sender, flooding the receiver with datagrams, + // and at some point the receiver would get into the broken state mentioned + // earlier. + std::unique_ptr<QThread> thread(QThread::create([&semaphore, port = receiver.localPort()]() { + QUdpSocket sender; + sender.connectToHost(QHostAddress(QHostAddress::LocalHost), port); + QCOMPARE(sender.state(), QUdpSocket::ConnectedState); + + constexpr qsizetype PayloadSize = 242; + const QByteArray payload(PayloadSize, 'a'); + + semaphore.acquire(); // Wait for main thread to be ready + while (true) { + // We send 100 datagrams at a time, then sleep. + // This is mostly to let the main thread catch up between bursts so + // it doesn't get stuck in the loop. + for (int i = 0; i < 100; ++i) { + [[maybe_unused]] + qsizetype sent = sender.write(payload); + Q_ASSERT(sent > 0); + } + if (QThread::currentThread()->isInterruptionRequested()) + break; + QThread::sleep(20ms); + } + })); + thread->start(); + auto threadStopAndWaitGuard = qScopeGuard([&thread] { + thread->requestInterruption(); + thread->quit(); + thread->wait(); + }); + + qsizetype count = 0; + QObject::connect(&receiver, &QUdpSocket::readyRead, &receiver, + [&] { + while (receiver.hasPendingDatagrams()) { + receiver.readDatagram(nullptr, 0); + ++count; + } + // If this prints `false, xxxx` we were pretty much guaranteed + // that we would not get called again: + // qDebug() << receiver.hasPendingDatagrams() << receiver.bytesAvailable(); + }, + Qt::QueuedConnection); + + semaphore.release(); + constexpr qsizetype MaxCount = 500; + QVERIFY2(QTest::qWaitFor([&] { return count >= MaxCount; }, 10s), + QByteArray::number(count).constData()); +} + QTEST_MAIN(tst_QUdpSocket) #include "tst_qudpsocket.moc" diff --git a/tests/auto/network/socket/qudpsocket/udpServer/.prev_CMakeLists.txt b/tests/auto/network/socket/qudpsocket/udpServer/.prev_CMakeLists.txt deleted file mode 100644 index 7796fbe476..0000000000 --- a/tests/auto/network/socket/qudpsocket/udpServer/.prev_CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -# Generated from udpServer.pro. - -##################################################################### -## udpServer Binary: -##################################################################### - -qt_add_executable(udpServer - SOURCES - main.cpp - PUBLIC_LIBRARIES - Qt::Network -) diff --git a/tests/auto/network/socket/qudpsocket/udpServer/CMakeLists.txt b/tests/auto/network/socket/qudpsocket/udpServer/CMakeLists.txt index d4909f94b2..7dd7f2ba5d 100644 --- a/tests/auto/network/socket/qudpsocket/udpServer/CMakeLists.txt +++ b/tests/auto/network/socket/qudpsocket/udpServer/CMakeLists.txt @@ -1,13 +1,14 @@ -# Generated from udpServer.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## udpServer Binary: ##################################################################### -qt_add_executable(udpServer - OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/./" # special case +qt_internal_add_executable(udpServer + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/./" SOURCES main.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Network ) diff --git a/tests/auto/network/socket/qudpsocket/udpServer/main.cpp b/tests/auto/network/socket/qudpsocket/udpServer/main.cpp index a5986c29c7..ba5bb3c0d0 100644 --- a/tests/auto/network/socket/qudpsocket/udpServer/main.cpp +++ b/tests/auto/network/socket/qudpsocket/udpServer/main.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtNetwork> class Server : public QObject diff --git a/tests/auto/network/socket/qudpsocket/udpServer/udpServer.pro b/tests/auto/network/socket/qudpsocket/udpServer/udpServer.pro deleted file mode 100644 index c8f9ebf648..0000000000 --- a/tests/auto/network/socket/qudpsocket/udpServer/udpServer.pro +++ /dev/null @@ -1,3 +0,0 @@ -SOURCES += main.cpp -QT = core network -CONFIG += cmdline diff --git a/tests/auto/network/socket/socket.pro b/tests/auto/network/socket/socket.pro deleted file mode 100644 index 1248d71172..0000000000 --- a/tests/auto/network/socket/socket.pro +++ /dev/null @@ -1,22 +0,0 @@ -TEMPLATE=subdirs -QT_FOR_CONFIG += network - -SUBDIRS=\ - qhttpsocketengine \ - qudpsocket \ - qtcpsocket \ - qlocalsocket \ - qtcpserver \ - qsocks5socketengine \ - qabstractsocket \ - platformsocketengine \ - qsctpsocket \ - -!qtConfig(private_tests): SUBDIRS -= \ - platformsocketengine \ - qtcpsocket \ - qhttpsocketengine \ - qsocks5socketengine \ - -!qtConfig(sctp): SUBDIRS -= \ - qsctpsocket \ diff --git a/tests/auto/network/ssl/CMakeLists.txt b/tests/auto/network/ssl/CMakeLists.txt index 6d4dc15cc8..b11b15b6ba 100644 --- a/tests/auto/network/ssl/CMakeLists.txt +++ b/tests/auto/network/ssl/CMakeLists.txt @@ -1,17 +1,21 @@ -# Generated from ssl.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause add_subdirectory(qpassworddigestor) -add_subdirectory(qsslcertificate) -add_subdirectory(qsslcipher) -add_subdirectory(qsslellipticcurve) -add_subdirectory(qsslerror) -add_subdirectory(qsslkey) +if(QT_FEATURE_ssl) + add_subdirectory(qsslcertificate) + add_subdirectory(qsslcipher) + add_subdirectory(qsslellipticcurve) + add_subdirectory(qsslkey) + add_subdirectory(qsslerror) +endif() if(QT_FEATURE_private_tests AND QT_FEATURE_ssl) add_subdirectory(qsslsocket) add_subdirectory(qsslsocket_onDemandCertificates_member) add_subdirectory(qsslsocket_onDemandCertificates_static) add_subdirectory(qasn1element) add_subdirectory(qssldiffiehellmanparameters) + add_subdirectory(qsslserver) endif() if(QT_FEATURE_dtls AND QT_FEATURE_private_tests AND QT_FEATURE_ssl) add_subdirectory(qdtlscookie) diff --git a/tests/auto/network/ssl/qasn1element/CMakeLists.txt b/tests/auto/network/ssl/qasn1element/CMakeLists.txt index a97a213603..7b01a0b22d 100644 --- a/tests/auto/network/ssl/qasn1element/CMakeLists.txt +++ b/tests/auto/network/ssl/qasn1element/CMakeLists.txt @@ -1,13 +1,26 @@ -# Generated from qasn1element.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qasn1element Test: ##################################################################### -qt_add_test(tst_qasn1element +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qasn1element LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qasn1element SOURCES tst_qasn1element.cpp - PUBLIC_LIBRARIES + ../../../../../src/plugins/tls/shared/qasn1element_p.h + ../../../../../src/plugins/tls/shared/qasn1element.cpp + INCLUDE_DIRECTORIES + ../../../../../src/plugins/tls/shared + LIBRARIES + Qt::Core Qt::Network Qt::NetworkPrivate + BUNDLE_ANDROID_OPENSSL_LIBS ) diff --git a/tests/auto/network/ssl/qasn1element/qasn1element.pro b/tests/auto/network/ssl/qasn1element/qasn1element.pro deleted file mode 100644 index 006ac3428c..0000000000 --- a/tests/auto/network/ssl/qasn1element/qasn1element.pro +++ /dev/null @@ -1,6 +0,0 @@ -CONFIG += testcase - -SOURCES += tst_qasn1element.cpp -QT = core network network-private testlib - -TARGET = tst_qasn1element diff --git a/tests/auto/network/ssl/qasn1element/tst_qasn1element.cpp b/tests/auto/network/ssl/qasn1element/tst_qasn1element.cpp index eb11384101..a54f0bd9d8 100644 --- a/tests/auto/network/ssl/qasn1element/tst_qasn1element.cpp +++ b/tests/auto/network/ssl/qasn1element/tst_qasn1element.cpp @@ -1,34 +1,12 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org> -** 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 "private/qasn1element_p.h" +// Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "qasn1element_p.h" + +#include <QTest> + +#include <QtCore/QDateTime> +#include <QtCore/QTimeZone> class tst_QAsn1Element : public QObject { @@ -127,7 +105,7 @@ void tst_QAsn1Element::dateTime_data() << QDateTime(); QTest::newRow("UTCTime - 070417074026Z") << QByteArray::fromHex("170d3037303431373037343032365a") - << QDateTime(QDate(2007, 4, 17), QTime(7, 40, 26), Qt::UTC); + << QDateTime(QDate(2007, 4, 17), QTime(7, 40, 26), QTimeZone::UTC); QTest::newRow("UTCTime - bad length") << QByteArray::fromHex("170c30373034313730373430325a") << QDateTime(); @@ -136,16 +114,19 @@ void tst_QAsn1Element::dateTime_data() << QDateTime(); QTest::newRow("UTCTime - year 1950") << QByteArray::fromHex("170d3530313232343035353530305a") - << QDateTime(QDate(1950, 12, 24), QTime(5, 55), Qt::UTC); + << QDateTime(QDate(1950, 12, 24), QTime(5, 55), QTimeZone::UTC); QTest::newRow("UTCTime - year 1999") << QByteArray::fromHex("170d3939313232343035353530305a") - << QDateTime(QDate(1999, 12, 24), QTime(5, 55), Qt::UTC); + << QDateTime(QDate(1999, 12, 24), QTime(5, 55), QTimeZone::UTC); QTest::newRow("UTCTime - year 2000") << QByteArray::fromHex("170d3030313232343035353530305a") - << QDateTime(QDate(2000, 12, 24), QTime(5, 55), Qt::UTC); + << QDateTime(QDate(2000, 12, 24), QTime(5, 55), QTimeZone::UTC); + QTest::newRow("UTCTime - leap day year 2000") + << QByteArray::fromHex("170d3030303232393035353530305a") + << QDateTime(QDate(2000, 2, 29), QTime(5, 55), QTimeZone::UTC); QTest::newRow("UTCTime - year 2049") << QByteArray::fromHex("170d3439313232343035353530305a") - << QDateTime(QDate(2049, 12, 24), QTime(5, 55), Qt::UTC); + << QDateTime(QDate(2049, 12, 24), QTime(5, 55), QTimeZone::UTC); QTest::newRow("UTCTime - invalid year ('-9')") << QByteArray::fromHex("170d2d39313232343035353530305a") << QDateTime(); @@ -163,7 +144,7 @@ void tst_QAsn1Element::dateTime_data() << QDateTime(); QTest::newRow("GeneralizedTime - 20510829095341Z") << QByteArray::fromHex("180f32303531303832393039353334315a") - << QDateTime(QDate(2051, 8, 29), QTime(9, 53, 41), Qt::UTC); + << QDateTime(QDate(2051, 8, 29), QTime(9, 53, 41), QTimeZone::UTC); QTest::newRow("GeneralizedTime - bad length") << QByteArray::fromHex("180e323035313038323930393533345a") << QDateTime(); diff --git a/tests/auto/network/ssl/qdtls/CMakeLists.txt b/tests/auto/network/ssl/qdtls/CMakeLists.txt index 8072d8d0e0..1d5eef094c 100644 --- a/tests/auto/network/ssl/qdtls/CMakeLists.txt +++ b/tests/auto/network/ssl/qdtls/CMakeLists.txt @@ -1,25 +1,24 @@ -# Generated from qdtls.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qdtls Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qdtls LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + # Collect test data list(APPEND test_data "certs") -qt_add_test(tst_qdtls +qt_internal_add_test(tst_qdtls SOURCES tst_qdtls.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::NetworkPrivate TESTDATA ${test_data} + BUNDLE_ANDROID_OPENSSL_LIBS ) - -## Scopes: -##################################################################### - -#### Keys ignored in scope 3:.:.:qdtls.pro:(CMAKE_BUILD_TYPE STREQUAL Debug): -# DESTDIR = "debug" - -#### Keys ignored in scope 4:.:.:qdtls.pro:else: -# DESTDIR = "release" diff --git a/tests/auto/network/ssl/qdtls/certs/fluke.cert b/tests/auto/network/ssl/qdtls/certs/fluke.cert index ace4e4f0eb..4cc4d9a5ea 100644 --- a/tests/auto/network/ssl/qdtls/certs/fluke.cert +++ b/tests/auto/network/ssl/qdtls/certs/fluke.cert @@ -1,75 +1,34 @@ -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 +MIIF6zCCA9OgAwIBAgIUfo9amJtJGWqWE6f+SkAO85zkGr4wDQYJKoZIhvcNAQEL +BQAwgYMxCzAJBgNVBAYTAk5PMQ0wCwYDVQQIDARPc2xvMQ0wCwYDVQQHDARPc2xv +MRcwFQYDVQQKDA5UaGUgUXQgQ29tcGFueTEMMAoGA1UECwwDUiZEMRIwEAYDVQQD +DAlIMiBUZXN0ZXIxGzAZBgkqhkiG9w0BCQEWDG1pbmltaUBxdC5pbzAgFw0yMDEw +MjYxMjAxMzFaGA8yMTIwMTAwMjEyMDEzMVowgYMxCzAJBgNVBAYTAk5PMQ0wCwYD +VQQIDARPc2xvMQ0wCwYDVQQHDARPc2xvMRcwFQYDVQQKDA5UaGUgUXQgQ29tcGFu +eTEMMAoGA1UECwwDUiZEMRIwEAYDVQQDDAlIMiBUZXN0ZXIxGzAZBgkqhkiG9w0B +CQEWDG1pbmltaUBxdC5pbzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +AOiUp5+E4blouKH7q+rVNR8NoYX2XkBW+q+rpy1zu5ssRSzbqxAjDx9dkht7Qlnf +VlDT00JvpOWdeuPon5915edQRsY4Unl6mKH29ra3OtUa1/yCJXsGVJTKCj7k4Bxb +5mZzb/fTlZntMLdTIBMfUbw62FKir1WjKIcJ9fCoG8JaGeKVO4Rh5p0ezd4UUUId +r1BXl5Nqdqy2vTMsEDnjOsD3egkv8I2SKN4O6n/C3wWYpMOWYZkGoZiKz7rJs/i/ +ez7bsV7JlwdzTlhpJzkcOSVFBP6JlEOxTNNxZ1wtKy7PtZGmsSSATq2e6+bw38Ae +Op0XnzzqcGjtDDofBmT7OFzZWjS9VZS6+DOOe2QHWle1nCHcHyH4ku6IRlsr9xkR +NAIlOfnvHHxqJUenoeaZ4oQDjCBKS1KXygJO/tL7BLTQVn/xK1EmPvKNnjzWk4tR +PnibUhhs5635qpOU/YPqFBh1JjVruZbsWcDAhRcew0uxONXOa9E+4lttQ9ySYa1A +LvWqJuAX7gu2BsBMLyqfm811YnA7CIFMyO+HlqmkLFfv5L/xIRAXR7l26YGO0VwX +CGjMfz4NVPMMke4nB7qa9NkpXQBQKMms3Qzd5JW0Hy9Ruj5O8GPcFZmV0twjd1uJ +PD/cAjkWLaXjdNsJ16QWc2nghQRS6HYqKRX6j+CXOxupAgMBAAGjUzBRMB0GA1Ud +DgQWBBRSCOU58j9NJZkMamt623qyCrhN3TAfBgNVHSMEGDAWgBRSCOU58j9NJZkM +amt623qyCrhN3TAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQCq +q4jxsWeNDv5Nq14hJtF9HB+ZL64zcZtRjJP1YgNs0QppKICmjPOL2nIMGmI/jKrs +0eGAL/9XXNVHPxm1OPOncvimMMmU6emZfpMdEtTfKP43+Pg9HgKRjLoQp406vGeQ +8ki/mbBhrItVPgEm3tu2AFA02XTYi+YxCI9kRZLGkM3FbgtOuTLPl0Z9y+kiPc9F +uCSC03anBEqv+vDSI8+wODymQ/IJ3Jyz1lxIRDfp4qAekmy0jU2c91VOHHEmOmqq +kqygGFRdwbe99m9yP63r6q0b5K3X2UnJ6bns0hmTwThYwpVPXLU8jdaTddbMukN2 +/Ef96Tsw8nWOEOPMySHOTIPgwyZRp26b0kA9EmhLwOP401SxXVQCmSRmtwNagmtg +jJKmZoYBN+//D45ibK8z6Q0oOm9P+Whf/uUXehcRxBxyV3xz7k0wKGQbHj/ddwcy +IUoIN4lrAlib+lK170kTKN352PDmrpo2gmIzPEsfurKAIMSelDl6H+kih16BtZ8y +Nz6fh9Soqrg3OSAware8pxV7k51crBMoPLN78KoRV8MFCK4K7Fddq4rRISq6hiXq +r1nsjoEPuKM9huprmZVZe9t5YcDa2I+wb3IiE3uwpZbAdaLDyQ5n6F/qpsiIkZXn +gtcF7oqpG5oYrwCcZ53y/ezUgUg7PlSz2XwAGvQtgg== -----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qdtls/certs/fluke.key b/tests/auto/network/ssl/qdtls/certs/fluke.key index 9d1664d609..337ce541a6 100644 --- a/tests/auto/network/ssl/qdtls/certs/fluke.key +++ b/tests/auto/network/ssl/qdtls/certs/fluke.key @@ -1,15 +1,52 @@ ------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----- +-----BEGIN PRIVATE KEY----- +MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQDolKefhOG5aLih ++6vq1TUfDaGF9l5AVvqvq6ctc7ubLEUs26sQIw8fXZIbe0JZ31ZQ09NCb6TlnXrj +6J+fdeXnUEbGOFJ5epih9va2tzrVGtf8giV7BlSUygo+5OAcW+Zmc2/305WZ7TC3 +UyATH1G8OthSoq9VoyiHCfXwqBvCWhnilTuEYeadHs3eFFFCHa9QV5eTanastr0z +LBA54zrA93oJL/CNkijeDup/wt8FmKTDlmGZBqGYis+6ybP4v3s+27FeyZcHc05Y +aSc5HDklRQT+iZRDsUzTcWdcLSsuz7WRprEkgE6tnuvm8N/AHjqdF5886nBo7Qw6 +HwZk+zhc2Vo0vVWUuvgzjntkB1pXtZwh3B8h+JLuiEZbK/cZETQCJTn57xx8aiVH +p6HmmeKEA4wgSktSl8oCTv7S+wS00FZ/8StRJj7yjZ481pOLUT54m1IYbOet+aqT +lP2D6hQYdSY1a7mW7FnAwIUXHsNLsTjVzmvRPuJbbUPckmGtQC71qibgF+4LtgbA +TC8qn5vNdWJwOwiBTMjvh5appCxX7+S/8SEQF0e5dumBjtFcFwhozH8+DVTzDJHu +Jwe6mvTZKV0AUCjJrN0M3eSVtB8vUbo+TvBj3BWZldLcI3dbiTw/3AI5Fi2l43Tb +CdekFnNp4IUEUuh2KikV+o/glzsbqQIDAQABAoICAFw1q6tr5I48vY7DF+rXsuLn +5ZUWE1IQ6fzB4lr72nJv/9EEGnMgYzt9PpMUsD6vdCpBgS2C0+6RHArFzJtNA+RM +iHLIG7K7702veyr/xBx/MwiSlMeMv/XpkFxVI6E6skMGG2s3AMXxKvJTy5CpRx+I +eQFyLG+Ya1X2lgJes/q+/CpAHkOjCOpcLySQC5NZ74q734V7nSdmn+Zs3tYEh+O/ +eiuwTP/j5b38Te5vVTqDxTciJPmljmXLCwa0N100lWlbcpvw8qbqiTI2Jm3XCbUE +AzHjW9vmrF3cRS1fXxKFGShw3SRqlkbxjfeWoi8qDPUBS4m8LOr8qG9Wo5Nfon0z +zLP4bci3zHDvVcaaZrrsUBs/yZbg+Dgka1DmX7ekmeccr2yTdKDFgPupYUyxVbTl +a9ZLJysjFD7rgBv1ZclHonLp6Vbm+ZoTqvteo4ikAy6L9RtBWJ23XEK34PkP/+c5 +2vWZaOrnjSeBHbFce8cdJSxqWpP+eSCI5I9XbDrYFIsQ/gqKgtzDKy2ihJ2Y8STL +yO4hyFPFjxc+Gg4/P2PpmT5CY2ty44M0BWs+JGW96CJPrrplf2lmQUQJj5LZY66X +Z/4C9L7ZYtKZ+bs5SvU46yWugAvQZX22Xm9xLXWyVXRdx3bj+3M3fDnF9di/zdbh +CgLx7oWPNrXc7FCajnn9AoIBAQD5FMYwRpw9NWT9WDxQwx+cSI4Icbd88ByTW63S +LzeRwZA0J9/SfwO+aBRupzc9GkGXCiZcGMw3AGsCtig8yFlw8E5KnzN7KlftDMnM +9NUxxzlR8VwKyLnZfG7sDTl057ZlUujnqhmt/F8F7dIy7FVO1dE/8nngA+FYTCOG +UZdGjwyBDlDM0JJdUWGY3xslutcpCDN5mzSTKjy9drMvImAshRawxRF6WBpn7vr2 +nC6vciqfx1Mzx1vyk0Jm0ilaydDdLMADjt/iL4Nkr0BEs4k+UzQiKDwp8gu7abQ1 +eBfxd9Iar4htQa2I1Ewl6P01G/q+ZYwgHhJ9RVn4AxQXefILAoIBAQDvCouORdQX +C8wsyp7MwXlF/3NQeNN5/+B2mhbxrBOf7PmMCXLnkRWcjwJtzypWFqJ0sqai/2+0 +bqbMcjX5maT8stT2shl3zXe/Ejt2e3TBYpc1tyuses8Kb5BMU8hu6tTd3G2CMXpD +dT6DVemJZCTtwj9aBNIxSizvlgMolJnCpzhPnlfHSI6E+g3m/LTTo3HwbjMSw/Uq +irgjOpI2wSBB6LZPSgjvfcYPRyWUk16L4A5uSX0cADnovDFLa5/h0wJvN/OoCSQg +rLCXG5E18EyL5Wc58BCY1ZvxmjG3lQtgPxYu2Jwc36R/y/JKlxW5suER5ZNpbbD4 +uOyTt2VxMQ2bAoIBAQC5+MzRFqdo/AjfL5Y5JrbfVTzXCTDa09xCGd16ZU60QTWN ++4ed/r+o1sUKqUcRFB2MzEM/2DQBjQpZB/CbEWvWa1XJWXxypXbowveZU+QqOnmN +uQvj8WLyA3o+PNF9e9QvauwCrHpn8VpxbtPWuaYoKnUFreFZZQxHhPGxRBIS2JOZ +eDrT8ZaWnkCkh1AZp5smQ71LOprSlmKrg4jd1GjCVMxQR5N5KXbtyv0OTCZ/UFqK +2aRBsMPyJgkaBChkZPLRcKwc+/wlQRx1fHQb14DNTApMxoXFO7eOwqmOkpAt9iyl +SBIwoS0UUI5ab88+bBmXNvKcuFdNuQ4nowTJUn9pAoIBADMNkILBXSvS5DeIyuO2 +Sp1tkoZUV+5NfPY3sMDK3KIibaW/+t+EOBZo4L7tKQCb8vRzl21mmsfxfgRaPDbj +3r3tv9g0b4YLxxBy52pFscj/soXRai17SS7UZwA2QK+XzgDYbDcLNC6mIsTQG4Gx +dsWk3/zs3KuUSQaehmwrWK+fIUK38c1pLK8v7LoxrLkqxlHwZ04RthHw8KTthH7X +Pnl1J0LF8CSeOyfWLSuPUfkT0GEzptnNHpEbaHfQM6R6eaGhVJPF6AZme4y6YYgg +m2ihhSt1n0XVEWpHYWjxFy3mK2mz75unFC4LM+NEY2p2zuUQoCw7NjnY3QYrfCnx +rRMCggEAXeXsMSLFjjyuoL7iKbAxo52HD/P0fBoy58LyRcwfNVr0lvYan4pYEx+o +KijIh9K16PqXZXKMA9v003B+ulmF8bJ7SddCZ5NGvnFhUTDe4DdTKgp2RuwQ3Bsc +3skPIDbhVETyOLCtys34USHrq8U/0DlGY3eLRfxw9GnbKxSBGa/KEu/qQLPNUo50 +7xHZDg7GKeC3kqNJeqKM9rkp0VzIGkEnaD9127LeNDmERDfftxJzFoC/THvUBLfU +6Sus2ZYwRE8VFvKC30Q45t/c54X3IuhYvAuiCuTmyfE4ruyzyOwKzhUkeeLq1APX +g0veFbyfzlJ0q8qzD/iffqqIa2ZSmQ== +-----END PRIVATE KEY----- diff --git a/tests/auto/network/ssl/qdtls/qdtls.pro b/tests/auto/network/ssl/qdtls/qdtls.pro deleted file mode 100644 index 19e13a965c..0000000000 --- a/tests/auto/network/ssl/qdtls/qdtls.pro +++ /dev/null @@ -1,16 +0,0 @@ -CONFIG += testcase - -SOURCES += tst_qdtls.cpp -QT = core network-private testlib - -TARGET = tst_qdtls - -win32 { - CONFIG(debug, debug|release) { - DESTDIR = debug - } else { - DESTDIR = release - } -} - -TESTDATA += certs diff --git a/tests/auto/network/ssl/qdtls/tst_qdtls.cpp b/tests/auto/network/ssl/qdtls/tst_qdtls.cpp index fd51c091a8..372ee3a181 100644 --- a/tests/auto/network/ssl/qdtls/tst_qdtls.cpp +++ b/tests/auto/network/ssl/qdtls/tst_qdtls.cpp @@ -1,32 +1,8 @@ -/**************************************************************************** -** -** Copyright (C) 2018 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> +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QTest> +#include <QTestEventLoop> #include <QtNetwork/qsslpresharedkeyauthenticator.h> #include <QtNetwork/qsslconfiguration.h> @@ -39,14 +15,19 @@ #include <QtNetwork/qdtls.h> #include <QtNetwork/qssl.h> -#include <QtCore/qbytearray.h> #include <QtCore/qcryptographichash.h> -#include <QtCore/qlist.h> +#include <QtCore/qscopeguard.h> +#include <QtCore/qbytearray.h> #include <QtCore/qobject.h> #include <QtCore/qstring.h> +#include <QtCore/qlist.h> + +#include "../shared/tlshelpers.h" #include <algorithm> +using namespace std::chrono_literals; + QT_BEGIN_NAMESPACE namespace @@ -148,8 +129,8 @@ private: DtlsPtr clientCrypto; QTestEventLoop testLoop; - const int handshakeTimeoutMS = 5000; - const int dataExchangeTimeoutMS = 1000; + static constexpr auto HandshakeTimeout = 5s; + static constexpr auto DataExchangeTimeout = 1s; const QByteArray presharedKey = "DEADBEEFDEADBEEF"; QString certDirPath; @@ -165,8 +146,13 @@ Q_DECLARE_METATYPE(QSslKey) QT_BEGIN_NAMESPACE +void qt_ForceTlsSecurityLevel(); + void tst_QDtls::initTestCase() { + if (!TlsAux::classImplemented(QSsl::ImplementedClass::Dtls)) + QSKIP("The active TLS backend does not support DTLS"); + certDirPath = QFileInfo(QFINDTESTDATA("certs")).absolutePath(); QVERIFY(certDirPath.size() > 0); certDirPath += QDir::separator() + QStringLiteral("certs") + QDir::separator(); @@ -189,7 +175,6 @@ void tst_QDtls::initTestCase() hostName = QStringLiteral("bob.org"); - void qt_ForceTlsSecurityLevel(); qt_ForceTlsSecurityLevel(); } @@ -287,7 +272,7 @@ void tst_QDtls::configuration() QFETCH(const QSslSocket::SslMode, mode); QDtls dtls(mode); QCOMPARE(dtls.dtlsConfiguration(), config); - config.setProtocol(QSsl::DtlsV1_0OrLater); + config.setProtocol(QSsl::DtlsV1_2); config.setDtlsCookieVerificationEnabled(false); QCOMPARE(config.dtlsCookieVerificationEnabled(), false); @@ -311,6 +296,19 @@ void tst_QDtls::configuration() QCOMPARE(dtls.dtlsError(), QDtlsError::InvalidOperation); QCOMPARE(dtls.dtlsConfiguration(), config); } + + static bool doneAlready = false; + if (!doneAlready) { + doneAlready = true; + QSslConfiguration nullConfig; + const auto defaultDtlsConfig = QSslConfiguration::defaultDtlsConfiguration(); + const auto restoreDefault = qScopeGuard([&defaultDtlsConfig] { + QSslConfiguration::setDefaultDtlsConfiguration(defaultDtlsConfig); + }); + QSslConfiguration::setDefaultDtlsConfiguration(nullConfig); + QCOMPARE(QSslConfiguration::defaultDtlsConfiguration(), nullConfig); + QVERIFY(QSslConfiguration::defaultDtlsConfiguration() != defaultDtlsConfig); + } } void tst_QDtls::invalidConfiguration() @@ -417,7 +415,7 @@ void tst_QDtls::handshake() QDTLS_VERIFY_NO_ERROR(clientCrypto); QCOMPARE(clientCrypto->handshakeState(), QDtls::HandshakeInProgress); - testLoop.enterLoopMSecs(handshakeTimeoutMS); + testLoop.enterLoop(HandshakeTimeout); QVERIFY(!testLoop.timeout()); @@ -477,7 +475,7 @@ void tst_QDtls::handshakeWithRetransmission() // client will re-transmit in 1s., the first part of 'ServerHello' to be // dropped, the client then will re-transmit after another 2 s. Thus it's ~3. // We err on safe side and double our (already quite generous) 5s. - testLoop.enterLoopMSecs(handshakeTimeoutMS * 2); + testLoop.enterLoop(HandshakeTimeout * 2); QVERIFY(!testLoop.timeout()); QDTLS_VERIFY_HANDSHAKE_SUCCESS(serverCrypto); @@ -500,7 +498,7 @@ void tst_QDtls::sessionCipher() QVERIFY(clientCrypto->setPeer(serverAddress, serverPort, hostName)); QVERIFY(clientCrypto->doHandshake(&clientSocket)); - testLoop.enterLoopMSecs(handshakeTimeoutMS); + testLoop.enterLoop(HandshakeTimeout); QVERIFY(!testLoop.timeout()); QDTLS_VERIFY_HANDSHAKE_SUCCESS(clientCrypto); @@ -563,7 +561,7 @@ void tst_QDtls::cipherPreferences() QVERIFY(clientCrypto->doHandshake(&clientSocket)); QDTLS_VERIFY_NO_ERROR(clientCrypto); - testLoop.enterLoopMSecs(handshakeTimeoutMS); + testLoop.enterLoop(HandshakeTimeout); QVERIFY(!testLoop.timeout()); QDTLS_VERIFY_HANDSHAKE_SUCCESS(clientCrypto); QDTLS_VERIFY_HANDSHAKE_SUCCESS(serverCrypto); @@ -583,20 +581,36 @@ void tst_QDtls::protocolVersionMatching_data() QTest::addColumn<QSsl::SslProtocol>("clientProtocol"); QTest::addColumn<bool>("works"); - QTest::addRow("DtlsV1_0 <-> DtlsV1_0") << QSsl::DtlsV1_0 << QSsl::DtlsV1_0 << true; - QTest::addRow("DtlsV1_0OrLater <-> DtlsV1_0") << QSsl::DtlsV1_0OrLater << QSsl::DtlsV1_0 << true; - QTest::addRow("DtlsV1_0 <-> DtlsV1_0OrLater") << QSsl::DtlsV1_0 << QSsl::DtlsV1_0OrLater << true; - QTest::addRow("DtlsV1_0OrLater <-> DtlsV1_0OrLater") << QSsl::DtlsV1_0OrLater << QSsl::DtlsV1_0OrLater << true; + //OPENSSL_VERSION_NUMBER : + //(OPENSSL_VERSION_MAJOR<<28) | (OPENSSL_VERSION_MINOR<<20) | (OPENSSL_VERSION_PATCH<<4) + const long ossl311 = 0x30100010; + + if (QSslSocket::sslLibraryVersionNumber() < ossl311) { +#if QT_DEPRECATED_SINCE(6, 3) +QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED + QTest::addRow("DtlsV1_0 <-> DtlsV1_0") << QSsl::DtlsV1_0 << QSsl::DtlsV1_0 << true; + QTest::addRow("DtlsV1_0OrLater <-> DtlsV1_0") << QSsl::DtlsV1_0OrLater << QSsl::DtlsV1_0 << true; + QTest::addRow("DtlsV1_0 <-> DtlsV1_0OrLater") << QSsl::DtlsV1_0 << QSsl::DtlsV1_0OrLater << true; + QTest::addRow("DtlsV1_0OrLater <-> DtlsV1_0OrLater") << QSsl::DtlsV1_0OrLater << QSsl::DtlsV1_0OrLater << true; +QT_WARNING_POP +#endif // QT_DEPRECATED_SINCE(6, 3) + } QTest::addRow("DtlsV1_2 <-> DtlsV1_2") << QSsl::DtlsV1_2 << QSsl::DtlsV1_2 << true; QTest::addRow("DtlsV1_2OrLater <-> DtlsV1_2") << QSsl::DtlsV1_2OrLater << QSsl::DtlsV1_2 << true; QTest::addRow("DtlsV1_2 <-> DtlsV1_2OrLater") << QSsl::DtlsV1_2 << QSsl::DtlsV1_2OrLater << true; QTest::addRow("DtlsV1_2OrLater <-> DtlsV1_2OrLater") << QSsl::DtlsV1_2OrLater << QSsl::DtlsV1_2OrLater << true; - QTest::addRow("DtlsV1_0 <-> DtlsV1_2") << QSsl::DtlsV1_0 << QSsl::DtlsV1_2 << false; - QTest::addRow("DtlsV1_0 <-> DtlsV1_2OrLater") << QSsl::DtlsV1_0 << QSsl::DtlsV1_2OrLater << false; - QTest::addRow("DtlsV1_2 <-> DtlsV1_0") << QSsl::DtlsV1_2 << QSsl::DtlsV1_0 << false; - QTest::addRow("DtlsV1_2OrLater <-> DtlsV1_0") << QSsl::DtlsV1_2OrLater << QSsl::DtlsV1_0 << false; + if (QSslSocket::sslLibraryVersionNumber() < ossl311) { +#if QT_DEPRECATED_SINCE(6, 3) +QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED + QTest::addRow("DtlsV1_0 <-> DtlsV1_2") << QSsl::DtlsV1_0 << QSsl::DtlsV1_2 << false; + QTest::addRow("DtlsV1_0 <-> DtlsV1_2OrLater") << QSsl::DtlsV1_0 << QSsl::DtlsV1_2OrLater << false; + QTest::addRow("DtlsV1_2 <-> DtlsV1_0") << QSsl::DtlsV1_2 << QSsl::DtlsV1_0 << false; + QTest::addRow("DtlsV1_2OrLater <-> DtlsV1_0") << QSsl::DtlsV1_2OrLater << QSsl::DtlsV1_0 << false; +QT_WARNING_POP +#endif // QT_DEPRECATED_SINCE(6, 3 + } } void tst_QDtls::protocolVersionMatching() @@ -622,7 +636,7 @@ void tst_QDtls::protocolVersionMatching() QVERIFY(clientCrypto->setPeer(serverAddress, serverPort)); QVERIFY(clientCrypto->doHandshake(&clientSocket)); - testLoop.enterLoopMSecs(handshakeTimeoutMS); + testLoop.enterLoop(HandshakeTimeout); if (works) { QDTLS_VERIFY_HANDSHAKE_SUCCESS(serverCrypto); @@ -657,7 +671,7 @@ void tst_QDtls::verificationErrors() // Now we are ready for handshake: QVERIFY(clientCrypto->doHandshake(&clientSocket)); - testLoop.enterLoopMSecs(handshakeTimeoutMS); + testLoop.enterLoop(HandshakeTimeout); QVERIFY(!testLoop.timeout()); QDTLS_VERIFY_NO_ERROR(serverCrypto); @@ -727,7 +741,7 @@ void tst_QDtls::presetExpectedErrors() QVERIFY(clientCrypto->setPeer(serverAddress, serverPort)); QVERIFY(clientCrypto->doHandshake(&clientSocket)); - testLoop.enterLoopMSecs(handshakeTimeoutMS); + testLoop.enterLoop(HandshakeTimeout); QVERIFY(!testLoop.timeout()); @@ -814,7 +828,7 @@ void tst_QDtls::verifyServerCertificate() QVERIFY(clientCrypto->doHandshake(&clientSocket)); - testLoop.enterLoopMSecs(handshakeTimeoutMS); + testLoop.enterLoop(HandshakeTimeout); QVERIFY(!testLoop.timeout()); if (serverKey.isNull() && !serverCerts.isEmpty()) { @@ -944,7 +958,7 @@ void tst_QDtls::verifyClientCertificate() QVERIFY(clientCrypto->doHandshake(&clientSocket)); QDTLS_VERIFY_NO_ERROR(clientCrypto); - testLoop.enterLoopMSecs(handshakeTimeoutMS); + testLoop.enterLoop(HandshakeTimeout); serverConfig = serverCrypto->dtlsConfiguration(); @@ -991,7 +1005,7 @@ void tst_QDtls::blacklistedCerificate() QVERIFY(clientCrypto->setPeer(serverAddress, serverPort, name)); QVERIFY(clientCrypto->doHandshake(&clientSocket)); - testLoop.enterLoopMSecs(handshakeTimeoutMS); + testLoop.enterLoop(HandshakeTimeout); QVERIFY(!testLoop.timeout()); QCOMPARE(clientCrypto->handshakeState(), QDtls::PeerVerificationFailed); QCOMPARE(clientCrypto->dtlsError(), QDtlsError::PeerVerificationError); @@ -1043,7 +1057,7 @@ void tst_QDtls::readWriteEncrypted() QCOMPARE(clientCrypto->dtlsError(), QDtlsError::InvalidOperation); // 1.2 Finish the handshake: - testLoop.enterLoopMSecs(handshakeTimeoutMS); + testLoop.enterLoop(HandshakeTimeout); QVERIFY(!testLoop.timeout()); QDTLS_VERIFY_HANDSHAKE_SUCCESS(clientCrypto); @@ -1061,7 +1075,7 @@ void tst_QDtls::readWriteEncrypted() QVERIFY(clientBytesWritten > 0); // 5. Exchange client/server messages: - testLoop.enterLoopMSecs(dataExchangeTimeoutMS); + testLoop.enterLoop(DataExchangeTimeout); QVERIFY(!testLoop.timeout()); QCOMPARE(serverExpectedPlainText, serverReceivedPlainText); @@ -1079,7 +1093,7 @@ void tst_QDtls::readWriteEncrypted() QCOMPARE(crypto->handshakeState(), QDtls::HandshakeNotStarted); QVERIFY(!crypto->isConnectionEncrypted()); // 8. Receive this read notification and handle it: - testLoop.enterLoopMSecs(dataExchangeTimeoutMS); + testLoop.enterLoop(DataExchangeTimeout); QVERIFY(!testLoop.timeout()); DtlsPtr &peerCrypto = serverSideShutdown ? clientCrypto : serverCrypto; @@ -1104,7 +1118,7 @@ void tst_QDtls::datagramFragmentation() QVERIFY(clientCrypto->doHandshake(&clientSocket)); - testLoop.enterLoopMSecs(handshakeTimeoutMS); + testLoop.enterLoop(HandshakeTimeout); QVERIFY(!testLoop.timeout()); QDTLS_VERIFY_HANDSHAKE_SUCCESS(clientCrypto); diff --git a/tests/auto/network/ssl/qdtlscookie/CMakeLists.txt b/tests/auto/network/ssl/qdtlscookie/CMakeLists.txt index c08bf6150a..d965c7efb6 100644 --- a/tests/auto/network/ssl/qdtlscookie/CMakeLists.txt +++ b/tests/auto/network/ssl/qdtlscookie/CMakeLists.txt @@ -1,21 +1,20 @@ -# Generated from qdtlscookie.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qdtlscookie Test: ##################################################################### -qt_add_test(tst_qdtlscookie +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qdtlscookie LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qdtlscookie SOURCES tst_qdtlscookie.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::NetworkPrivate + BUNDLE_ANDROID_OPENSSL_LIBS ) - -## Scopes: -##################################################################### - -#### Keys ignored in scope 3:.:.:qdtlscookie.pro:(CMAKE_BUILD_TYPE STREQUAL Debug): -# DESTDIR = "debug" - -#### Keys ignored in scope 4:.:.:qdtlscookie.pro:else: -# DESTDIR = "release" diff --git a/tests/auto/network/ssl/qdtlscookie/qdtlscookie.pro b/tests/auto/network/ssl/qdtlscookie/qdtlscookie.pro deleted file mode 100644 index 4caa89fe49..0000000000 --- a/tests/auto/network/ssl/qdtlscookie/qdtlscookie.pro +++ /dev/null @@ -1,15 +0,0 @@ -CONFIG += testcase - -SOURCES += tst_qdtlscookie.cpp -QT = core network-private testlib - -TARGET = tst_qdtlscookie - -win32 { - CONFIG(debug, debug|release) { - DESTDIR = debug - } else { - DESTDIR = release - } -} - diff --git a/tests/auto/network/ssl/qdtlscookie/tst_qdtlscookie.cpp b/tests/auto/network/ssl/qdtlscookie/tst_qdtlscookie.cpp index a273ceaa17..167a196104 100644 --- a/tests/auto/network/ssl/qdtlscookie/tst_qdtlscookie.cpp +++ b/tests/auto/network/ssl/qdtlscookie/tst_qdtlscookie.cpp @@ -1,32 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2018 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> +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QTest> +#include <QTestEventLoop> + +#include "../shared/tlshelpers.h" #include <QtNetwork/qhostaddress.h> #include <QtNetwork/qsslsocket.h> @@ -44,6 +22,8 @@ #include <utility> #include <vector> +using namespace std::chrono_literals; + QT_BEGIN_NAMESPACE #define STOP_ON_FAILURE \ @@ -98,7 +78,7 @@ private: quint16 serverPort = 0; QTestEventLoop testLoop; - int handshakeTimeoutMS = 500; + static constexpr auto HandshakeTimeout = 500ms; QDtlsClientVerifier listener; using HandshakePtr = QSharedPointer<QDtls>; @@ -138,6 +118,12 @@ QHostAddress tst_QDtlsCookie::toNonAny(const QHostAddress &addr) void tst_QDtlsCookie::initTestCase() { + using TlsCl = QSsl::ImplementedClass; + using TlsAux::classImplemented; + + if (!classImplemented(TlsCl::DtlsCookie) || !classImplemented(TlsCl::Dtls)) + QSKIP("The active TLS backend does not support DTLS"); + QVERIFY(noiseMaker.bind()); spammerAddress = toNonAny(noiseMaker.localAddress()); spammerPort = noiseMaker.localPort(); @@ -288,6 +274,20 @@ void tst_QDtlsCookie::verifyClient() clientPort), true); QCOMPARE(anotherListener.verifiedHello(), dgram); QCOMPARE(anotherListener.dtlsError(), QDtlsError::NoError); + + // Now, let's test if a DTLS server is able to create a new TLS session + // re-using the client's 'Hello' with a cookie inside: + QDtls session(QSslSocket::SslServerMode); + auto dtlsConf = QSslConfiguration::defaultDtlsConfiguration(); + dtlsConf.setDtlsCookieVerificationEnabled(true); + session.setDtlsConfiguration(dtlsConf); + session.setPeer(clientAddress, clientPort); + // Borrow a secret and hash algorithm: + session.setCookieGeneratorParameters(listener.cookieGeneratorParameters()); + // Trigger TLS state machine change to think it accepted a cookie and started + // a handshake: + QVERIFY(session.doHandshake(&serverSocket, dgram)); + // Now let's use a wrong port: QCOMPARE(listener.verifyClient(&serverSocket, dgram, clientAddress, serverPort), false); // Invalid cookie, no verified hello message: @@ -329,7 +329,7 @@ void tst_QDtlsCookie::verifyMultipleClients() clientsToAdd = clientsToWait = 100; - testLoop.enterLoop(handshakeTimeoutMS * clientsToWait); + testLoop.enterLoop(HandshakeTimeout * clientsToWait); QVERIFY(!testLoop.timeout()); QVERIFY(clientsToWait == 0); } @@ -353,7 +353,7 @@ void tst_QDtlsCookie::receiveMessage(QUdpSocket *socket, QByteArray *message, Q_ASSERT(socket && message); if (socket->pendingDatagramSize() <= 0) - testLoop.enterLoopMSecs(handshakeTimeoutMS); + testLoop.enterLoop(HandshakeTimeout); QVERIFY(!testLoop.timeout()); QVERIFY(socket->pendingDatagramSize()); diff --git a/tests/auto/network/ssl/qocsp/CMakeLists.txt b/tests/auto/network/ssl/qocsp/CMakeLists.txt index 7997461004..98d38ec1c0 100644 --- a/tests/auto/network/ssl/qocsp/CMakeLists.txt +++ b/tests/auto/network/ssl/qocsp/CMakeLists.txt @@ -1,22 +1,26 @@ -# Generated from qocsp.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qocsp Test: ##################################################################### -qt_add_test(tst_qocsp +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qocsp LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qocsp SOURCES tst_qocsp.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Network Qt::NetworkPrivate + BUNDLE_ANDROID_OPENSSL_LIBS ) -## Scopes: -##################################################################### - -#### Keys ignored in scope 3:.:.:qocsp.pro:(CMAKE_BUILD_TYPE STREQUAL Debug): -# DESTDIR = "debug" - -#### Keys ignored in scope 4:.:.:qocsp.pro:else: -# DESTDIR = "release" +qt_internal_extend_target(tst_qocsp CONDITION QT_FEATURE_openssl_linked + LIBRARIES + WrapOpenSSL::WrapOpenSSL +) diff --git a/tests/auto/network/ssl/qocsp/qocsp.pro b/tests/auto/network/ssl/qocsp/qocsp.pro deleted file mode 100644 index f4e846f39b..0000000000 --- a/tests/auto/network/ssl/qocsp/qocsp.pro +++ /dev/null @@ -1,15 +0,0 @@ -CONFIG += testcase - -SOURCES += tst_qocsp.cpp -QT = core network network-private testlib - -TARGET = tst_qocsp - -win32 { - CONFIG(debug, debug|release) { - DESTDIR = debug - } else { - DESTDIR = release - } -} - diff --git a/tests/auto/network/ssl/qocsp/tst_qocsp.cpp b/tests/auto/network/ssl/qocsp/tst_qocsp.cpp index 365a08683e..81ce030be0 100644 --- a/tests/auto/network/ssl/qocsp/tst_qocsp.cpp +++ b/tests/auto/network/ssl/qocsp/tst_qocsp.cpp @@ -1,39 +1,15 @@ -/**************************************************************************** - ** - ** Copyright (C) 2018 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> +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QTest> +#include <QTestEventLoop> #include <QtNetwork/private/qtnetworkglobal_p.h> -#include <QtNetwork/private/qsslsocket_openssl_symbols_p.h> -#include <QtNetwork/private/qsslsocket_openssl_p.h> +#include "../shared/qopenssl_symbols.h" #include <QtNetwork/qsslcertificate.h> +#include <QtNetwork/qocspresponse.h> #include <QtNetwork/qtcpserver.h> #include <QtNetwork/qsslerror.h> #include <QtNetwork/qsslkey.h> @@ -52,6 +28,8 @@ #include <algorithm> #include <utility> +using namespace std::chrono_literals; + // NOTE: the word 'subject' in the code below means the subject of a status request, // so in general it's our peer's certificate we are asking about. @@ -73,7 +51,6 @@ using CertId = QSharedPointer<OCSP_CERTID>; using EvpKey = QSharedPointer<EVP_PKEY>; using Asn1Time = QSharedPointer<ASN1_TIME>; using CertificateChain = QList<QSslCertificate>; - using NativeX509Ptr = X509 *; class X509Stack { @@ -377,7 +354,6 @@ void OcspServer::incomingConnection(qintptr socketDescriptor) class tst_QOcsp : public QObject { Q_OBJECT - public slots: void initTestCase(); @@ -412,7 +388,7 @@ private: void (QSslSocket::*tlsErrorsSignal)(const QList<QSslError> &) = &QSslSocket::sslErrors; void (QTestEventLoop::*exitLoopSlot)() = &QTestEventLoop::exitLoop; - const int handshakeTimeoutMS = 500; + static constexpr auto HandshakeTimeout = 500ms; QTestEventLoop loop; std::vector<QSslError::SslError> ocspErrorCodes = {QSslError::OcspNoResponseFound, @@ -450,7 +426,13 @@ QString tst_QOcsp::certDirPath; void tst_QOcsp::initTestCase() { - QVERIFY(QSslSocket::supportsSsl()); + // I'm not testing feature here, I need 'openssl', since the test + // is very OpenSSL-oriented: + if (QSslSocket::activeBackend() != QStringLiteral("openssl")) + QSKIP("This test requires the OpenSSL backend"); + + if (!qt_auto_test_resolve_OpenSSL_symbols()) + QSKIP("Failed to resolve OpenSSL symbols required by this test"); certDirPath = QFileInfo(QFINDTESTDATA("certs")).absolutePath(); QVERIFY(certDirPath.size() > 0); @@ -482,7 +464,7 @@ void tst_QOcsp::connectSelfSigned() auto roots = clientConfig.caCertificates(); setupOcspClient(clientSocket, issuerToChain(subjectChain), server.peerVerifyName()); clientSocket.connectToHostEncrypted(server.hostName(), server.serverPort()); - loop.enterLoopMSecs(handshakeTimeoutMS); + loop.enterLoop(HandshakeTimeout); QVERIFY(!clientSocket.isEncrypted()); QCOMPARE_SINGLE_ERROR(clientSocket, expectedError); @@ -490,17 +472,30 @@ void tst_QOcsp::connectSelfSigned() { // Now the server will send a valid 'status: good' response. OcspServer server(subjectChain, privateKey); - const QByteArray response(goodResponse(subjectChain, responderChain, privateKey)); - QVERIFY(response.size()); - server.configureResponse(response); + const QByteArray responseData(goodResponse(subjectChain, responderChain, privateKey)); + QVERIFY(responseData.size()); + server.configureResponse(responseData); QVERIFY(server.listen()); QSslSocket clientSocket; setupOcspClient(clientSocket, issuerToChain(subjectChain), server.peerVerifyName()); clientSocket.connectToHostEncrypted(server.hostName(), server.serverPort()); - loop.enterLoopMSecs(handshakeTimeoutMS); + loop.enterLoop(HandshakeTimeout); QVERIFY_HANDSHAKE_WITHOUT_ERRORS(clientSocket); + + const auto responses = clientSocket.ocspResponses(); + QCOMPARE(responses.size(), 1); + const auto &response = responses.at(0); + QVERIFY(response != QOcspResponse()); + const auto copy = response; + QCOMPARE(copy, response); + QVERIFY(qHash(response, 0) != 0); + + QCOMPARE(response.revocationReason(), QOcspRevocationReason::None); + QCOMPARE(response.certificateStatus(), QOcspCertificateStatus::Good); + QCOMPARE(response.subject(), clientSocket.peerCertificate()); + QCOMPARE(response.responder(), clientSocket.peerCertificate()); } } @@ -550,7 +545,7 @@ void tst_QOcsp::badStatus() QSslSocket clientSocket; setupOcspClient(clientSocket, issuerToChain(subjectChain), server.peerVerifyName()); clientSocket.connectToHostEncrypted(server.hostName(), server.serverPort()); - loop.enterLoopMSecs(handshakeTimeoutMS); + loop.enterLoop(HandshakeTimeout); QVERIFY(!clientSocket.isEncrypted()); QCOMPARE_SINGLE_ERROR(clientSocket, expectedError.error()); @@ -581,7 +576,7 @@ void tst_QOcsp::multipleSingleResponses() QSslSocket clientSocket; setupOcspClient(clientSocket, issuerToChain(responderChain), server.peerVerifyName()); clientSocket.connectToHostEncrypted(server.hostName(), server.serverPort()); - loop.enterLoopMSecs(handshakeTimeoutMS); + loop.enterLoop(HandshakeTimeout); QVERIFY(!clientSocket.isEncrypted()); QCOMPARE_SINGLE_ERROR(clientSocket, expectedError); @@ -601,7 +596,7 @@ void tst_QOcsp::malformedResponse() QSslSocket clientSocket; setupOcspClient(clientSocket, issuerToChain(serverChain), server.peerVerifyName()); clientSocket.connectToHostEncrypted(server.hostName(), server.serverPort()); - loop.enterLoopMSecs(handshakeTimeoutMS); + loop.enterLoop(HandshakeTimeout); QVERIFY(!clientSocket.isEncrypted()); QCOMPARE(clientSocket.error(), QAbstractSocket::SslHandshakeFailedError); @@ -640,7 +635,7 @@ void tst_QOcsp::expiredResponse() QSslSocket clientSocket; setupOcspClient(clientSocket, issuerToChain(subjectChain), server.peerVerifyName()); clientSocket.connectToHostEncrypted(server.hostName(), server.serverPort()); - loop.enterLoopMSecs(handshakeTimeoutMS); + loop.enterLoop(HandshakeTimeout); QVERIFY(!clientSocket.isEncrypted()); QCOMPARE_SINGLE_ERROR(clientSocket, expectedError); @@ -671,7 +666,7 @@ void tst_QOcsp::noNextUpdate() QSslSocket clientSocket; setupOcspClient(clientSocket, issuerToChain(subjectChain), server.peerVerifyName()); clientSocket.connectToHostEncrypted(server.hostName(), server.serverPort()); - loop.enterLoopMSecs(handshakeTimeoutMS); + loop.enterLoop(HandshakeTimeout); QVERIFY_HANDSHAKE_WITHOUT_ERRORS(clientSocket); } @@ -717,7 +712,7 @@ void tst_QOcsp::wrongCertificateInResponse() QSslSocket clientSocket; setupOcspClient(clientSocket, issuerToChain(subjectChain), server.peerVerifyName()); clientSocket.connectToHostEncrypted(server.hostName(), server.serverPort()); - loop.enterLoopMSecs(handshakeTimeoutMS); + loop.enterLoop(HandshakeTimeout); QVERIFY(!clientSocket.isEncrypted()); QVERIFY(containsError(clientSocket.sslHandshakeErrors(), expectedError)); @@ -742,7 +737,7 @@ void tst_QOcsp::untrustedResponder() QSslSocket clientSocket; setupOcspClient(clientSocket, {}, server.peerVerifyName()); clientSocket.connectToHostEncrypted(server.hostName(), server.serverPort()); - loop.enterLoopMSecs(handshakeTimeoutMS); + loop.enterLoop(HandshakeTimeout); QVERIFY(!clientSocket.isEncrypted()); QVERIFY(containsError(clientSocket.sslHandshakeErrors(), expectedError)); diff --git a/tests/auto/network/ssl/qpassworddigestor/CMakeLists.txt b/tests/auto/network/ssl/qpassworddigestor/CMakeLists.txt index 1bb8b2f29b..96491eada9 100644 --- a/tests/auto/network/ssl/qpassworddigestor/CMakeLists.txt +++ b/tests/auto/network/ssl/qpassworddigestor/CMakeLists.txt @@ -1,12 +1,20 @@ -# Generated from qpassworddigestor.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qpassworddigestor Test: ##################################################################### -qt_add_test(tst_qpassworddigestor +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qpassworddigestor LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qpassworddigestor SOURCES tst_qpassworddigestor.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Network + BUNDLE_ANDROID_OPENSSL_LIBS ) diff --git a/tests/auto/network/ssl/qpassworddigestor/qpassworddigestor.pro b/tests/auto/network/ssl/qpassworddigestor/qpassworddigestor.pro deleted file mode 100644 index 3e2685f579..0000000000 --- a/tests/auto/network/ssl/qpassworddigestor/qpassworddigestor.pro +++ /dev/null @@ -1,4 +0,0 @@ -CONFIG += testcase -TARGET = tst_qpassworddigestor -QT = core network testlib -SOURCES = tst_qpassworddigestor.cpp diff --git a/tests/auto/network/ssl/qpassworddigestor/tst_qpassworddigestor.cpp b/tests/auto/network/ssl/qpassworddigestor/tst_qpassworddigestor.cpp index bbd6c72ca8..1876c955af 100644 --- a/tests/auto/network/ssl/qpassworddigestor/tst_qpassworddigestor.cpp +++ b/tests/auto/network/ssl/qpassworddigestor/tst_qpassworddigestor.cpp @@ -1,45 +1,79 @@ -/**************************************************************************** -** -** Copyright (C) 2018 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> +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QTest> #include <QtNetwork/qpassworddigestor.h> +#include <QtCore/qcryptographichash.h> #include <QtCore/QByteArray> +#include <limits> + class tst_QPasswordDigestor : public QObject { Q_OBJECT private Q_SLOTS: + void inputSanityChecks(); void pbkdf1Vectors_data(); void pbkdf1Vectors(); void pbkdf2Vectors_data(); void pbkdf2Vectors(); }; +void tst_QPasswordDigestor::inputSanityChecks() +{ + const QByteArray pass("password"); + const QByteArray salt("saltsalt"); +#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1 + //1. PBKDF1 supports only SHA1 and (if not disabled in Qt) MD5 algorithms. + QTest::ignoreMessage(QtWarningMsg, "The only supported algorithms for pbkdf1 are SHA-1 and MD5!"); + auto derivedKey = QPasswordDigestor::deriveKeyPbkdf1(QCryptographicHash::Sha224, pass, salt, 2, 48); + QCOMPARE(derivedKey, QByteArray()); +#endif // QT_CRYPTOGRAPHICHASH_ONLY_SHA1 + + // 2. Salt size must be == 8: + QTest::ignoreMessage(QtWarningMsg, "The salt must be 8 bytes long!"); + derivedKey = QPasswordDigestor::deriveKeyPbkdf1(QCryptographicHash::Sha1, pass, "salt", 2, 48); + QCOMPARE(derivedKey, QByteArray()); + + // 3. An illegal number of iterations (0): + derivedKey = QPasswordDigestor::deriveKeyPbkdf1(QCryptographicHash::Sha1, pass, salt, 0, 48); + QCOMPARE(derivedKey, QByteArray()); + + // 4. An illegal number of iterations (-10): + derivedKey = QPasswordDigestor::deriveKeyPbkdf1(QCryptographicHash::Sha1, pass, salt, -10, 48); + QCOMPARE(derivedKey, QByteArray()); + + // 5. An invalid key size (0): + derivedKey = QPasswordDigestor::deriveKeyPbkdf1(QCryptographicHash::Sha1, + "password", "saltsalt", 1, 0); + QCOMPARE(derivedKey, QByteArray()); + + // 6. Requested key is too large: + QTest::ignoreMessage(QtWarningMsg, "Derived key too long:\n" + " QCryptographicHash::Sha1 was chosen which" + " produces output of length 20 but 120 was requested."); + derivedKey = QPasswordDigestor::deriveKeyPbkdf1(QCryptographicHash::Sha1, pass, salt, 1, + quint64(QCryptographicHash::hashLength(QCryptographicHash::Sha1) + 100)); + QCOMPARE(derivedKey, QByteArray()); + + // 7. Key size is too large, max is quint64(std::numeric_limits<quint32>::max() - 1) * hashLen + const auto invalidDkLen = quint64(QCryptographicHash::hashLength(QCryptographicHash::Sha1)) + * (std::numeric_limits<quint32>::max() - 1) + 1; + QTest::ignoreMessage(QtWarningMsg, "Derived key too long:\n" + "QCryptographicHash::Sha1 was chosen which produces output" + " of length 85899345880 but 85899345881 was requested."); + derivedKey = QPasswordDigestor::deriveKeyPbkdf2(QCryptographicHash::Sha1, pass, salt, 1, invalidDkLen); + QCOMPARE(derivedKey, QByteArray()); + + // 8. Invalid number of iterations. + derivedKey = QPasswordDigestor::deriveKeyPbkdf2(QCryptographicHash::Sha1, pass, salt, 0, 100); + QCOMPARE(derivedKey, QByteArray()); + + // 9. Invalid (negative) number of iterations. + derivedKey = QPasswordDigestor::deriveKeyPbkdf2(QCryptographicHash::Sha1, pass, salt, -100, 100); + QCOMPARE(derivedKey, QByteArray()); +} + void tst_QPasswordDigestor::pbkdf1Vectors_data() { QTest::addColumn<QCryptographicHash::Algorithm>("algorithm"); diff --git a/tests/auto/network/ssl/qsslcertificate/.prev_CMakeLists.txt b/tests/auto/network/ssl/qsslcertificate/.prev_CMakeLists.txt deleted file mode 100644 index c55b2a86a3..0000000000 --- a/tests/auto/network/ssl/qsslcertificate/.prev_CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -# Generated from qsslcertificate.pro. - -##################################################################### -## tst_qsslcertificate Test: -##################################################################### - -# Collect test data -file(GLOB_RECURSE test_data_glob - RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} - certificates/*) -list(APPEND test_data ${test_data_glob}) -file(GLOB_RECURSE test_data_glob - RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} - more-certificates/*) -list(APPEND test_data ${test_data_glob}) -file(GLOB_RECURSE test_data_glob - RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} - verify-certs/*) -list(APPEND test_data ${test_data_glob}) -file(GLOB_RECURSE test_data_glob - RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} - pkcs12/*) -list(APPEND test_data ${test_data_glob}) - -qt_add_test(tst_qsslcertificate - SOURCES - tst_qsslcertificate.cpp - PUBLIC_LIBRARIES - Qt::Network - TESTDATA ${test_data} -) diff --git a/tests/auto/network/ssl/qsslcertificate/CMakeLists.txt b/tests/auto/network/ssl/qsslcertificate/CMakeLists.txt index 7dd8fa00db..6f81a5e030 100644 --- a/tests/auto/network/ssl/qsslcertificate/CMakeLists.txt +++ b/tests/auto/network/ssl/qsslcertificate/CMakeLists.txt @@ -1,15 +1,20 @@ -# Generated from qsslcertificate.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qsslcertificate Test: ##################################################################### -# special case begin +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qsslcertificate LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + # This test requires private tests to properly build if (NOT QT_FEATURE_private_tests) return() endif() -# special case end # Collect test data file(GLOB_RECURSE test_data_glob @@ -29,10 +34,11 @@ file(GLOB_RECURSE test_data_glob pkcs12/*) list(APPEND test_data ${test_data_glob}) -qt_add_test(tst_qsslcertificate +qt_internal_add_test(tst_qsslcertificate SOURCES tst_qsslcertificate.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Network TESTDATA ${test_data} + BUNDLE_ANDROID_OPENSSL_LIBS ) diff --git a/tests/auto/network/ssl/qsslcertificate/certificates/gencertificates.sh b/tests/auto/network/ssl/qsslcertificate/certificates/gencertificates.sh index 4d68549396..cdc1019dcb 100755 --- a/tests/auto/network/ssl/qsslcertificate/certificates/gencertificates.sh +++ b/tests/auto/network/ssl/qsslcertificate/certificates/gencertificates.sh @@ -1,31 +1,6 @@ #!/bin/sh -############################################################################# -## -## Copyright (C) 2016 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is the build configuration utility 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$ -## -############################################################################# +# Copyright (C) 2016 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 # This script generates digital certificates of different types. diff --git a/tests/auto/network/ssl/qsslcertificate/more-certificates/aspiriniks.ca.crt b/tests/auto/network/ssl/qsslcertificate/more-certificates/aspiriniks.ca.crt new file mode 100644 index 0000000000..36436b6248 --- /dev/null +++ b/tests/auto/network/ssl/qsslcertificate/more-certificates/aspiriniks.ca.crt @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDnDCCAoQCCQDV3otC4hs2KTANBgkqhkiG9w0BAQUFADCBjzELMAkGA1UEBhMC +Tk8xDTALBgNVBAgTBE9zbG8xDTALBgNVBAcTBE9zbG8xDzANBgNVBAoTBlRUIEFT +QTEOMAwGA1UECxMFUVQgU1cxHDAaBgNVBAMTE2FzcGlyaW5pa3MudHJvbGwubm8x +IzAhBgkqhkiG9w0BCQEWFGFiYWJpY0B0cm9sbHRlY2guY29tMB4XDTA4MTEwMTA4 +NTcyOFoXDTA5MTEwMTA4NTcyOFowgY8xCzAJBgNVBAYTAk5PMQ0wCwYDVQQIEwRP +c2xvMQ0wCwYDVQQHEwRPc2xvMQ8wDQYDVQQKEwZUVCBBU0ExDjAMBgNVBAsTBVFU +IFNXMRwwGgYDVQQDExNhc3BpcmluaWtzLnRyb2xsLm5vMSMwIQYJKoZIhvcNAQkB +FhRhYmFiaWNAdHJvbGx0ZWNoLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAMV2bMD1DN3DMgbxU3DXw2i7EWGDXcWjTDtdHvqgIb+9nHqo3MJSrzJy +qgEPoOsXqswMla9wDPZAsWv5gVAmVSqpy2lfEgfY7LaSHiGD75seF7zIy+CxREHW +DofHXpJGGJpBCZEKQt2HfHu3+yAYNPucN78tWNZAcPbUg5tfxMZeepRimAZNIxBI +93SDrl/f9Ka7hvPSzUQsnp8hfdpHlFPFznKfD6yPrjxgz2mT9efavJ4DhtyIa4m+ +paiX515CidDz4A8CFxKZbYvuqq1ilibF/si2so9VhALC77ZcAJP1IMuT8T+WUCxq +skJqiSCncl0Hgr+ba8MDGF9UQYowgjMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA +KcJuNUHvjB8ok3cnTmQEeF0LPPkgj28Tqb5TFB8xpVfRI+wvTYsHsmGdOKCgYJ3a +7VflIsr63ojG8/rXK8H/cx2o2f2Hr3liJdi1UnoLDDRjBqGGz7JNuMreYokPvIbm +eP01mVyK4PO2iYRwHUIAw5eeB1vMWKX2z95MupD+HRLtmGyaLALg8aQxj5N84Ewl +eU2PQfhv8A1wj7aL17kfEUxDerQ1kUzlThJMV1J8Dl0l4C9N8evQkelROJU00i46 +oJikA8BW6EpgbnGyNyyj5Loy4wLPKew9nTS8MCJ5xPMQc0urbY/VzuOeUK7WQof7 +xOFSsRAVyQv+yqgmcZMCtg== +-----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qsslcertificate/more-certificates/cert-cn.pem b/tests/auto/network/ssl/qsslcertificate/more-certificates/cert-cn.pem new file mode 100644 index 0000000000..fc77399f8c --- /dev/null +++ b/tests/auto/network/ssl/qsslcertificate/more-certificates/cert-cn.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFfTCCA2WgAwIBAgIUEciqqaXfpL5/Ytf0D64oDHQQ2fIwDQYJKoZIhvcNAQEL +BQAwTTELMAkGA1UEBhMCTk8xDTALBgNVBAgMBE9zbG8xDTALBgNVBAcMBE9zbG8x +DDAKBgNVBAsMA1ImRDESMBAGA1UEAwwJWU9VUiBuYW1lMCAXDTIwMTExOTEzMzEw +NVoYDzIxMjAxMDI2MTMzMTA1WjBNMQswCQYDVQQGEwJOTzENMAsGA1UECAwET3Ns +bzENMAsGA1UEBwwET3NsbzEMMAoGA1UECwwDUiZEMRIwEAYDVQQDDAlZT1VSIG5h +bWUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDCZmoIs4mApLPRw+gI +DxOkTyT/Zyma2LILF26vxOrqE5ygwcJYVWg8HTSlCuJ8Gc22UofuNYvtKLcv8xpz +/mzhOAvsmL9Q7vPlMshUxz0ITPCD/0R4Z95U9vw4/ytzUvf2sz1tgqc08QAS+TyJ +wzljHyN8a+M7yZK71OF+Qto9bFgdA0nWC2AcoHcRhL1UJUSVAl8Ifi7n/lnPIMqr +bvmFfn4wkE+EDO3QnkBNMI5fsvPrfC8TV1D/zGQUZGp/AjqzVZtAonjzE1qVu5IX +ye3Kl9VTsbM0Ms7HnNk7c0ysXnneoIyLl+Gd4EaogFPKjysOidzA2aZIx/aEtPAU +RzL5yxZaVuXEqsqkAcyt2EAhh225ybQPNhi9hy9cFKDpjmngv1UppfAk0FMgmNbr +/GCO4I1J8Bt4/54WhSQuvK8WIo1OcALifOuTalzhmX/ndyoT79SwTZShNasQYEl7 +i9EjKCx0tOWG3yO1I6cyeycQcTCJCmFa3/SdnYuooZ6enlvwHP1cTeNdu2d40hxu +mtlhd7n21FWFHnoMUyBw6ZsWnicY/Nne2a7wCivF7uEjmzFkjNDDoK7xaFz9G2bn +IkdI3R7kNPA4Z+iJKguu6xD63ZOjlB7hRQHhtYxvKhsNNQv90a+eh5EPE8aacGwr +1P04f40Ap/41lAuL/7dS41jGkwIDAQABo1MwUTAdBgNVHQ4EFgQUU0ZlIZM8B5kb +butAVOJkN0VSTB0wHwYDVR0jBBgwFoAUU0ZlIZM8B5kbbutAVOJkN0VSTB0wDwYD +VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAE7SoFANxr/JsSE2NhxBE +yXyLo2Tqv1izBMWXk1HSQJr6Vhoi1g0r3yexIbLbWNelgh7V+oicjHmlqmwi0t+c +7wyhNTc7HUHWQRGO8y//4GSSgGbjNTt5FY7wo+X3QwbH5mGUwRPqfGm/H+f1vRCZ +Gc2e6YSrDtVwuCT4IwoJQEC/6bFDPlkXBDvlKp7pC67arr/LwXdTv8MGkZjYIKgy +PlbAGiWmpSgmUrU9Q/DnQRlvi2DYOE5fTENrDhXGG0La8h3lTqqm7X0fwY73ZoaG +VO0WXoYZmY8t+UuD39gYHR6kOzZN48D4G41HEBP01c6MQU6ocgkxFwI5IyBR3nwf +UEMpTuWTPUokDI2UzrCjigedXb8WhAOnm6IyOgBOtQrfF5xwZd0Jt5tZCszw7stE +3bz8FVAECPZ3LB2lWidwuHpcyFRvYMMoWIzzwl+BsM95rI0IyBpM3nNLwMk4Gy4Y +uuZTSkNDO1tuUjppf6J7iIq272xlBt6xxTGvlWZEPYQyYeNWd9yZ0NXQZBwBSyo8 +Twf4TyeHDvBNnOQIlzPAnONJWDUWWFT0pJfn0cVFypA0FZ6ZPgIlLfgjNgKDyHH9 +NCtBF9luhfMY5ncX9bB+foRdyceAnM3LJCLjNEmzKC7gZ9H9yyaOVgtHyZmwecE5 +H/WJbjX6rYLrU2reHuVGf30= +-----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qsslcertificate/more-certificates/cert-large-expiration-date.txt.0.9.8 b/tests/auto/network/ssl/qsslcertificate/more-certificates/cert-large-expiration-date.txt.0.9.8 deleted file mode 100644 index 20500b221f..0000000000 --- a/tests/auto/network/ssl/qsslcertificate/more-certificates/cert-large-expiration-date.txt.0.9.8 +++ /dev/null @@ -1,42 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - ce:db:31:28:45:c4:05:40 - Signature Algorithm: sha1WithRSAEncryption - Issuer: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd - Validity - Not Before: Aug 4 09:53:41 2010 GMT - Not After : Aug 29 09:53:41 2051 GMT - Subject: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public Key: (1024 bit) - Modulus (1024 bit): - 00:cd:aa:db:6f:d6:34:c9:a7:f1:c0:be:e4:41:18: - 19:e2:02:c9:22:e6:a7:d5:ba:03:2e:9e:28:7a:f4: - 5f:1a:77:5f:77:a9:11:3b:8f:7e:f0:2e:c6:9e:eb: - 3a:d9:12:d7:c1:0c:51:e8:24:52:3f:23:c3:42:0c: - 11:c6:f2:1c:a1:42:fe:b4:c2:69:83:ad:f7:70:b1: - 18:15:cc:20:28:62:30:f0:2c:15:e6:33:19:af:c3: - eb:1c:c0:91:f7:11:68:94:50:f8:49:37:08:32:d7: - 3e:75:df:a3:bc:69:00:15:de:cd:87:0f:5c:02:6b: - 82:c8:01:7d:6a:f0:1d:dc:73 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Subject Key Identifier: - 8A:6E:19:E7:97:9B:8F:D9:7F:B3:BB:01:4F:E8:6A:2F:52:95:0D:D9 - X509v3 Authority Key Identifier: - keyid:8A:6E:19:E7:97:9B:8F:D9:7F:B3:BB:01:4F:E8:6A:2F:52:95:0D:D9 - - X509v3 Basic Constraints: - CA:TRUE - Signature Algorithm: sha1WithRSAEncryption - a1:74:8e:5d:36:96:2c:05:7e:ea:66:cc:2e:68:c7:3d:93:dc: - 8c:a3:11:ad:b5:7e:6e:d0:04:c4:09:bd:0a:f9:39:3b:97:d7: - f0:bb:0c:09:7b:83:fe:bf:87:b0:47:e8:94:b7:aa:9c:79:ad: - 71:9e:b7:c4:99:98:6f:1d:38:32:f8:a3:75:38:c4:e5:e7:37: - 37:21:ec:7b:50:8b:15:b0:97:1e:17:9c:50:17:3c:c1:df:94: - 55:fb:60:2e:50:40:d1:ea:23:c6:3c:21:6f:97:8c:06:16:a5: - 82:72:c1:63:14:64:86:eb:d7:ff:72:f6:09:f5:6d:e6:04:13: - 7a:6a diff --git a/tests/auto/network/ssl/qsslcertificate/more-certificates/cert-large-expiration-date.txt.1.0.1 b/tests/auto/network/ssl/qsslcertificate/more-certificates/cert-large-expiration-date.txt.1.0.1 deleted file mode 100644 index 1a7d945b76..0000000000 --- a/tests/auto/network/ssl/qsslcertificate/more-certificates/cert-large-expiration-date.txt.1.0.1 +++ /dev/null @@ -1,42 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - ce:db:31:28:45:c4:05:40 - Signature Algorithm: sha1WithRSAEncryption - Issuer: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd - Validity - Not Before: Aug 4 09:53:41 2010 GMT - Not After : Aug 29 09:53:41 2051 GMT - Subject: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (1024 bit) - Modulus: - 00:cd:aa:db:6f:d6:34:c9:a7:f1:c0:be:e4:41:18: - 19:e2:02:c9:22:e6:a7:d5:ba:03:2e:9e:28:7a:f4: - 5f:1a:77:5f:77:a9:11:3b:8f:7e:f0:2e:c6:9e:eb: - 3a:d9:12:d7:c1:0c:51:e8:24:52:3f:23:c3:42:0c: - 11:c6:f2:1c:a1:42:fe:b4:c2:69:83:ad:f7:70:b1: - 18:15:cc:20:28:62:30:f0:2c:15:e6:33:19:af:c3: - eb:1c:c0:91:f7:11:68:94:50:f8:49:37:08:32:d7: - 3e:75:df:a3:bc:69:00:15:de:cd:87:0f:5c:02:6b: - 82:c8:01:7d:6a:f0:1d:dc:73 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Subject Key Identifier: - 8A:6E:19:E7:97:9B:8F:D9:7F:B3:BB:01:4F:E8:6A:2F:52:95:0D:D9 - X509v3 Authority Key Identifier: - keyid:8A:6E:19:E7:97:9B:8F:D9:7F:B3:BB:01:4F:E8:6A:2F:52:95:0D:D9 - - X509v3 Basic Constraints: - CA:TRUE - Signature Algorithm: sha1WithRSAEncryption - a1:74:8e:5d:36:96:2c:05:7e:ea:66:cc:2e:68:c7:3d:93:dc: - 8c:a3:11:ad:b5:7e:6e:d0:04:c4:09:bd:0a:f9:39:3b:97:d7: - f0:bb:0c:09:7b:83:fe:bf:87:b0:47:e8:94:b7:aa:9c:79:ad: - 71:9e:b7:c4:99:98:6f:1d:38:32:f8:a3:75:38:c4:e5:e7:37: - 37:21:ec:7b:50:8b:15:b0:97:1e:17:9c:50:17:3c:c1:df:94: - 55:fb:60:2e:50:40:d1:ea:23:c6:3c:21:6f:97:8c:06:16:a5: - 82:72:c1:63:14:64:86:eb:d7:ff:72:f6:09:f5:6d:e6:04:13: - 7a:6a diff --git a/tests/auto/network/ssl/qsslcertificate/more-certificates/cert-large-expiration-date.txt.1.0.1c b/tests/auto/network/ssl/qsslcertificate/more-certificates/cert-large-expiration-date.txt.1.0.1c deleted file mode 100644 index a45ed864f4..0000000000 --- a/tests/auto/network/ssl/qsslcertificate/more-certificates/cert-large-expiration-date.txt.1.0.1c +++ /dev/null @@ -1,41 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 14905561440751715648 (0xcedb312845c40540) - Signature Algorithm: sha1WithRSAEncryption - Issuer: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd - Validity - Not Before: Aug 4 09:53:41 2010 GMT - Not After : Aug 29 09:53:41 2051 GMT - Subject: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (1024 bit) - Modulus: - 00:cd:aa:db:6f:d6:34:c9:a7:f1:c0:be:e4:41:18: - 19:e2:02:c9:22:e6:a7:d5:ba:03:2e:9e:28:7a:f4: - 5f:1a:77:5f:77:a9:11:3b:8f:7e:f0:2e:c6:9e:eb: - 3a:d9:12:d7:c1:0c:51:e8:24:52:3f:23:c3:42:0c: - 11:c6:f2:1c:a1:42:fe:b4:c2:69:83:ad:f7:70:b1: - 18:15:cc:20:28:62:30:f0:2c:15:e6:33:19:af:c3: - eb:1c:c0:91:f7:11:68:94:50:f8:49:37:08:32:d7: - 3e:75:df:a3:bc:69:00:15:de:cd:87:0f:5c:02:6b: - 82:c8:01:7d:6a:f0:1d:dc:73 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Subject Key Identifier: - 8A:6E:19:E7:97:9B:8F:D9:7F:B3:BB:01:4F:E8:6A:2F:52:95:0D:D9 - X509v3 Authority Key Identifier: - keyid:8A:6E:19:E7:97:9B:8F:D9:7F:B3:BB:01:4F:E8:6A:2F:52:95:0D:D9 - - X509v3 Basic Constraints: - CA:TRUE - Signature Algorithm: sha1WithRSAEncryption - a1:74:8e:5d:36:96:2c:05:7e:ea:66:cc:2e:68:c7:3d:93:dc: - 8c:a3:11:ad:b5:7e:6e:d0:04:c4:09:bd:0a:f9:39:3b:97:d7: - f0:bb:0c:09:7b:83:fe:bf:87:b0:47:e8:94:b7:aa:9c:79:ad: - 71:9e:b7:c4:99:98:6f:1d:38:32:f8:a3:75:38:c4:e5:e7:37: - 37:21:ec:7b:50:8b:15:b0:97:1e:17:9c:50:17:3c:c1:df:94: - 55:fb:60:2e:50:40:d1:ea:23:c6:3c:21:6f:97:8c:06:16:a5: - 82:72:c1:63:14:64:86:eb:d7:ff:72:f6:09:f5:6d:e6:04:13: - 7a:6a diff --git a/tests/auto/network/ssl/qsslcertificate/more-certificates/cert-large-expiration-date.txt.1.0.0 b/tests/auto/network/ssl/qsslcertificate/more-certificates/cert-large-expiration-date.txt.3.0.5 index b2ccb2751e..a2cf759c10 100644 --- a/tests/auto/network/ssl/qsslcertificate/more-certificates/cert-large-expiration-date.txt.1.0.0 +++ b/tests/auto/network/ssl/qsslcertificate/more-certificates/cert-large-expiration-date.txt.3.0.5 @@ -27,11 +27,11 @@ Certificate: X509v3 Subject Key Identifier: 8A:6E:19:E7:97:9B:8F:D9:7F:B3:BB:01:4F:E8:6A:2F:52:95:0D:D9 X509v3 Authority Key Identifier: - keyid:8A:6E:19:E7:97:9B:8F:D9:7F:B3:BB:01:4F:E8:6A:2F:52:95:0D:D9 - + 8A:6E:19:E7:97:9B:8F:D9:7F:B3:BB:01:4F:E8:6A:2F:52:95:0D:D9 X509v3 Basic Constraints: CA:TRUE Signature Algorithm: sha1WithRSAEncryption + Signature Value: a1:74:8e:5d:36:96:2c:05:7e:ea:66:cc:2e:68:c7:3d:93:dc: 8c:a3:11:ad:b5:7e:6e:d0:04:c4:09:bd:0a:f9:39:3b:97:d7: f0:bb:0c:09:7b:83:fe:bf:87:b0:47:e8:94:b7:aa:9c:79:ad: diff --git a/tests/auto/network/ssl/qsslcertificate/more-certificates/cert-noname.pem b/tests/auto/network/ssl/qsslcertificate/more-certificates/cert-noname.pem new file mode 100644 index 0000000000..8c1baa97c2 --- /dev/null +++ b/tests/auto/network/ssl/qsslcertificate/more-certificates/cert-noname.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFfTCCA2WgAwIBAgIUDI7wlRkJ11GOMiPwMqLUHtQvzaQwDQYJKoZIhvcNAQEL +BQAwTTELMAkGA1UEBhMCTk8xDTALBgNVBAgMBE9zbG8xDTALBgNVBAcMBE9zbG8x +IDAeBgkqhkiG9w0BCQEWEW1pbmltaUBkcmV2aWwuY29tMCAXDTIwMTExOTEzMzQ0 +MloYDzIxMjAxMDI2MTMzNDQyWjBNMQswCQYDVQQGEwJOTzENMAsGA1UECAwET3Ns +bzENMAsGA1UEBwwET3NsbzEgMB4GCSqGSIb3DQEJARYRbWluaW1pQGRyZXZpbC5j +b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDR4hy/ySyPy6y/TTWI +zHBbN8Lw6IiCtemmKdwzf32RKubV7iErJwCQ0QxPvqJSzVBfHYzzjlRzQ5bTWeVg +7pcUY1W51J9bgpC95gDviOnjkDEBIocapcGGLqMVZuoghZrKDXdzA9r2TQ/bfWIR +6mB2ZgYMUN+5xa7ytvCrz/oYEIGGGojfyK8DPsz5qnV7csnZT+5tDOjkx8dQsDrf +Ob69WKpb6+vPAdh2zWMg+25DamXzLqmEcmAgfAJu6MhtWf787zdsXXsxOHcBOjSJ +plRG4Di0+aV84fnJWvv1+LNmstSGpO3jnrl6bpQVyCBn6/RHcO8bt0oDZ4nJhc6n +5x1VmmWpo11YOJgR6smrUn+OdwZVASCdeaD46X7dmgjg1BTRdIDLDFlF2V/cZRu0 +afeRyHGN0PmusMrARYaCxiXBLLSLrDhxkbT8U4yb36uxWP672aHgpStzbhIPs4HU +/2MzZ9kHHbQVoYJEgAUhi3LyeSHFjkhSk2ZIRpQtjYLFXyngfJ//UqqCYtjY75cZ +X3P+CG35QP1uF6ORWAxTedESX5qSQyc7YUq5H14NvcwY/hqLmjm1EvCKuPrKRD9C +/V0GzBcB7seW0gB0h5+1xMzPhEeubqo965w3NRezUjCmSMkRZGcKGdV9zBq2XD9F +964yS6wxNkAxi5CpcAzD+EIu7QIDAQABo1MwUTAdBgNVHQ4EFgQUB4K2uwCB1DGy +eC5hLGQvh8rvdwEwHwYDVR0jBBgwFoAUB4K2uwCB1DGyeC5hLGQvh8rvdwEwDwYD +VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAluDSEjAtVYepxcBt1Azi +7V6Ux0t7AFRfHxBViBzEhCJ8po+TejgDQpWsc6i5/upaqZb5ADoytiPnwAS9X620 +/Q3Q87wXHyHtUuW89p9DCynZpGYQAhSXbLd3YHn2fn2/WeyqX9YjiZvO2AJhdEz2 +o0jM1RQZDT5I9e/bxHKxOd1gv/zBSrDh1CMCmoPcCHMWyr5lN8He8IpKnIXj6DIq +mJxgNfM1WFraFp1Qc5V27iH69iNJuvR2bHY+772BzFkBis3jA8A55uUaP9EhU8EH +/dnBf6RwUrtTaa7ym5rFrJNiCT/AOmCFkTHMC2KNYAJ2WsQlFo2LUfuWUKN9aN9a +jrnXMgSlY2sWJxPpzR/Z1yNPLqxexr2axMX9LS2WoJMPPChSGERAPlaiBlj8ZE42 +JmYjxf5CxN7EgbZP8HjwueXFP2j+2eZEN08lDZJqWu8Q3OzvRSzYyE674tfL0TJX +q9SYDK/Js04wjsYxR+py7Rz9elu5jHin+2qiVw7Z+6GlAxdrviirEPYoc87y26Va +hpfMwrYB+7M8CrLLtwIRkZSHiHhcgw6wAGaYYCxsYjtDcjc4OLCUbYqRbI86vZ9M +qXfM189o5TMkgamKO+TdUQSZT+7iUvhffI7Daq3+F/UKCLDSIPXvmasAP7cMKhQy +tZkqJ5oHw1YBsGSZoL10TZs= +-----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qsslcertificate/more-certificates/cert-on.pem b/tests/auto/network/ssl/qsslcertificate/more-certificates/cert-on.pem new file mode 100644 index 0000000000..c75e335ed8 --- /dev/null +++ b/tests/auto/network/ssl/qsslcertificate/more-certificates/cert-on.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFVTCCAz2gAwIBAgIUcX6P/xc82lIq8PrtHoW3JO02VL0wDQYJKoZIhvcNAQEL +BQAwOTELMAkGA1UEBhMCTk8xDTALBgNVBAgMBE9zbG8xDTALBgNVBAcMBE9zbG8x +DDAKBgNVBAoMA1ImRDAgFw0yMDExMTkxMjI4NDRaGA8yMTIwMTAyNjEyMjg0NFow +OTELMAkGA1UEBhMCTk8xDTALBgNVBAgMBE9zbG8xDTALBgNVBAcMBE9zbG8xDDAK +BgNVBAoMA1ImRDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOHvuJbt +o70wSSarD6Dslu3XqONT2x6zDXODltVmX0XEgb1S4tKG9p/Ax+h2EFnoNRs0mTSM +hZfdbwwI7XzIAhIQMWvef/3P/BQNy8DRSGSGya4DY0E2qFJHJR6ijGuQfHrhsBSV +eIXOx7mf05pX1ra0lhqRuLQPxPioDqeNxuSdfYfP4DM6ZicFfkfk7cU+xrXTieWI +qGx7ZBN8VMUVZq/uw4MfBiZcP+Xqp3YOVlfqhEcxTFvl8dwBb2Yblgl1ujb4YR4F +pC/M2kPVEBTT1LLwhVWy9rRMS0Jk656q/31p7qQCp4xrv5RLfc0YR3cdwhePKQlo +XXmtrUupbvq9z8hmFo7rqtGZ4xN1cDuaHi9ufe/l9NmGtI4qTqbFtWBMfh3+psB3 +wNMwtLXi/a2x9Ucg8atljC5kk0O5MxtLJwL0MIQpIzpbAy9ZMb4qSOeB5ZrsvILl ++6oQcSBLqzwZ8x6f/3igWTh3H/xJRTbE5W5a47L2LCLk8HYP8hfpG24Rn3cuS2oO +eFFePjylebTAYU4CQ2bpWxkEEs/QMv50sB526GZm47RrFLllj1sTBGWOUYf6+Kqw +LhpO4aO9PmClKYrcrD+5N2IMUbBLQTRw2lyzQ//yKTHrAD6FMrPVrPOT2Hg6Kl+X +/Z+a+o9nIOqi2vj2f542QqGsYlxOQNhyx0+NAgMBAAGjUzBRMB0GA1UdDgQWBBSP +gJvZEkM5CdPIyXU/HxWD8+VRrTAfBgNVHSMEGDAWgBSPgJvZEkM5CdPIyXU/HxWD +8+VRrTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQDh24bPfdni +Ao3r/KRHSeOVAdIjLpJ4pCdkWb/fQTjX/R/UCzAXGb9fZC9P83R/ySMNa+c/t1xQ +FYFuo72DxQokWA8gc25gmibt+zCVP8ociOA//XTh2HEaq3rXmBjG6uTzxe1l1JTg +5HFGSc345fgZrTHRs8MoPxZh842WZ4Z14vwfjoRDN75/N11Pe9muTTQbeFcESYay +L46gRq6RDK1ZxwMY+HzBn9cVjcPgOCdedhEL5kHkSY65qnQJZkqguY+sAWcVKBH2 ++dXori9kNdv/fzr1w4swiqAtIcNauRoiQ1Gh7m3881AxQXT2pYKpl3zu268sx33i +XIBcXoRdwBvy80Ave0Z+nihZU6R+CXJtb9xl4kfJof8cgagAkuNLRpY9OW6n8rBo +yX9mwg7z8tKV+2AaUJl+kiRfhujLmoohouP34/LdTHXTdIh1O0Jwx36QY4ara9ER +QsQjUmnmWJREvwzzUVsqcOOduHPEJyz5wIDFpw2KLR+8N2i6/jBs9/dWps476Ohj +b9+y/tXKcWt+ja9MGvw0Bn8pqU8r4Kj3aYM8KzezRSEL7KKPSNFKkOZYzRYwGkXn +O+ZIyasjjO/C4aSlpZCgWQ1B400ZlrXKmEiFJpkGBnQP/offQJKeSxlfnWwOQ4Og +0TsWxr+VMy7uRq8ltTKbE0UvHPQqf9AmkQ== +-----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qsslcertificate/more-certificates/cert-oun.pem b/tests/auto/network/ssl/qsslcertificate/more-certificates/cert-oun.pem new file mode 100644 index 0000000000..e244bf2889 --- /dev/null +++ b/tests/auto/network/ssl/qsslcertificate/more-certificates/cert-oun.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFZTCCA02gAwIBAgIUDufSooDGcwmx5dTWzw76lAH4m+EwDQYJKoZIhvcNAQEL +BQAwQTELMAkGA1UEBhMCTk8xDTALBgNVBAgMBE9zbG8xDTALBgNVBAcMBE9zbG8x +FDASBgNVBAsMC0ZvdW5kYXRpb25zMCAXDTIwMTExOTEzMjczM1oYDzIxMjAxMDI2 +MTMyNzMzWjBBMQswCQYDVQQGEwJOTzENMAsGA1UECAwET3NsbzENMAsGA1UEBwwE +T3NsbzEUMBIGA1UECwwLRm91bmRhdGlvbnMwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQDEtFnz4VNkh/4eX8jh/QWaJXR8lMliZ/CBqheresvlQPIVpO/i +iDsPeY6eZazko/B0NOoM+oJ0PBGepC8AJOdHf6peo4iNXiA7odczUBUoC1ALal03 +V1KbRfATPYiDaPAUWg1nyEnb5DymLeX0lEwRitPxobYzIw00h/YpHnABj8MwyyNM +vgk+wYrPCwVUyZwrhS+FClm12Eoff9sWJ+sqqlJZT0CQfKGbYd6h/itHcGVuCBPK +pHgGrd2xuqK+CYrYLlyIFOWpk2ICRNGDHmNwj55+Sbj83Ryo40IkECBza9ge1axA +qwYaVORWVSkXet6bN+d2alasJOCPkRvA88wTU+/CSQEtDiiHJMw0LOpyEZMq/0y8 +RcGHqMpTEIbkhzXh9BxyVFsOL0TNdMSfjZwlT405pYJlODxSSgtYD1Fsu1T0ZMO2 +37EcvImUni0ZrrC8S+QRac4nKM5mWjT5kB5XfKOLWzW2uZTTqpya0HJijfwcX6wA +j3mb4w33NXb6zzbZQVVBsPdl1K2J8Q/lXjDvDA3SvusT9mt/0eCu/HYdyBmkMsA3 +ILIJbU1+xKN5GHZdFDtjzGb3UjV5dLqzgBzn6z4vStBbM4rilhW17gPEmpseB1h4 +iM5IUUyKwMavJSChxipkS2c8K6c42AkGBf6mMpGlGNXWyYUvH8mOLeU4LwIDAQAB +o1MwUTAdBgNVHQ4EFgQUz/t+47C+Cdk/uidYWQt9hdNHZU4wHwYDVR0jBBgwFoAU +z/t+47C+Cdk/uidYWQt9hdNHZU4wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B +AQsFAAOCAgEATF8PkW3GNFXiYy3K8mF0yoZdp0nX771h2Et7FbgNLh25Uv+76amT +ujHzobjQRtx8Ewzl+oJnWPmOqMm3bn6BWBR0tWH136ACFBAV4W9Zr3eAwCbQQgU0 +0okRGDVG/tIVjSym9/5/TF37jkQRGCwHaQdjIRFbKiDhy7P7D4qobNs5G0mUqmxj +DY7lmq93/RhMOQE2JYdx2VrU8IxGZ8v3s3Dzl/ln0iw2wb2inj+YviQRs+vss7mU +lXGS+MTo17OQBLPDBuZWV9x28I79hIaYgEYAcIid0IqV0Mp0ISYOhjOp1X9A/UJi +lSMTMCm2kmrrrHmtJ/G9ztkm4Yc/TUl9qAIlXaY9KN5k+GuSLrxIdA9VII3GvuRg +u2ghKl0xgC+uHfLwlfAxJwWbLyJS/ji3Y5yADc700D++pjZI1rWaC7jbOjH0wocA +DW2tQY6Eh4MA1xQyj2IF24j+wfBNdWg/Ndc9BvCuG00v1qAje7lAZOuA8P2977SS +0zqdgSbkAM83c4O6+kWaiRFb8pPBciSxR0YwIchxjjJWSlcqop6cJxtOKhvG+RQX +oLIkpHJznI8aXK5rEniDb6YJm7o+a0i5cQkJQht1lDPI9WW5d7sliozrm1s+pmcr +AM2KHvDxb9Pur6jIOqm9mvYpI3llJu2ICcp/HKiRI0iVV2a/bd1YQzY= +-----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qsslcertificate/qsslcertificate.pro b/tests/auto/network/ssl/qsslcertificate/qsslcertificate.pro deleted file mode 100644 index 7e6870f74b..0000000000 --- a/tests/auto/network/ssl/qsslcertificate/qsslcertificate.pro +++ /dev/null @@ -1,8 +0,0 @@ -CONFIG += testcase - -SOURCES += tst_qsslcertificate.cpp -QT = core network testlib - -TARGET = tst_qsslcertificate - -TESTDATA += certificates/* more-certificates/* verify-certs/* pkcs12/* diff --git a/tests/auto/network/ssl/qsslcertificate/tst_qsslcertificate.cpp b/tests/auto/network/ssl/qsslcertificate/tst_qsslcertificate.cpp index 2c7bafba23..b51053effd 100644 --- a/tests/auto/network/ssl/qsslcertificate/tst_qsslcertificate.cpp +++ b/tests/auto/network/ssl/qsslcertificate/tst_qsslcertificate.cpp @@ -1,40 +1,22 @@ -/**************************************************************************** -** -** 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> +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QTest> + +#include <QtNetwork/qtnetworkglobal.h> + +#include <QtCore/qdatetime.h> +#include <QtCore/qtimezone.h> +#include <QtCore/qscopeguard.h> +#include <QtCore/qset.h> + #include <qsslcertificate.h> #include <qsslkey.h> #include <qsslsocket.h> #include <qsslcertificateextension.h> -#include <qscopeguard.h> #ifndef QT_NO_OPENSSL +#include <openssl/opensslv.h> #include <openssl/obj_mac.h> #endif @@ -58,14 +40,14 @@ class tst_QSslCertificate : public QObject QMap<QString, QString> sha1Map; void createTestRows(); -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) void compareCertificates(const QSslCertificate & cert1, const QSslCertificate & cert2); #endif public slots: void initTestCase(); -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) private slots: void hash(); void emptyConstructor(); @@ -80,6 +62,9 @@ private slots: void subjectAlternativeNames_data(); void utf8SubjectNames(); void subjectAlternativeNames(); + void subjectInfoToString(); + void subjectIssuerDisplayName_data(); + void subjectIssuerDisplayName(); void publicKey_data(); void publicKey(); void toPemOrDer_data(); @@ -114,9 +99,34 @@ private slots: // ### add tests for certificate bundles (multiple certificates concatenated into a single // structure); both PEM and DER formatted -#endif +#endif // QT_CONFIG(ssl) private: QString testDataDir; + + enum class TLSBackend { + OpenSSL, + Schannel, + SecureTransport, + CertOnly, + Unknown, + }; + static TLSBackend currentBackend() + { + static TLSBackend activeBackend = []() { + using namespace Qt::StringLiterals; + const QString active = QSslSocket::activeBackend(); + if (active == "openssl"_L1) + return TLSBackend::OpenSSL; + if (active == "schannel") + return TLSBackend::Schannel; + if (active == "securetransport") + return TLSBackend::SecureTransport; + if (active == "cert-only") + return TLSBackend::CertOnly; + return TLSBackend::Unknown; + }(); + return activeBackend; + } }; void tst_QSslCertificate::initTestCase() @@ -128,13 +138,13 @@ void tst_QSslCertificate::initTestCase() testDataDir += QLatin1String("/"); QDir dir(testDataDir + "certificates"); - QFileInfoList fileInfoList = dir.entryInfoList(QDir::Files | QDir::Readable); + const QFileInfoList fileInfoList = dir.entryInfoList(QDir::Files | QDir::Readable); QRegularExpression rxCert(QLatin1String("^.+\\.(pem|der)$")); QRegularExpression rxSan(QLatin1String("^(.+\\.(?:pem|der))\\.san$")); QRegularExpression rxPubKey(QLatin1String("^(.+\\.(?:pem|der))\\.pubkey$")); QRegularExpression rxDigest(QLatin1String("^(.+\\.(?:pem|der))\\.digest-(md5|sha1)$")); QRegularExpressionMatch match; - foreach (QFileInfo fileInfo, fileInfoList) { + for (const QFileInfo &fileInfo : fileInfoList) { if ((match = rxCert.match(fileInfo.fileName())).hasMatch()) certInfoList << CertInfo(fileInfo, @@ -152,7 +162,7 @@ void tst_QSslCertificate::initTestCase() } } -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) void tst_QSslCertificate::hash() { @@ -166,7 +176,7 @@ static QByteArray readFile(const QString &absFilePath) { QFile file(absFilePath); if (!file.open(QIODevice::ReadOnly)) { - QWARN("failed to open file"); + qWarning("failed to open file"); return QByteArray(); } return file.readAll(); @@ -197,7 +207,7 @@ void tst_QSslCertificate::createTestRows() { QTest::addColumn<QString>("absFilePath"); QTest::addColumn<QSsl::EncodingFormat>("format"); - foreach (CertInfo certInfo, certInfoList) { + for (const CertInfo &certInfo : std::as_const(certInfoList)) { QTest::newRow(certInfo.fileInfo.fileName().toLatin1()) << certInfo.fileInfo.absoluteFilePath() << certInfo.format; } @@ -328,7 +338,7 @@ void tst_QSslCertificate::digest_data() QTest::addColumn<QSsl::EncodingFormat>("format"); QTest::addColumn<QString>("absFilePath_digest_md5"); QTest::addColumn<QString>("absFilePath_digest_sha1"); - foreach (CertInfo certInfo, certInfoList) { + for (const CertInfo &certInfo : std::as_const(certInfoList)) { QString certName = certInfo.fileInfo.fileName(); QTest::newRow(certName.toLatin1()) << certInfo.fileInfo.absoluteFilePath() @@ -381,7 +391,7 @@ void tst_QSslCertificate::subjectAlternativeNames_data() QTest::addColumn<QSsl::EncodingFormat>("format"); QTest::addColumn<QString>("subjAltNameFilePath"); - foreach (CertInfo certInfo, certInfoList) { + for (const CertInfo &certInfo : std::as_const(certInfoList)) { QString certName = certInfo.fileInfo.fileName(); if (subjAltNameMap.contains(certName)) QTest::newRow(certName.toLatin1()) @@ -437,6 +447,61 @@ void tst_QSslCertificate::subjectAlternativeNames() } } +void tst_QSslCertificate::subjectInfoToString() +{ + QFile certFile(testDataDir + "more-certificates/aspiriniks.ca.crt"); + const bool ok = certFile.open(QIODevice::ReadOnly); + QVERIFY(ok); + const auto chain = QSslCertificate::fromDevice(&certFile, QSsl::Pem); + QCOMPARE(chain.size(), 1); + const auto cert = chain.at(0); + QVERIFY(!cert.isNull()); + + const auto testInfo = [&cert](QSslCertificate::SubjectInfo info, const QString &expected) { + const auto infoAsList = cert.subjectInfo(info); + if (infoAsList.size()) + return expected == infoAsList.at(0); + return expected == QString(); + }; + + QVERIFY(testInfo(QSslCertificate::Organization, QStringLiteral("TT ASA"))); + QVERIFY(testInfo(QSslCertificate::CommonName, QStringLiteral("aspiriniks.troll.no"))); + QVERIFY(testInfo(QSslCertificate::LocalityName, QStringLiteral("Oslo"))); + QVERIFY(testInfo(QSslCertificate::OrganizationalUnitName, QStringLiteral("QT SW"))); + QVERIFY(testInfo(QSslCertificate::CountryName, QStringLiteral("NO"))); + QVERIFY(testInfo(QSslCertificate::StateOrProvinceName, QStringLiteral("Oslo"))); + QVERIFY(testInfo(QSslCertificate::DistinguishedNameQualifier, QString())); + QVERIFY(testInfo(QSslCertificate::SerialNumber, QString())); + // TODO: check why generic code does not handle this! + if (currentBackend() == TLSBackend::OpenSSL) + QVERIFY(testInfo(QSslCertificate::EmailAddress, QStringLiteral("ababic@trolltech.com"))); +} + +void tst_QSslCertificate::subjectIssuerDisplayName_data() +{ + QTest::addColumn<QString>("certName"); + QTest::addColumn<QString>("expectedName"); + + QTest::addRow("CommonName") << QStringLiteral("more-certificates/cert-cn.pem") << QStringLiteral("YOUR name"); + QTest::addRow("OrganizationName") << QStringLiteral("more-certificates/cert-on.pem") << QStringLiteral("R&D"); + QTest::addRow("OrganizationUnitName") << QStringLiteral("more-certificates/cert-oun.pem") << QStringLiteral("Foundations"); + if (currentBackend() == TLSBackend::OpenSSL) + QTest::addRow("NoSubjectName") << QStringLiteral("more-certificates/cert-noname.pem") << QString(); +} + +void tst_QSslCertificate::subjectIssuerDisplayName() +{ + QFETCH(const QString, certName); + QFETCH(const QString, expectedName); + + const auto chain = QSslCertificate::fromPath(testDataDir + certName); + QCOMPARE(chain.size(), 1); + const auto cert = chain.at(0); + QVERIFY(!cert.isNull()); + QCOMPARE(cert.subjectDisplayName(), expectedName); + QCOMPARE(cert.issuerDisplayName(), expectedName); +} + void tst_QSslCertificate::utf8SubjectNames() { QSslCertificate cert = QSslCertificate::fromPath(testDataDir + "certificates/cert-ss-san-utf8.pem", QSsl::Pem, @@ -451,7 +516,7 @@ void tst_QSslCertificate::utf8SubjectNames() static const char *ou = "\xe3\x88\xa7" "A" "\xe3\x89\x81\xef\xbd\xab" "BC"; // the following two tests should help find "\x"-literal encoding bugs in the test itself - QCOMPARE(cert.subjectInfo("O")[0].length(), QString::fromUtf8(o).length()); + QCOMPARE(cert.subjectInfo("O")[0].size(), QString::fromUtf8(o).size()); QCOMPARE (cert.subjectInfo("O")[0].toUtf8().toHex(), QByteArray(o).toHex()); QCOMPARE(cert.subjectInfo("O")[0], QString::fromUtf8(o)); @@ -464,7 +529,7 @@ void tst_QSslCertificate::publicKey_data() QTest::addColumn<QSsl::EncodingFormat>("format"); QTest::addColumn<QString>("pubkeyFilePath"); - foreach (CertInfo certInfo, certInfoList) { + for (const CertInfo &certInfo : std::as_const(certInfoList)) { QString certName = certInfo.fileInfo.fileName(); if (pubkeyMap.contains(certName)) QTest::newRow(certName.toLatin1()) @@ -545,8 +610,15 @@ void tst_QSslCertificate::toPemOrDer() void tst_QSslCertificate::fromDevice() { QTest::ignoreMessage(QtWarningMsg, "QSslCertificate::fromDevice: cannot read from a null device"); - QList<QSslCertificate> certs = QSslCertificate::fromDevice(0); // don't crash + QList<QSslCertificate> certs = QSslCertificate::fromDevice(nullptr); // don't crash QVERIFY(certs.isEmpty()); + + QFile certFile(testDataDir + "certificates/cert.der"); + const bool ok = certFile.open(QIODevice::ReadOnly); + QVERIFY(ok); + const auto chain = QSslCertificate::fromDevice(&certFile, QSsl::Der); + QCOMPARE(chain.size(), 1); + QVERIFY(!chain.at(0).isNull()); } void tst_QSslCertificate::fromPath_qregularexpression_data() @@ -759,8 +831,10 @@ void tst_QSslCertificate::certInfo() QCOMPARE(cert.digest(QCryptographicHash::Sha1), QByteArray::fromHex("B6:D1:51:82:E0:29:CA:59:96:38:BD:B6:F9:40:05:91:6D:49:09:60")); - QCOMPARE(cert.effectiveDate().toUTC(), QDateTime(QDate(2007, 4, 17), QTime(7,40,26), Qt::UTC)); - QCOMPARE(cert.expiryDate().toUTC(), QDateTime(QDate(2007, 5, 17), QTime(7,40,26), Qt::UTC)); + QCOMPARE(cert.effectiveDate().toUTC(), + QDateTime(QDate(2007, 4, 17), QTime(7,40,26), QTimeZone::UTC)); + QCOMPARE(cert.expiryDate().toUTC(), + QDateTime(QDate(2007, 5, 17), QTime(7,40,26), QTimeZone::UTC)); QVERIFY(cert.expiryDate() < QDateTime::currentDateTime()); // cert has expired QSslCertificate copy = cert; @@ -822,9 +896,9 @@ void tst_QSslCertificate::task256066toPem() void tst_QSslCertificate::nulInCN() { -#if QT_CONFIG(securetransport) || QT_CONFIG(schannel) - QSKIP("Generic QSslCertificatePrivate fails this test"); -#endif + if (currentBackend() != TLSBackend::OpenSSL) + QSKIP("Generic QSslCertificatePrivate fails this test"); + QList<QSslCertificate> certList = QSslCertificate::fromPath(testDataDir + "more-certificates/badguy-nul-cn.crt", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString); QCOMPARE(certList.size(), 1); @@ -841,9 +915,10 @@ void tst_QSslCertificate::nulInCN() void tst_QSslCertificate::nulInSan() { -#if QT_CONFIG(securetransport) || QT_CONFIG(schannel) - QSKIP("Generic QSslCertificatePrivate fails this test"); -#endif + + if (currentBackend() != TLSBackend::OpenSSL) + QSKIP("Generic QSslCertificatePrivate fails this test"); + QList<QSslCertificate> certList = QSslCertificate::fromPath(testDataDir + "more-certificates/badguy-nul-san.crt", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString); QCOMPARE(certList.size(), 1); @@ -883,16 +958,18 @@ void tst_QSslCertificate::largeExpirationDate() // QTBUG-12489 const QSslCertificate &cert = certList.at(0); QVERIFY(!cert.isNull()); - QCOMPARE(cert.effectiveDate().toUTC(), QDateTime(QDate(2010, 8, 4), QTime(9, 53, 41), Qt::UTC)); + QCOMPARE(cert.effectiveDate().toUTC(), + QDateTime(QDate(2010, 8, 4), QTime(9, 53, 41), QTimeZone::UTC)); // if the date is larger than 2049, then the generalized time format is used - QCOMPARE(cert.expiryDate().toUTC(), QDateTime(QDate(2051, 8, 29), QTime(9, 53, 41), Qt::UTC)); + QCOMPARE(cert.expiryDate().toUTC(), + QDateTime(QDate(2051, 8, 29), QTime(9, 53, 41), QTimeZone::UTC)); } void tst_QSslCertificate::blacklistedCertificates() { QList<QSslCertificate> blacklistedCerts = QSslCertificate::fromPath(testDataDir + "more-certificates/blacklisted*.pem", QSsl::Pem, QSslCertificate::PatternSyntax::Wildcard); - QVERIFY(blacklistedCerts.count() > 0); - for (int a = 0; a < blacklistedCerts.count(); a++) { + QVERIFY(blacklistedCerts.size() > 0); + for (int a = 0; a < blacklistedCerts.size(); a++) { QVERIFY(blacklistedCerts.at(a).isBlacklisted()); } } @@ -906,51 +983,35 @@ void tst_QSslCertificate::selfsignedCertificates() void tst_QSslCertificate::toText() { + if (currentBackend() != TLSBackend::OpenSSL) + QSKIP("QSslCertificate::toText is not implemented on platforms which do not use openssl"); + QList<QSslCertificate> certList = QSslCertificate::fromPath(testDataDir + "more-certificates/cert-large-expiration-date.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString); QCOMPARE(certList.size(), 1); const QSslCertificate &cert = certList.at(0); - // Openssl's cert dump method changed slightly between 0.9.8, 1.0.0 and 1.01 versions, so we want it to match any output - - QFile f098(testDataDir + "more-certificates/cert-large-expiration-date.txt.0.9.8"); - QVERIFY(f098.open(QIODevice::ReadOnly | QFile::Text)); - QByteArray txt098 = f098.readAll(); - - QFile f100(testDataDir + "more-certificates/cert-large-expiration-date.txt.1.0.0"); - QVERIFY(f100.open(QIODevice::ReadOnly | QFile::Text)); - QByteArray txt100 = f100.readAll(); - - QFile f101(testDataDir + "more-certificates/cert-large-expiration-date.txt.1.0.1"); - QVERIFY(f101.open(QIODevice::ReadOnly | QFile::Text)); - QByteArray txt101 = f101.readAll(); - - QFile f101c(testDataDir + "more-certificates/cert-large-expiration-date.txt.1.0.1c"); - QVERIFY(f101c.open(QIODevice::ReadOnly | QFile::Text)); - QByteArray txt101c = f101c.readAll(); - + // Openssl's cert dump method changed slightly between 1.1.1 and 3.0.5 versions, so we want it to match any output QFile f111(testDataDir + "more-certificates/cert-large-expiration-date.txt.1.1.1"); QVERIFY(f111.open(QIODevice::ReadOnly | QFile::Text)); QByteArray txt111 = f111.readAll(); + QFile f305(testDataDir + "more-certificates/cert-large-expiration-date.txt.3.0.5"); + QVERIFY(f305.open(QIODevice::ReadOnly | QFile::Text)); + QByteArray txt305 = f305.readAll(); + QString txtcert = cert.toText(); -#ifdef QT_NO_OPENSSL - QEXPECT_FAIL("", "QSslCertificate::toText is not implemented on platforms which do not use openssl", Continue); -#endif - QVERIFY(QString::fromLatin1(txt098) == txtcert || - QString::fromLatin1(txt100) == txtcert || - QString::fromLatin1(txt101) == txtcert || - QString::fromLatin1(txt101c) == txtcert || - QString::fromLatin1(txt111) == txtcert ); + QVERIFY(QString::fromLatin1(txt111) == txtcert || + QString::fromLatin1(txt305) == txtcert); } void tst_QSslCertificate::multipleCommonNames() { QList<QSslCertificate> certList = QSslCertificate::fromPath(testDataDir + "more-certificates/test-cn-two-cns-cert.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString); - QVERIFY(certList.count() > 0); + QVERIFY(certList.size() > 0); QStringList commonNames = certList[0].subjectInfo(QSslCertificate::CommonName); QVERIFY(commonNames.contains(QString("www.example.com"))); @@ -961,18 +1022,19 @@ void tst_QSslCertificate::subjectAndIssuerAttributes() { QList<QSslCertificate> certList = QSslCertificate::fromPath(testDataDir + "more-certificates/test-cn-with-drink-cert.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString); - QVERIFY(certList.count() > 0); + QVERIFY(certList.size() > 0); QList<QByteArray> attributes = certList[0].subjectInfoAttributes(); QVERIFY(attributes.contains(QByteArray("favouriteDrink"))); attributes.clear(); certList = QSslCertificate::fromPath(testDataDir + "more-certificates/natwest-banking.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString); - QVERIFY(certList.count() > 0); + QVERIFY(certList.size() > 0); QByteArray shortName("1.3.6.1.4.1.311.60.2.1.3"); #if !defined(QT_NO_OPENSSL) && defined(SN_jurisdictionCountryName) - shortName = SN_jurisdictionCountryName; + if (currentBackend() == TLSBackend::OpenSSL) + shortName = SN_jurisdictionCountryName; #endif attributes = certList[0].subjectInfoAttributes(); QVERIFY(attributes.contains(shortName)); @@ -980,9 +1042,9 @@ void tst_QSslCertificate::subjectAndIssuerAttributes() void tst_QSslCertificate::verify() { -#if QT_CONFIG(securetransport) - QSKIP("Not implemented in SecureTransport"); -#endif + if (currentBackend() != TLSBackend::OpenSSL) + QSKIP("Only implemented for OpenSSL"); + QList<QSslError> errors; QList<QSslCertificate> toVerify; @@ -992,12 +1054,9 @@ void tst_QSslCertificate::verify() qPrintable(QString("errors: %1").arg(toString(errors))) \ ) -#ifdef QT_NO_OPENSSL - QEXPECT_FAIL("", "Verifying a chain is not supported without openssl", Abort); // TODO? -#endif // Empty chain is unspecified error errors = QSslCertificate::verify(toVerify); - VERIFY_VERBOSE(errors.count() == 1); + VERIFY_VERBOSE(errors.size() == 1); VERIFY_VERBOSE(errors[0] == QSslError(QSslError::UnspecifiedError)); errors.clear(); @@ -1016,14 +1075,14 @@ void tst_QSslCertificate::verify() toVerify = QSslCertificate::fromPath(testDataDir + "verify-certs/test-ocsp-good-cert.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString); errors = QSslCertificate::verify(toVerify); - VERIFY_VERBOSE(errors.count() == 0); + VERIFY_VERBOSE(errors.size() == 0); errors.clear(); // Test a blacklisted certificate toVerify = QSslCertificate::fromPath(testDataDir + "verify-certs/test-addons-mozilla-org-cert.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString); errors = QSslCertificate::verify(toVerify); bool foundBlack = false; - foreach (const QSslError &error, errors) { + for (const QSslError &error : std::as_const(errors)) { if (error.error() == QSslError::CertificateBlacklisted) { foundBlack = true; break; @@ -1051,11 +1110,11 @@ void tst_QSslCertificate::verify() toVerify << QSslCertificate::fromPath(testDataDir + "verify-certs/test-intermediate-is-ca-cert.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString).first(); toVerify << QSslCertificate::fromPath(testDataDir + "verify-certs/test-intermediate-ca-cert.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString).first(); errors = QSslCertificate::verify(toVerify); - VERIFY_VERBOSE(errors.count() == 0); + VERIFY_VERBOSE(errors.size() == 0); // Recheck the above with hostname validation errors = QSslCertificate::verify(toVerify, QLatin1String("example.com")); - VERIFY_VERBOSE(errors.count() == 0); + VERIFY_VERBOSE(errors.size() == 0); // Recheck the above with a bad hostname errors = QSslCertificate::verify(toVerify, QLatin1String("fail.example.com")); @@ -1069,9 +1128,8 @@ QString tst_QSslCertificate::toString(const QList<QSslError>& errors) { QStringList errorStrings; - foreach (const QSslError& error, errors) { + for (const QSslError &error : errors) errorStrings.append(QLatin1Char('"') + error.errorString() + QLatin1Char('"')); - } return QLatin1String("[ ") + errorStrings.join(QLatin1String(", ")) + QLatin1String(" ]"); } @@ -1080,11 +1138,11 @@ void tst_QSslCertificate::extensions() { QList<QSslCertificate> certList = QSslCertificate::fromPath(testDataDir + "more-certificates/natwest-banking.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString); - QVERIFY(certList.count() > 0); + QVERIFY(certList.size() > 0); QSslCertificate cert = certList[0]; QList<QSslCertificateExtension> extensions = cert.extensions(); - QCOMPARE(extensions.count(), 9); + QCOMPARE(extensions.size(), 9); int unknown_idx = -1; int authority_info_idx = -1; @@ -1092,7 +1150,7 @@ void tst_QSslCertificate::extensions() int subject_key_idx = -1; int auth_key_idx = -1; - for (int i=0; i < extensions.length(); ++i) { + for (int i=0; i < extensions.size(); ++i) { QSslCertificateExtension ext = extensions[i]; //qDebug() << i << ":" << ext.name() << ext.oid(); @@ -1178,16 +1236,16 @@ void tst_QSslCertificate::extensionsCritical() { QList<QSslCertificate> certList = QSslCertificate::fromPath(testDataDir + "verify-certs/test-addons-mozilla-org-cert.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString); - QVERIFY(certList.count() > 0); + QVERIFY(certList.size() > 0); QSslCertificate cert = certList[0]; QList<QSslCertificateExtension> extensions = cert.extensions(); - QCOMPARE(extensions.count(), 9); + QCOMPARE(extensions.size(), 9); int basic_constraints_idx = -1; int key_usage_idx = -1; - for (int i=0; i < extensions.length(); ++i) { + for (int i=0; i < extensions.size(); ++i) { QSslCertificateExtension ext = extensions[i]; if (ext.name() == QStringLiteral("basicConstraints")) @@ -1325,6 +1383,9 @@ void tst_QSslCertificate::pkcs12() return; } + if (currentBackend() == TLSBackend::OpenSSL && QSslSocket::sslLibraryVersionNumber() >= 0x30000000L) + QSKIP("leaf.p12 is using RC2, which is disabled by default in OpenSSL v >= 3"); + QFile f(testDataDir + QLatin1String("pkcs12/leaf.p12")); bool ok = f.open(QIODevice::ReadOnly); QVERIFY(ok); @@ -1333,9 +1394,9 @@ void tst_QSslCertificate::pkcs12() QSslCertificate cert; QList<QSslCertificate> caCerts; -#ifdef QT_NO_OPENSSL - QEXPECT_FAIL("", "pkcs12 imports are only supported when openssl is used", Abort); // TODO? -#endif + if (currentBackend() != TLSBackend::OpenSSL) + QEXPECT_FAIL("", "pkcs12 imports are not available with the current TLS backend", Abort); // TODO? + ok = QSslCertificate::importPkcs12(&f, &key, &cert, &caCerts); QVERIFY(ok); f.close(); @@ -1366,7 +1427,8 @@ void tst_QSslCertificate::pkcs12() QFile nocert(testDataDir + QLatin1String("pkcs12/leaf-nokey.p12")); ok = nocert.open(QIODevice::ReadOnly); QVERIFY(ok); - QTest::ignoreMessage(QtWarningMsg, "Unable to convert private key"); + if (currentBackend() == TLSBackend::OpenSSL) + QTest::ignoreMessage(QtWarningMsg, "Unable to convert private key"); ok = QSslCertificate::importPkcs12(&nocert, &key, &cert, &caCerts); QVERIFY(!ok); nocert.close(); @@ -1411,7 +1473,7 @@ void tst_QSslCertificate::invalidDateTime() } } -#endif // QT_NO_SSL +#endif // QT_CONFIG(ssl) QTEST_MAIN(tst_QSslCertificate) #include "tst_qsslcertificate.moc" diff --git a/tests/auto/network/ssl/qsslcertificate/verify-certs/README b/tests/auto/network/ssl/qsslcertificate/verify-certs/README index 87cb293ef6..f4317331b6 100644 --- a/tests/auto/network/ssl/qsslcertificate/verify-certs/README +++ b/tests/auto/network/ssl/qsslcertificate/verify-certs/README @@ -1,2 +1,9 @@ openssl verify -CAfile cacert.pem -untrusted test-intermediate-ca-cert.pem test-intermediate-is-ca-cert.pem openssl verify -CAfile cacert.pem -untrusted test-ocsp-good-cert.pem test-intermediate-not-ca-cert.pem + +1. cacert.pem is, obviously, a root CA certificate. +2. test-intermediate-ca-cert.pem is a certificate, signed by the root CA, an intermediate CA. +3. test-intermediate-is-ca-cert.pem is a certificate, signed by test-intermediate-ca-cert.pem. +4. test-ocsp-good-cert.pem is signed by root CA, it has CA:FALSE but keyUsage allowing to sign + CSRs - this is how OpenSSL would report us 'invalid CA certificate' instead of 'No issuer found'. +5. test-intermediate-not-ca-cert.pem is signed by test-ocsp-good-cert.pem. diff --git a/tests/auto/network/ssl/qsslcertificate/verify-certs/cacert.pem b/tests/auto/network/ssl/qsslcertificate/verify-certs/cacert.pem index 8c75c54bcb..5b9b570479 100644 --- a/tests/auto/network/ssl/qsslcertificate/verify-certs/cacert.pem +++ b/tests/auto/network/ssl/qsslcertificate/verify-certs/cacert.pem @@ -1,23 +1,25 @@ -----BEGIN CERTIFICATE----- -MIID6zCCAtOgAwIBAgIJAP4bjANFSx0BMA0GCSqGSIb3DQEBBQUAMIGrMSYwJAYD -VQQDEx1XZXN0cG9pbnQgQ2VydGlmaWNhdGUgVGVzdCBDQTETMBEGA1UECBMKTGFu -Y2FzaGlyZTELMAkGA1UEBhMCVUsxHTAbBgkqhkiG9w0BCQEWDmNhQGV4YW1wbGUu -Y29tMUAwPgYDVQQKEzdXZXN0cG9pbnQgQ2VydGlmaWNhdGUgVGVzdCBSb290IENl -cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTExMDczMTIxMDExNloXDTIxMDcyODIx -MDExNlowgasxJjAkBgNVBAMTHVdlc3Rwb2ludCBDZXJ0aWZpY2F0ZSBUZXN0IENB -MRMwEQYDVQQIEwpMYW5jYXNoaXJlMQswCQYDVQQGEwJVSzEdMBsGCSqGSIb3DQEJ -ARYOY2FAZXhhbXBsZS5jb20xQDA+BgNVBAoTN1dlc3Rwb2ludCBDZXJ0aWZpY2F0 -ZSBUZXN0IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQC5xMKXviXuxFO67WzFIImO5RY3Y+dqt7maTB+p -JiHkn98rJoBB4J1cDnEUIs5ErO+kqOjW7JwF50fePNJ5K+I6SbRVn9gxAI59ZA6O -9UvOPZOw4/6GM24UY4B4mUcp8oXg9fhwgtjVhfXiMD2GvKQq3RazIiCoSW4aJWEq -L58Q+sIo+jL72qwk648xIwIhuC3XzcOOE/+rCOtZmu812/NN08UfsL2qup0aaaGv -aL36n6OIx5AYFcCD5uOxXAmUy14mhwQyDHAl6K42ghSm5b43VMMSQ+N9AQpentWl -RH6Vt1eY52YTxjNxpRlj88GBnYxdr8WgjKOV7v8OPGXP6zWlAgMBAAGjEDAOMAwG -A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADptDEfvsh8aq/tTc7ciGkHG -jh7WFELVTcdWBTyveZ24298Hl9UOfsAfLqjMGMs3delAaZocchba9Og2xSZyRstH -GUtlJXd4PnSJSx/TksPf2DCANo5sxBWBITs1Iprm3Nlm3/xPZM2QLIamRYi2J6Ed -JTfWvMpoaW1umJX49jKqk1gfdcS6eUSaXetgYP2FQV7DstqPLYfQ731nEXZ1LXFM -PO7IoPccqk4YJ0KOV7hFb7NCq4a6cz/Gf0S0qJ44vqHz6iRZpmWIo5UFivwtLw9r -iMbdJ1mCCMR0oN5om3muKc7Sz+l2ItxdYMcLkZ1/3ouvQqOX+qIOrYEUN1RZCzI= +MIIENzCCAx+gAwIBAgIUdn+WSglXIMBvW46H1+kauM81p1UwDQYJKoZIhvcNAQEL +BQAwgaIxCzAJBgNVBAYTAk5PMQ8wDQYDVQQIDAZOb3J3YXkxDTALBgNVBAcMBE9z +bG8xDTALBgNVBAoMBFRRdEMxLzAtBgNVBAsMJlRRdEMgVGVzdCBSb290IEF1dGhv +cml6YXRpb24gQXV0aG9yaXR5MRowGAYDVQQDDBFUUXRDIHRlc3Qgcm9vdCBDQTEX +MBUGCSqGSIb3DQEJARYIY2FAcXQuaW8wHhcNMjEwNzI5MTIzNDM5WhcNMzEwNzI3 +MTIzNDM5WjCBojELMAkGA1UEBhMCTk8xDzANBgNVBAgMBk5vcndheTENMAsGA1UE +BwwET3NsbzENMAsGA1UECgwEVFF0QzEvMC0GA1UECwwmVFF0QyBUZXN0IFJvb3Qg +QXV0aG9yaXphdGlvbiBBdXRob3JpdHkxGjAYBgNVBAMMEVRRdEMgdGVzdCByb290 +IENBMRcwFQYJKoZIhvcNAQkBFghjYUBxdC5pbzCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAOXrt0DU0NCmvB/vsw3d5Ztn3Ab77AmnVSNSkWKOyei7bQ55 +Qx2FR+ihcPL3+HRQ+UAZsV/ryurkrCdFOOpkBC8a1Kq1ErXM9RbBdX9kyX7IG1KD +iwnFuci/2cDgounfxNDLPCWImukKfWGUfWlpnbbF4nYdaeP/S+LvsCklgphGdtLE +uO+bNLUNFT61X3d0eg/NQ0tMFFgjTQkKYueYpoAtS8zsHfJxLKzNVjdkUaqEsN1x +AmE6LLVhMwf7EHwlgCMb3H59R9N+kz8bjCNQrErctF0crvdZjlX9AudZGz6e6xso +Mmw6epkGSGF6eMjK62mQX4Y/15ruNIvuLla1dzcCAwEAAaNjMGEwHQYDVR0OBBYE +FFpvgro1qjV/QzO+gq/hScIGw7CpMB8GA1UdIwQYMBaAFFpvgro1qjV/QzO+gq/h +ScIGw7CpMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 +DQEBCwUAA4IBAQC+Xbv1f2r2YBXTM7/Uc48DFjdCb4dOKOF8anIGmsG5IfcG77DW +PkyVvPVBVQYw11GtyEwdl5nYyM5VMUT2Jv0kL3sRjQASaQLQCJa3KpYKUV6/7+0W +h8oUSb6FyP8Ks/GTVgHGlSSWU6TixG2k85kKSDNinUDHqrjyS+EYXR4FZHY68lu1 +JSSDBrdEEMmBcChj7Yze9LcdcEUbsALori4363rJCsDmfE6M5nZCFGSn1oUAB8LS +XJ62DI16XbKjwSSFsvJA87n3Ujivytjgdq0e1EgpeNjFvcq5lJ83pQHK/G6+hIna +toLOSqYHUzZv5+NalkbfTUOLSuecUMDTz+KG -----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qsslcertificate/verify-certs/test-intermediate-ca-cert.pem b/tests/auto/network/ssl/qsslcertificate/verify-certs/test-intermediate-ca-cert.pem index d00490caba..4e850907ad 100644 --- a/tests/auto/network/ssl/qsslcertificate/verify-certs/test-intermediate-ca-cert.pem +++ b/tests/auto/network/ssl/qsslcertificate/verify-certs/test-intermediate-ca-cert.pem @@ -1,66 +1,26 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 28 (0x1c) - Signature Algorithm: sha1WithRSAEncryption - Issuer: CN=Westpoint Certificate Test CA, ST=Lancashire, C=UK/emailAddress=ca@example.com, O=Westpoint Certificate Test Root Certification Authority - Validity - Not Before: Jul 31 21:01:18 2011 GMT - Not After : Jul 28 21:01:18 2021 GMT - Subject: ST=Lancashire, C=UK/emailAddress=test@example.com, O=Test intermediate CA - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (1024 bit) - Modulus: - 00:bc:bd:83:c1:bc:36:d8:9c:74:68:5a:46:48:25: - 83:59:f8:35:1e:8f:dc:2c:52:3b:7c:2e:ea:40:c4: - 93:b6:39:31:df:f5:a6:f8:01:17:67:93:21:59:9b: - 89:7f:ed:2a:19:7b:25:a5:e1:71:12:99:e5:14:28: - df:75:b5:17:1c:3b:1d:3d:74:48:4f:b7:42:f4:3a: - ab:56:05:2b:fc:d3:27:97:01:08:5b:ad:26:9b:f2: - 87:51:9c:7e:e1:f1:ef:1c:bf:ad:7e:38:d9:76:89: - 30:a6:8c:2f:6f:87:9f:9e:57:13:14:b4:45:30:f3: - be:58:df:8a:d2:ee:7b:1d:89 - Exponent: 65537 (0x10001) - X509v3 extensions: - Authority Information Access: - OCSP - URI:http://ocsp.example.com:8888/ - - X509v3 Basic Constraints: - CA:TRUE - Signature Algorithm: sha1WithRSAEncryption - 33:84:9d:0e:b2:59:04:dc:ef:e3:04:8b:00:6c:64:ea:58:9e: - 36:59:76:27:59:a0:b8:ee:0d:86:83:ff:db:65:eb:6c:1f:16: - 47:e7:f5:e6:c3:88:81:73:7e:ed:12:8d:7e:fd:5e:b1:5c:68: - 47:f8:f9:ca:e3:e0:c0:f3:12:b2:24:3b:77:2c:98:de:05:6d: - a8:ec:27:b8:af:ab:84:25:26:73:b4:58:4c:7c:c1:74:97:98: - ab:0e:e6:99:70:bc:38:b0:9a:e3:d9:5c:75:fa:46:d2:87:55: - 09:86:8f:ef:4a:e4:ef:3e:32:c6:ac:9d:27:86:29:b8:78:38: - 7b:87:6c:57:72:bd:57:99:73:36:db:fa:52:bd:7b:a7:05:cd: - 28:b8:85:fc:11:47:5e:c6:77:72:6a:fb:73:3e:8b:a4:6d:f8: - 17:f4:12:d5:36:e0:ef:5c:f8:b2:a1:69:3e:4c:cf:86:5f:63: - f6:02:60:95:7f:61:e8:cb:7f:14:66:da:36:2e:78:13:3e:68: - ae:3f:13:c1:79:88:18:18:3f:23:f3:9a:e1:e7:7e:ae:50:e4: - b7:80:76:31:92:74:79:2c:de:d0:74:fe:81:7c:f6:01:14:6a: - 1f:5f:88:85:6a:11:1d:50:af:f1:97:4d:67:40:c3:e9:ae:6f: - 60:e2:bc:e2 -----BEGIN CERTIFICATE----- -MIIDUDCCAjigAwIBAgIBHDANBgkqhkiG9w0BAQUFADCBqzEmMCQGA1UEAxMdV2Vz -dHBvaW50IENlcnRpZmljYXRlIFRlc3QgQ0ExEzARBgNVBAgTCkxhbmNhc2hpcmUx -CzAJBgNVBAYTAlVLMR0wGwYJKoZIhvcNAQkBFg5jYUBleGFtcGxlLmNvbTFAMD4G -A1UEChM3V2VzdHBvaW50IENlcnRpZmljYXRlIFRlc3QgUm9vdCBDZXJ0aWZpY2F0 -aW9uIEF1dGhvcml0eTAeFw0xMTA3MzEyMTAxMThaFw0yMTA3MjgyMTAxMThaMGIx -EzARBgNVBAgTCkxhbmNhc2hpcmUxCzAJBgNVBAYTAlVLMR8wHQYJKoZIhvcNAQkB -FhB0ZXN0QGV4YW1wbGUuY29tMR0wGwYDVQQKExRUZXN0IGludGVybWVkaWF0ZSBD -QTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvL2Dwbw22Jx0aFpGSCWDWfg1 -Ho/cLFI7fC7qQMSTtjkx3/Wm+AEXZ5MhWZuJf+0qGXslpeFxEpnlFCjfdbUXHDsd -PXRIT7dC9DqrVgUr/NMnlwEIW60mm/KHUZx+4fHvHL+tfjjZdokwpowvb4efnlcT -FLRFMPO+WN+K0u57HYkCAwEAAaNLMEkwOQYIKwYBBQUHAQEELTArMCkGCCsGAQUF -BzABhh1odHRwOi8vb2NzcC5leGFtcGxlLmNvbTo4ODg4LzAMBgNVHRMEBTADAQH/ -MA0GCSqGSIb3DQEBBQUAA4IBAQAzhJ0OslkE3O/jBIsAbGTqWJ42WXYnWaC47g2G -g//bZetsHxZH5/Xmw4iBc37tEo1+/V6xXGhH+PnK4+DA8xKyJDt3LJjeBW2o7Ce4 -r6uEJSZztFhMfMF0l5irDuaZcLw4sJrj2Vx1+kbSh1UJho/vSuTvPjLGrJ0nhim4 -eDh7h2xXcr1XmXM22/pSvXunBc0ouIX8EUdexndyavtzPoukbfgX9BLVNuDvXPiy -oWk+TM+GX2P2AmCVf2Hoy38UZto2LngTPmiuPxPBeYgYGD8j85rh536uUOS3gHYx -knR5LN7QdP6BfPYBFGofX4iFahEdUK/xl01nQMPprm9g4rzi +MIIEbTCCA1WgAwIBAgICEAcwDQYJKoZIhvcNAQELBQAwgaIxCzAJBgNVBAYTAk5P +MQ8wDQYDVQQIDAZOb3J3YXkxDTALBgNVBAcMBE9zbG8xDTALBgNVBAoMBFRRdEMx +LzAtBgNVBAsMJlRRdEMgVGVzdCBSb290IEF1dGhvcml6YXRpb24gQXV0aG9yaXR5 +MRowGAYDVQQDDBFUUXRDIHRlc3Qgcm9vdCBDQTEXMBUGCSqGSIb3DQEJARYIY2FA +cXQuaW8wHhcNMjEwNzI5MTcxNjA3WhcNMzEwNjA3MTcxNjA3WjCBqzELMAkGA1UE +BhMCTk8xDzANBgNVBAgMBk5vcndheTENMAsGA1UECgwEVFF0QzEwMC4GA1UECwwn +VFF0QyBJbnRlcm1lZGlhdGUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MTAwLgYDVQQD +DCdUUXRDIEludGVybWVkaWF0ZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxGDAWBgkq +hkiG9w0BCQEWCWljYUBxdC5pbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAK1zsW+VafypIPdVrDavxgPJ8LIdYyIJtijHNvWmGDl9fgK8EZWm6uIsvHOL +D2ZtHmBRXCGXOuXFonZh2vpuPUzBdD8E4CQVE31QHHb2eoalpNgiIRODJEfOwMJZ +V5FP/iE5g5TJmbiqMwui2v4g4AWoQpsiSYnlgLd/XbZePpSSAqyZYsxGmzbcf2Vq +v5Tv8SbjLjuRZdwHsrXi/7S4qyybiPHLLoLD7+woDRo8wy+z0wQ8v2XsRzjqvBUn +QvuOvk5MXKHQzXheClMizcDDOcjaK0AKzVopQa6s0+Pmg+DW162DOrK4SGqpeBlp +OujEtiQk9+1hycAadbntYQ+/kHcCAwEAAaOBoTCBnjAdBgNVHQ4EFgQUemD1HaWM +WxNLlSONkvAiFhlmtVowHwYDVR0jBBgwFoAUWm+CujWqNX9DM76Cr+FJwgbDsKkw +EgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwOAYIKwYBBQUHAQEE +LDAqMCgGCCsGAQUFBzABhhxodHRwOi8vb2NzcC5leGFtcGxlLmNvbTo4ODg4MA0G +CSqGSIb3DQEBCwUAA4IBAQBxfeQrh/xnjL8vLLQB0PrPawCUB4X0RHheNAB8BZh/ +5t96StDZspB1p14iW1b9ziiN+w8hghdLO+UbEmbnfK9m0sxXPxGdO/dK5PeKkEZA +1Clbu1qPEwmbCeuPDHpcXMzYUEm/vHTJFNxfvLgiLYwZpxhYZiHeMMEUYxQRrmI1 +DJbcpZT4nYyaVKinvMmw5KG85cLsyjIgzhUwLGSAfB+p4pIX+R8GQZtdn26+FN9c +U+ZDfAUJ0hrPmd89KuSXm96tarx/EYnGzwletTL2IJWS1zxpGFlpyFgWq3m054iD +UAWX8IPCQRMwhoKmSqNbhtYIKLXyDe3Xg6yD0ySDKjlB -----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qsslcertificate/verify-certs/test-intermediate-is-ca-cert.pem b/tests/auto/network/ssl/qsslcertificate/verify-certs/test-intermediate-is-ca-cert.pem index 396cad86cb..3f13c93473 100644 --- a/tests/auto/network/ssl/qsslcertificate/verify-certs/test-intermediate-is-ca-cert.pem +++ b/tests/auto/network/ssl/qsslcertificate/verify-certs/test-intermediate-is-ca-cert.pem @@ -1,53 +1,25 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 29 (0x1d) - Signature Algorithm: sha1WithRSAEncryption - Issuer: ST=Lancashire, C=UK/emailAddress=test@example.com, O=Test intermediate CA - Validity - Not Before: Jul 31 21:01:18 2011 GMT - Not After : Jul 28 21:01:18 2021 GMT - Subject: CN=example.com - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (1024 bit) - Modulus: - 00:c9:bb:98:5b:27:cd:b1:8a:a9:38:fc:aa:bb:ad: - a1:ed:cb:94:94:3e:79:90:ae:35:f3:87:b1:2a:4e: - d5:ff:55:93:e0:1a:68:2a:36:94:05:38:a7:72:64: - a3:31:0f:61:5c:ec:76:41:f1:35:4a:5e:bc:ef:51: - 90:9e:33:b4:08:7a:3f:f0:04:a8:46:99:96:25:b3: - 03:c8:cd:8c:33:42:76:82:b9:db:61:c6:91:ed:76: - 86:ae:04:38:d7:e5:5c:a9:a9:f9:b6:13:f4:90:40: - 6d:ec:2f:ba:ed:bc:ff:88:05:f0:7b:c8:ac:bd:d0: - 72:3a:91:64:86:06:89:66:0d - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: - CA:FALSE - Authority Information Access: - OCSP - URI:http://ocsp.example.com:8888/ - - Signature Algorithm: sha1WithRSAEncryption - 22:30:97:01:ea:d0:a8:d8:b5:32:97:c8:c9:8b:7d:01:02:53: - 74:f8:0a:10:dc:fc:73:b2:50:bb:59:47:f3:e4:9f:44:94:d5: - ca:c0:64:da:83:00:95:43:15:a5:e3:30:ce:66:ca:55:8c:16: - 03:1e:55:02:8b:c7:ad:ed:2e:ae:ee:31:59:53:37:ff:26:86: - 93:9d:e2:69:2e:c0:2a:66:38:a5:b5:54:a1:02:0a:83:67:e0: - 91:cf:fc:09:c3:70:71:b6:cf:fc:d3:e9:9f:f5:1c:4d:55:ec: - 66:f7:07:71:fc:d6:17:de:e1:ab:e6:f2:7b:83:46:1e:b9:96: - 95:8f -----BEGIN CERTIFICATE----- -MIICNjCCAZ+gAwIBAgIBHTANBgkqhkiG9w0BAQUFADBiMRMwEQYDVQQIEwpMYW5j -YXNoaXJlMQswCQYDVQQGEwJVSzEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxl -LmNvbTEdMBsGA1UEChMUVGVzdCBpbnRlcm1lZGlhdGUgQ0EwHhcNMTEwNzMxMjEw -MTE4WhcNMjEwNzI4MjEwMTE4WjAWMRQwEgYDVQQDEwtleGFtcGxlLmNvbTCBnzAN -BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAybuYWyfNsYqpOPyqu62h7cuUlD55kK41 -84exKk7V/1WT4BpoKjaUBTincmSjMQ9hXOx2QfE1Sl6871GQnjO0CHo/8ASoRpmW -JbMDyM2MM0J2grnbYcaR7XaGrgQ41+Vcqan5thP0kEBt7C+67bz/iAXwe8isvdBy -OpFkhgaJZg0CAwEAAaNIMEYwCQYDVR0TBAIwADA5BggrBgEFBQcBAQQtMCswKQYI -KwYBBQUHMAGGHWh0dHA6Ly9vY3NwLmV4YW1wbGUuY29tOjg4ODgvMA0GCSqGSIb3 -DQEBBQUAA4GBACIwlwHq0KjYtTKXyMmLfQECU3T4ChDc/HOyULtZR/Pkn0SU1crA -ZNqDAJVDFaXjMM5mylWMFgMeVQKLx63tLq7uMVlTN/8mhpOd4mkuwCpmOKW1VKEC -CoNn4JHP/AnDcHG2z/zT6Z/1HE1V7Gb3B3H81hfe4avm8nuDRh65lpWP +MIIEMjCCAxqgAwIBAgIUaR2Q0yCxxvaNVph0ASc+zhzQj2wwDQYJKoZIhvcNAQEL +BQAwgasxCzAJBgNVBAYTAk5PMQ8wDQYDVQQIDAZOb3J3YXkxDTALBgNVBAoMBFRR +dEMxMDAuBgNVBAsMJ1RRdEMgSW50ZXJtZWRpYXRlIENlcnRpZmljYXRlIEF1dGhv +cml0eTEwMC4GA1UEAwwnVFF0QyBJbnRlcm1lZGlhdGUgQ2VydGlmaWNhdGUgQXV0 +aG9yaXR5MRgwFgYJKoZIhvcNAQkBFglpY2FAcXQuaW8wHhcNMjEwNzI5MTcyODQy +WhcNMzEwNjA3MTcyODQyWjCBjDELMAkGA1UEBhMCTk8xDzANBgNVBAgMBk5vcndh +eTENMAsGA1UEBwwET3NsbzENMAsGA1UECgwEVFF0QzEXMBUGA1UECwwOUXQgRm91 +bmRhdGlvbnMxFDASBgNVBAMMC2V4YW1wbGUuY29tMR8wHQYJKoZIhvcNAQkBFhB0 +ZXN0QGV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +4oQJn7Q5RC3suFgq+mDXbheEG8CQWlCgRoiX4s6ZYVvkwAyh+AfKz6bF6uAkGhSU +BqRGfrTnU46V+IHZT3mxa9KUThhQKzGwEACAoZK1IivDRxA6y/BK3LfJc/hcFqA1 +kVWAs949fOgmJpai8LHXlGMdVnoWJE9jL4OnfHDloVzFLXqUzcvJWOFiEHnGvD8J +S+VmYbMc5Yyw73hrqVgpe302TdGr5x4vgeQwk99r37v1dmHKWiI9PcQyy/Qp576Y +V6pdL164D4cD6OgohSzqd0d3BwAvC8lO9MCJiL5l2TiaJpcEMxS8ycQCwaUp6HC1 +y+HHtfSYu9DRu4PXKccWlQIDAQABo2swaTAOBgNVHQ8BAf8EBAMCBeAwHQYDVR0l +BBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMDgGCCsGAQUFBwEBBCwwKjAoBggrBgEF +BQcwAYYcaHR0cDovL29jc3AuZXhhbXBsZS5jb206ODg4ODANBgkqhkiG9w0BAQsF +AAOCAQEAcMAO6aZesrll+VnceYD2A77Uckqu7UaJ+Cno/aXxaZuBVmfyhdUyK9DF +bqLNGooR2DGbCjnoOpAaNGngfEkLH/aiDOaGgF9hPOfeUo2Axw7ElfVvwoyEy4zy +h7GLaA491mjg3XF5ZB56wxbWiBO7nvnHP2ln6x8L5A9RZIofxmChwNuDulB5aog5 +xfoZn8nqM+HQZNUNx5gX/QgPaVu3ytcVy0t8KYQesATc4hu3kaUPP372Unm4qOyA +WjX8g4zgCs4aVhjNqWEuX4FPyZQeY0IE5BK+H50z0m+rfH02Amlvq7TYpN50A9wL +qLirP+moVzEWJKJP0HWT/jo7Ze53FA== -----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qsslcertificate/verify-certs/test-intermediate-not-ca-cert.pem b/tests/auto/network/ssl/qsslcertificate/verify-certs/test-intermediate-not-ca-cert.pem index 34ad2b10a8..836afd85d3 100644 --- a/tests/auto/network/ssl/qsslcertificate/verify-certs/test-intermediate-not-ca-cert.pem +++ b/tests/auto/network/ssl/qsslcertificate/verify-certs/test-intermediate-not-ca-cert.pem @@ -1,54 +1,24 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 27 (0x1b) - Signature Algorithm: sha1WithRSAEncryption - Issuer: CN=example.com, ST=Lancashire, C=UK/emailAddress=test@example.com, O=Some organisation - Validity - Not Before: Jul 31 21:01:18 2011 GMT - Not After : Jul 28 21:01:18 2021 GMT - Subject: CN=example.com - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (1024 bit) - Modulus: - 00:ea:d6:97:b5:3c:f4:37:8a:58:b4:7a:49:31:55: - dd:c8:84:ee:36:f6:72:3a:31:99:d1:df:af:bb:f9: - 17:e9:d8:47:d2:20:4b:94:ce:ea:c1:6b:23:9a:da: - 02:41:29:51:34:05:13:c0:98:4d:87:f8:91:a8:85: - 81:e4:ab:26:3d:26:59:29:16:7d:04:db:57:7b:f0: - b6:2b:5d:cf:e7:82:ba:83:a7:bc:63:43:03:2a:2b: - 18:40:89:4c:1e:90:bc:bf:10:24:81:50:0d:2e:e8: - 8e:a9:0a:fc:f8:cd:97:98:3c:cc:55:b7:f2:b2:0d: - 0e:36:53:3a:b2:d0:45:90:8b - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: - CA:FALSE - Authority Information Access: - OCSP - URI:http://ocsp.example.com:8888/ - - Signature Algorithm: sha1WithRSAEncryption - 82:d8:53:9c:d8:0b:0a:b3:9d:b4:0a:9f:93:ec:96:a6:31:6b: - 79:c9:d2:1c:76:0b:b7:f3:9f:b9:7a:dd:d7:b7:7b:26:ba:0a: - 54:2a:a3:ad:89:8e:3c:b8:8e:ea:09:53:58:73:9a:b3:a0:40: - 90:02:f2:60:04:b8:f0:2a:61:bd:91:9b:5e:81:5f:bf:cc:f2: - 33:33:8a:70:07:f5:ea:c0:05:38:34:f7:dc:ea:0c:74:01:5d: - dd:92:ab:f2:87:64:1b:7c:be:ae:37:c1:6c:ae:99:73:a5:aa: - 45:20:32:57:19:cb:30:45:61:2c:3b:23:52:ee:f0:cc:12:80: - 97:34 -----BEGIN CERTIFICATE----- -MIICSTCCAbKgAwIBAgIBGzANBgkqhkiG9w0BAQUFADB1MRQwEgYDVQQDEwtleGFt -cGxlLmNvbTETMBEGA1UECBMKTGFuY2FzaGlyZTELMAkGA1UEBhMCVUsxHzAdBgkq -hkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20xGjAYBgNVBAoTEVNvbWUgb3JnYW5p -c2F0aW9uMB4XDTExMDczMTIxMDExOFoXDTIxMDcyODIxMDExOFowFjEUMBIGA1UE -AxMLZXhhbXBsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOrWl7U8 -9DeKWLR6STFV3ciE7jb2cjoxmdHfr7v5F+nYR9IgS5TO6sFrI5raAkEpUTQFE8CY -TYf4kaiFgeSrJj0mWSkWfQTbV3vwtitdz+eCuoOnvGNDAyorGECJTB6QvL8QJIFQ -DS7ojqkK/PjNl5g8zFW38rINDjZTOrLQRZCLAgMBAAGjSDBGMAkGA1UdEwQCMAAw -OQYIKwYBBQUHAQEELTArMCkGCCsGAQUFBzABhh1odHRwOi8vb2NzcC5leGFtcGxl -LmNvbTo4ODg4LzANBgkqhkiG9w0BAQUFAAOBgQCC2FOc2AsKs520Cp+T7JamMWt5 -ydIcdgu385+5et3Xt3smugpUKqOtiY48uI7qCVNYc5qzoECQAvJgBLjwKmG9kZte -gV+/zPIzM4pwB/XqwAU4NPfc6gx0AV3dkqvyh2QbfL6uN8FsrplzpapFIDJXGcsw -RWEsOyNS7vDMEoCXNA== +MIID+jCCAuKgAwIBAgIUM3pG/f45Mn2QOCxAjTxuzXfIYj4wDQYJKoZIhvcNAQEL +BQAwgYcxCzAJBgNVBAYTAk5PMQ8wDQYDVQQIDAZOb3J3YXkxDTALBgNVBAcMBE9z +bG8xDTALBgNVBAoMBFRRdEMxEjAQBgNVBAsMCVNvbWUgVW5pdDEUMBIGA1UEAwwL +ZXhhbXBsZS5jb20xHzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20wHhcN +MjEwODA2MDQ0MjE1WhcNMzEwNjE1MDQ0MjE1WjCBjDELMAkGA1UEBhMCTk8xDzAN +BgNVBAgMBk5vcndheTENMAsGA1UEBwwET3NsbzENMAsGA1UECgwEVFF0QzEUMBIG +A1UECwwLRm91bmRhdGlvbnMxFDASBgNVBAMMC2V4YW1wbGUuY29tMSIwIAYJKoZI +hvcNAQkBFhNzaWduZWRieW5vbmNhQHF0LmlvMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEApXDPgUmyVw89XB1o+9yPepTyXOUnY4/4JHu333l3IQcEsK17 +tmOftWOa2TGzScrN0sbi73IhCx48/hYI3skHNiocXhHlrNI8tHkwHKWf5k957tMN +xeSIgddRXMegMc4Xxo9IMxFmvAi1q7gnIkEpBg+6NWRGhB3N2Iw8nUtyOc+wx6Us +EzRi/HpITzNsmeuwHPzlKe8HQsL5VeM9oo7HdH7Bb2M7t4+oizZe8jbvhbUWbylb +HDkD1ZoxDRyYAPYkYyvsIodDBSFOQmon7kZtshrmZO+VGPEDisaDJFYppyZNOmmA +g65IUf+0oJW73uuG5dZWwmjEhHlKhkmvqXBoUQIDAQABo1cwVTAOBgNVHQ8BAf8E +BAMCBeAwOAYIKwYBBQUHAQEELDAqMCgGCCsGAQUFBzABhhxodHRwOi8vb2NzcC5l +eGFtcGxlLmNvbTo4ODg4MAkGA1UdEwQCMAAwDQYJKoZIhvcNAQELBQADggEBACBb +ERwLEJ9zGMk4lpnSK4hr2v8JZdVRbozKHUo0Vky3yyVoaFfKZqha9JpP0Ig71lSv +h8tmM41uFmIWCBc+JEu3PIGvZcs45/Py7NHHY5bua3/szRhkz0FbsEYbrCCE/Fom +rYxOd21q9+Aj0/ZGFccpc5v47SW8UFFjn5rhDKXqX7IZjFY/O6ILD/MnDePK963C +pGltAzKw1RRTQoXQWWWOQZx6jT+JFRQ1cc+QlY106461/qg1m1AhBG6/S6tjkcdI +h1jq4yMhfPP9BhxquZB4/mrBUY2rvUO40973m50trszjXSsdRgyScmEJKWco4MAZ +ZccSsplcBjL5ksfejH4= -----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qsslcertificate/verify-certs/test-ocsp-good-cert.pem b/tests/auto/network/ssl/qsslcertificate/verify-certs/test-ocsp-good-cert.pem index 34b26c6d5e..d4cd3e1f92 100644 --- a/tests/auto/network/ssl/qsslcertificate/verify-certs/test-ocsp-good-cert.pem +++ b/tests/auto/network/ssl/qsslcertificate/verify-certs/test-ocsp-good-cert.pem @@ -1,67 +1,24 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: 1 (0x1) - Signature Algorithm: sha1WithRSAEncryption - Issuer: CN=Westpoint Certificate Test CA, ST=Lancashire, C=UK/emailAddress=ca@example.com, O=Westpoint Certificate Test Root Certification Authority - Validity - Not Before: Jul 31 21:01:16 2011 GMT - Not After : Jul 28 21:01:16 2021 GMT - Subject: CN=example.com, ST=Lancashire, C=UK/emailAddress=test@example.com, O=Some organisation - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - Public-Key: (1024 bit) - Modulus: - 00:97:c9:92:27:81:a7:4c:64:82:a2:30:d6:07:b7: - 57:e0:9c:ea:cd:eb:53:be:ea:b6:b5:47:66:d0:68: - 54:25:a7:ed:21:5c:dc:fd:da:41:f6:c7:c0:35:ae: - 97:72:fd:8b:af:29:3d:38:5a:67:8b:39:8a:ce:86: - 25:0f:38:a7:b5:38:b3:8e:81:f0:ea:79:99:cb:f5: - 23:64:55:f3:4b:a4:b6:23:64:29:ea:ba:f3:29:52: - a7:7f:32:dc:0d:b6:d9:d4:e6:13:de:01:41:86:9a: - 2d:8f:bb:0c:18:88:09:ac:d4:6a:e9:cb:8a:17:8a: - 85:09:a6:ae:a6:1c:05:e9:55 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Basic Constraints: - CA:FALSE - Authority Information Access: - OCSP - URI:http://ocsp.example.com:8888/ - - Signature Algorithm: sha1WithRSAEncryption - 8b:9b:96:fb:8e:1b:77:f5:70:39:fe:76:51:ac:a9:6b:80:a5: - b7:95:8b:c3:1a:9c:1f:bb:d1:d1:68:43:40:96:62:d6:a6:da: - d9:fd:9d:9a:9e:8a:84:fa:f5:54:ce:a8:d7:37:c7:0c:95:fc: - 11:8b:e9:32:53:e5:59:61:0a:53:70:f3:d6:ed:3f:b1:f4:49: - bf:86:c1:77:0d:b1:ac:65:7e:62:d2:f2:5a:31:50:a7:ed:28: - bb:63:d5:f3:4f:43:3a:3f:bf:3b:d0:94:aa:a1:74:95:be:a4: - 0f:8b:e0:6f:d8:33:84:76:71:b2:da:f4:0e:1e:d2:eb:f0:c3: - 1e:33:79:21:35:93:18:05:38:db:63:85:1a:e4:84:41:0a:c3: - fb:fd:5c:69:3d:18:0a:38:b8:16:18:d3:23:b9:51:47:2e:54: - 08:d1:fc:2e:b6:63:62:78:9c:26:59:c2:5e:5a:38:76:47:e7: - f0:f8:7b:b7:00:46:34:b0:44:28:a9:33:d7:e5:1d:52:c8:fb: - 32:a5:25:86:21:0c:80:f0:4b:37:60:a0:45:69:9f:6b:b0:34: - 91:5e:4c:62:45:99:83:1d:80:48:78:bb:ee:d4:83:39:76:c3: - e6:fb:31:e9:20:f0:64:90:24:4e:c6:07:75:40:1f:7e:97:77: - 1f:bf:a2:ef -----BEGIN CERTIFICATE----- -MIIDYDCCAkigAwIBAgIBATANBgkqhkiG9w0BAQUFADCBqzEmMCQGA1UEAxMdV2Vz -dHBvaW50IENlcnRpZmljYXRlIFRlc3QgQ0ExEzARBgNVBAgTCkxhbmNhc2hpcmUx -CzAJBgNVBAYTAlVLMR0wGwYJKoZIhvcNAQkBFg5jYUBleGFtcGxlLmNvbTFAMD4G -A1UEChM3V2VzdHBvaW50IENlcnRpZmljYXRlIFRlc3QgUm9vdCBDZXJ0aWZpY2F0 -aW9uIEF1dGhvcml0eTAeFw0xMTA3MzEyMTAxMTZaFw0yMTA3MjgyMTAxMTZaMHUx -FDASBgNVBAMTC2V4YW1wbGUuY29tMRMwEQYDVQQIEwpMYW5jYXNoaXJlMQswCQYD -VQQGEwJVSzEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbTEaMBgGA1UE -ChMRU29tZSBvcmdhbmlzYXRpb24wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGB -AJfJkieBp0xkgqIw1ge3V+Cc6s3rU77qtrVHZtBoVCWn7SFc3P3aQfbHwDWul3L9 -i68pPThaZ4s5is6GJQ84p7U4s46B8Op5mcv1I2RV80uktiNkKeq68ylSp38y3A22 -2dTmE94BQYaaLY+7DBiICazUaunLiheKhQmmrqYcBelVAgMBAAGjSDBGMAkGA1Ud -EwQCMAAwOQYIKwYBBQUHAQEELTArMCkGCCsGAQUFBzABhh1odHRwOi8vb2NzcC5l -eGFtcGxlLmNvbTo4ODg4LzANBgkqhkiG9w0BAQUFAAOCAQEAi5uW+44bd/VwOf52 -Uaypa4Clt5WLwxqcH7vR0WhDQJZi1qba2f2dmp6KhPr1VM6o1zfHDJX8EYvpMlPl -WWEKU3Dz1u0/sfRJv4bBdw2xrGV+YtLyWjFQp+0ou2PV809DOj+/O9CUqqF0lb6k -D4vgb9gzhHZxstr0Dh7S6/DDHjN5ITWTGAU422OFGuSEQQrD+/1caT0YCji4FhjT -I7lRRy5UCNH8LrZjYnicJlnCXlo4dkfn8Ph7twBGNLBEKKkz1+UdUsj7MqUlhiEM -gPBLN2CgRWmfa7A0kV5MYkWZgx2ASHi77tSDOXbD5vsx6SDwZJAkTsYHdUAffpd3 -H7+i7w== +MIIEEDCCAvigAwIBAgIUQrpDlYwLae3IBtw7fjH/oCSCWMYwDQYJKoZIhvcNAQEL +BQAwgaIxCzAJBgNVBAYTAk5PMQ8wDQYDVQQIDAZOb3J3YXkxDTALBgNVBAcMBE9z +bG8xDTALBgNVBAoMBFRRdEMxLzAtBgNVBAsMJlRRdEMgVGVzdCBSb290IEF1dGhv +cml6YXRpb24gQXV0aG9yaXR5MRowGAYDVQQDDBFUUXRDIHRlc3Qgcm9vdCBDQTEX +MBUGCSqGSIb3DQEJARYIY2FAcXQuaW8wHhcNMjEwODA2MDQzNzIyWhcNMzEwNjE1 +MDQzNzIyWjCBhzELMAkGA1UEBhMCTk8xDzANBgNVBAgMBk5vcndheTENMAsGA1UE +BwwET3NsbzENMAsGA1UECgwEVFF0QzESMBAGA1UECwwJU29tZSBVbml0MRQwEgYD +VQQDDAtleGFtcGxlLmNvbTEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNv +bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMEmu/GCuiQwbQf8qluK +5UovaQ4L3MHScVFbHlHu1Nyc12wmhhpzC3jC+OikxdCPpvxdNmdsOHonhNkO55sL +YygX4c4sCNM4B6VbJTfdOKHRBV6ySxFVS4jjBwB88Ouz9KieGiOAA6Lf6nqIBitU +eYQtBPye1lSqX4dAFHx7Il6Ad8Z3U9hUkqEpcW3AGSxFS6GebfTNleN85lXyLhHm +v66vEcHOGM7YSjWjUDto4C5LpYQHMvKe4/oZylQkRwevy8pZ+dK6ZiJuxzKVu2M2 ++LuYFeCRnFry5NBUBhpeLSOgJO2BYJZroRWygjBNUD6yToZFOX77ctL0+lXIgqZ8 +vT0CAwEAAaNXMFUwDgYDVR0PAQH/BAQDAgLkMDgGCCsGAQUFBwEBBCwwKjAoBggr +BgEFBQcwAYYcaHR0cDovL29jc3AuZXhhbXBsZS5jb206ODg4ODAJBgNVHRMEAjAA +MA0GCSqGSIb3DQEBCwUAA4IBAQAReaLhTl0k8+pmVNvnqkPg7UvwmZ1EStWyz0hn +Ar+NZSIdHUWqGqvoQVzcH5ODW3yfkNadhwfm8BJcFuy0ioTqhGuho3cI8Qr9MRQl +s0NNIjeENYbBElBXmJup4OdgCSy0GL3DeCoe3xR+IwHYeER/oH6VDBZrpVovHAk9 +6FlL6eBXgWu1YzXhKU4/enVIJ0A4LRF9WnyhQSucLwo3+bOvPxLBtmP+lWtXyKap +wMMNPu6EULAQ2IYcTgafCW9BWR1UWDXHBRO5ytBV4KFrhXiPoPmA4x0ACxnclH41 +b3Pj0pBur9cQuvap/FSz1uEfJdsYISw6srTfD4zNUuXXhSbz -----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qsslcipher/CMakeLists.txt b/tests/auto/network/ssl/qsslcipher/CMakeLists.txt index b6a2348fca..8538f56acd 100644 --- a/tests/auto/network/ssl/qsslcipher/CMakeLists.txt +++ b/tests/auto/network/ssl/qsslcipher/CMakeLists.txt @@ -1,21 +1,20 @@ -# Generated from qsslcipher.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qsslcipher Test: ##################################################################### -qt_add_test(tst_qsslcipher +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qsslcipher LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qsslcipher SOURCES tst_qsslcipher.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Network + BUNDLE_ANDROID_OPENSSL_LIBS ) - -## Scopes: -##################################################################### - -#### Keys ignored in scope 3:.:.:qsslcipher.pro:(CMAKE_BUILD_TYPE STREQUAL Debug): -# DESTDIR = "debug" - -#### Keys ignored in scope 4:.:.:qsslcipher.pro:else: -# DESTDIR = "release" diff --git a/tests/auto/network/ssl/qsslcipher/qsslcipher.pro b/tests/auto/network/ssl/qsslcipher/qsslcipher.pro deleted file mode 100644 index 392d22c054..0000000000 --- a/tests/auto/network/ssl/qsslcipher/qsslcipher.pro +++ /dev/null @@ -1,14 +0,0 @@ -CONFIG += testcase - -SOURCES += tst_qsslcipher.cpp -QT = core network testlib - -TARGET = tst_qsslcipher - -win32 { - CONFIG(debug, debug|release) { - DESTDIR = debug -} else { - DESTDIR = release - } -} diff --git a/tests/auto/network/ssl/qsslcipher/tst_qsslcipher.cpp b/tests/auto/network/ssl/qsslcipher/tst_qsslcipher.cpp index 9ffba1ec94..6810149c11 100644 --- a/tests/auto/network/ssl/qsslcipher/tst_qsslcipher.cpp +++ b/tests/auto/network/ssl/qsslcipher/tst_qsslcipher.cpp @@ -1,37 +1,9 @@ -/**************************************************************************** -** -** 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 <qsslcipher.h> +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + -#include <QtNetwork/qhostaddress.h> -#include <QtNetwork/qnetworkproxy.h> +#include <QTest> +#include <qsslcipher.h> class tst_QSslCipher : public QObject { @@ -50,6 +22,15 @@ private slots: void tst_QSslCipher::constructing() { QSslCipher cipher; + + QVERIFY(cipher.isNull()); + QCOMPARE(cipher.name(), QString()); + QCOMPARE(cipher.supportedBits(), 0); + QCOMPARE(cipher.usedBits(), 0); + QCOMPARE(cipher.keyExchangeMethod(), QString()); + QCOMPARE(cipher.authenticationMethod(), QString()); + QCOMPARE(cipher.protocolString(), QString()); + QCOMPARE(cipher.protocol(), QSsl::UnknownProtocol); } #endif // QT_NO_SSL diff --git a/tests/auto/network/ssl/qssldiffiehellmanparameters/CMakeLists.txt b/tests/auto/network/ssl/qssldiffiehellmanparameters/CMakeLists.txt index 0beb896018..3ac34b2f6c 100644 --- a/tests/auto/network/ssl/qssldiffiehellmanparameters/CMakeLists.txt +++ b/tests/auto/network/ssl/qssldiffiehellmanparameters/CMakeLists.txt @@ -1,12 +1,20 @@ -# Generated from qssldiffiehellmanparameters.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qssldiffiehellmanparameters Test: ##################################################################### -qt_add_test(tst_qssldiffiehellmanparameters +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qssldiffiehellmanparameters LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qssldiffiehellmanparameters SOURCES tst_qssldiffiehellmanparameters.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Network + BUNDLE_ANDROID_OPENSSL_LIBS ) diff --git a/tests/auto/network/ssl/qssldiffiehellmanparameters/qssldiffiehellmanparameters.pro b/tests/auto/network/ssl/qssldiffiehellmanparameters/qssldiffiehellmanparameters.pro deleted file mode 100644 index 2d45f4476c..0000000000 --- a/tests/auto/network/ssl/qssldiffiehellmanparameters/qssldiffiehellmanparameters.pro +++ /dev/null @@ -1,7 +0,0 @@ -CONFIG += testcase -CONFIG += parallel_test - -SOURCES += tst_qssldiffiehellmanparameters.cpp -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 index 60add4a51c..d8c6d9158a 100644 --- a/tests/auto/network/ssl/qssldiffiehellmanparameters/tst_qssldiffiehellmanparameters.cpp +++ b/tests/auto/network/ssl/qssldiffiehellmanparameters/tst_qssldiffiehellmanparameters.cpp @@ -1,32 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk> -** 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> +// Copyright (C) 2015 Mikkel Krautz <mikkel@krautz.dk> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QTest> + +#include <QtNetwork/qtnetworkglobal.h> + #include <QSslDiffieHellmanParameters> #include <QSslSocket> #include <QByteArray> @@ -42,8 +20,9 @@ class tst_QSslDiffieHellmanParameters : public QObject { Q_OBJECT -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) private Q_SLOTS: + void initTestCase(); void constructionEmpty(); void constructionDefault(); void constructionDER(); @@ -51,10 +30,16 @@ private Q_SLOTS: void unsafe512Bits(); void unsafeNonPrime(); void defaultIsValid(); -#endif +#endif // Feature 'ssl'. }; -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) + +void tst_QSslDiffieHellmanParameters::initTestCase() +{ + if (QSslSocket::activeBackend() != QStringLiteral("openssl")) + QSKIP("The active TLS backend does not support QSslDiffieHellmanParameters"); +} void tst_QSslDiffieHellmanParameters::constructionEmpty() { @@ -69,10 +54,8 @@ 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() @@ -91,10 +74,8 @@ void tst_QSslDiffieHellmanParameters::constructionDER() "52DcHKlsqDuafQ1XVGmzVIrKtBi2gfLtPqY4v6g6v26l8gbzK67PpWstllHiPb4VMCAQI=" )), QSsl::Der); -#ifndef QT_NO_OPENSSL QCOMPARE(dh.isValid(), true); QCOMPARE(dh.error(), QSslDiffieHellmanParameters::NoError); -#endif } void tst_QSslDiffieHellmanParameters::constructionPEM() @@ -116,10 +97,8 @@ void tst_QSslDiffieHellmanParameters::constructionPEM() "-----END DH PARAMETERS-----\n" ), QSsl::Pem); -#ifndef QT_NO_OPENSSL QCOMPARE(dh.isValid(), true); QCOMPARE(dh.error(), QSslDiffieHellmanParameters::NoError); -#endif } void tst_QSslDiffieHellmanParameters::unsafe512Bits() @@ -132,10 +111,8 @@ void tst_QSslDiffieHellmanParameters::unsafe512Bits() "-----END DH PARAMETERS-----\n" ), QSsl::Pem); -#ifndef QT_NO_OPENSSL QCOMPARE(dh.isValid(), false); QCOMPARE(dh.error(), QSslDiffieHellmanParameters::UnsafeParametersError); -#endif } void tst_QSslDiffieHellmanParameters::unsafeNonPrime() @@ -148,10 +125,8 @@ void tst_QSslDiffieHellmanParameters::unsafeNonPrime() "vholAW9zilkoYkB6sqwxY1Z2dbpTWajCsUAWZQ0AIP4Y5nesAgEC" )), QSsl::Der); -#ifndef QT_NO_OPENSSL QCOMPARE(dh.isValid(), false); QCOMPARE(dh.error(), QSslDiffieHellmanParameters::UnsafeParametersError); -#endif } void tst_QSslDiffieHellmanParameters::defaultIsValid() @@ -173,15 +148,13 @@ void tst_QSslDiffieHellmanParameters::defaultIsValid() const auto defaultdh = QSslDiffieHellmanParameters::defaultParameters(); -#ifndef QT_NO_OPENSSL QCOMPARE(dh.isEmpty(), false); QCOMPARE(dh.isValid(), true); QCOMPARE(dh.error(), QSslDiffieHellmanParameters::NoError); QCOMPARE(dh, defaultdh); -#endif } -#endif // QT_NO_SSL +#endif // Feature 'ssl'. QTEST_MAIN(tst_QSslDiffieHellmanParameters) #include "tst_qssldiffiehellmanparameters.moc" diff --git a/tests/auto/network/ssl/qsslellipticcurve/CMakeLists.txt b/tests/auto/network/ssl/qsslellipticcurve/CMakeLists.txt index 89ee2a1b91..dd031a991b 100644 --- a/tests/auto/network/ssl/qsslellipticcurve/CMakeLists.txt +++ b/tests/auto/network/ssl/qsslellipticcurve/CMakeLists.txt @@ -1,12 +1,20 @@ -# Generated from qsslellipticcurve.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qsslellipticcurve Test: ##################################################################### -qt_add_test(tst_qsslellipticcurve +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qsslellipticcurve LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qsslellipticcurve SOURCES tst_qsslellipticcurve.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Network + BUNDLE_ANDROID_OPENSSL_LIBS ) diff --git a/tests/auto/network/ssl/qsslellipticcurve/qsslellipticcurve.pro b/tests/auto/network/ssl/qsslellipticcurve/qsslellipticcurve.pro deleted file mode 100644 index 7eae6ae864..0000000000 --- a/tests/auto/network/ssl/qsslellipticcurve/qsslellipticcurve.pro +++ /dev/null @@ -1,6 +0,0 @@ -CONFIG += testcase - -SOURCES += tst_qsslellipticcurve.cpp -QT = core network testlib - -TARGET = tst_qsslellipticcurve diff --git a/tests/auto/network/ssl/qsslellipticcurve/tst_qsslellipticcurve.cpp b/tests/auto/network/ssl/qsslellipticcurve/tst_qsslellipticcurve.cpp index 7e268ddb62..96ef7e9828 100644 --- a/tests/auto/network/ssl/qsslellipticcurve/tst_qsslellipticcurve.cpp +++ b/tests/auto/network/ssl/qsslellipticcurve/tst_qsslellipticcurve.cpp @@ -1,33 +1,14 @@ -/**************************************************************************** -** -** 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> +// Copyright (C) 2014 Governikus GmbH & Co. KG. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QTest> + +#include <QtNetwork/qtnetworkglobal.h> + +#if QT_CONFIG(ssl) +#include <QSslSocket> +#endif // ssl + #include <QSslEllipticCurve> #include <QSslConfiguration> @@ -35,30 +16,35 @@ class tst_QSslEllipticCurve : public QObject { Q_OBJECT -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) private Q_SLOTS: + void initTestCase(); void constExpr(); void construction(); void fromShortName_data(); void fromShortName(); void fromLongName_data(); void fromLongName(); -#endif +#endif // Feature 'ssl'. }; -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) + +void tst_QSslEllipticCurve::initTestCase() +{ + // At the moment only OpenSSL backend properly supports + // QSslEllipticCurve. + if (QSslSocket::activeBackend() != QStringLiteral("openssl")) + QSKIP("The active TLS backend does not support QSslEllipticCurve"); +} void tst_QSslEllipticCurve::constExpr() { -#ifdef Q_COMPILER_CONSTEXPR // check that default ctor and op ==/!= are constexpr: char array1[QSslEllipticCurve() == QSslEllipticCurve() ? 1 : -1]; char array2[QSslEllipticCurve() != QSslEllipticCurve() ? -1 : 1]; Q_UNUSED(array1); Q_UNUSED(array2); -#else - QSKIP("This test requires C++11 generalized constant expression support enabled in the compiler."); -#endif } void tst_QSslEllipticCurve::construction() @@ -79,7 +65,8 @@ void tst_QSslEllipticCurve::fromShortName_data() QTest::newRow("QString()") << QString() << QSslEllipticCurve() << false; QTest::newRow("\"\"") << QString("") << QSslEllipticCurve() << false; QTest::newRow("does-not-exist") << QStringLiteral("does-not-exist") << QSslEllipticCurve() << false; - Q_FOREACH (QSslEllipticCurve ec, QSslConfiguration::supportedEllipticCurves()) { + const auto supported = QSslConfiguration::supportedEllipticCurves(); + for (QSslEllipticCurve ec : supported) { const QString sN = ec.shortName(); QTest::newRow(qPrintable("supported EC \"" + sN + '"')) << sN << ec << true; // At least in the OpenSSL impl, the short name is case-sensitive. That feels odd. @@ -112,7 +99,8 @@ void tst_QSslEllipticCurve::fromLongName_data() QTest::newRow("QString()") << QString() << QSslEllipticCurve() << false; QTest::newRow("\"\"") << QString("") << QSslEllipticCurve() << false; QTest::newRow("does-not-exist") << QStringLiteral("does-not-exist") << QSslEllipticCurve() << false; - Q_FOREACH (QSslEllipticCurve ec, QSslConfiguration::supportedEllipticCurves()) { + const auto supported = QSslConfiguration::supportedEllipticCurves(); + for (QSslEllipticCurve ec : supported) { const QString lN = ec.longName(); QTest::newRow(qPrintable("supported EC \"" + lN + '"')) << lN << ec << true; } @@ -131,7 +119,7 @@ void tst_QSslEllipticCurve::fromLongName() QCOMPARE(result.longName(), valid ? longName : QString()); } -#endif // QT_NO_SSL +#endif // Feature 'ssl'. QTEST_MAIN(tst_QSslEllipticCurve) #include "tst_qsslellipticcurve.moc" diff --git a/tests/auto/network/ssl/qsslerror/CMakeLists.txt b/tests/auto/network/ssl/qsslerror/CMakeLists.txt index 8324220b46..006bec3ef2 100644 --- a/tests/auto/network/ssl/qsslerror/CMakeLists.txt +++ b/tests/auto/network/ssl/qsslerror/CMakeLists.txt @@ -1,21 +1,20 @@ -# Generated from qsslerror.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qsslerror Test: ##################################################################### -qt_add_test(tst_qsslerror +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qsslerror LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt_internal_add_test(tst_qsslerror SOURCES tst_qsslerror.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Network + BUNDLE_ANDROID_OPENSSL_LIBS ) - -## Scopes: -##################################################################### - -#### Keys ignored in scope 3:.:.:qsslerror.pro:(CMAKE_BUILD_TYPE STREQUAL Debug): -# DESTDIR = "debug" - -#### Keys ignored in scope 4:.:.:qsslerror.pro:else: -# DESTDIR = "release" diff --git a/tests/auto/network/ssl/qsslerror/qsslerror.pro b/tests/auto/network/ssl/qsslerror/qsslerror.pro deleted file mode 100644 index 83644d093c..0000000000 --- a/tests/auto/network/ssl/qsslerror/qsslerror.pro +++ /dev/null @@ -1,14 +0,0 @@ -CONFIG += testcase - -SOURCES += tst_qsslerror.cpp -QT = core network testlib - -TARGET = tst_qsslerror - -win32 { - CONFIG(debug, debug|release) { - DESTDIR = debug -} else { - DESTDIR = release - } -} diff --git a/tests/auto/network/ssl/qsslerror/tst_qsslerror.cpp b/tests/auto/network/ssl/qsslerror/tst_qsslerror.cpp index 438234b6dd..981fe3a0d5 100644 --- a/tests/auto/network/ssl/qsslerror/tst_qsslerror.cpp +++ b/tests/auto/network/ssl/qsslerror/tst_qsslerror.cpp @@ -1,78 +1,115 @@ -/**************************************************************************** -** -** 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> +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + + +#include <QtNetwork/qtnetworkglobal.h> + +#include <qsslcertificate.h> #include <qsslerror.h> -#include <QtNetwork/qhostaddress.h> -#include <QtNetwork/qnetworkproxy.h> +#include <QTest> +#include <QTestEventLoop> +#include <QtCore/qmetaobject.h> +#include <QtCore/qbytearray.h> +#include <QtCore/qstring.h> +#include <QtCore/qset.h> + +QT_USE_NAMESPACE + +const QByteArray certificateBytes = + "-----BEGIN CERTIFICATE-----\n" + "MIIEjjCCBDOgAwIBAgIQCQsKtxCf9ik3vIVQ+PMa5TAKBggqhkjOPQQDAjBKMQsw\n" + "CQYDVQQGEwJVUzEZMBcGA1UEChMQQ2xvdWRmbGFyZSwgSW5jLjEgMB4GA1UEAxMX\n" + "Q2xvdWRmbGFyZSBJbmMgRUNDIENBLTMwHhcNMjAwODE2MDAwMDAwWhcNMjEwODE2\n" + "MTIwMDAwWjBhMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDVNh\n" + "biBGcmFuY2lzY28xGTAXBgNVBAoTEENsb3VkZmxhcmUsIEluYy4xEjAQBgNVBAMT\n" + "CXd3dy5xdC5pbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABP/r0xH22wdU8fLk\n" + "RsXhxRj5fmUNUo7rxnUl3lyqYYp53cLvn3agQifXkegpE8Xv4pGmuyWZj85FtoeZ\n" + "UZh8iyCjggLiMIIC3jAfBgNVHSMEGDAWgBSlzjfq67B1DpRniLRF+tkkEIeWHzAd\n" + "BgNVHQ4EFgQU7qPYGi9VtC4/6MS+54LNEAXApBgwFAYDVR0RBA0wC4IJd3d3LnF0\n" + "LmlvMA4GA1UdDwEB/wQEAwIHgDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH\n" + "AwIwewYDVR0fBHQwcjA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0Ns\n" + "b3VkZmxhcmVJbmNFQ0NDQS0zLmNybDA3oDWgM4YxaHR0cDovL2NybDQuZGlnaWNl\n" + "cnQuY29tL0Nsb3VkZmxhcmVJbmNFQ0NDQS0zLmNybDBMBgNVHSAERTBDMDcGCWCG\n" + "SAGG/WwBATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20v\n" + "Q1BTMAgGBmeBDAECAjB2BggrBgEFBQcBAQRqMGgwJAYIKwYBBQUHMAGGGGh0dHA6\n" + "Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBABggrBgEFBQcwAoY0aHR0cDovL2NhY2VydHMu\n" + "ZGlnaWNlcnQuY29tL0Nsb3VkZmxhcmVJbmNFQ0NDQS0zLmNydDAMBgNVHRMBAf8E\n" + "AjAAMIIBBAYKKwYBBAHWeQIEAgSB9QSB8gDwAHYA9lyUL9F3MCIUVBgIMJRWjuNN\n" + "Exkzv98MLyALzE7xZOMAAAFz90PlSQAABAMARzBFAiAhrrtxdmuxpCy8HAJJ5Qkg\n" + "WNvlo8nZqfe6pqGUcz0dmwIhAOMqDtd5ZhcfRk96GAJxPm8bH4hDnmqDP/zJG2Mq\n" + "nFpMAHYAXNxDkv7mq0VEsV6a1FbmEDf71fpH3KFzlLJe5vbHDsoAAAFz90PlewAA\n" + "BAMARzBFAiB/EkdY10LDdaRcf6eSc/QxucxU+2PI+3pWjh/21A8ZUAIhAK2Qz9Kw\n" + "onlRNyHpV3E6qyVydkXihj3c3q5UclpURYcmMAoGCCqGSM49BAMCA0kAMEYCIQDz\n" + "K/lzLb2Rbeg1HErRLLm2HkJUmfOGU2+tbROSTGK8ugIhAKA+MKqaZ8VjPxQ+Ho4v\n" + "fuwccvZfkU/fg8tAHTOzX23v\n" + "-----END CERTIFICATE-----"; class tst_QSslError : 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(); - } - -#ifndef QT_NO_SSL private slots: void constructing(); + void nonDefaultConstructors(); void hash(); -#endif - -private: - static int loopLevel; }; -int tst_QSslError::loopLevel = 0; - -#ifndef QT_NO_SSL - void tst_QSslError::constructing() { - QSslError error; + const QSslError error; + QCOMPARE(error.error(), QSslError::NoError); + QCOMPARE(error.errorString(), QStringLiteral("No error")); + QVERIFY(error.certificate().isNull()); +} + +void tst_QSslError::nonDefaultConstructors() +{ + if (!QSslSocket::supportsSsl()) + QSKIP("This test requires a working TLS library"); + + const auto chain = QSslCertificate::fromData(certificateBytes); + QCOMPARE(chain.size(), 1); + const auto certificate = chain.at(0); + QVERIFY(!certificate.isNull()); + + const auto visitor = QSslError::staticMetaObject; + const int nEnums = visitor.enumeratorCount(); + QMetaEnum errorCodesEnum; + for (int i = 0; i < nEnums; ++i) { + const auto metaEnum = visitor.enumerator(i); + if (metaEnum.enumName() == QStringLiteral("SslError")) { + errorCodesEnum = metaEnum; + break; + } + } + + QCOMPARE(errorCodesEnum.enumName(), QStringLiteral("SslError")); + for (int i = 0, e = errorCodesEnum.keyCount(); i < e; ++i) { + const int value = errorCodesEnum.value(i); + if (value == -1) { + QVERIFY(i); + break; + } + const auto errorCode = QSslError::SslError(value); + QSslError error(errorCode); + + const auto basicChecks = [](const QSslError &err, QSslError::SslError code) { + QCOMPARE(err.error(), code); + const auto errorString = err.errorString(); + if (code == QSslError::NoError) + QCOMPARE(errorString, QStringLiteral("No error")); + else + QVERIFY(errorString != QStringLiteral("No error")); + }; + + basicChecks(error, errorCode); + + // ;) + error = QSslError(errorCode, certificate); + + basicChecks(error, errorCode); + QVERIFY(!error.certificate().isNull()); + } } void tst_QSslError::hash() @@ -83,7 +120,5 @@ void tst_QSslError::hash() QCOMPARE(errors.size(), 1); } -#endif // QT_NO_SSL - QTEST_MAIN(tst_QSslError) #include "tst_qsslerror.moc" diff --git a/tests/auto/network/ssl/qsslkey/BLACKLIST b/tests/auto/network/ssl/qsslkey/BLACKLIST deleted file mode 100644 index 19fb15cd1f..0000000000 --- a/tests/auto/network/ssl/qsslkey/BLACKLIST +++ /dev/null @@ -1,9 +0,0 @@ -[constructor] -rhel -[length] -rhel -[toEncryptedPemOrDer] -rhel -[toPemOrDer] -rhel - diff --git a/tests/auto/network/ssl/qsslkey/CMakeLists.txt b/tests/auto/network/ssl/qsslkey/CMakeLists.txt index e83f4c1f40..aae017562a 100644 --- a/tests/auto/network/ssl/qsslkey/CMakeLists.txt +++ b/tests/auto/network/ssl/qsslkey/CMakeLists.txt @@ -1,9 +1,16 @@ -# Generated from qsslkey.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qsslkey Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qsslkey LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + # Collect test data file(GLOB_RECURSE test_data_glob RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} @@ -14,19 +21,25 @@ file(GLOB_RECURSE test_data_glob rsa-*.pem) list(APPEND test_data ${test_data_glob}) -qt_add_test(tst_qsslkey +qt_internal_add_test(tst_qsslkey SOURCES tst_qsslkey.cpp - PUBLIC_LIBRARIES + LIBRARIES Qt::Network TESTDATA ${test_data} + BUNDLE_ANDROID_OPENSSL_LIBS +) + +qt_internal_extend_target(tst_qsslkey CONDITION QT_FEATURE_developer_build AND QT_FEATURE_openssl_linked + LIBRARIES + WrapOpenSSL::WrapOpenSSL ) ## Scopes: ##################################################################### -qt_extend_target(tst_qsslkey CONDITION QT_FEATURE_private_tests - PUBLIC_LIBRARIES +qt_internal_extend_target(tst_qsslkey CONDITION QT_FEATURE_developer_build + LIBRARIES Qt::CorePrivate Qt::NetworkPrivate ) diff --git a/tests/auto/network/ssl/qsslkey/keys/genkeys.sh b/tests/auto/network/ssl/qsslkey/keys/genkeys.sh index 0106953bff..afa4b7fe84 100755 --- a/tests/auto/network/ssl/qsslkey/keys/genkeys.sh +++ b/tests/auto/network/ssl/qsslkey/keys/genkeys.sh @@ -1,31 +1,6 @@ #!/bin/sh -############################################################################# -## -## Copyright (C) 2016 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is the build configuration utility 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$ -## -############################################################################# +# Copyright (C) 2016 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 # This script generates cryptographic keys of different types. diff --git a/tests/auto/network/ssl/qsslkey/qsslkey.pro b/tests/auto/network/ssl/qsslkey/qsslkey.pro deleted file mode 100644 index 8ed65e68ad..0000000000 --- a/tests/auto/network/ssl/qsslkey/qsslkey.pro +++ /dev/null @@ -1,12 +0,0 @@ -CONFIG += testcase - -SOURCES += tst_qsslkey.cpp -QT = core network testlib -qtConfig(private_tests) { - QT += core-private network-private -} - -TARGET = tst_qsslkey - -TESTDATA += keys/* \ - rsa-*.pem diff --git a/tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp b/tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp index b1dbd2773b..79bae3c270 100644 --- a/tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp +++ b/tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp @@ -1,33 +1,7 @@ -/**************************************************************************** -** -** 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> +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QTest> #include <qsslkey.h> #include <qsslsocket.h> #include <QScopeGuard> @@ -41,16 +15,22 @@ #include <QtCore/qdebug.h> #include <QtCore/qlist.h> +using namespace Qt::StringLiterals; + #ifdef QT_BUILD_INTERNAL - #ifndef QT_NO_SSL + #if QT_CONFIG(ssl) #include "private/qsslkey_p.h" #define TEST_CRYPTO #endif #ifndef QT_NO_OPENSSL - #include "private/qsslsocket_openssl_symbols_p.h" + #include "../shared/qopenssl_symbols.h" #endif #endif +#if QT_CONFIG(ssl) +#include <QtNetwork/qsslsocket.h> +#endif // QT_CONFIG(ssl) + #include <algorithm> class tst_QSslKey : public QObject @@ -79,7 +59,7 @@ public: public slots: void initTestCase(); -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) private slots: void emptyConstructor(); @@ -107,16 +87,23 @@ private slots: void encrypt(); #endif -#endif +#endif // ssl private: QString testDataDir; bool fileContainsUnsupportedEllipticCurve(const QString &fileName) const; + bool algorithmsSupported(const QString &fileName) const; QVector<QString> unsupportedCurves; + + bool isOpenSsl = false; + bool isOpenSslResolved = false; + bool isSecureTransport = false; + bool isSchannel = false; }; tst_QSslKey::tst_QSslKey() { +#if QT_CONFIG(ssl) const QString expectedCurves[] = { // See how we generate them in keys/genkey.sh. QStringLiteral("secp224r1"), @@ -139,6 +126,25 @@ tst_QSslKey::tst_QSslKey() unsupportedCurves.push_back(requestedEc); } } + // Alas, we don't use network-private (and why?). + const auto backendName = QSslSocket::activeBackend(); + isOpenSsl = backendName == QStringLiteral("openssl"); + + if (isOpenSsl) { +#if !defined(QT_NO_OPENSSL) && defined(QT_BUILD_INTERNAL) + isOpenSslResolved = qt_auto_test_resolve_OpenSSL_symbols(); +#else + isOpenSslResolved = false; // not 'unused variable' anymore. +#endif + } else { + isSecureTransport = backendName == QStringLiteral("securetransport"); + } + + if (!isOpenSsl && !isSecureTransport) + isSchannel = backendName == QStringLiteral("schannel"); +#else + unsupportedCurves = {}; // not unsued anymore. +#endif } bool tst_QSslKey::fileContainsUnsupportedEllipticCurve(const QString &fileName) const @@ -150,6 +156,37 @@ bool tst_QSslKey::fileContainsUnsupportedEllipticCurve(const QString &fileName) return false; } +bool tst_QSslKey::algorithmsSupported(const QString &fileName) const +{ +#if QT_CONFIG(ssl) + if (isSchannel && fileName.contains("RC2-64")) // Schannel treats RC2 as 128 bit + return false; + + if (isSchannel || isSecureTransport) { + // No AES support in the generic back-end, PKCS#12 algorithms not supported either. + return !(fileName.contains(QRegularExpression("-aes\\d\\d\\d-")) || fileName.contains("pkcs8-pkcs12")); + } + + if (!isOpenSsl || QSslSocket::sslLibraryVersionNumber() >> 28 < 3) + return true; + + // OpenSSL v3 first introduced the notion of 'providers'. Many algorithms + // were moved into the 'legacy' provider. While they are still supported in theory, + // the 'legacy' provider is NOT loaded by default and we are not loading it either. + // Thus, some of the keys we are using in tst_QSslKey would fail the test. We + // have to filter them out. + const auto name = fileName.toLower(); + if (name.contains("-des.")) + return false; + + return !name.contains("-rc2-") && !name.contains("-rc4-"); +#else + Q_UNUSED(fileName); + return false; +#endif // QT_CONFIG(ssl) +} + + void tst_QSslKey::initTestCase() { testDataDir = QFileInfo(QFINDTESTDATA("rsa-without-passphrase.pem")).absolutePath(); @@ -178,13 +215,13 @@ void tst_QSslKey::initTestCase() } } -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) static QByteArray readFile(const QString &absFilePath) { QFile file(absFilePath); if (!file.open(QIODevice::ReadOnly)) { - QWARN("failed to open file"); + qWarning("failed to open file"); return QByteArray(); } return file.readAll(); @@ -214,19 +251,12 @@ void tst_QSslKey::createPlainTestRows(bool pemOnly) QTest::addColumn<QSsl::KeyType>("type"); QTest::addColumn<int>("length"); QTest::addColumn<QSsl::EncodingFormat>("format"); - foreach (KeyInfo keyInfo, keyInfoList) { + for (const KeyInfo &keyInfo : std::as_const(keyInfoList)) { if (pemOnly && keyInfo.format != QSsl::EncodingFormat::Pem) continue; -#if QT_CONFIG(schannel) - if (keyInfo.fileInfo.fileName().contains("RC2-64")) - continue; // Schannel treats RC2 as 128 bit -#endif -#if !defined(QT_NO_SSL) && defined(QT_NO_OPENSSL) // generic backend - if (keyInfo.fileInfo.fileName().contains(QRegularExpression("-aes\\d\\d\\d-"))) - continue; // No AES support in the generic back-end - if (keyInfo.fileInfo.fileName().contains("pkcs8-pkcs12")) - continue; // The generic back-end doesn't support PKCS#12 algorithms -#endif + + if (!algorithmsSupported(keyInfo.fileInfo.fileName())) + continue; QTest::newRow(keyInfo.fileInfo.fileName().toLatin1()) << keyInfo.fileInfo.absoluteFilePath() << keyInfo.algorithm << keyInfo.type @@ -269,7 +299,7 @@ void tst_QSslKey::constructorHandle() #ifndef QT_BUILD_INTERNAL QSKIP("This test requires -developer-build."); #else - if (!QSslSocket::supportsSsl()) + if (!isOpenSslResolved) return; QFETCH(QString, absFilePath); @@ -287,7 +317,7 @@ void tst_QSslKey::constructorHandle() passphrase = "1234"; BIO* bio = q_BIO_new(q_BIO_s_mem()); - q_BIO_write(bio, pem.constData(), pem.length()); + q_BIO_write(bio, pem.constData(), pem.size()); EVP_PKEY *origin = func(bio, nullptr, nullptr, static_cast<void *>(passphrase.data())); Q_ASSERT(origin); q_EVP_PKEY_up_ref(origin); @@ -327,7 +357,7 @@ void tst_QSslKey::constructorHandle() #endif } -#endif +#endif // !QT_NO_OPENSSL void tst_QSslKey::copyAndAssign_data() { @@ -415,13 +445,13 @@ void tst_QSslKey::toPemOrDer() QByteArray dataTag = QByteArray(QTest::currentDataTag()); if (dataTag.contains("-pkcs8-")) // these are encrypted QSKIP("Encrypted PKCS#8 keys gets decrypted when loaded. So we can't compare it to the encrypted version."); -#ifndef QT_NO_OPENSSL - if (dataTag.contains("pkcs8")) - QSKIP("OpenSSL converts PKCS#8 keys to other formats, invalidating comparisons."); -#else // !openssl - if (dataTag.contains("pkcs8") && dataTag.contains("rsa")) - QSKIP("PKCS#8 RSA keys are changed into a different format in the generic back-end, meaning the comparison fails."); -#endif // openssl + + if (dataTag.contains("pkcs8")) { + if (isOpenSsl) + QSKIP("OpenSSL converts PKCS#8 keys to other formats, invalidating comparisons."); + else if (dataTag.contains("rsa")) + QSKIP("PKCS#8 RSA keys are changed into a different format in the generic back-end, meaning the comparison fails."); + } QByteArray encoded = readFile(absFilePath); QSslKey key(encoded, algorithm, format, type); @@ -439,13 +469,18 @@ void tst_QSslKey::toEncryptedPemOrDer_data() QTest::addColumn<QSsl::EncodingFormat>("format"); QTest::addColumn<QString>("password"); - QStringList passwords; - passwords << " " << "foobar" << "foo bar" - << "aAzZ`1234567890-=~!@#$%^&*()_+[]{}\\|;:'\",.<>/?"; // ### add more (?) - foreach (KeyInfo keyInfo, keyInfoList) { + const QString passwords[] = { + u" "_s, + u"foobar"_s, + u"foo bar"_s, + u"aAzZ`1234567890-=~!@#$%^&*()_+[]{}\\|;:'\",.<>/?"_s, + // ### add more (?) + }; + + for (const KeyInfo &keyInfo : std::as_const(keyInfoList)) { if (keyInfo.fileInfo.fileName().contains("pkcs8")) continue; // pkcs8 keys are encrypted in a different way than the other keys - foreach (QString password, passwords) { + for (const QString &password : passwords) { const QByteArray testName = keyInfo.fileInfo.fileName().toLatin1() + '-' + (keyInfo.algorithm == QSsl::Rsa ? "RSA" : (keyInfo.algorithm == QSsl::Dsa ? "DSA" : "EC")) @@ -511,20 +546,29 @@ void tst_QSslKey::toEncryptedPemOrDer() void tst_QSslKey::passphraseChecks_data() { + if (!QSslSocket::supportsSsl()) + QSKIP("This test requires a working TLS library"); + QTest::addColumn<QString>("fileName"); QTest::addColumn<QByteArray>("passphrase"); const QByteArray pass("123"); const QByteArray aesPass("1234"); - QTest::newRow("DES") << QString(testDataDir + "rsa-with-passphrase-des.pem") << pass; + if (!isOpenSsl || QSslSocket::sslLibraryVersionNumber() >> 28 < 3) { + // DES and RC2 are not provided by default in OpenSSL v3. + // This part is for either non-OpenSSL build, or OpenSSL v < 3.x. + QTest::newRow("DES") << QString(testDataDir + "rsa-with-passphrase-des.pem") << pass; + QTest::newRow("RC2") << QString(testDataDir + "rsa-with-passphrase-rc2.pem") << pass; + } + QTest::newRow("3DES") << QString(testDataDir + "rsa-with-passphrase-3des.pem") << pass; - QTest::newRow("RC2") << QString(testDataDir + "rsa-with-passphrase-rc2.pem") << pass; -#if (!defined(QT_NO_OPENSSL) && !defined(OPENSSL_NO_AES)) || (defined(QT_NO_OPENSSL) && QT_CONFIG(ssl)) + +#if defined(QT_NO_OPENSSL) || !defined(OPENSSL_NO_AES) QTest::newRow("AES128") << QString(testDataDir + "rsa-with-passphrase-aes128.pem") << aesPass; QTest::newRow("AES192") << QString(testDataDir + "rsa-with-passphrase-aes192.pem") << aesPass; QTest::newRow("AES256") << QString(testDataDir + "rsa-with-passphrase-aes256.pem") << aesPass; -#endif // (OpenSSL && AES) || generic backend +#endif // Generic backend || OpenSSL built with AES } void tst_QSslKey::passphraseChecks() @@ -536,7 +580,7 @@ void tst_QSslKey::passphraseChecks() QVERIFY(keyFile.exists()); { if (!keyFile.isOpen()) - keyFile.open(QIODevice::ReadOnly); + QVERIFY(keyFile.open(QIODevice::ReadOnly)); else keyFile.reset(); QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey); @@ -544,7 +588,7 @@ void tst_QSslKey::passphraseChecks() } { if (!keyFile.isOpen()) - keyFile.open(QIODevice::ReadOnly); + QVERIFY(keyFile.open(QIODevice::ReadOnly)); else keyFile.reset(); QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, ""); @@ -552,7 +596,7 @@ void tst_QSslKey::passphraseChecks() } { if (!keyFile.isOpen()) - keyFile.open(QIODevice::ReadOnly); + QVERIFY(keyFile.open(QIODevice::ReadOnly)); else keyFile.reset(); QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "WRONG!"); @@ -560,7 +604,7 @@ void tst_QSslKey::passphraseChecks() } { if (!keyFile.isOpen()) - keyFile.open(QIODevice::ReadOnly); + QVERIFY(keyFile.open(QIODevice::ReadOnly)); else keyFile.reset(); QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, passphrase); @@ -570,12 +614,15 @@ void tst_QSslKey::passphraseChecks() void tst_QSslKey::noPassphraseChecks() { + if (!QSslSocket::supportsSsl()) + QSKIP("This test requires a working TLS library"); + // be sure and check a key without passphrase too QString fileName(testDataDir + "rsa-without-passphrase.pem"); QFile keyFile(fileName); { if (!keyFile.isOpen()) - keyFile.open(QIODevice::ReadOnly); + QVERIFY(keyFile.open(QIODevice::ReadOnly)); else keyFile.reset(); QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey); @@ -583,7 +630,7 @@ void tst_QSslKey::noPassphraseChecks() } { if (!keyFile.isOpen()) - keyFile.open(QIODevice::ReadOnly); + QVERIFY(keyFile.open(QIODevice::ReadOnly)); else keyFile.reset(); QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, ""); @@ -591,7 +638,7 @@ void tst_QSslKey::noPassphraseChecks() } { if (!keyFile.isOpen()) - keyFile.open(QIODevice::ReadOnly); + QVERIFY(keyFile.open(QIODevice::ReadOnly)); else keyFile.reset(); QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "xxx"); @@ -604,139 +651,145 @@ Q_DECLARE_METATYPE(QSslKeyPrivate::Cipher) void tst_QSslKey::encrypt_data() { - QTest::addColumn<QSslKeyPrivate::Cipher>("cipher"); + using QTlsPrivate::Cipher; + + QTest::addColumn<Cipher>("cipher"); QTest::addColumn<QByteArray>("key"); QTest::addColumn<QByteArray>("plainText"); QTest::addColumn<QByteArray>("cipherText"); QTest::addColumn<QByteArray>("iv"); QByteArray iv("abcdefgh"); +#if OPENSSL_VERSION_MAJOR < 3 + // Either non-OpenSSL build, or OpenSSL v < 3 + // (with DES and other legacy algorithms available by default) QTest::newRow("DES-CBC, length 0") - << QSslKeyPrivate::DesCbc << QByteArray("01234567") + << Cipher::DesCbc << QByteArray("01234567") << QByteArray() << QByteArray::fromHex("956585228BAF9B1F") << iv; QTest::newRow("DES-CBC, length 1") - << QSslKeyPrivate::DesCbc << QByteArray("01234567") + << Cipher::DesCbc << QByteArray("01234567") << QByteArray(1, 'a') << QByteArray::fromHex("E6880AF202BA3C12") << iv; QTest::newRow("DES-CBC, length 2") - << QSslKeyPrivate::DesCbc << QByteArray("01234567") + << Cipher::DesCbc << QByteArray("01234567") << QByteArray(2, 'a') << QByteArray::fromHex("A82492386EED6026") << iv; QTest::newRow("DES-CBC, length 3") - << QSslKeyPrivate::DesCbc << QByteArray("01234567") + << Cipher::DesCbc << QByteArray("01234567") << QByteArray(3, 'a') << QByteArray::fromHex("90B76D5B79519CBA") << iv; QTest::newRow("DES-CBC, length 4") - << QSslKeyPrivate::DesCbc << QByteArray("01234567") + << Cipher::DesCbc << QByteArray("01234567") << QByteArray(4, 'a') << QByteArray::fromHex("63E3DD6FED87052A") << iv; QTest::newRow("DES-CBC, length 5") - << QSslKeyPrivate::DesCbc << QByteArray("01234567") + << Cipher::DesCbc << QByteArray("01234567") << QByteArray(5, 'a') << QByteArray::fromHex("03ACDB0EACBDFA94") << iv; QTest::newRow("DES-CBC, length 6") - << QSslKeyPrivate::DesCbc << QByteArray("01234567") + << Cipher::DesCbc << QByteArray("01234567") << QByteArray(6, 'a') << QByteArray::fromHex("7D95024E42A3A88A") << iv; QTest::newRow("DES-CBC, length 7") - << QSslKeyPrivate::DesCbc << QByteArray("01234567") + << Cipher::DesCbc << QByteArray("01234567") << QByteArray(7, 'a') << QByteArray::fromHex("5003436B8A8E42E9") << iv; QTest::newRow("DES-CBC, length 8") - << QSslKeyPrivate::DesCbc << QByteArray("01234567") + << Cipher::DesCbc << QByteArray("01234567") << QByteArray(8, 'a') << QByteArray::fromHex("E4C1F054BF5521C0A4A0FD4A2BC6C1B1") << iv; QTest::newRow("DES-EDE3-CBC, length 0") - << QSslKeyPrivate::DesEde3Cbc << QByteArray("0123456789abcdefghijklmn") + << Cipher::DesEde3Cbc << QByteArray("0123456789abcdefghijklmn") << QByteArray() << QByteArray::fromHex("3B2B4CD0B0FD495F") << iv; QTest::newRow("DES-EDE3-CBC, length 8") - << QSslKeyPrivate::DesEde3Cbc << QByteArray("0123456789abcdefghijklmn") + << Cipher::DesEde3Cbc << QByteArray("0123456789abcdefghijklmn") << QByteArray(8, 'a') << QByteArray::fromHex("F2A5A87763C54A72A3224103D90CDB03") << iv; QTest::newRow("RC2-40-CBC, length 0") - << QSslKeyPrivate::Rc2Cbc << QByteArray("01234") + << Cipher::Rc2Cbc << QByteArray("01234") << QByteArray() << QByteArray::fromHex("6D05D52392FF6E7A") << iv; QTest::newRow("RC2-40-CBC, length 8") - << QSslKeyPrivate::Rc2Cbc << QByteArray("01234") + << Cipher::Rc2Cbc << QByteArray("01234") << QByteArray(8, 'a') << QByteArray::fromHex("75768E64C5749072A5D168F3AFEB0005") << iv; QTest::newRow("RC2-64-CBC, length 0") - << QSslKeyPrivate::Rc2Cbc << QByteArray("01234567") + << Cipher::Rc2Cbc << QByteArray("01234567") << QByteArray() << QByteArray::fromHex("ADAE6BF70F420130") << iv; QTest::newRow("RC2-64-CBC, length 8") - << QSslKeyPrivate::Rc2Cbc << QByteArray("01234567") + << Cipher::Rc2Cbc << QByteArray("01234567") << QByteArray(8, 'a') << QByteArray::fromHex("C7BF5C80AFBE9FBEFBBB9FD935F6D0DF") << iv; QTest::newRow("RC2-128-CBC, length 0") - << QSslKeyPrivate::Rc2Cbc << QByteArray("012345679abcdefg") + << Cipher::Rc2Cbc << QByteArray("012345679abcdefg") << QByteArray() << QByteArray::fromHex("1E965D483A13C8FB") << iv; QTest::newRow("RC2-128-CBC, length 8") - << QSslKeyPrivate::Rc2Cbc << QByteArray("012345679abcdefg") + << Cipher::Rc2Cbc << QByteArray("012345679abcdefg") << QByteArray(8, 'a') << QByteArray::fromHex("5AEC1A5B295660B02613454232F7DECE") << iv; +#endif // OPENSSL_VERSION_MAJOR -#if (!defined(QT_NO_OPENSSL) && !defined(OPENSSL_NO_AES)) || (defined(QT_NO_OPENSSL) && QT_CONFIG(ssl)) +#if defined(QT_NO_OPENSSL) || !defined(OPENSSL_NO_AES) // AES needs a longer IV iv = QByteArray("abcdefghijklmnop"); QTest::newRow("AES-128-CBC, length 0") - << QSslKeyPrivate::Aes128Cbc << QByteArray("012345679abcdefg") + << Cipher::Aes128Cbc << QByteArray("012345679abcdefg") << QByteArray() << QByteArray::fromHex("28DE1A9AA26601C30DD2527407121D1A") << iv; QTest::newRow("AES-128-CBC, length 8") - << QSslKeyPrivate::Aes128Cbc << QByteArray("012345679abcdefg") + << Cipher::Aes128Cbc << QByteArray("012345679abcdefg") << QByteArray(8, 'a') << QByteArray::fromHex("08E880B1BA916F061C1E801D7F44D0EC") << iv; QTest::newRow("AES-192-CBC, length 0") - << QSslKeyPrivate::Aes192Cbc << QByteArray("0123456789abcdefghijklmn") + << Cipher::Aes192Cbc << QByteArray("0123456789abcdefghijklmn") << QByteArray() << QByteArray::fromHex("E169E0E205CDC2BA895B7CF6097673B1") << iv; QTest::newRow("AES-192-CBC, length 8") - << QSslKeyPrivate::Aes192Cbc << QByteArray("0123456789abcdefghijklmn") + << Cipher::Aes192Cbc << QByteArray("0123456789abcdefghijklmn") << QByteArray(8, 'a') << QByteArray::fromHex("3A227D6A3A13237316D30AA17FF9B0A7") << iv; QTest::newRow("AES-256-CBC, length 0") - << QSslKeyPrivate::Aes256Cbc << QByteArray("0123456789abcdefghijklmnopqrstuv") + << Cipher::Aes256Cbc << QByteArray("0123456789abcdefghijklmnopqrstuv") << QByteArray() << QByteArray::fromHex("4BAACAA0D22199C97DE206C465B7B14A") << iv; QTest::newRow("AES-256-CBC, length 8") - << QSslKeyPrivate::Aes256Cbc << QByteArray("0123456789abcdefghijklmnopqrstuv") + << Cipher::Aes256Cbc << QByteArray("0123456789abcdefghijklmnopqrstuv") << QByteArray(8, 'a') << QByteArray::fromHex("879C8C25EC135CDF0B14490A0A7C2F67") << iv; -#endif // (OpenSSL && AES) || generic backend +#endif // Generic backend || OpenSSL built with AES } void tst_QSslKey::encrypt() @@ -747,21 +800,22 @@ void tst_QSslKey::encrypt() QFETCH(QByteArray, cipherText); QFETCH(QByteArray, iv); -#if QT_CONFIG(schannel) - QEXPECT_FAIL("RC2-40-CBC, length 0", "Schannel treats RC2 as 128-bit", Abort); - QEXPECT_FAIL("RC2-40-CBC, length 8", "Schannel treats RC2 as 128-bit", Abort); - QEXPECT_FAIL("RC2-64-CBC, length 0", "Schannel treats RC2 as 128-bit", Abort); - QEXPECT_FAIL("RC2-64-CBC, length 8", "Schannel treats RC2 as 128-bit", Abort); -#endif + if (isSchannel) { + QEXPECT_FAIL("RC2-40-CBC, length 0", "Schannel treats RC2 as 128-bit", Abort); + QEXPECT_FAIL("RC2-40-CBC, length 8", "Schannel treats RC2 as 128-bit", Abort); + QEXPECT_FAIL("RC2-64-CBC, length 0", "Schannel treats RC2 as 128-bit", Abort); + QEXPECT_FAIL("RC2-64-CBC, length 8", "Schannel treats RC2 as 128-bit", Abort); + } + QByteArray encrypted = QSslKeyPrivate::encrypt(cipher, plainText, key, iv); QCOMPARE(encrypted, cipherText); QByteArray decrypted = QSslKeyPrivate::decrypt(cipher, cipherText, key, iv); QCOMPARE(decrypted, plainText); } -#endif +#endif // TEST_CRYPTO -#endif +#endif // ssl QTEST_MAIN(tst_QSslKey) #include "tst_qsslkey.moc" diff --git a/tests/auto/network/ssl/qsslserver/CMakeLists.txt b/tests/auto/network/ssl/qsslserver/CMakeLists.txt new file mode 100644 index 0000000000..5957b2720e --- /dev/null +++ b/tests/auto/network/ssl/qsslserver/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qsslserver LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +if(NOT QT_FEATURE_private_tests) + return() +endif() + +##################################################################### +## tst_qsslserver Test: +##################################################################### + +# Collect test data +list(APPEND test_data "certs") + +qt_internal_add_test(tst_qsslserver + SOURCES + tst_qsslserver.cpp + LIBRARIES + Qt::CorePrivate + Qt::NetworkPrivate + TESTDATA ${test_data} + BUNDLE_ANDROID_OPENSSL_LIBS +) diff --git a/tests/auto/network/ssl/qsslserver/certs/selfsigned-client.crt b/tests/auto/network/ssl/qsslserver/certs/selfsigned-client.crt new file mode 100644 index 0000000000..88da2db920 --- /dev/null +++ b/tests/auto/network/ssl/qsslserver/certs/selfsigned-client.crt @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC6TCCAdECCC/r9KvmbWTKMA0GCSqGSIb3DQEBCwUAMDUxFDASBgNVBAMMC0F1 +c3dlaXNBcHAyMR0wGwYDVQQFExQxODIzNTE0MTY0NzI5NDg5NDM3MTAiGA8xOTcw +MDEwMTAwMDAwMFoYDzk5OTkxMjMxMjM1OTU5WjA1MRQwEgYDVQQDDAtBdXN3ZWlz +QXBwMjEdMBsGA1UEBRMUMTgyMzUxNDE2NDcyOTQ4OTQzNzEwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCahBpcZyr+PJBCpolzQeFVvDKABwlpdRKGZ8qq +jD4sq2L7VlBJslgJGv5vsB5oJbnX1FFEu4Uw2kYb/LhnFCEXEFtGKRpWOEZOOqWb +4l4q2MCa82ZCoIDt8yoAt0sSShbtR6pjW+l0lwAOEpfGvMaMVo5JUyspRxhl1dSu +sS2Wf65zliqF5VSM2r4xMfJ6LVytxDZsGfTe/HFT2OYYrF+UQZg0mNL39rYWOK4R +xoOz8eLl3K5hKuHNfn5zPt5QtMhaIvebijBg23xJpl+BeoS37WzaK1f+NyWZKPFb +rttvSnFxpkyRHqJJ5piNGH6pkQ1+zhd7uh7eOIwxktjYBOFzAgMBAAEwDQYJKoZI +hvcNAQELBQADggEBADw3MYPft+X78OK/2HAltzsKjfxv/D5qVizm9hcyG1GYe5pS +qgFn0trCyJopYdbRr+hP7CuHwMmv62CZiHSog3CBPoUh19JENUDGbHXxTEFleB0i +Fd8I2+WvRjbQ+ehaeTJPx88v5kkJnB2tZUNZuhEws8emCwr1G0TQv1tRYCR1Lp9i +8/I3FSFpL1zyk47WfM/THa279MPw9WtrFGA6oi36gH9mYxek7n/zQTVi54xDx9GT +KigBYqavjFdNXryjLTCCtJpMTDePgP66NAUnxn0D/amI2vSbIN++PSTsBm+n4Ti5 +QW/ShFQDNb4bDiwjtTKCeKwvAp2/6GSHVkYy28M= +-----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qsslserver/certs/selfsigned-client.key b/tests/auto/network/ssl/qsslserver/certs/selfsigned-client.key new file mode 100644 index 0000000000..9e59342963 --- /dev/null +++ b/tests/auto/network/ssl/qsslserver/certs/selfsigned-client.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAmoQaXGcq/jyQQqaJc0HhVbwygAcJaXUShmfKqow+LKti+1ZQ +SbJYCRr+b7AeaCW519RRRLuFMNpGG/y4ZxQhFxBbRikaVjhGTjqlm+JeKtjAmvNm +QqCA7fMqALdLEkoW7UeqY1vpdJcADhKXxrzGjFaOSVMrKUcYZdXUrrEtln+uc5Yq +heVUjNq+MTHyei1crcQ2bBn03vxxU9jmGKxflEGYNJjS9/a2FjiuEcaDs/Hi5dyu +YSrhzX5+cz7eULTIWiL3m4owYNt8SaZfgXqEt+1s2itX/jclmSjxW67bb0pxcaZM +kR6iSeaYjRh+qZENfs4Xe7oe3jiMMZLY2AThcwIDAQABAoIBAFjgvc0C5t8AdTZx +VsS+U2Aedang4lAPsE0xbIj3TFgjaTcLKfmKJUtvhIU39/WOJbz4+pofhvhXxVYZ +4vQfxvzeQrIzuFt52S7sWxA0gFgC/57hfKO8cQzt/u4UgJEPnupze5XVa47NwJFX +rof5U/erXgLdXQlMRMNm4QRvE7rp58E2MkSYNur0Xgy9L7cRcUQJ8iuMaxBpOzhS +fbNFi5zT7RCGcQSIDcb1JFlgs5tMUs6jzLoDSVD2+vvsN4i4LAAPkJSGTGed5vY1 +xn4G8KPR4HHrnBYEb0SGu4ZTznOnQ+JSKhQrbnvEzXM4RTfjqn0YvF8x70+pWSMi +Fb4mlBECgYEAzW82O79HAlMm8LD7J4byPfVc/1M5/JOnE9H+RR5Vt4jZQGyjCmJu +cj4UeZyVim0xg30sSYrJ2Urd27CtHp+sMgHkvJt3/ZgcfMZJbMKNGq/OUtV8s/cA +nkU++/LgeW8r7wpaDjT7bfnOdcf16mYoXrmk0rTJvRqGXCBvCxtt5bsCgYEAwIxu +vZjPV4Vu/VX6sH2d31D9EFZuZKjGhqukFVtRqLbeosqT9mA+LhQ/wP5qoR2gLQbe +EwxJLJwGFjUhyhbHNlo6oHv3fWkzmHIMPwDRRI3Ktwi/50SwNSnyERUQcLaiwqKx +BqaxPYNnspUt0nKE0LFZsSlrfEyxajqAlUEgm6kCgYAV+uQumFScpxDvh8AXhpS8 +lFgS6XC22YVy1XEDLC+3p2i3P+hh4A45IvNF378QRIabrvTiGXtnSF9cdhbPw/3E +i/dRRsEb3P6PSxfoDxjR1iWZL0Zcav0h8f6/LkleNMralJz2EC0moye36mEhZzTC +jdJYyQccuI3PpZi7839aqQKBgGezOnEiO4kHdB88jyc+gCglliWWZx4PR9x/1H8s +D26uDnneYJHwg4yNm0h1vTfInNujNzdLBp3f6edL9kbAvcmoDqsgGMqSPhd8VNwZ +tJsXQnYRYElN1RjM3nIUxiXuNvpcZLsQS6S1gMPNVEBjLOS4n3WquRjYtTRhDZ9U +1BsBAoGAUFrIatOLFhcgaqENHyUbMx5uSx0lIfF6Xd5KIAgi+btdmugHe+NK8Cd2 +Rc2bQLQ9K1SvKFX6nFuEsGxnXkKuyhL/j0Kgm8nZin4uAcrtFnNdFumvCL6YgYSc +IvvM+uVfGEdbqm4pTuiLBfzOXIIy3kVlLGo402QG1pBzOtmsRMs= +-----END RSA PRIVATE KEY----- diff --git a/tests/auto/network/ssl/qsslserver/certs/selfsigned-server.crt b/tests/auto/network/ssl/qsslserver/certs/selfsigned-server.crt new file mode 100644 index 0000000000..c97d27721c --- /dev/null +++ b/tests/auto/network/ssl/qsslserver/certs/selfsigned-server.crt @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC5TCCAc0CCAO22gNi0v20MA0GCSqGSIb3DQEBCwUAMDMxFDASBgNVBAMMC0F1 +c3dlaXNBcHAyMRswGQYDVQQFExIyNTIxMTE1NjY3NjM2MjExODgwIhgPMTk3MDAx +MDEwMDAwMDBaGA85OTk5MTIzMTIzNTk1OVowMzEUMBIGA1UEAwwLQXVzd2Vpc0Fw +cDIxGzAZBgNVBAUTEjI1MjExMTU2Njc2MzYyMTE4ODCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAL+Fl6v5dcU7qk7vbINclWOhvCe/uklKnXV2QU382x7g +qpbYxJiJvz24C6tgDMmE0pwEz6PiCbh1dkc8+9cdp37eBcFLCOXYQb27gqVVyVtu +xO0LLVXPCv48bGSwljOz0FRC3FolzWxzrZogM/i2b/lmehHJ3D4ejmINmIgtFJ9P +JNNCH4Oh5YEbaFFlNf2m7lCoSuQkOlLZcGeLoipK2XvhZJff6c1uxValh/Mx5dNB +5Mgd5cOZSSEhwf7mcE8C3SHVfjeNfZGIqlkwdY8lvAOjirAtj6Yl88sJOUID/Q/N +hU9D8IZy6+Bk2cJQwI/Gzr590VYvlSTI+6lXr//oBBECAwEAATANBgkqhkiG9w0B +AQsFAAOCAQEArSMO88AYT+9tPCl5lXtSRa0OycqKNlW58GujxIDuR8WX1eFmGSHQ +uijo5KPYUnqydZzAewGC8NvC9WcLwFltNZ9igXikUHiAHc1JLfW7+7SgKpwOUb02 +rJkUkpPA/SmwkLSKYiR1prt5wgSulU1HPBESep05DfR8MCU5+KHkLyXDqtrbudJ4 +lQd9dSKJFn+cSjUC5JNxCPHoIISe7hfGFMLkd0/tVfSIXLVOAZG4K6zExUdjyPi8 +qEuPq6QCRyIJbYQc5HfnARgwK6GXHqkyLWlqK946Yz8VOba7Nan5uQ6xCjUMHw8Z +z/673o/3DCaQ9N6dWahNQ09a9ZH8U1X4iA== +-----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qsslserver/certs/selfsigned-server.key b/tests/auto/network/ssl/qsslserver/certs/selfsigned-server.key new file mode 100644 index 0000000000..b7be118cb9 --- /dev/null +++ b/tests/auto/network/ssl/qsslserver/certs/selfsigned-server.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAv4WXq/l1xTuqTu9sg1yVY6G8J7+6SUqddXZBTfzbHuCqltjE +mIm/PbgLq2AMyYTSnATPo+IJuHV2Rzz71x2nft4FwUsI5dhBvbuCpVXJW27E7Qst +Vc8K/jxsZLCWM7PQVELcWiXNbHOtmiAz+LZv+WZ6EcncPh6OYg2YiC0Un08k00If +g6HlgRtoUWU1/abuUKhK5CQ6UtlwZ4uiKkrZe+Fkl9/pzW7FVqWH8zHl00HkyB3l +w5lJISHB/uZwTwLdIdV+N419kYiqWTB1jyW8A6OKsC2PpiXzywk5QgP9D82FT0Pw +hnLr4GTZwlDAj8bOvn3RVi+VJMj7qVev/+gEEQIDAQABAoIBADdoXsjSEtBMwqiz +e6FFV7LLR7P4M9ygSY2B+MKnNH1qYe/iJn4626jvZfDeiNSEKKoaejffXRCQaveR +HQrO+XYqpV+WZayZM+vAI7vRZb+d/DrX0PXSQEvtDy7SJ6Itk0fNUBKEfTmy/bZp +Op/pp9tvWkFrNNyD2o1jgY1j/WNY8g605m0oURJ9WQsMUu/Kzu+NMoaKTIoQGb3d +dP71F4KaTXHYxj3B0c+y0NedKbrvnBsP6XbEpgJBaXjtD9z+z/aMF6dmuvpkx7uY +qzwPMRw05QPyJ9x+1V/v4TytY5f596NgW2niVj77BunkZasTYIEX7bjByrlTeLdx +xvPRpAECgYEA5KkM/ORbhN1oaw9+tQxA48oG2DFqChBr+vc4NU4j5SNFn9ks5nHI +xdJNZ9k+bjVUkBP4m88Wd07SW9zXCL8Q5lczb+p5SWl/Pp7ltqaxpH17uzamsaIv +KIBkeJTOU5TuWdXiV5FY+ofK9ojyEaqX1tmylWnoVe4bIMRWXE5bMSkCgYEA1mvJ +snkNzPFG0RK7ikjsNxrhzE07+7RSnoM9WeW8y2lvQ9MjdR6eOgqnnlcdk2A7OVbf +culNgLc0qx/PxZ4BV+8yLLb1EBBGvuVG+x4a6H2mLHdFCJekByZHaQNs9ogVLvdv +3z8D59KknBUjtj9dCw90Z41yMM4kpWMG9yfSEKkCgYEAvuCvytwF2d/JrrV8nD3i +XUTkecymLEiRGysMbNMR+9F56XotlSEe7KQloa8kAnPaZ3uEaOxyYJ4X1D+B8fct +cFsSwTYGkVXTtr6GG/cDC8EEbL+uX1J382Nae54croEAh1WYYGkg0eJRd4PSLxUt +M1j/TuLd4/2j/7JmNR/j2CECgYBdB3MBHghgzKXe+/OmMbFazyz8SN4nfLsDzwkF +QenBj0MY+DhADkK0B/9lcYKBeJT5cbmMz7AykkolnK22nbETh9ILGG4GxCkNlchQ +F2WxTSKV1EF9Ut11xKPi6fuSksQuFmjRQTPelsOYfIt7/M3PiKsGapYKmsXHg8l3 +3i0D0QKBgQCi+HNOaYqduxwjrj8h4eUbiwjID8DCNJ+jXsuGVa6jcsfFpdpivx2c +ytYSXuTXLRq0I3c1ChUOGQQeztJ5GtCPnXjLHHMf3f6yr7Pk56AUmUsaIlR1Q2Zo +gqpFD8zYD5UFc2KM7Y38YTh4j82uDzDvHBBFpli7dEmSn2WpcmzFag== +-----END RSA PRIVATE KEY----- diff --git a/tests/auto/network/ssl/qsslserver/tst_qsslserver.cpp b/tests/auto/network/ssl/qsslserver/tst_qsslserver.cpp new file mode 100644 index 0000000000..26d3a50a5b --- /dev/null +++ b/tests/auto/network/ssl/qsslserver/tst_qsslserver.cpp @@ -0,0 +1,531 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QTest> +#include <QDebug> +#include <QSignalSpy> +#include <QTimer> + +#include <QtNetwork/QSslServer> +#include <QtNetwork/QSslKey> +#include "private/qtlsbackend_p.h" + +class tst_QSslServer : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + void testOneSuccessfulConnection(); + void testSelfSignedCertificateRejectedByServer(); + void testSelfSignedCertificateRejectedByClient(); +#if QT_CONFIG(openssl) + void testHandshakeInterruptedOnError(); + void testPreSharedKeyAuthenticationRequired(); +#endif + void plaintextClient(); + void quietClient(); + void twoGoodAndManyBadClients(); + +private: + QString testDataDir; + bool isTestingOpenSsl = false; + QSslConfiguration selfSignedClientQSslConfiguration(); + QSslConfiguration selfSignedServerQSslConfiguration(); + QSslConfiguration createQSslConfiguration(QString keyFileName, QString certificateFileName); +}; + +class SslServerSpy : public QObject +{ + Q_OBJECT + +public: + SslServerSpy(QSslConfiguration &configuration); + + QSslServer server; + QSignalSpy sslErrorsSpy; + QSignalSpy peerVerifyErrorSpy; + QSignalSpy errorOccurredSpy; + QSignalSpy pendingConnectionAvailableSpy; + QSignalSpy preSharedKeyAuthenticationRequiredSpy; + QSignalSpy alertSentSpy; + QSignalSpy alertReceivedSpy; + QSignalSpy handshakeInterruptedOnErrorSpy; + QSignalSpy startedEncryptionHandshakeSpy; +}; + +SslServerSpy::SslServerSpy(QSslConfiguration &configuration) + : server(), + sslErrorsSpy(&server, &QSslServer::sslErrors), + peerVerifyErrorSpy(&server, &QSslServer::peerVerifyError), + errorOccurredSpy(&server, &QSslServer::errorOccurred), + pendingConnectionAvailableSpy(&server, &QSslServer::pendingConnectionAvailable), + preSharedKeyAuthenticationRequiredSpy(&server, + &QSslServer::preSharedKeyAuthenticationRequired), + alertSentSpy(&server, &QSslServer::alertSent), + alertReceivedSpy(&server, &QSslServer::alertReceived), + handshakeInterruptedOnErrorSpy(&server, &QSslServer::handshakeInterruptedOnError), + startedEncryptionHandshakeSpy(&server, &QSslServer::startedEncryptionHandshake) +{ + server.setSslConfiguration(configuration); +} + +void tst_QSslServer::initTestCase() +{ + testDataDir = QFileInfo(QFINDTESTDATA("certs")).absolutePath(); + if (testDataDir.isEmpty()) + testDataDir = QCoreApplication::applicationDirPath(); + if (!testDataDir.endsWith(QLatin1String("/"))) + testDataDir += QLatin1String("/"); + + const QString openSslBackend = QTlsBackend::builtinBackendNames[QTlsBackend::nameIndexOpenSSL]; + const auto &tlsBackends = QSslSocket::availableBackends(); + if (tlsBackends.contains(openSslBackend)) { + isTestingOpenSsl = true; + } +} + +QSslConfiguration tst_QSslServer::selfSignedClientQSslConfiguration() +{ + return createQSslConfiguration(testDataDir + "certs/selfsigned-client.key", + testDataDir + "certs/selfsigned-client.crt"); +} + +QSslConfiguration tst_QSslServer::selfSignedServerQSslConfiguration() +{ + return createQSslConfiguration(testDataDir + "certs/selfsigned-server.key", + testDataDir + "certs/selfsigned-server.crt"); +} + +QSslConfiguration tst_QSslServer::createQSslConfiguration(QString keyFileName, + QString certificateFileName) +{ + QSslConfiguration configuration(QSslConfiguration::defaultConfiguration()); + + QFile keyFile(keyFileName); + if (keyFile.open(QIODevice::ReadOnly)) { + QSslKey key(keyFile.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey); + if (!key.isNull()) { + configuration.setPrivateKey(key); + } else { + qCritical() << "Could not parse key: " << keyFileName; + } + } else { + qCritical() << "Could not find key: " << keyFileName; + } + + QList<QSslCertificate> localCert = QSslCertificate::fromPath(certificateFileName); + if (!localCert.isEmpty() && !localCert.first().isNull()) { + configuration.setLocalCertificate(localCert.first()); + } else { + qCritical() << "Could not find certificate: " << certificateFileName; + } + return configuration; +} + +void tst_QSslServer::testOneSuccessfulConnection() +{ + // Setup server + QSslConfiguration serverConfiguration = selfSignedServerQSslConfiguration(); + SslServerSpy server(serverConfiguration); + QVERIFY(server.server.listen()); + + // Check that all signal spys are valid + QVERIFY(server.sslErrorsSpy.isValid()); + QVERIFY(server.peerVerifyErrorSpy.isValid()); + QVERIFY(server.errorOccurredSpy.isValid()); + QVERIFY(server.pendingConnectionAvailableSpy.isValid()); + QVERIFY(server.preSharedKeyAuthenticationRequiredSpy.isValid()); + QVERIFY(server.alertSentSpy.isValid()); + QVERIFY(server.alertReceivedSpy.isValid()); + QVERIFY(server.handshakeInterruptedOnErrorSpy.isValid()); + QVERIFY(server.startedEncryptionHandshakeSpy.isValid()); + + // Check that no connections has occurred + QCOMPARE(server.sslErrorsSpy.size(), 0); + QCOMPARE(server.peerVerifyErrorSpy.size(), 0); + QCOMPARE(server.errorOccurredSpy.size(), 0); + QCOMPARE(server.pendingConnectionAvailableSpy.size(), 0); + QCOMPARE(server.preSharedKeyAuthenticationRequiredSpy.size(), 0); + QCOMPARE(server.alertSentSpy.size(), 0); + QCOMPARE(server.alertReceivedSpy.size(), 0); + QCOMPARE(server.handshakeInterruptedOnErrorSpy.size(), 0); + QCOMPARE(server.startedEncryptionHandshakeSpy.size(), 0); + + // Connect client + QSslSocket client; + QSslConfiguration clientConfiguration = QSslConfiguration::defaultConfiguration(); + client.setSslConfiguration(clientConfiguration); + client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), + server.server.serverPort()); + + // Type of certificate error to expect + const auto certificateError = + isTestingOpenSsl ? QSslError::SelfSignedCertificate : QSslError::CertificateUntrusted; + // Expected errors + connect(&client, &QSslSocket::sslErrors, + [&certificateError, &client](const QList<QSslError> &errors) { + QCOMPARE(errors.size(), 2); + for (auto error : errors) { + QVERIFY(error.error() == certificateError + || error.error() == QSslError::HostNameMismatch); + } + client.ignoreSslErrors(); + }); + + QEventLoop loop; + int waitFor = 2; + connect(&client, &QSslSocket::encrypted, [&loop, &waitFor]() { + if (!--waitFor) + loop.quit(); + }); + connect(&server.server, &QTcpServer::pendingConnectionAvailable, [&loop, &waitFor]() { + if (!--waitFor) + loop.quit(); + }); + QTimer::singleShot(5000, &loop, SLOT(quit())); + loop.exec(); + + // Check that one encrypted connection has occurred without error + QCOMPARE(server.sslErrorsSpy.size(), 0); + QCOMPARE(server.peerVerifyErrorSpy.size(), 0); + QCOMPARE(server.errorOccurredSpy.size(), 0); + QCOMPARE(server.pendingConnectionAvailableSpy.size(), 1); + QCOMPARE(server.preSharedKeyAuthenticationRequiredSpy.size(), 0); + QCOMPARE(server.alertSentSpy.size(), 0); + QCOMPARE(server.alertReceivedSpy.size(), 0); + QCOMPARE(server.handshakeInterruptedOnErrorSpy.size(), 0); + QCOMPARE(server.startedEncryptionHandshakeSpy.size(), 1); + + // Check client socket + QVERIFY(client.isEncrypted()); + QCOMPARE(client.state(), QAbstractSocket::ConnectedState); +} + +void tst_QSslServer::testSelfSignedCertificateRejectedByServer() +{ + // Set up server that verifies client + QSslConfiguration serverConfiguration = selfSignedServerQSslConfiguration(); + serverConfiguration.setPeerVerifyMode(QSslSocket::VerifyPeer); + SslServerSpy server(serverConfiguration); + QVERIFY(server.server.listen()); + + // Connect client + QSslSocket client; + QSslConfiguration clientConfiguration = selfSignedClientQSslConfiguration(); + clientConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone); + client.setSslConfiguration(clientConfiguration); + client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), + server.server.serverPort()); + + QEventLoop loop; + QObject::connect(&client, SIGNAL(disconnected()), &loop, SLOT(quit())); + QTimer::singleShot(5000, &loop, SLOT(quit())); + loop.exec(); + + // Check that one encrypted connection has failed + QCOMPARE(server.sslErrorsSpy.size(), 1); + QCOMPARE(server.peerVerifyErrorSpy.size(), 1); + QCOMPARE(server.errorOccurredSpy.size(), 1); + QCOMPARE(server.pendingConnectionAvailableSpy.size(), 0); + QCOMPARE(server.preSharedKeyAuthenticationRequiredSpy.size(), 0); + QCOMPARE(server.alertSentSpy.size(), + isTestingOpenSsl ? 1 : 0); // OpenSSL only signal + QCOMPARE(server.alertReceivedSpy.size(), 0); + QCOMPARE(server.handshakeInterruptedOnErrorSpy.size(), 0); + QCOMPARE(server.startedEncryptionHandshakeSpy.size(), 1); + + // Type of certificate error to expect + const auto certificateError = + isTestingOpenSsl ? QSslError::SelfSignedCertificate : QSslError::CertificateUntrusted; + + // Check the sslErrorsSpy + const auto sslErrorsSpyErrors = + qvariant_cast<QList<QSslError>>(std::as_const(server.sslErrorsSpy).first()[1]); + QCOMPARE(sslErrorsSpyErrors.size(), 1); + QCOMPARE(sslErrorsSpyErrors.first().error(), certificateError); + + // Check the peerVerifyErrorSpy + const auto peerVerifyErrorSpyError = + qvariant_cast<QSslError>(std::as_const(server.peerVerifyErrorSpy).first()[1]); + QCOMPARE(peerVerifyErrorSpyError.error(), certificateError); + + // Check client socket + QVERIFY(!client.isEncrypted()); + QCOMPARE(client.state(), QAbstractSocket::UnconnectedState); +} + +void tst_QSslServer::testSelfSignedCertificateRejectedByClient() +{ + // Set up server without verification of client + QSslConfiguration serverConfiguration = selfSignedServerQSslConfiguration(); + SslServerSpy server(serverConfiguration); + QVERIFY(server.server.listen()); + + // Connect client that authenticates server + QSslSocket client; + QSslConfiguration clientConfiguration = selfSignedClientQSslConfiguration(); + if (isTestingOpenSsl) { + clientConfiguration.setHandshakeMustInterruptOnError(true); + QVERIFY(clientConfiguration.handshakeMustInterruptOnError()); + } + client.setSslConfiguration(clientConfiguration); + QSignalSpy clientConnectedSpy(&client, SIGNAL(connected())); + QSignalSpy clientHostFoundSpy(&client, SIGNAL(hostFound())); + QSignalSpy clientDisconnectedSpy(&client, SIGNAL(disconnected())); + QSignalSpy clientConnectionEncryptedSpy(&client, SIGNAL(encrypted())); + QSignalSpy clientSslErrorsSpy(&client, SIGNAL(sslErrors(QList<QSslError>))); + QSignalSpy clientErrorOccurredSpy(&client, SIGNAL(errorOccurred(QAbstractSocket::SocketError))); + client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), + server.server.serverPort()); + QEventLoop loop; + QTimer::singleShot(1000, &loop, SLOT(quit())); + loop.exec(); + + // Type of socket error to expect + const auto socketError = isTestingOpenSsl + ? QAbstractSocket::SocketError::SslHandshakeFailedError + : QAbstractSocket::SocketError::RemoteHostClosedError; + + QTcpSocket *connection = server.server.nextPendingConnection(); + if (connection == nullptr) { + // Client disconnected before connection accepted by server + QCOMPARE(server.sslErrorsSpy.size(), 0); + QCOMPARE(server.peerVerifyErrorSpy.size(), 0); + QCOMPARE(server.errorOccurredSpy.size(), 1); // Client rejected first + QCOMPARE(server.pendingConnectionAvailableSpy.size(), 0); + QCOMPARE(server.preSharedKeyAuthenticationRequiredSpy.size(), 0); + QCOMPARE(server.alertSentSpy.size(), 0); + QCOMPARE(server.alertReceivedSpy.size(), + isTestingOpenSsl ? 1 : 0); // OpenSSL only signal + QCOMPARE(server.handshakeInterruptedOnErrorSpy.size(), 0); + QCOMPARE(server.startedEncryptionHandshakeSpy.size(), 1); + + const auto errrOccuredSpyError = qvariant_cast<QAbstractSocket::SocketError>( + std::as_const(server.errorOccurredSpy).first()[1]); + QCOMPARE(errrOccuredSpyError, socketError); + } else { + // Client disconnected after connection accepted by server + QCOMPARE(server.sslErrorsSpy.size(), 0); + QCOMPARE(server.peerVerifyErrorSpy.size(), 0); + QCOMPARE(server.errorOccurredSpy.size(), 0); // Server accepted first + QCOMPARE(server.pendingConnectionAvailableSpy.size(), 1); + QCOMPARE(server.preSharedKeyAuthenticationRequiredSpy.size(), 0); + QCOMPARE(server.alertSentSpy.size(), 0); + QCOMPARE(server.alertReceivedSpy.size(), + isTestingOpenSsl ? 1 : 0); // OpenSSL only signal + QCOMPARE(server.handshakeInterruptedOnErrorSpy.size(), 0); + QCOMPARE(server.startedEncryptionHandshakeSpy.size(), 1); + + QCOMPARE(connection->state(), QAbstractSocket::UnconnectedState); + QCOMPARE(connection->error(), socketError); + auto sslConnection = qobject_cast<QSslSocket *>(connection); + QVERIFY(sslConnection); + QVERIFY(!sslConnection->isEncrypted()); + } + + // Check that client has rejected server + QCOMPARE(clientConnectedSpy.size(), 1); + QCOMPARE(clientHostFoundSpy.size(), 1); + QCOMPARE(clientDisconnectedSpy.size(), 1); + QCOMPARE(clientConnectionEncryptedSpy.size(), 0); + QCOMPARE(clientSslErrorsSpy.size(), isTestingOpenSsl ? 0 : 1); + QCOMPARE(clientErrorOccurredSpy.size(), 1); + + // Check client socket + QVERIFY(!client.isEncrypted()); + QCOMPARE(client.state(), QAbstractSocket::UnconnectedState); +} + +#if QT_CONFIG(openssl) + +void tst_QSslServer::testHandshakeInterruptedOnError() +{ + if (!isTestingOpenSsl) + QSKIP("This test requires OpenSSL as the active TLS backend"); + + auto serverConfiguration = selfSignedServerQSslConfiguration(); + serverConfiguration.setHandshakeMustInterruptOnError(true); + QVERIFY(serverConfiguration.handshakeMustInterruptOnError()); + serverConfiguration.setPeerVerifyMode(QSslSocket::VerifyPeer); + SslServerSpy server(serverConfiguration); + server.server.listen(); + + QSslSocket client; + auto clientConfiguration = selfSignedClientQSslConfiguration(); + clientConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone); + client.setSslConfiguration(clientConfiguration); + client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), + server.server.serverPort()); + + QEventLoop loop; + QObject::connect(&client, SIGNAL(disconnected()), &loop, SLOT(quit())); + QTimer::singleShot(5000, &loop, SLOT(quit())); + loop.exec(); + + // Check that client certificate causes handshake interrupted signal to be emitted + QCOMPARE(server.sslErrorsSpy.size(), 0); + QCOMPARE(server.peerVerifyErrorSpy.size(), 0); + QCOMPARE(server.errorOccurredSpy.size(), 1); + QCOMPARE(server.pendingConnectionAvailableSpy.size(), 0); + QCOMPARE(server.preSharedKeyAuthenticationRequiredSpy.size(), 0); + QCOMPARE(server.alertSentSpy.size(), 1); + QCOMPARE(server.alertReceivedSpy.size(), 0); + QCOMPARE(server.handshakeInterruptedOnErrorSpy.size(), 1); + QCOMPARE(server.startedEncryptionHandshakeSpy.size(), 1); +} + +void tst_QSslServer::testPreSharedKeyAuthenticationRequired() +{ + if (!isTestingOpenSsl) + QSKIP("This test requires OpenSSL as the active TLS backend"); + + auto serverConfiguration = QSslConfiguration::defaultConfiguration(); + serverConfiguration.setPeerVerifyMode(QSslSocket::VerifyPeer); + serverConfiguration.setProtocol(QSsl::TlsV1_2); + serverConfiguration.setCiphers({ QSslCipher("PSK-AES256-CBC-SHA") }); + serverConfiguration.setPreSharedKeyIdentityHint("Server Y"); + SslServerSpy server(serverConfiguration); + connect(&server.server, &QSslServer::preSharedKeyAuthenticationRequired, + [](QSslSocket *, QSslPreSharedKeyAuthenticator *authenticator) { + QCOMPARE(authenticator->identity(), QByteArray("Client X")); + authenticator->setPreSharedKey("123456"); + }); + server.server.listen(); + + QSslSocket client; + auto clientConfiguration = QSslConfiguration::defaultConfiguration(); + clientConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone); + clientConfiguration.setProtocol(QSsl::TlsV1_2); + clientConfiguration.setCiphers({ QSslCipher("PSK-AES256-CBC-SHA") }); + client.setSslConfiguration(clientConfiguration); + connect(&client, &QSslSocket::preSharedKeyAuthenticationRequired, + [](QSslPreSharedKeyAuthenticator *authenticator) { + QCOMPARE(authenticator->identityHint(), QByteArray("Server Y")); + authenticator->setPreSharedKey("123456"); + authenticator->setIdentity("Client X"); + }); + client.connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), + server.server.serverPort()); + + connect(&server.server, &QSslServer::sslErrors, + [](QSslSocket *socket, const QList<QSslError> &errors) { + for (auto error : errors) { + QCOMPARE(error.error(), QSslError::NoPeerCertificate); + } + socket->ignoreSslErrors(); + }); + + QEventLoop loop; + QObject::connect(&client, SIGNAL(encrypted()), &loop, SLOT(quit())); + QTimer::singleShot(5000, &loop, SLOT(quit())); + loop.exec(); + + // Check that server is connected + QCOMPARE(server.sslErrorsSpy.size(), 1); + QCOMPARE(server.peerVerifyErrorSpy.size(), 1); + QCOMPARE(server.errorOccurredSpy.size(), 0); + QCOMPARE(server.pendingConnectionAvailableSpy.size(), 1); + QCOMPARE(server.preSharedKeyAuthenticationRequiredSpy.size(), 1); + QCOMPARE(server.alertSentSpy.size(), 0); + QCOMPARE(server.alertReceivedSpy.size(), 0); + QCOMPARE(server.handshakeInterruptedOnErrorSpy.size(), 0); + QCOMPARE(server.startedEncryptionHandshakeSpy.size(), 1); + + // Check client socket + QVERIFY(client.isEncrypted()); + QCOMPARE(client.state(), QAbstractSocket::ConnectedState); +} + +#endif + +void tst_QSslServer::plaintextClient() +{ + QSslConfiguration serverConfiguration = selfSignedServerQSslConfiguration(); + SslServerSpy server(serverConfiguration); + QVERIFY(server.server.listen()); + + QTcpSocket socket; + QSignalSpy socketDisconnectedSpy(&socket, &QTcpSocket::disconnected); + socket.connectToHost(QHostAddress::LocalHost, server.server.serverPort()); + QVERIFY(socket.waitForConnected()); + QTest::qWait(100); + // No disconnect from short break...: + QCOMPARE(socket.state(), QAbstractSocket::SocketState::ConnectedState); + + // ... but we write some plaintext data...: + socket.write("Hello World!"); + socket.waitForBytesWritten(); + // ... and quickly get disconnected: + QTRY_COMPARE_GT(socketDisconnectedSpy.size(), 0); + QCOMPARE(socket.state(), QAbstractSocket::SocketState::UnconnectedState); +} + +void tst_QSslServer::quietClient() +{ + QSslConfiguration serverConfiguration = selfSignedServerQSslConfiguration(); + SslServerSpy server(serverConfiguration); + server.server.setHandshakeTimeout(1'000); + QVERIFY(server.server.listen()); + + quint16 serverPeerPort = 0; + auto grabServerPeerPort = [&serverPeerPort](QSslSocket *socket) { + serverPeerPort = socket->peerPort(); + }; + QObject::connect(&server.server, &QSslServer::errorOccurred, &server.server, + grabServerPeerPort); + + QTcpSocket socket; + QSignalSpy socketDisconnectedSpy(&socket, &QTcpSocket::disconnected); + socket.connectToHost(QHostAddress::LocalHost, server.server.serverPort()); + quint16 clientLocalPort = socket.localPort(); + QVERIFY(socket.waitForConnected()); + // Disconnects after overlong break: + QVERIFY(socketDisconnectedSpy.wait(5'000)); + QCOMPARE(socket.state(), QAbstractSocket::SocketState::UnconnectedState); + + QCOMPARE_GT(server.errorOccurredSpy.size(), 0); + QCOMPARE(serverPeerPort, clientLocalPort); +} + +void tst_QSslServer::twoGoodAndManyBadClients() +{ + QSslConfiguration serverConfiguration = selfSignedServerQSslConfiguration(); + SslServerSpy server(serverConfiguration); + server.server.setHandshakeTimeout(750); + constexpr qsizetype ExpectedConnections = 5; + server.server.setMaxPendingConnections(ExpectedConnections); + QVERIFY(server.server.listen()); + + auto connectGoodClient = [&server](QSslSocket *socket) { + QObject::connect(socket, &QSslSocket::sslErrors, socket, + qOverload<const QList<QSslError> &>(&QSslSocket::ignoreSslErrors)); + socket->connectToHostEncrypted("127.0.0.1", server.server.serverPort()); + }; + // Connect one socket encrypted so we have a socket in the regular queue + QSslSocket tlsSocket; + connectGoodClient(&tlsSocket); + + // Then we connect a bunch of TCP sockets who will not send any data at all + std::array<QTcpSocket, size_t(ExpectedConnections) * 2> sockets; + for (QTcpSocket &socket : sockets) + socket.connectToHost(QHostAddress::LocalHost, server.server.serverPort()); + QTest::qWait(500); // some leeway to let connections try to connect... + + // I happen to know the sockets are all children of the server, so let's see + // how many are created: + qsizetype connectedCount = server.server.findChildren<QSslSocket *>().size(); + QCOMPARE(connectedCount, ExpectedConnections); + // 1 socket is ready and pending + QCOMPARE(server.pendingConnectionAvailableSpy.size(), 1); + + // Connect another client to make sure that the server is accepting connections again even after + // all the bad actors tried to connect: + QSslSocket goodClient; + connectGoodClient(&goodClient); + QTRY_COMPARE(server.pendingConnectionAvailableSpy.size(), 2); +} + +QTEST_MAIN(tst_QSslServer) + +#include "tst_qsslserver.moc" diff --git a/tests/auto/network/ssl/qsslsocket/BLACKLIST b/tests/auto/network/ssl/qsslsocket/BLACKLIST index 749c59d968..b990516676 100644 --- a/tests/auto/network/ssl/qsslsocket/BLACKLIST +++ b/tests/auto/network/ssl/qsslsocket/BLACKLIST @@ -1,11 +1,6 @@ [deprecatedProtocols] windows -[spontaneousWrite] -windows-7sp1 [connectToHostEncrypted] macos -[setSslConfiguration] -windows-10 msvc-2015 -windows-7sp1 [connectToHostEncryptedWithVerificationPeerName] macos diff --git a/tests/auto/network/ssl/qsslsocket/CMakeLists.txt b/tests/auto/network/ssl/qsslsocket/CMakeLists.txt index d0307042f4..456deacb60 100644 --- a/tests/auto/network/ssl/qsslsocket/CMakeLists.txt +++ b/tests/auto/network/ssl/qsslsocket/CMakeLists.txt @@ -1,4 +1,11 @@ -# Generated from qsslsocket.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qsslsocket LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() if(NOT QT_FEATURE_private_tests) return() @@ -11,29 +18,19 @@ endif() # Collect test data list(APPEND test_data "certs") -qt_add_test(tst_qsslsocket +qt_internal_add_test(tst_qsslsocket SOURCES tst_qsslsocket.cpp - DEFINES - SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/\\\" - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::NetworkPrivate + Qt::TestPrivate TESTDATA ${test_data} - QT_TEST_SERVER_LIST "squid" "danted" "cyrus" "apache2" "echo" # special case + QT_TEST_SERVER_LIST "squid" "danted" "cyrus" "apache2" "echo" + BUNDLE_ANDROID_OPENSSL_LIBS ) -#### Keys ignored in scope 1:.:.:qsslsocket.pro:<TRUE>: -# _REQUIREMENTS = "qtConfig(private_tests)" - -## Scopes: -##################################################################### - -#### Keys ignored in scope 3:.:.:qsslsocket.pro:(CMAKE_BUILD_TYPE STREQUAL Debug): -# DESTDIR = "debug" - -#### Keys ignored in scope 4:.:.:qsslsocket.pro:else: -# DESTDIR = "release" - -#### Keys ignored in scope 5:.:.:qsslsocket.pro:LINUX: -# QT_TEST_SERVER_LIST = "squid" "danted" "cyrus" "apache2" "echo" +qt_internal_extend_target(tst_qsslsocket CONDITION QT_FEATURE_private_tests AND QT_FEATURE_openssl_linked + LIBRARIES + WrapOpenSSL::WrapOpenSSL +) diff --git a/tests/auto/network/ssl/qsslsocket/certs/ca-generate.sh b/tests/auto/network/ssl/qsslsocket/certs/ca-generate.sh new file mode 100644 index 0000000000..10aea0905e --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket/certs/ca-generate.sh @@ -0,0 +1,21 @@ +#!/bin/sh +# Copyright (C) 2016 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +# generate ca.crt +openssl genrsa -out ca.key 8192 +openssl req -x509 -new -sha512 -nodes -key ca.key -days 10000 -out ca.crt -config ca.conf + +# generate inter.crt +openssl genrsa -out inter.key 8192 +openssl req -new -sha512 -nodes -key inter.key -out inter.csr -config inter.conf +openssl x509 -req -sha512 -days 45 -in inter.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out inter.crt +rm inter.csr +rm ca.srl + +# generate leaf.crt +openssl genrsa -out leaf.key 8192 +openssl req -new -sha512 -nodes -key leaf.key -out leaf.csr -config leaf.conf +openssl x509 -req -sha512 -days 45 -in leaf.csr -CA inter.crt -CAkey inter.key -CAcreateserial -out leaf.crt +rm leaf.csr +rm inter.srl diff --git a/tests/auto/network/ssl/qsslsocket/certs/ca.conf b/tests/auto/network/ssl/qsslsocket/certs/ca.conf new file mode 100644 index 0000000000..1f94247a2f --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket/certs/ca.conf @@ -0,0 +1,10 @@ +basicConstraints = CA:TRUE +keyUsage = cRLSign, keyCertSign +[req] +distinguished_name = network-tests.qt-project.org +prompt = no +[network-tests.qt-project.org] +C = NO +ST = Oslo +L = Oslo +CN = Fake Qt Project Certificate Authority diff --git a/tests/auto/network/ssl/qsslsocket/certs/ca.crt b/tests/auto/network/ssl/qsslsocket/certs/ca.crt index 5cbe8ef726..8e6c6e255c 100644 --- a/tests/auto/network/ssl/qsslsocket/certs/ca.crt +++ b/tests/auto/network/ssl/qsslsocket/certs/ca.crt @@ -1,22 +1,52 @@ -----BEGIN CERTIFICATE----- -MIIDpTCCAl2gAwIBAgIQAKraD9BoqaSa75qOqcP7ZTANBgkqhkiG9w0BAQUFADA8 -MQswCQYDVQQGEwJHQjEZMBcGA1UEChMQV2VzdHBvaW50IENBIEtleTESMBAGA1UE -ChMJV2VzdHBvaW50MB4XDTEzMDIxNjE2NTMwOFoXDTIzMDIxNjE2NTMwOFowPDEL -MAkGA1UEBhMCR0IxGTAXBgNVBAoTEFdlc3Rwb2ludCBDQSBLZXkxEjAQBgNVBAoT -CVdlc3Rwb2ludDCCAVIwDQYJKoZIhvcNAQEBBQADggE/ADCCAToCggExAJv0H92j -WjDB9h1DmSQzt772IPSirpE82sN9ls5J19TJcPnw49LdUUqkELJkpS1ty2hYPdUw -7q3n00D+nzS+rt1QIDSKwDVoqeIyFZw4h0ULbASErfy51xBjVIr6NNoiqazp59wQ -RDvqps7of+b/NcbOh73MsiYi8T5OoI4Quv9rMBefQTAI3d2NRQ4GUzS6Hzh2INOc -4twApTDYY+yrU8IalXttIOVdKJZTHeTCdIXD3HMfHCkzyELz8rCI1/wDEp8zyoqF -/tpBStZ5LUSrlRRM7PegqcnM+aojXyrEiXBvPuqO7tabU3nsfix9+8+7GDweDXsP -OUHv+ahGNTUya7hBDaQmVk3/5hbig9kQlNiOcvcdnYYyJqiXhvjPPzOBbRaFNvBT -uG/ehHNHYsdhEBkCAwEAAaNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNVHQ8BAf8E -BQMDBwYAMB0GA1UdDgQWBBSUJzi1uYQUxqb3Nr33LOLCaUUTyTANBgkqhkiG9w0B -AQUFAAOCATEAPeGh2GiIhT3cii3DU8ihd5TmnEstuHKz2FwHDChmen0zxE8lf08/ -onL1yIeaxbDA8KwZnv71/zZHJv02sPtIMUfuXQc0wOIFjDf0ngc6xIBuU7FUpLxF -2dK7g9OsiNeC7L/ZemRXgpJURdNF2Ujge9/H9yfpHFBXZztmaWir+TXc5g3PKIu6 -97t75Og+stPhTcSlph8ZHYep08b2uthCfcnuIRGeDW9LkfR8VugnuUf7GoIlqSTs -SR6bNuyTnnCHQMJzbsQ472+ag3aZS5HzoR8wyGiPmpc43lQM5ZEDrWGu8bub2gKa -/+KeqHd0wnl7Y5cxnmAptQjxvzBXX/pl4sWczesiGcYm5z5mabp4CY09Y8JtrJZT -IJodXy9ykRmEurgtRoRVc1aSp+xfV725bQ== +MIIJPzCCBScCFEE7H06QrHfL4z31/1+EDVDhQUAeMA0GCSqGSIb3DQEBDQUAMFsx +CzAJBgNVBAYTAk5PMQ0wCwYDVQQIDARPc2xvMQ0wCwYDVQQHDARPc2xvMS4wLAYD +VQQDDCVGYWtlIFF0IFByb2plY3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MCAXDTIy +MDkwMjE1MDIyMFoYDzIwNTAwMTE4MTUwMjIwWjBbMQswCQYDVQQGEwJOTzENMAsG +A1UECAwET3NsbzENMAsGA1UEBwwET3NsbzEuMCwGA1UEAwwlRmFrZSBRdCBQcm9q +ZWN0IENlcnRpZmljYXRlIEF1dGhvcml0eTCCBCIwDQYJKoZIhvcNAQEBBQADggQP +ADCCBAoCggQBAOMlzl5JB31G5CmRRKltbua0LtM0U7mh/yeK7jNaRAY5VKmmh4mg +N/Ib7Rn4jCY5ccGaOdxtHdPE6WN4v4GZJ23dr+AofJnZHj+wiYjE+KKpoiuPDqhP +F231zg16WGlc2HWbpX93InnxnO7KRwHumn0Xxn50BfKgyvmdDQBtAkYU868GWwqR +cy+K4c+tB46XGS1URv/PDYy15IbcOwpDUSpXQBrHZHyje2iwZR6AKESGZRkSttyY +oSJAmfIhDST41g+9uV9zA9u1XAVYb3kAstSU1nWEYZ7oBQEhh6LIR34YjCE/ThQy +djWlc9afnFxA8r+q/mjAOTsH/Pml6Z/DQKW9Bfjw9ne0Oeiz+Z1J8Goj/YzGsKeI +u2XPU8bbjxv32IkhZmH/g22a9Jl41nAYGmAzP7yfOCSRTDTn5JybInxaEdrPrgS2 +A66+NiFWIu/QKnBrKwVlINOdi0z533Aejmc3ybtyJeHPeG0deNbfJbEavfq4yb4P +DlWpWA4yMbZCqazP/Yku9DkJoT8kAKOaGK2Swjt3NvnT4LaKIPXLCwz/HUjWcppx +54acMDOUz2ch/yIXx/m/jnl1hMHnv2KPoxgQYeRs0iX4lwd79zaRydMmLYceY64H +Ek4b+vSsuEnOTThx9jv358aFI7f9fL0Qbqknf9EUo5X4OTCFIkdtLEYsU5+uzmqC +LgB6musrIaMgNLef7VbKPgtqZDEvWbm0tqdh5dk/wpyFimc8x9V9MSBNAqGE/dm4 +KCtRGBiyQ1KRB+RRqAKMHaR8dFBuHtDvSq20logNTab6eTE79zNMyo0W61GrriQt +94a0ahTSKaySXRgTKhElAp3n5v5YDTO1DEYtMy0hI/wx1d2bkJsO8gSr+aBzVZUc +QsWFK3qgmDfC9ZF5CsvLEPy7I5pf2TcaQjTrr4XcTPSHEyN2WI7bj9sU6+tkLi/Y +OI3z0NsXOZM2OJPZ523TJbnhCRX9wEvh+sts5cbMgAbZVYWHImjmkdnssAChhrCh +DPaq20KVma00ZvbbfICG/1QiSY9FVX/AVID8yDc49ZfLiLWTLoEFoYH0lqGj0817 +4LwWswNlH86EeY1KPxmNPCF0bzj39hnYN1kd5qTxg5hwPTZehw5JR6w1eQ0VamV1 +Al1u8XqBkrk48iWeOBQr0u6HiNNElCjH+j/hC8Ms4Ykmh8iaJhlpwKt6pGoROX6l ++T98AvrzFUmh+NJu+bGWATBrGmaSjW8AUYwVSbHDL2jk41uVGQdgFTCHwhh6/OV8 +VuladbVA5aA33Jky6SKUNeUh+WcVuwMa1Y/ZKX8Klo7p8ZmxCeAOmcd8fbTfQVu5 +fqu1Oz4Ai6cMQmPpOi9tMzr86ig9NlZPxA8CAwEAATANBgkqhkiG9w0BAQ0FAAOC +BAEAsYfgbpxN2SzVk8FWs+fHnMkMVX4KUPSKHCea6YoaPJN3glH0Y8I7uYpbwmWf +AqaXmZhY4YFGG77uao533hS7gapnkuoH+e4LZ0G1QrlCDhl69iNgL/HG/yq1eCDu +M3Oc8ujpkFoGkDQUVqVSqFvSOGm/KKVazQDF9VhUrlmfHapMYlrSZssbibzfjoKp +DKMQHYN5OiX6WZ7PVCvGn53ufO1dtENbBRHCD/ck7dMM/bzANXDd+Yw2rHAuXnRX +Lyp7XoqD/coB+Nn23mKtn+HLOYp1MkaONO/JruFV+HYd9kP+yoICTOWDU6Nx/Knz +0pnGktQwySha6cDKB8V/rLLrnyZGRLbmajtlGQNnYeeJdQFjFP8dnCjHS78KxURe +zqKAcO79hzZNqcsGxHVfS49+j8NOvUzKfj6Rda4x1Yb7Cnm0VAs1lo+rtQbRdB2z +KVNVed7ns4eO2jM/UYRse66RHsIY4+45fQH4OwshJNU2Rn8nDUikrCo7G2MDeTq3 +4M0y0W8tr4NbnTGNVQLnY+HX5AWoB12E++rfv7CACKDxvJ519Ai/uxZSLWcmPM05 +g/JDKi6Rn1EbAZlru+9GV19QAq60elaLMDUVGZ4EYhjunF2syewqCkeyXWC3zMDL +pNdq8t0IM5Q9x1Vfj9XAecO5QftS54K5RAxiMTPBwYSWA3yduEPfSQSRYovVarLd +gsOWWSNwJ16wxEibCgueo6njB+9yfbFTtYLTpQKDVAgV7IBiATW6LcR2WgF4g9zq +vduJYu5uQFSC0g9/2uZ7wqihEVdNEecOHz/uidpK8K4vlJ5oPKUo/YS4ok5rOPFd +BocpE8stbr6seRmkQcjrjqjLkzdi/lag2giuWglgjyL18MG6lBKFD9I/0iade3J+ +H7GaWZkLhsng2vG9ix+fQkq68yZwq8sx91nE1RJPeLaNkgX9oUtSg6e7I5ks6lS5 +UxBPouki7wH/kHY/xG+YVhm499s9KRdv7ZUGB/OhwdiBJW1DduPBIklMA8YHnWGG +2om0dCno+K/g88JzEI29Ob3AwIbtMI5vbWI8hWAfHEH0zEyfl9rB6/TcsHY8hjqj +cSCFT2rdno/S8gbBTuTLK8RhgmXKpZxVmLMz1rSRpMby5HAJ4Sh11bYzu4x1SuUo +HHiypXjIjBvwnX5/so2q4mw2TNZR0QQ9dQ8bcG74h6cJxSv2pXQTwQRP5PkMpmOF +JIgv+Pa0UOG+ejcKc94PhLAZmpxwdjlyfdCHT+RW6znqsCDHVvace/gHUY0bkUaD +rQSwaeiNTc5l7MP8Xb1k6DwsEnuaAGTua/fX41Qk/XE3acUz0kmr2As/IlABqyJ6 +i+VYGJPNrI6E/LMy1lq/iCVQJQ== -----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qsslsocket/certs/ca.key b/tests/auto/network/ssl/qsslsocket/certs/ca.key new file mode 100644 index 0000000000..eb2c48dbac --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket/certs/ca.key @@ -0,0 +1,99 @@ +-----BEGIN RSA PRIVATE KEY----- +MIISKgIBAAKCBAEA4yXOXkkHfUbkKZFEqW1u5rQu0zRTuaH/J4ruM1pEBjlUqaaH +iaA38hvtGfiMJjlxwZo53G0d08TpY3i/gZknbd2v4Ch8mdkeP7CJiMT4oqmiK48O +qE8XbfXODXpYaVzYdZulf3ciefGc7spHAe6afRfGfnQF8qDK+Z0NAG0CRhTzrwZb +CpFzL4rhz60HjpcZLVRG/88NjLXkhtw7CkNRKldAGsdkfKN7aLBlHoAoRIZlGRK2 +3JihIkCZ8iENJPjWD725X3MD27VcBVhveQCy1JTWdYRhnugFASGHoshHfhiMIT9O +FDJ2NaVz1p+cXEDyv6r+aMA5Owf8+aXpn8NApb0F+PD2d7Q56LP5nUnwaiP9jMaw +p4i7Zc9TxtuPG/fYiSFmYf+DbZr0mXjWcBgaYDM/vJ84JJFMNOfknJsifFoR2s+u +BLYDrr42IVYi79AqcGsrBWUg052LTPnfcB6OZzfJu3Il4c94bR141t8lsRq9+rjJ +vg8OValYDjIxtkKprM/9iS70OQmhPyQAo5oYrZLCO3c2+dPgtoog9csLDP8dSNZy +mnHnhpwwM5TPZyH/IhfH+b+OeXWEwee/Yo+jGBBh5GzSJfiXB3v3NpHJ0yYthx5j +rgcSThv69Ky4Sc5NOHH2O/fnxoUjt/18vRBuqSd/0RSjlfg5MIUiR20sRixTn67O +aoIuAHqa6yshoyA0t5/tVso+C2pkMS9ZubS2p2Hl2T/CnIWKZzzH1X0xIE0CoYT9 +2bgoK1EYGLJDUpEH5FGoAowdpHx0UG4e0O9KrbSWiA1Npvp5MTv3M0zKjRbrUauu +JC33hrRqFNIprJJdGBMqESUCnefm/lgNM7UMRi0zLSEj/DHV3ZuQmw7yBKv5oHNV +lRxCxYUreqCYN8L1kXkKy8sQ/Lsjml/ZNxpCNOuvhdxM9IcTI3ZYjtuP2xTr62Qu +L9g4jfPQ2xc5kzY4k9nnbdMlueEJFf3AS+H6y2zlxsyABtlVhYciaOaR2eywAKGG +sKEM9qrbQpWZrTRm9tt8gIb/VCJJj0VVf8BUgPzINzj1l8uItZMugQWhgfSWoaPT +zXvgvBazA2UfzoR5jUo/GY08IXRvOPf2Gdg3WR3mpPGDmHA9Nl6HDklHrDV5DRVq +ZXUCXW7xeoGSuTjyJZ44FCvS7oeI00SUKMf6P+ELwyzhiSaHyJomGWnAq3qkahE5 +fqX5P3wC+vMVSaH40m75sZYBMGsaZpKNbwBRjBVJscMvaOTjW5UZB2AVMIfCGHr8 +5XxW6Vp1tUDloDfcmTLpIpQ15SH5ZxW7AxrVj9kpfwqWjunxmbEJ4A6Zx3x9tN9B +W7l+q7U7PgCLpwxCY+k6L20zOvzqKD02Vk/EDwIDAQABAoIEAQDUCUGYIAHevuNT +rihzJBVnRIGFZI5XddJSHk13IGbpjHDsoOha33X6CnmNScfCEtOOzyH+EtnKCkF3 +OotCNi5pT4zS6dhOYS/sciYgxwX2CfW5RaSAFryfR9peGHwZdrMVLgMSdqp3PMSq +36XjNtF9vkjrV/EJaXGwCxvM7vU1aG+FTaCEv/vPQIzEKRgp0gCNoONZ/fT/CfhW +r5RpYyeMJ8BOfxzdgFo+ApOSIj30oaQUALU0PUIFUFqkfJfhkGt6bDdz01Chsq1A +zCnawX0uFfYP41ChXqL1SFBt8xlRqyZ8DrUbA3P3Zgg5K+tw7qvroXo1XGLQKQfM +H0VzfneFf2ro1D6uxU1dXUvAuPm0iv4vgHX9HhUY162zrtbrW7QFZmlFR5hvIzv7 +W6KJJubQMGbp85McB4okxOdSDTrm68lJAZ7HBQVxBFxRSC/6vs4u/Ms/EQTQpXsY +kxQxfESgM6Kb2NVl8h7PdLiNk+aCaZ04Q3EHetR9wEPTlKV1Jstu5wUcHvmZmNSt +tTTng3xP4vRvQDzQfymAHHbiGvSo4Ch9CroWVAe1T21raRkmg8S/FYX2LAuac8pG +m8e7AKxVVU2cRrzw9xo8wUqm5PaKpVPQktyn4jADO/lKl0S8mNjavP8HQcZZOYV7 +RiQ/9Ovn+VhGW0bNQtZX5Z93H4E5ynrYZ+Bu4E6KBzApeG1wiSCGhyo2q8hMBLPy +52YcPEj7LYeoBCjExgHUmE4FEKq6+zC067jjLB65D9vouoni4lPnH4SEYQudumU9 +ywUG88Wg3p4wTekaFdObadL+hEVY96PqwLHj03YxlPzVZc2hYTYbTR5HG0X+wyeQ +pHhZ3O93bOq8i3IP1yBue6P3t7zp/iKNi4LZos043RWF2n9Q9RTMVNaRpdbaEMm4 +/JckhjjF6OgqYs7/ju5m8Oi8bEvi3+XETzHzGEaiYKfadrIaR+NpuGla61lCvKo8 +G2Uq/WwJxUICiDvAy3y5Z/FoXe0r87KF9LdC6MhRJvQ8dAEZWVCNs9HaLb+t/G1Y +H2vLmTtUJUXkuLtNpQdQZnAN7HQ8Y/qRXslLcoGC733L81PQcm3rojAUInyoc5M9 +JJWWk0DLP3BpFCo2cOrsjYzBO4ZC/PNNeJY938JXpvSIz+y+fuXV/Vd/EWNaQylb +6chCI7Pyz2HZhaKLI7+KPkEBprKbNBQDX4/uZuHtsccPguKF8yrLxk29u/Zy02Lp +TAGKB3gk8xsDSOKtTalEEHW2aXKvo3tkdRUqjJ4Q5vBO/mmiOZHhmYneumT9SIH7 +jt4wJS56Kh5utHT3RXgmrZn/XX7PoNGkW29HdHive7q/L8WnNar8Yloarn01wE04 +CE+x5vL5AoICAQDzIRy/LzkKOOz8Pz7qO66yLa/dxdiNud0IIYtB705RZduQ7wdD +oO0J8VOzrgy048EdOKf7mP2zma+xXPCfWHKMXRxIH+ewtNo5mxMxxPSkaUy25pK7 +vB6bOAIYvIZU/eMGtE5GTTMeJvyWC+uKVY4HUlzPaFmzz6KEJiTTVxwCi6SYikKB +EpJdaZ3S03Gxky4Nlr6ILk1lPKCdWIN/9EeFdjvgN/Cx21wI+9untNfIRKRLbNAe +dD4jC8mvx/Cb07Yzq+apkYWA7S2i30nocfWE3Wl0nk7nPTiIubetqNn15AjdOt+l +AyG8ZuaRbcemfQ+slLZ9jkvHCSlUVpYAo+iiztYtViLIWTzGk+VeJhvjdZq7K1+7 +5iph2G9gt2WFaaK4/Ikkz3Uq+SMSlW3iAb1Zj60qzzx1+ZlNMq/MvqJNAzPBxoFY +33ZySKnQSCOjVSr1K+PUO1m2Jisz6Fhj8lquCttZUrIudPaDVNmVXPXExxnnMu8x +ms9oOQPozgcUYW9MLv8NVRg5bIqvEb/j/cVnQm4l7eSj8WvkDi+xGEpO5AFJSb/A +rO9f61JamuHU2RwH2wq7ATMyG3chOu1b1jIuUFIt8cgAbUuTLbIuFQrTzXOMVch1 +dNVIPq8/vuLiNtXW3KhQFiM7AsvUQtsXbGuL8R4w4QM/DOkUK90gXXjlbQKCAgEA +7ywcQpTjEmuj2xo+FGiZo8hV1cT7yUjbTCtyMReVOFY0+/LP+XldOpi1d73GoUE4 +keXDSXh70AjeHH4KVRzYk2qBNG7ejscX7MhLIlVV6rp6EE1MFPDX1Z2tnwHwz9lb +kUgGs+Allg1dY6+B2Wmo7vWQ9EHwaGteLanfWsJtHpVEsRwSMSl3XUeydXf9x2nz +eRJ23V+e07XzeLvL4kn7vPZ8v0qRF+WLy9IBngO1RlrPrI+b//Vsk/2Mf3pfkm1M +g50Owm+fTOftcUvWkiIcUYCRVbOIBrTGEu4zLaNo3wHshuNmDWNr84lKEmVoXnoS +fpZ1IUwlLchzTD+Iv88kIVwBE4kMXlU8qZlffVCxAQWOOSS178v7iwc/ApU6aln5 +lXr8JmxjD0Wi1PpHRK4ogtnhikkkN67++aHJKBEYELKeashdxB04kokBl32ywJRf +oekeqCB/s5xlck7d4hFK3wfawxXqkNaN1q0q39BaaqOPRZFPaJ06umLb2Dy+raMX +7lNVv30rtiwEUYQiXcEF0j1XNABP14Qkwvk6rDUhM6s1B9c17ZOONeUt03kHjRg8 +tZ3FDAIqHeF67ZROK8WDuVxNCNarS0zn48YZo6xN8+lAn7kNsIVmmio0ChMDJIOk +hlvlBtO5wd7/9u0+MrcfMej21qbehRltuqi9eFRlLesCggIBAOaoMFyU0XmIPhSl +b+vKiVcTDvjIPUVf4nlXUYVRIi0JBEBA9NRNNPSs1aruYbGvLUOqv3trTq14DX2n +3cRepfXSVAV891LmkO372D7sSug72gLfRrACrcq2XQ7YtFynrR1sK6J4lRlzBUjY +sDJCLod1tQU0S33Sa60RfvhdeP5VOudYq/VGCEPE8mzUGtXL+vH7ZHFP9C8qUHpW +QhM/Tico3289wwUJRgxj3KUDZX/i1zeTWPK7d0PKaCJy/irntMDawe93Vn/VA+m0 +CqsSikntwKFZmyO4Kg1UnBSNz5J/L4Wq2Af1q6jQuseXrcSeeyNQxrzhJbUDVQll +R9P9rLPgpMLIKCGIv6bpIr6qSuUFarFNWfqqRuUi76+C7jae3DjBpN6eTtthFswH +pgK3gcsZCsFFcGfAT5c0kiIdbV7AvfaFe6sz/Ww40Zn/BohrQWDtraxoThkHpw8M +y+auQydAt47LbK20WzaHZhFU6vkvprx3zwNxinmnNbVE2OSV94AASgp9A4lfF0c2 +AKWs2P24wUUMp1B9tszaRJavo7eqiincZKXHqyWF3FCHBd7nxrcRMOHvJoHQGroU +7KCm2l6j5wMdkZAOIJfVz2f2oJoGHSwzKgV8vOdYSOyiDR9txHueRbQM/Il8gqGy +d6aGPpW6P9lBb9H+TpXLc3LEGvEVAoICAF6cf21jQlQ2GnKA9g/StPxSMopGyyd7 +16xQ/3ImFxRbHciQ6+6PMO8OG7MLcni1uTAVyOPWcnwAFgUFYwb6Sz49gnEAbq/i +WDeFoBsr0LnzHHg4a6FZCLhrEJR3CxDdtdhJusULJTMvhEL72YzsvDQTFk1ZjEVy +O6Yqrb1UbiAMAklhhlzGP3657wGC/vQUmIjLYhP+UHEFaBPZjjSs+ZVtmDl/wNfI +KT3ujE86vknfgImNobNmHZaJVTvUZ9wfuoXR6lXGHCkrEgWgb3gNYFBpYJSbWXL1 +rektKzehjcmyFCPj7qnbK4gCRjfyv4+oEIrc7+bFHWv4AIwoEet2gJ9lqtNUgn0K +kN2yW1DSS8LQtMssF4CNm6sKqcVWzO3nO9EC/p4ggCs5a8l+XBTyI/pnQE4Y0ufo +JNsRQebEpFVuozYwns8GlCt7YRLRWZXO2+nLsyHlAT9G3eaTBjj4iDqj+8jycYDs +Lt2+UNiKrknC+9kUO2px0BqNItRuayt6+euAMcp3NIRy8x5f+8xEoA3j0Aw1F2B0 +2Kn8N1aKCeFLl8XLP30EwtvVFgSyuub4sINTrvAqJwj8+kjjQu0TzCDWP28ApHA8 +MvsqkVfqwEd9fN/yL1Ul4EmZ6k4V6UdXgAzaa0YBGVl04qKGhPVA9Wkj9AlDp4DV +Z0/Qkmr4T7ITAoICAQDntedF62qFLmlgum58QBAbZiEDNiwUlSPUlk6o0Cs/bsSA +4xIYoxGfQP3T9caKSKGS+JGfiONYgemLWW0V4U5/v+YlJMXctl/TJmi7v43m0tPD +frjspJjfl3DGOWOb7lVAMOWL0b0MyOV9oBdL+WSBR7+ZiHo6FABqOdJBomO6wrHB +rKe8DnxE62d9fu1YRL0XVTcJQcSPFhd0JxY8fV9OKPtDLNR6+Q19b3B8MoIrAugp +M9DLyQwsObCa22A7MP9uLBBTJa2ubJfusW6V11Hf/48rFg6t1ahCYa3gyn6MHxji +aKIrXH2J8l2pOcf2aAuF1SgeSqnvtnFBgI1vebK+crXVDNYW7GvLaTfEdWRHpNc/ +9/ajew5rRS2HHO907Zub7dNckNeOInpSY7mBoSh1EG/IkdUYZ4hMWlxJzNSu3WWl +YprvHghpt2uyVMM1fsd39DLTtGv51NJJ5od9GKFWFBI/DRc6iwenKDGIpFi23jie +c9qb2J2oBiBH9Nt+0hpkqAt61U+306GgrIIUOHbdLWwXy8LOzaZxxVQ4KyVYvDJj +4zPT6SLaKCqHe8SWSXZyfa3zRIe8pBbAw3+L26yHI7X3aXJGHq6Yy7TbLFypDDoa +9DNXth8P3qxQq0AckCajAx4ka1glU9vuCAmsetHkgXybSJ1Wire2/zbqQRpWtQ== +-----END RSA PRIVATE KEY----- diff --git a/tests/auto/network/ssl/qsslsocket/certs/fluke.cert b/tests/auto/network/ssl/qsslsocket/certs/fluke.cert index 069fa6b341..4cc4d9a5ea 100644 --- a/tests/auto/network/ssl/qsslsocket/certs/fluke.cert +++ b/tests/auto/network/ssl/qsslsocket/certs/fluke.cert @@ -1,75 +1,34 @@ -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 +MIIF6zCCA9OgAwIBAgIUfo9amJtJGWqWE6f+SkAO85zkGr4wDQYJKoZIhvcNAQEL +BQAwgYMxCzAJBgNVBAYTAk5PMQ0wCwYDVQQIDARPc2xvMQ0wCwYDVQQHDARPc2xv +MRcwFQYDVQQKDA5UaGUgUXQgQ29tcGFueTEMMAoGA1UECwwDUiZEMRIwEAYDVQQD +DAlIMiBUZXN0ZXIxGzAZBgkqhkiG9w0BCQEWDG1pbmltaUBxdC5pbzAgFw0yMDEw +MjYxMjAxMzFaGA8yMTIwMTAwMjEyMDEzMVowgYMxCzAJBgNVBAYTAk5PMQ0wCwYD +VQQIDARPc2xvMQ0wCwYDVQQHDARPc2xvMRcwFQYDVQQKDA5UaGUgUXQgQ29tcGFu +eTEMMAoGA1UECwwDUiZEMRIwEAYDVQQDDAlIMiBUZXN0ZXIxGzAZBgkqhkiG9w0B +CQEWDG1pbmltaUBxdC5pbzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +AOiUp5+E4blouKH7q+rVNR8NoYX2XkBW+q+rpy1zu5ssRSzbqxAjDx9dkht7Qlnf +VlDT00JvpOWdeuPon5915edQRsY4Unl6mKH29ra3OtUa1/yCJXsGVJTKCj7k4Bxb +5mZzb/fTlZntMLdTIBMfUbw62FKir1WjKIcJ9fCoG8JaGeKVO4Rh5p0ezd4UUUId +r1BXl5Nqdqy2vTMsEDnjOsD3egkv8I2SKN4O6n/C3wWYpMOWYZkGoZiKz7rJs/i/ +ez7bsV7JlwdzTlhpJzkcOSVFBP6JlEOxTNNxZ1wtKy7PtZGmsSSATq2e6+bw38Ae +Op0XnzzqcGjtDDofBmT7OFzZWjS9VZS6+DOOe2QHWle1nCHcHyH4ku6IRlsr9xkR +NAIlOfnvHHxqJUenoeaZ4oQDjCBKS1KXygJO/tL7BLTQVn/xK1EmPvKNnjzWk4tR +PnibUhhs5635qpOU/YPqFBh1JjVruZbsWcDAhRcew0uxONXOa9E+4lttQ9ySYa1A +LvWqJuAX7gu2BsBMLyqfm811YnA7CIFMyO+HlqmkLFfv5L/xIRAXR7l26YGO0VwX +CGjMfz4NVPMMke4nB7qa9NkpXQBQKMms3Qzd5JW0Hy9Ruj5O8GPcFZmV0twjd1uJ +PD/cAjkWLaXjdNsJ16QWc2nghQRS6HYqKRX6j+CXOxupAgMBAAGjUzBRMB0GA1Ud +DgQWBBRSCOU58j9NJZkMamt623qyCrhN3TAfBgNVHSMEGDAWgBRSCOU58j9NJZkM +amt623qyCrhN3TAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQCq +q4jxsWeNDv5Nq14hJtF9HB+ZL64zcZtRjJP1YgNs0QppKICmjPOL2nIMGmI/jKrs +0eGAL/9XXNVHPxm1OPOncvimMMmU6emZfpMdEtTfKP43+Pg9HgKRjLoQp406vGeQ +8ki/mbBhrItVPgEm3tu2AFA02XTYi+YxCI9kRZLGkM3FbgtOuTLPl0Z9y+kiPc9F +uCSC03anBEqv+vDSI8+wODymQ/IJ3Jyz1lxIRDfp4qAekmy0jU2c91VOHHEmOmqq +kqygGFRdwbe99m9yP63r6q0b5K3X2UnJ6bns0hmTwThYwpVPXLU8jdaTddbMukN2 +/Ef96Tsw8nWOEOPMySHOTIPgwyZRp26b0kA9EmhLwOP401SxXVQCmSRmtwNagmtg +jJKmZoYBN+//D45ibK8z6Q0oOm9P+Whf/uUXehcRxBxyV3xz7k0wKGQbHj/ddwcy +IUoIN4lrAlib+lK170kTKN352PDmrpo2gmIzPEsfurKAIMSelDl6H+kih16BtZ8y +Nz6fh9Soqrg3OSAware8pxV7k51crBMoPLN78KoRV8MFCK4K7Fddq4rRISq6hiXq +r1nsjoEPuKM9huprmZVZe9t5YcDa2I+wb3IiE3uwpZbAdaLDyQ5n6F/qpsiIkZXn +gtcF7oqpG5oYrwCcZ53y/ezUgUg7PlSz2XwAGvQtgg== -----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qsslsocket/certs/fluke.key b/tests/auto/network/ssl/qsslsocket/certs/fluke.key index 9d1664d609..337ce541a6 100644 --- a/tests/auto/network/ssl/qsslsocket/certs/fluke.key +++ b/tests/auto/network/ssl/qsslsocket/certs/fluke.key @@ -1,15 +1,52 @@ ------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----- +-----BEGIN PRIVATE KEY----- +MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQDolKefhOG5aLih ++6vq1TUfDaGF9l5AVvqvq6ctc7ubLEUs26sQIw8fXZIbe0JZ31ZQ09NCb6TlnXrj +6J+fdeXnUEbGOFJ5epih9va2tzrVGtf8giV7BlSUygo+5OAcW+Zmc2/305WZ7TC3 +UyATH1G8OthSoq9VoyiHCfXwqBvCWhnilTuEYeadHs3eFFFCHa9QV5eTanastr0z +LBA54zrA93oJL/CNkijeDup/wt8FmKTDlmGZBqGYis+6ybP4v3s+27FeyZcHc05Y +aSc5HDklRQT+iZRDsUzTcWdcLSsuz7WRprEkgE6tnuvm8N/AHjqdF5886nBo7Qw6 +HwZk+zhc2Vo0vVWUuvgzjntkB1pXtZwh3B8h+JLuiEZbK/cZETQCJTn57xx8aiVH +p6HmmeKEA4wgSktSl8oCTv7S+wS00FZ/8StRJj7yjZ481pOLUT54m1IYbOet+aqT +lP2D6hQYdSY1a7mW7FnAwIUXHsNLsTjVzmvRPuJbbUPckmGtQC71qibgF+4LtgbA +TC8qn5vNdWJwOwiBTMjvh5appCxX7+S/8SEQF0e5dumBjtFcFwhozH8+DVTzDJHu +Jwe6mvTZKV0AUCjJrN0M3eSVtB8vUbo+TvBj3BWZldLcI3dbiTw/3AI5Fi2l43Tb +CdekFnNp4IUEUuh2KikV+o/glzsbqQIDAQABAoICAFw1q6tr5I48vY7DF+rXsuLn +5ZUWE1IQ6fzB4lr72nJv/9EEGnMgYzt9PpMUsD6vdCpBgS2C0+6RHArFzJtNA+RM +iHLIG7K7702veyr/xBx/MwiSlMeMv/XpkFxVI6E6skMGG2s3AMXxKvJTy5CpRx+I +eQFyLG+Ya1X2lgJes/q+/CpAHkOjCOpcLySQC5NZ74q734V7nSdmn+Zs3tYEh+O/ +eiuwTP/j5b38Te5vVTqDxTciJPmljmXLCwa0N100lWlbcpvw8qbqiTI2Jm3XCbUE +AzHjW9vmrF3cRS1fXxKFGShw3SRqlkbxjfeWoi8qDPUBS4m8LOr8qG9Wo5Nfon0z +zLP4bci3zHDvVcaaZrrsUBs/yZbg+Dgka1DmX7ekmeccr2yTdKDFgPupYUyxVbTl +a9ZLJysjFD7rgBv1ZclHonLp6Vbm+ZoTqvteo4ikAy6L9RtBWJ23XEK34PkP/+c5 +2vWZaOrnjSeBHbFce8cdJSxqWpP+eSCI5I9XbDrYFIsQ/gqKgtzDKy2ihJ2Y8STL +yO4hyFPFjxc+Gg4/P2PpmT5CY2ty44M0BWs+JGW96CJPrrplf2lmQUQJj5LZY66X +Z/4C9L7ZYtKZ+bs5SvU46yWugAvQZX22Xm9xLXWyVXRdx3bj+3M3fDnF9di/zdbh +CgLx7oWPNrXc7FCajnn9AoIBAQD5FMYwRpw9NWT9WDxQwx+cSI4Icbd88ByTW63S +LzeRwZA0J9/SfwO+aBRupzc9GkGXCiZcGMw3AGsCtig8yFlw8E5KnzN7KlftDMnM +9NUxxzlR8VwKyLnZfG7sDTl057ZlUujnqhmt/F8F7dIy7FVO1dE/8nngA+FYTCOG +UZdGjwyBDlDM0JJdUWGY3xslutcpCDN5mzSTKjy9drMvImAshRawxRF6WBpn7vr2 +nC6vciqfx1Mzx1vyk0Jm0ilaydDdLMADjt/iL4Nkr0BEs4k+UzQiKDwp8gu7abQ1 +eBfxd9Iar4htQa2I1Ewl6P01G/q+ZYwgHhJ9RVn4AxQXefILAoIBAQDvCouORdQX +C8wsyp7MwXlF/3NQeNN5/+B2mhbxrBOf7PmMCXLnkRWcjwJtzypWFqJ0sqai/2+0 +bqbMcjX5maT8stT2shl3zXe/Ejt2e3TBYpc1tyuses8Kb5BMU8hu6tTd3G2CMXpD +dT6DVemJZCTtwj9aBNIxSizvlgMolJnCpzhPnlfHSI6E+g3m/LTTo3HwbjMSw/Uq +irgjOpI2wSBB6LZPSgjvfcYPRyWUk16L4A5uSX0cADnovDFLa5/h0wJvN/OoCSQg +rLCXG5E18EyL5Wc58BCY1ZvxmjG3lQtgPxYu2Jwc36R/y/JKlxW5suER5ZNpbbD4 +uOyTt2VxMQ2bAoIBAQC5+MzRFqdo/AjfL5Y5JrbfVTzXCTDa09xCGd16ZU60QTWN ++4ed/r+o1sUKqUcRFB2MzEM/2DQBjQpZB/CbEWvWa1XJWXxypXbowveZU+QqOnmN +uQvj8WLyA3o+PNF9e9QvauwCrHpn8VpxbtPWuaYoKnUFreFZZQxHhPGxRBIS2JOZ +eDrT8ZaWnkCkh1AZp5smQ71LOprSlmKrg4jd1GjCVMxQR5N5KXbtyv0OTCZ/UFqK +2aRBsMPyJgkaBChkZPLRcKwc+/wlQRx1fHQb14DNTApMxoXFO7eOwqmOkpAt9iyl +SBIwoS0UUI5ab88+bBmXNvKcuFdNuQ4nowTJUn9pAoIBADMNkILBXSvS5DeIyuO2 +Sp1tkoZUV+5NfPY3sMDK3KIibaW/+t+EOBZo4L7tKQCb8vRzl21mmsfxfgRaPDbj +3r3tv9g0b4YLxxBy52pFscj/soXRai17SS7UZwA2QK+XzgDYbDcLNC6mIsTQG4Gx +dsWk3/zs3KuUSQaehmwrWK+fIUK38c1pLK8v7LoxrLkqxlHwZ04RthHw8KTthH7X +Pnl1J0LF8CSeOyfWLSuPUfkT0GEzptnNHpEbaHfQM6R6eaGhVJPF6AZme4y6YYgg +m2ihhSt1n0XVEWpHYWjxFy3mK2mz75unFC4LM+NEY2p2zuUQoCw7NjnY3QYrfCnx +rRMCggEAXeXsMSLFjjyuoL7iKbAxo52HD/P0fBoy58LyRcwfNVr0lvYan4pYEx+o +KijIh9K16PqXZXKMA9v003B+ulmF8bJ7SddCZ5NGvnFhUTDe4DdTKgp2RuwQ3Bsc +3skPIDbhVETyOLCtys34USHrq8U/0DlGY3eLRfxw9GnbKxSBGa/KEu/qQLPNUo50 +7xHZDg7GKeC3kqNJeqKM9rkp0VzIGkEnaD9127LeNDmERDfftxJzFoC/THvUBLfU +6Sus2ZYwRE8VFvKC30Q45t/c54X3IuhYvAuiCuTmyfE4ruyzyOwKzhUkeeLq1APX +g0veFbyfzlJ0q8qzD/iffqqIa2ZSmQ== +-----END PRIVATE KEY----- diff --git a/tests/auto/network/ssl/qsslsocket/certs/inter.conf b/tests/auto/network/ssl/qsslsocket/certs/inter.conf new file mode 100644 index 0000000000..ed350da8ea --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket/certs/inter.conf @@ -0,0 +1,14 @@ +[req] +default_md = sha512 +basicConstraints = CA:TRUE +keyUsage = cRLSign, keyCertSign +[req] +distinguished_name = intermediate_authority +prompt = no +[intermediate_authority] +C = NO +ST = Oslo +L = Oslo +O = The Qt Project +OU = The Qt Project +CN = Fake Qt Project Intermediate Certificate diff --git a/tests/auto/network/ssl/qsslsocket/certs/inter.crt b/tests/auto/network/ssl/qsslsocket/certs/inter.crt index 4e1d67c3e0..2d924f3a96 100644 --- a/tests/auto/network/ssl/qsslsocket/certs/inter.crt +++ b/tests/auto/network/ssl/qsslsocket/certs/inter.crt @@ -1,22 +1,53 @@ -----BEGIN CERTIFICATE----- -MIIDvDCCAnSgAwIBAgIQO+uZxerYC10Ll11PBnVL4TANBgkqhkiG9w0BAQUFADA8 -MQswCQYDVQQGEwJHQjEZMBcGA1UEChMQV2VzdHBvaW50IENBIEtleTESMBAGA1UE -ChMJV2VzdHBvaW50MB4XDTEzMDIxNjE2NTMwOFoXDTIzMDIxNjE2NTMwOFowMjEL -MAkGA1UEBhMCR0IxIzAhBgNVBAoTGldlc3Rwb2ludCBJbnRlcm1lZGlhdGUgS2V5 -MIIBUjANBgkqhkiG9w0BAQEFAAOCAT8AMIIBOgKCATEAsR4tRskg2IFfQFMfGBJ1 -eqlrNejANw0oM6k5HlEB8uFA9qeyAzmflwQUPoJ55KRQ/gVHTOBdWrtgGgPMiekF -1Q36Ry1elwbAl4a+LZ6qsc9ASipvk8HirKpt1v5L9hG+aI4yDxyvjNztFtg5R4P5 -zqsh/WwhCgsYmEVfcSDbhUjqoqxGRLaZxPKO+IMCNFrjZqi0yxc8f6Un4G5SQzHA -4szi/ezcITnAFYWxHG2yaed4hawpxNS1WXabk2rzCi0pWeIcHuIczaCfZ7ElRcqV -VNNXbGTtUDlfIsh6FAVI5kTUDcPV27uf6BmHuFOu/R9Tjni25+vBFvohwQh7ZwCX -5COXnfkJLPkJQQEFVQv8nS27ht/vmyoKjERUeiuMd+hFcN5zl7bS5A2JCgi7erlP -ZQIDAQABo2QwYjAPBgNVHRMBAf8EBTADAQH/MA8GA1UdDwEB/wQFAwMHBgAwHQYD -VR0OBBYEFGn5shQ0SeTcc3x/cNu6TkoV0bPmMB8GA1UdIwQYMBaAFJQnOLW5hBTG -pvc2vfcs4sJpRRPJMA0GCSqGSIb3DQEBBQUAA4IBMQAVDS0enQQ1FL0d92xOFfwx -mjcNPz9oO7jMyEVxAs2eR2QD+xZ3Xj4gAiUEp40aGieDcLv+dg+cmuBFWF61IYSR -UyuoakVm08VDcLAwUzU+xtSvJiSSROb0GsAnVsYZj4TYlvKDplqfapOYaiIkwF+c -iE4n7G0hQW9fzqO+n3FGtBD8YUjghRqLggeRVJ2+8S3Bm8cfx8xPpRIO3ksA6opn -CORRGuzetDHihbks59mkoY3GqKFgBOyrC3kG07nv5wtKjdKDtmD/kS/SAc4fIXKy -Uruq2uXNf/1BUgF5gFGRyj22yB2D0763fJJpl5nqcLrL5RmnVObQKZGhE2VsRTV0 -untj+AmiJivhiAjjkHfw3XDf8tuL7D4pTmEkGgl5xl23fyeTIuygDCLT8fRD3ZqQ +MIIJczCCBVsCFBFyNLwh5soEJBP4NUiEpuneliIVMA0GCSqGSIb3DQEBDQUAMFsx +CzAJBgNVBAYTAk5PMQ0wCwYDVQQIDARPc2xvMQ0wCwYDVQQHDARPc2xvMS4wLAYD +VQQDDCVGYWtlIFF0IFByb2plY3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTIy +MDkwMjE1MDIyMVoXDTIyMTAxNzE1MDIyMVowgZAxCzAJBgNVBAYTAk5PMQ0wCwYD +VQQIDARPc2xvMQ0wCwYDVQQHDARPc2xvMRcwFQYDVQQKDA5UaGUgUXQgUHJvamVj +dDEXMBUGA1UECwwOVGhlIFF0IFByb2plY3QxMTAvBgNVBAMMKEZha2UgUXQgUHJv +amVjdCBJbnRlcm1lZGlhdGUgQ2VydGlmaWNhdGUwggQiMA0GCSqGSIb3DQEBAQUA +A4IEDwAwggQKAoIEAQDf31Hd+5tMLrBf966j4BiTBP7yIS7BJ7jBSUWVStd8F1Pc +hxB/h8hKj8T8M8Fq2prmxkkjg4epxmgqYeGqYnBqPY0Gke0RXC506WGW8B4IQ+qk +szVHJyNC2dnZ7byaqj1/vleQESmaQhXRxSvaw3Qu54/SbXuEOot8tiBZ90oVvHHt +yn1nQYpGGDszTATKMaaqaE+D/lsNzxJGGzndbg9yjrvLRKBRbFIhT7L7ME4d2NLm +AcXvFHHjV2bEBCvQrShXE0t11qAUrT48rDcBA0OsMW6YwxCBoFXvnpg5iuCfbQGf +zRVgGIhb8Bo1dV2nTBTMpz9ssupTOmlS1/WJ99w4nPHUHBtYe8QBaWigHbIqyxlP +hm6NBe4i1EoqY7fsfI6uH9eo0l8ZvB/tLCgFRE5OqHQZXPUHutnlhSoouj7gA7Lp +VPYundGY8mauVV9YFVDECh8oiJI9/dqq4i6QhLHFXFUG6P95yqgzv9fsy2HKKr06 +2deBjOGMoQv7CRgRr9/JOAYOdk8SeQ1eWRA2O2Vx9N2davIczvuODqP2Y2IqJ9/x +xvYVZNlnLIrtJvTCh4ROe3+ecdLeg/hFT/J2BmG6oHeNm0TJPnI1bK6TDJYb/Nqi +EIuDDpbNs4IZn70DCU+Fg1FiV+evAziQ67utijyOg/xooUKVvXH4c5s7jUcFmYJd +Zf/3GwwLVoTpeBpAKyuZ/ffUZkXUi4GhBS5g+3P+O5LASKiA+785qk/FtY7tYo/H +VfH+3n1hQK4xdw8VA81LSanhZMYkwpKSh4Per0jeGz5GeYfCbBuxlfZovmUHcq2s +1seIcxRzcI4f+uAsjdAh5dAn3OFqComcbGls9iWn+mGs41tLgNf+J357N66234DQ +K0FXrRGyjmlYNPibS3DkCJCmEslNjSh/ObvMSTiJkpVYEXP5lo6Rq67C0iaF8yxs +jsMfzINqQX0gQj8QYbxmy3M89dTwNoiJ/XJuDKwAGdsfJZV7clUY2cLcCue/XiXM +xOmGvSU/Bkq6vb2ij7TPeMoV7gNVhNfVyM+h09q1CesTjAauRMp4/ZYYETPkdII0 +Hkd7J9QQP/aUHX56vl+R6kEBE+IMfEIXpsmnKjwxdfbYfiJZP0wewkM0LfdI9T00 +DVc9NI2xqZLPx8N2WxnvmDHrz2kpITBdiseddNK/L6X/sZdxFf+2YQiA3o+nvifd +iq9/2MyVnghcGOazlmzTB366OS6vbePWObm2+9t4h1yJMOIoXr69XkMzsmNCHyR3 +q84/VmDACRfoeA0h68wpeMphKKjlJhGWD4e3k4hIvbKW5/HvtIJfaW1RBXtpiS+3 +tJwjpHdIZGKW9CKheupACkARHO2udeJRYFi29RMNAgMBAAEwDQYJKoZIhvcNAQEN +BQADggQBAEMvISwrzGYljSkM/04Iym9m1nLZ8teOLxar0bULGIAVGZ01uBwSwapm +C5lvsNU+IY3O4TgjhMMq/cLXM0KUyhNK/oD0oEjNKuk10uoqs2sRU6+t+iFtf/74 +xPYImmDCqEfVu2Eew0SMKclPlPOBGHXVm4oOcbCp7xFTTg2YIrRDa0cKekaDDtsy +gQqMKNk/wGHI9SQVjVerzsqg31x4rvVaI31Ss/KosZWi0La/QjvJzhFF+UJ+AGkX +0p0iOKzGbMgi9tSLrLTK87n+x48XayW/P1+BKdvXUGXQUskCaEdhRvUHTi5LKFyP +mZ6xkyCxNig5fuwUnfrb/976VzQCucR5kIVh52WBusgEnCj8mvdlHQov5Vy8dwxF +4tO51lb92R5Gu0e7XuKK3LMANQO1HNFDASPyI2AQXXCVgrxOqnNSyk9sAFsyRWDx +9m0v4KjOezukbJ5OssBNVj/aQrvYq+L88Z8NFq9q0DoM2fVzxfbSixpRh3wbMm4c +Ttv7zXgLFhA/jrrUCiQVzgp0KSnM2Fchi/IxaVH34+8JCC+tKX4EK6vaIif8Omzb +iEsPUUbINcoIHgfVEYmmk6Z4KcHBKOz/iiTgaPiQJyymGlgXRLKjpkbifbRIm31M +UxCpv+KyTmjDeDFRXX+Yl/b1/sRNg4TfGTVySsb56vzRMghRPJlnHfMxJRroBo6L +FZfimQUcJxbNpavPdj29Vg3Y6bXGdUATx1YDHFSCynOnwXE4kgDvQGyoWHHN1zWm +Fl6JyVor9vb6viBB5HCerZsQ5HDpmQ9UqVs0iWJqYfgyFThW6mZGbBY2inw4hjtT +oVxVzW8gTTaeYLlrY7BqSpjtWQduSzSgaIiCGuvM3Yg2N6jiHzlN0h0pI+uHbvNW +F5ZMfVMU8IcheMilj1a7lgmQQas4xy0emo1H1GH9Lcw6+yW7yN77grKOgWhimvMX +UvoHaxE/T67jpK+SLyyzhfsGwOWhx91BzAFpyDqrYd5ERR8EUUUEVKLYofmDh5Ey +FqMqQEwXOBQxB1Y/1UcSbycu+Zr6raKJ0G6eCS7O6dlCpIZwpggqqnKZYFnunskE +lNw5ZpsSHADp8rwRVJGlLxgqM0TEvQa07+wb85sR8Hl47Y5QSq0E/Hn8a2ZcGERR +chsW89yr7qpUNPoTQUDQ3ZGByzeXMYSvNWvsChomy6GqSmFtnuI6Ta07CNdcbqQ+ +8Pmo8Mi3UUNZueP2VNIdHXeYEabjwl7v8KjyT4bc0/SKk/4L7ADvLxV4Fe1Na73Z +2hrMwmHCWJ+4sdVFF/3t0yDg9GQMGCTXkbd8ofJwIkM72NAUYAkMvOBx8+NaSDBW +wvnYOPu8PDnRWerAdoRZUNlKigb6oUA= -----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qsslsocket/certs/inter.key b/tests/auto/network/ssl/qsslsocket/certs/inter.key new file mode 100644 index 0000000000..8d282647e5 --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket/certs/inter.key @@ -0,0 +1,99 @@ +-----BEGIN RSA PRIVATE KEY----- +MIISKQIBAAKCBAEA399R3fubTC6wX/euo+AYkwT+8iEuwSe4wUlFlUrXfBdT3IcQ +f4fISo/E/DPBatqa5sZJI4OHqcZoKmHhqmJwaj2NBpHtEVwudOlhlvAeCEPqpLM1 +RycjQtnZ2e28mqo9f75XkBEpmkIV0cUr2sN0LueP0m17hDqLfLYgWfdKFbxx7cp9 +Z0GKRhg7M0wEyjGmqmhPg/5bDc8SRhs53W4Pco67y0SgUWxSIU+y+zBOHdjS5gHF +7xRx41dmxAQr0K0oVxNLddagFK0+PKw3AQNDrDFumMMQgaBV756YOYrgn20Bn80V +YBiIW/AaNXVdp0wUzKc/bLLqUzppUtf1iffcOJzx1BwbWHvEAWlooB2yKssZT4Zu +jQXuItRKKmO37HyOrh/XqNJfGbwf7SwoBUROTqh0GVz1B7rZ5YUqKLo+4AOy6VT2 +Lp3RmPJmrlVfWBVQxAofKIiSPf3aquIukISxxVxVBuj/ecqoM7/X7Mthyiq9OtnX +gYzhjKEL+wkYEa/fyTgGDnZPEnkNXlkQNjtlcfTdnWryHM77jg6j9mNiKiff8cb2 +FWTZZyyK7Sb0woeETnt/nnHS3oP4RU/ydgZhuqB3jZtEyT5yNWyukwyWG/zaohCL +gw6WzbOCGZ+9AwlPhYNRYlfnrwM4kOu7rYo8joP8aKFClb1x+HObO41HBZmCXWX/ +9xsMC1aE6XgaQCsrmf331GZF1IuBoQUuYPtz/juSwEiogPu/OapPxbWO7WKPx1Xx +/t59YUCuMXcPFQPNS0mp4WTGJMKSkoeD3q9I3hs+RnmHwmwbsZX2aL5lB3KtrNbH +iHMUc3COH/rgLI3QIeXQJ9zhagqJnGxpbPYlp/phrONbS4DX/id+ezeutt+A0CtB +V60Rso5pWDT4m0tw5AiQphLJTY0ofzm7zEk4iZKVWBFz+ZaOkauuwtImhfMsbI7D +H8yDakF9IEI/EGG8ZstzPPXU8DaIif1ybgysABnbHyWVe3JVGNnC3Arnv14lzMTp +hr0lPwZKur29oo+0z3jKFe4DVYTX1cjPodPatQnrE4wGrkTKeP2WGBEz5HSCNB5H +eyfUED/2lB1+er5fkepBARPiDHxCF6bJpyo8MXX22H4iWT9MHsJDNC33SPU9NA1X +PTSNsamSz8fDdlsZ75gx689pKSEwXYrHnXTSvy+l/7GXcRX/tmEIgN6Pp74n3Yqv +f9jMlZ4IXBjms5Zs0wd+ujkur23j1jm5tvvbeIdciTDiKF6+vV5DM7JjQh8kd6vO +P1ZgwAkX6HgNIevMKXjKYSio5SYRlg+Ht5OISL2ylufx77SCX2ltUQV7aYkvt7Sc +I6R3SGRilvQioXrqQApAERztrnXiUWBYtvUTDQIDAQABAoIEABn2G9hSRUAgafO3 +FVmLs03ZVnddwb5EjPhdNuSJOVP6oI8CWrdvV5rN8VoN5nAtyajZdcHYjvLxP0Mq +9rB7me24FZKdeZB50ClepyKJ1fG/boaLAbKupzgpa0oKd8S32UnnGOBsHRb2cvFQ +nDVSVTbbQ6Jzb891updLx5SnSMAcilm5EbHXt+FJDhR0zFlmSJ2aWx5DcOu5B7V5 +ksxK5x+xzbVU0AKhPST/yRG4GFb9vfdOXVXMWSi0CgbRNQOOEQ+H/Ug9C3NaY81F +a1uCtWZSlTDB7jgaD90p1x1VLZdPXNDbR49NSQLgZSmt4p50BDV3b7N7TBE6xNwG +j0Lgq3klOiYO3Fz2fVRslOV8jBzKULUYMdnIxkTjuXYQ+lNCXolyx9+cBctGNa2b +YUi7ExmsD0qhrQiocnxbZPg0IPZ5d1X3tFTTmGrUMXQmElh0oFkbk2Fv9QWbWrBW +am/382Wfv3x9qKLHDZpytOeQ7lYzfp5EhOlRHRbh1jHWbCQg8SK0jH9A2QqbXyGB +0o93c9wzOT/4FvugRSvEJt97xvZ8iUvQdtkkSNHeKH439kpYzM8NI0+Mg5eqVjAz +hTqKouqxkSuqxd9Qjo4DfHsxCndUa0ZABO29018nYf72t0SS39Xr1JRC/WseRIEJ +1UnargsY4zx+9unGfmEBhw7w4zuSyiMARmEmigdKvofTj7V4nIBWmy64Pvp9U3iQ ++lx9mtqcybdNLA5VOrzF03W8snO3xxSBC2If9Vr9uelRtBecTYa2pRVAhfwrLlVR +fexDIzOTHrm7kwZnFAfVf5y6pz7m2b7kMZxjRvZZ+WQVGGwafwPAaCeHR3txKd1L +ixHRUwvoseef3hqDPzA/0CtcuSfk+IPSrCGbymWMpRYtSDkHectI6o2BolUzjY95 +dpzILDlCHewAWJbP11Hugi+NZOFXluom0vCVYgs8Y61S62xFqHifzF/usHmQ4laP +zHQkoIaZlTHA3gxKDpYpyJw5/x7WQ4UAtXW/GzS0Bec5FOEv5NtyEW4s/jYkX8J4 +DlmI/iW/q/LG+G7EL+AnOqnnoBhY045mUFjXO7OpWH2Kjt7XG6zXMSAsDKm8Wp0o +Ily9FgfPxsHOw6i3NrOWNVmURVyCqY1Ut8F/T1vQ2e8b8O4FlaIMQN/tjgSpkaDa +8ziPehQEZqZZKkmq6InZlY1MlqXrXivZYkDJCqzhGKxIPt0C3sfTBQxCzJwIO9ma +STOxdgj1HfczNyaTwRYtbdtkroOKWclmB3lbQrZmT5DVKCtLvwFAG1LYGGy4w8gf +6/IEsV3uRGLMbnY+qvl2eI2wwI0FYYaxdydiNDYHyiK/Wea8QCsbU48QlBB7W1Of +zzNv+gECggIBAPvP57PPQaeDKZRb/lbVjw8IIPN36Vb2ZSRBoYuvSb+a+62czrYI +ZNbadBb9VCx99VlDaxthE/9m5Xa5JhfHckf0dSYuXzX/fnzXlT+J/SKLhGVXsqG/ +HBhXu75wn6cvxV8D0WQ+C7I8xIXHeQsyC5u/HFHtOiAZjjg/BInBIenCdtDLehBL +axBN363U7hmd/u0wDiiKKSKTDZwBcnfQUdEmdDT7VvnYdQVwsBmYXR0XNS2bROGH +NaJWxIUUPS3Sv5KIkNSzGCgD/FDGa2w1tRfKalMXZ9ttzCzmKGcHNLtLSeC0Be5Z +mG6Jc1dTKbhD29VLTJgidnNne6VkZjQoLXJEeWWQeRqpCqOx8AUp0b1d9Zhdf52b +FYazIyoD2ARMyj6S16xalSS6mYYMzvXI+LXMjS3WEM6Vxxk1is9LhQdD7voszCVI +SOIZheub+ifssPvbw2fdR9V+euT/Gx8IAnYYFPtW8BLvAAvp7Rgximbp5bs8SdkV +9ciPCJAC7DRgBUT3CI3Img5c53ZONoWUJVjTBh3BULBdsk5QFLUxj4WXv+ckoq4T +2qCWMXdFF6EFbh31dfz1S+97snOIkaJDlo+nNvUIPYeNuPMwFaNLcg4XebVFw2in +24C5l7V+jAE123seJLquupQETAOGCkEYwPcQPRw+jDnyAfIsLFKc5G3VAoICAQDj +mHXltSg9zQACyk5ky+EHyc8nwJ3i6zWGIlaaJ/6G1t2pLXv9ZsLLvYI0nuBM3Qb8 ++SJajT2TKsH9kLd0BmoBMgqM/+cA5aGCCrdpmAdSSkrHQOOSaNVSEu3oqz5n0/ft +/sh4Sj07n7w1rsorK3RbP8ZltYjrQriATiIRV9/tTayZfi9uwpl+0ByvZbfqGGbC +wbDFHyskbwe4OZOrKDkf6sKCyzLsVI8mujmqE6BZ6pskbrXIGbUPvau9azpHbcvY +WY8Bk8Rv29BCHt8m9Qvgfet3dxoWVaMV3W13DvVs0zEhYTfphL6WP+STNt8vuU5/ +A8C5MOwelLzzGxeIl915rC3Y7PzYZlO9V1KQv3DhBTub7Ow8Jilhzsan3Sx0CikO +B+HdcjzW2YWxglqC/QX7jtVUIfHvssQajNzv9C+feXU//Fn0uudX3xMUxbBXsBJ3 +x17IXHP3a8PGEbBp454KhhFlmTyk1rUkGboctakepV+nkl4FZs7ClK4u9plMGuvy +02QDuy0cVn9pLrqpKimKNUzv0Uz6UQfZXphCB31BDA7nxhCvK1LQv79BIBon0jhk +KMBMMJ4/FsNO+vU0a2fApu99ZkbpIPPWsDnj0W5uyULVZiJWh4pHb+Azo8/EptA/ +PdcYIZm7pT2NmXyWalaNE+2Fj5iuT5riKsGr/P1UWQKCAgEAo83y470G8HkaKzBM +myABF74p8TcnyzItSRCIjd1RFBs1bRJ8RV3gewNQUUQp5Wdqms6Idh8IazP8QObg +KMfNR5F2Q4gW14GEPqHerJ6O1FH9pg8OXLl9BTjNIG0S7ibdNZm+NH9IDIILNRs1 +WlsLwhznx0OSdB8rrNsRkKrZ7L5bnCdBGCh3VPvTbbj9yhxFIPYJv8VgTOVsDPfE +Bry0/GEPZwe45H4yYX+UjpHWwH3AUhKXFD5oXVokLI2l3pEhnajIzhRSunUdRU5N +wu6NBxTdZX/sR4l9MBfoYF0HqG6peEqjMRGHXyB6r2uh0AQUlQOOp8iDVT8T59sP +wQ4BwjtY3QDGRtl/2kx93l392jms8Zig0112+1C8pzAo7WMmjN3o/m1OZ74a8GCU +oL5DS7/sdsyx0jEMexGhYoe12awPYR6TDg2fm7UOsN2eNSp7Vtr2mjIP8Il+WEi6 +08zaDQhNXdKICUj/tsBNQ1e2uIuerdXiFB187SJeZ4//J3Lu+pXYMqMz0/QLfaIT +RYHBaa6cY+7FFnVc8CSX0+aRfk3gv/PM/4Baz+vj8bo4TL7DiymJvyuyYe8Nfqpw +UiW1Y21bCrp5jBxdG5VD/h2t7AzJV2oyW3oWB/6y+ZWAbakjRUuuiOHw7Sh+aixf +r0jy/cTKe/0UKv2K1oZ1rqfw0KECggIBAOHCKbBhsjkbUBd0da6mTeFb3ZChD/w3 +NDCJfz4Kzf8Sw209IPCLLk7K/I0Vy4hy9quYtOr9j0ab8zGCi3cbparp6G1Uqd/J +6BsGZkjn9Ns7tlFPnG1ub6up+zQAKTb0m8oIIPKxMWwjVp4pc4C+6fxZloLtP5Od +60XaOxDZCdZqZfsboBFOFtQju1CApZ4f9k7Zsm7WLAVH3XBwLHpqu79dLvRue2TR +u+2+a9S5AyYuARZyev6yAVhL3D9YTcbssnc43xHBcelDMaFk3hXWnKFiRl+KVOYy +rELUEfE3dVstYl6qALwyYJrJZgJhO6IrPiHfpxwL2yu6fnLnPMDRY299yzySV3yQ +hCAcrlnGjEGo3ygcK3i+oe3THlsEmUPBkFfKmdD/sDmuK1+Y3g9wzK5rUFDUGxiZ +SszLTZz3qwWVhSijONf5TeFr9ZF1Rya0EJ2ftfUpQB79VoTypvtiPTJTKo6NIgqg +r63Plz1DNS6g+/FMztas1AtPUDhlhEppqgKEjYDl+ilR47CCGcYTfIELvfVkt+bU +2eRUYNOeejA7tc1SOtqHLu7CRQRkw40cibNQeO8ait4pxjJh3TjSEWiYLpdFDLHT +bgxXYhUJeXGLUjA7z3PlntSdtNeEdmOq1Ibm4KWfLs9jaVs8FMlfUds/GSyS8/B0 +Jj6SCup/WQqBAoICAEkNfMe4BOR5jm3l625O2w28b37tzl/MIpvofXX/pIw3E7Bb +KL5Djv/rQNx5FmwEdE/1iR5fqQtY17nhxVQEoAPUrdJxaPR6rWnnDLI7tg+Vme27 +x+KDaonj0mMqVopBCs+G7+E8SDDeFnDyOgJEd32q/m4Mwujv7AuKH7uDl2cER2gc +5xnYyJexlk42DW7X+6fdYZxyMoGFz+Qxylj4kO9UpEXk6Yb09uFZaX1yGJZhuCWs +NgEXYYfTHV47XTF7hOrs+KlYQt33TY+zfOV+ySn0B1PFJ5fpCC1n4qoysdfjquwJ +Q1FmNCRYfA/SS8rnzZVTY4zh5//cryvzhiVNWDEoXx4PDEkH/xgvag/KVKDZahCr +lwXG8Ipqn8WUZWy/fq6ItOKPQOIECk/hctf9awBYU97G1Qk4LoCNOzbcnBY4BvKo +roxcm3N3uaGPiDuapmnCfKNrvGmlQvWWtI39paXRWezARHBFQVFzp3w69/MnVDD8 +zmeNrOLCxCxmMxCrE+nARSHANUG5VXLbAK0dfPm5+3eLnvuD0GxkDhUwQS7r8kcP +xalXLIa5oul8gBwQf1YV/FPNzTxsB9EyaTAWJzaLOYwq/ugtzr6yHvDIUvOxhnHr +r0sXSrqOWhl6uMaMoExTTmVsEXgzCFiXBufo7CwT1DFyS10nNNvA/kxh3rDc +-----END RSA PRIVATE KEY----- diff --git a/tests/auto/network/ssl/qsslsocket/certs/leaf.conf b/tests/auto/network/ssl/qsslsocket/certs/leaf.conf new file mode 100644 index 0000000000..5ecbd31b55 --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket/certs/leaf.conf @@ -0,0 +1,14 @@ +[req] +default_md = sha512 +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +[req] +distinguished_name = leaf_cert +prompt = no +[leaf_cert] +C = NO +ST = Oslo +L = Oslo +O = The Qt Project +OU = The Qt Project +CN = networking-tests.qt-project.org diff --git a/tests/auto/network/ssl/qsslsocket/certs/leaf.crt b/tests/auto/network/ssl/qsslsocket/certs/leaf.crt index 4a7dc40540..b9af13b896 100644 --- a/tests/auto/network/ssl/qsslsocket/certs/leaf.crt +++ b/tests/auto/network/ssl/qsslsocket/certs/leaf.crt @@ -1,23 +1,54 @@ -----BEGIN CERTIFICATE----- -MIID3zCCApegAwIBAgIQEKCtd1j2bq5Gk6ND+VmKnjANBgkqhkiG9w0BAQUFADAy -MQswCQYDVQQGEwJHQjEjMCEGA1UEChMaV2VzdHBvaW50IEludGVybWVkaWF0ZSBL -ZXkwHhcNMTMwMjE2MTY1MzA4WhcNMjMwMjE2MTY1MzA4WjA1MQswCQYDVQQGEwJH -QjESMBAGA1UEChMJV2VzdHBvaW50MRIwEAYDVQQDEwkxMjcuMC4wLjEwggFSMA0G -CSqGSIb3DQEBAQUAA4IBPwAwggE6AoIBMQC7EIWIzb7XCfmQQ1KFdZ5E9f49eNK/ -KvsXYfq/iV29K1cz2hUyvfdKgyU5F/+BOPQKQ5zdWn1CraZosFv/ibuO3mhRpMfB -SfNn3rfdrE7WtA0wgT2YNIN0L4aCe+C15j2ESdmyMaFLUaUIS47JS66UtaYxp5ia -mJFO1hSNaoI0pGHyPFTTtfOza9z/01qkBbHB4htzauqs/fX5ZrnyCDSrfpVipXke -zkPKg4MkkytEkjRKw6tSXLpWIgF3ee2N/jBdefqlw8YPW08K0wmwF5qGuX6PZ8vB -sOZeWeCfVr136BopkbfP3TkGWw2BrD8xSzOUez9HVc0v4SZ/7pe5w3L4V/mzYQLt -O+1AHevCjX8+M58HYGBaWCAjxYUPGcGKcj0LLtgZgL6wY88N7RtfeOY3AgMBAAGj -gY0wgYowFAYDVR0RBA0wC4IJMTI3LjAuMC4xMAwGA1UdEwEB/wQCMAAwEwYDVR0l -BAwwCgYIKwYBBQUHAwEwDwYDVR0PAQH/BAUDAwcoADAdBgNVHQ4EFgQUKKuyJSrT -Y+dnm1do7l0sVMX96SYwHwYDVR0jBBgwFoAUafmyFDRJ5NxzfH9w27pOShXRs+Yw -DQYJKoZIhvcNAQEFBQADggExAHELijlIFdcncP3B+vxEp0SGKl0arIaCXahivb2F -VxeM3WajN6O+oDRLFltzMeDKA9RVkao7fgITzXQgCGzeNhKv0vc9iDyvR9/67vuS -W8xEEJrYowtw3VK5H1y0ewqZaxJhvKUjm4TBRWe8FGKD3s64lEsfbjOaI5VPidVc -DXmdAlXsj0Hk+v4Ej8mshPQAnVSyJ3D0ZMgTjk8Di28N0qROFIYJaTObK1rCb1nQ -GaCcmbZU6JnkYvVZ+iUe5U0GXFbb+LRNTUT8/fw1zADeHnv/G+WWVrfND+sov5Oc -33fkNE6z+n6ayABVnGLuCYhbzD38sv0dnxeh8vbykNBPzYdzPg6nw3Czv2vlhKpJ -8Yj/maoXuAyTXVf30K1/fAWyU45noq57MjQpU6UxIX1D7qw= +MIIJoDCCBYgCFFjfM8GbvMVRegCGZEOUQeIm7z+JMA0GCSqGSIb3DQEBDQUAMIGQ +MQswCQYDVQQGEwJOTzENMAsGA1UECAwET3NsbzENMAsGA1UEBwwET3NsbzEXMBUG +A1UECgwOVGhlIFF0IFByb2plY3QxFzAVBgNVBAsMDlRoZSBRdCBQcm9qZWN0MTEw +LwYDVQQDDChGYWtlIFF0IFByb2plY3QgSW50ZXJtZWRpYXRlIENlcnRpZmljYXRl +MB4XDTIyMDkwMjE1MDIzMFoXDTIyMTAxNzE1MDIzMFowgYcxCzAJBgNVBAYTAk5P +MQ0wCwYDVQQIDARPc2xvMQ0wCwYDVQQHDARPc2xvMRcwFQYDVQQKDA5UaGUgUXQg +UHJvamVjdDEXMBUGA1UECwwOVGhlIFF0IFByb2plY3QxKDAmBgNVBAMMH25ldHdv +cmtpbmctdGVzdHMucXQtcHJvamVjdC5vcmcwggQiMA0GCSqGSIb3DQEBAQUAA4IE +DwAwggQKAoIEAQCjQsmsZpATuLv54ERkqSdjWZYuulm5gZwzz9fS7R/K1CoSFQza +T+rY7Kauv1zpalfZGNs4zmEiHDsJ/hhVxCC0L6L2PqmkZjFT9psAkPHENRMIvBYl +QsrJbSNj09UeBfAR+ux2vktreyZc3UFyq74iQbHeXFuzDnH17BZMR8nMs72wDD5J +QMaRmvtEvOlNuiT6X7YluO7L3f4EAGbLh3s4OxDHOIqtSXkFjMlgmqU3fKBsZ89F +YlYH/v0X6ItK7tMbwJjXea1gPomO7pIH2H7CzTQ2DNL6fGRvqCFjZeseZudgRhwN +LYz67yDKtZ0TvjqD3ShEboh5CxjL+8kskmofBf4WcF0z8xg2GtopAwFQU6ZI+FKY +rNbUvTWcew4Q/Q0Ya01obeTXsOKZ7IVAo5SxOFSdBa+wS4Igekl7A0C9d9QTduxA +4fnD+Rhw0dvZqL3lBnSisIsCIo/WK6g2L/gYvgRG/3ChRibfeW81rU8q6+MJIx4P +Ad3f1wvEWGAWiYYnHfF0qpxhd3UYUN/31w3idaA4LAuQCOSfQHKnGEhp0hVng68H +seclzMWNHSGoJ+BpOfyYBCA75qIGWjM9RLam2J1qh6ODYVs8XWBdbnoWgWjBluCd +MQyWSjaJB0m2loe+NGSnBdatEadsq4+axBuiKrSrz7KSiISdozEFq2Ua8HXAntII +GLEOP4rtep10w/VLxF5y/3LV/8p1I0betPvrL226/zZJQep1bttodL9Yh2xNLk2J +h9GdxIw1CGJYQmLWxwUYpYyq05WSZyjC8e10xE4po/f4Os89Nj9LG2IdW2VKdOsn +kRqeTJaCGtJOpcebzBSbHQ2YWcQLhLS/CmmxEAaWLZuQUOMx85dGTonqvmdmLwgm +KSNQMRvvEKt8lwqCuw5nPmFyHpnK/l6B9OA96FO9RbSwYOEmHK0EJM4tY8swYCsG +aYdb13MzHW1g1bnsyZbXbOOn3DbyudIWpIvMhJxjBXapDKb3oGMacLfAtlWK2GvY +wD3UrQhxqvwPcDngqOWKkNtGoRKrqhxbp6CnoUxMEn9Lzw9TlSCcGlXQo1m4CF1K +0yP7CzTgkBSemAs8VIOh0zNBCI6VKV148r4+j/eMrt25WawAAFddNsPQMFxxd3kk +wkVi+/YAISLeArR55vsg+FaspD4o/IXIsFYnU/FfNPkz02BaUR/Rz99dv7doM3m7 +dT0kTuZiyGbwXxeY5NYhHfhkEk/1wMfoHRBFSjXwDmIU7CULfWE5HKlfcE9FBS4V +R4LL9b7b6z1Yj+rNHVeQfIlTSTeX7694rB51zn2FRBr85c6TxfpbZu6j00d5qS0n +hr16guvSxKdWFmhghJmZmWDkkMcOakY5MG3RAgMBAAEwDQYJKoZIhvcNAQENBQAD +ggQBAN43Kko2uq+2tejqyRQS+oUQkM4zshCTP3E4pXKZZrsx2j1gqHqA+2ltrCji +YUIDNuLgQa/gvww1wfmLWOgRdq7cNXZJnXbyOog005aiwlShLGwD3JdEcjjc0nBD +oGiym83piLuuoEiM/z/v/4lXzWdjOUalnmkYGLs4BonKCjCNuM6skompycMw/DOu +Ou0QW7VVWsn2yR5VT1+BIEgjFNjk94mTkEDo2R7CqZhxMnqb+dNQ17J55YI13IsB +DFNbSPdABi8ve5jJg3fvgC/u7+DKQP97D9Rc6RNw4zHzmpBYWvlEzygc1GQb5R5l +rki2cDz88W0VD7d0lZEeZV2w7ZcGTNDVDAAuQYC75Gyb0/69/5aiV4LlfyayZFgB +hQBlgKffD3CpcH/YzWeDjsspzpR656jAZhdbeRNhKX9ifdwh97Xf4fapJ1YFLdZG +dNqz8Y3SrT09k9tORP2Tpsx9spA5hT4I+PAVEJzJP01MSOqm/wNcd15NEtGFrbhq +eru4GKmMZFmfQIA6pnP4t1C/pTSYCESLnXvXmGYBX2Co6Os8vmAok1BQTyWBbOxE +nCm8lChE1/i4qjBiiPIZU8w6J+PwADfRU2wRiSVRWmL5hmTqtb/4yNkytNw0HyKe +98hnrrwd6B+ZnzvNk3NTGLJbebhHalDR4gSNrh4cgn09VWxH5gSsDsZI0US9q4i/ +yLiHJ0Ol1T7kilURO4+8qxNK411wNW8AW23tVa82uprpB5IYciQkLLyoK1XfdMRf +aGoGT1lZQl6da/20iihQCWAENdiaoCC6/h9hZF3Jwj0tEPB83qGuriQflP9MxS+D +2/IeTtSLfpbBOo5O5kJ2okKGOrp5X8+QWMS99Wk+jpFdmg/t2D3cS3JsrwPGlBU8 ++PiW1SklS9pbt08o5O7jT2dwJd1oPk8woeJl5uft2EoPwaiF1rCYaEi7tWMQPxt4 +10SlaDQ8GyLCOz5NFyyn/ilOmwy7L1FDOhnnTu2JO+K8MSi/x1a8YXSEifCGQbvr +niHxP0g1SQQB8yOyo6booHuJI1kl1h8J5mDotl8XZ04jtjvg4Bcdi+CsfBkS6nJq +2FwY82yFQyVRw8j24DExDKyZO/0yDY/9olkI06W/HcOhdm/zVwDBDJRDILPrdoI1 +29KIs7acAsdVNLMf8a9Eljl847+sFlKiCQ93AmobcmNN7QcjPVF3e7IF6XMoY05H +JmYjbHfoUIbv0N6BKIAuPF/dGO0BFLuE7QLQ1d4Gyg00QI/9QV7yKP1LCTy4yano +WTmoSRsgChQ7BcfNNV9ucHrZlbtgXQf59A7CDY/z6tUajtjkmOrDEVpkE96he+fe +y7Sk5pZgg67qgXybVQfxbPwEK6A= -----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qsslsocket/certs/leaf.key b/tests/auto/network/ssl/qsslsocket/certs/leaf.key index 54327925d8..738d5ea8b9 100644 --- a/tests/auto/network/ssl/qsslsocket/certs/leaf.key +++ b/tests/auto/network/ssl/qsslsocket/certs/leaf.key @@ -1,32 +1,99 @@ -----BEGIN RSA PRIVATE KEY----- -MIIFfAIBAAKCATEAuxCFiM2+1wn5kENShXWeRPX+PXjSvyr7F2H6v4ldvStXM9oV -Mr33SoMlORf/gTj0CkOc3Vp9Qq2maLBb/4m7jt5oUaTHwUnzZ9633axO1rQNMIE9 -mDSDdC+GgnvgteY9hEnZsjGhS1GlCEuOyUuulLWmMaeYmpiRTtYUjWqCNKRh8jxU -07Xzs2vc/9NapAWxweIbc2rqrP31+Wa58gg0q36VYqV5Hs5DyoODJJMrRJI0SsOr -Uly6ViIBd3ntjf4wXXn6pcPGD1tPCtMJsBeahrl+j2fLwbDmXlngn1a9d+gaKZG3 -z905BlsNgaw/MUszlHs/R1XNL+Emf+6XucNy+Ff5s2EC7TvtQB3rwo1/PjOfB2Bg -WlggI8WFDxnBinI9Cy7YGYC+sGPPDe0bX3jmNwIDAQABAoIBMQCczBNyAStGqjjC -oHuKHHWmTh9mPWFBFfDTv6/jXmvxRWPZtaHxH2Qp09Wejqv/D9MWy2ev7spx2oZS -2Ai1ICjTbz83uAwryyW4Wen6aBTJSLCJiLstWk8ZU0DHHLjVH4FO4mwUPh95t5zC -YDr2JXbXdY8xrc5vPxUFZNJjWvR61ZK37bQYpTn5mZ7r3KfsNk2yOylRTDwa9XFo -ZZ+B82NKdrrz0UvGOnXZa5qd1ap7V+67FIAS2Mt8AMzSCG8TW0JXRUk89ISgAd8r -NQTPtX9XCnMZSbBzDKdznXfHS9ZlJcSrpsbQCPcvMVNrdBfCF0eNnsRJffJGdaXI -MsN6PvbcXWD08lXNGyeLjon03RdJnTAamNM3YQEIcjFmu5Y0o0CCJkZSCJPKJGMG -0d/1tN/5AoGZANOcOgQZ9Wiu0ej3YoQ3aSHu3y8ZBJH4B3ViX8i+2x/6UnG7KNaa -4Ygid1upnX6hk4CW5WZcoxGFacrFRpInKh5Ng8lEIHGp0VSzOBVDR0L5sAxutFuX -6N9C0CuH80vD101mOloNnfT5KHZMI5RXqP6sDGUFlwak2XybDL1qOAza3gZAy25H -vS/ll1BneBavikR5j+zxoTztAoGZAOJOJ5RyOrqpNuhiWZylah5LIFT9N1lCF4Hl -ZbFIjUZ4jcApJ7JxkMXNQ4RU/3AiKCC1xr5ib7dd/qyjKXhdMo4SnLoKhapx5R9G -3XOsQMahiCD/Zcymv9tmk8MxxzbLxhZYhEPzIP/NFkua3CHiX+d1e6fkzFLF/EiX -ZGQOgRcFKrlzUeBputRQRXAkKJH+kMClgAWvy28zAoGYKyaMXhG9DV+4xjzMBhIW -iijfsgbz+6AMRU+OIK1qmZa+ARsdNMXYf54noLVxvETOg0ZB+SGizwvZitO3lE4Q -NKWx3fTaeNMcMJ1rLkrN2UZ5M8/PT24muoAxWu8aGbURzmKuO3bTYwT7z0OvbayC -dYw36tG8/knXX6Vub6GdVGG9LKFB2nceiQnUVT0EK/wXwebYBoUvT/ECgZgF9qdG -Wyg/CPyAbS8NWLKOL86fTrjpqjsyWhgu7smCROT/XlZEdoepHrqbvx2oF85U5lVh -aPimrVxrsjUCjfoqEkV9BY/2KOAvzc9CIBTo5xLOQ8yr8uz1XCOiriogwIfsyNJb -dAm3k/D1dxQ79FowoEDs8LONrtfyFcM4e8VdFO7GSkqrDj41IBRkWx+SkVHBMdtI -yxQiTwKBmQCWym2iDCJg1ZZq4/lVwRudMhVmHoD0yoCAwADYHjjAi8QBplM0vfdd -CESKsnBhlcrPGB279BKVJyZHehKZG+/dfnFs+to14l6A3IqU2d6+pu3EyFNX34HS -xo+64QxMeF0akWnSaIPfUJfk36phjCvLBr4eLXN1i4jW3RdGFwF1THXt29VSSGmU -q/hM51H0bsQ13AIVUSdNHA== +MIISKgIBAAKCBAEAo0LJrGaQE7i7+eBEZKknY1mWLrpZuYGcM8/X0u0fytQqEhUM +2k/q2Oymrr9c6WpX2RjbOM5hIhw7Cf4YVcQgtC+i9j6ppGYxU/abAJDxxDUTCLwW +JULKyW0jY9PVHgXwEfrsdr5La3smXN1Bcqu+IkGx3lxbsw5x9ewWTEfJzLO9sAw+ +SUDGkZr7RLzpTbok+l+2Jbjuy93+BABmy4d7ODsQxziKrUl5BYzJYJqlN3ygbGfP +RWJWB/79F+iLSu7TG8CY13mtYD6Jju6SB9h+ws00NgzS+nxkb6ghY2XrHmbnYEYc +DS2M+u8gyrWdE746g90oRG6IeQsYy/vJLJJqHwX+FnBdM/MYNhraKQMBUFOmSPhS +mKzW1L01nHsOEP0NGGtNaG3k17DimeyFQKOUsThUnQWvsEuCIHpJewNAvXfUE3bs +QOH5w/kYcNHb2ai95QZ0orCLAiKP1iuoNi/4GL4ERv9woUYm33lvNa1PKuvjCSMe +DwHd39cLxFhgFomGJx3xdKqcYXd1GFDf99cN4nWgOCwLkAjkn0BypxhIadIVZ4Ov +B7HnJczFjR0hqCfgaTn8mAQgO+aiBlozPUS2ptidaoejg2FbPF1gXW56FoFowZbg +nTEMlko2iQdJtpaHvjRkpwXWrRGnbKuPmsQboiq0q8+ykoiEnaMxBatlGvB1wJ7S +CBixDj+K7XqddMP1S8Recv9y1f/KdSNG3rT76y9tuv82SUHqdW7baHS/WIdsTS5N +iYfRncSMNQhiWEJi1scFGKWMqtOVkmcowvHtdMROKaP3+DrPPTY/SxtiHVtlSnTr +J5EankyWghrSTqXHm8wUmx0NmFnEC4S0vwppsRAGli2bkFDjMfOXRk6J6r5nZi8I +JikjUDEb7xCrfJcKgrsOZz5hch6Zyv5egfTgPehTvUW0sGDhJhytBCTOLWPLMGAr +BmmHW9dzMx1tYNW57MmW12zjp9w28rnSFqSLzIScYwV2qQym96BjGnC3wLZVithr +2MA91K0Icar8D3A54KjlipDbRqESq6ocW6egp6FMTBJ/S88PU5UgnBpV0KNZuAhd +StMj+ws04JAUnpgLPFSDodMzQQiOlSldePK+Po/3jK7duVmsAABXXTbD0DBccXd5 +JMJFYvv2ACEi3gK0eeb7IPhWrKQ+KPyFyLBWJ1PxXzT5M9NgWlEf0c/fXb+3aDN5 +u3U9JE7mYshm8F8XmOTWIR34ZBJP9cDH6B0QRUo18A5iFOwlC31hORypX3BPRQUu +FUeCy/W+2+s9WI/qzR1XkHyJU0k3l++veKwedc59hUQa/OXOk8X6W2buo9NHeakt +J4a9eoLr0sSnVhZoYISZmZlg5JDHDmpGOTBt0QIDAQABAoIEAG4O1A2YhoAFBROK +EBEbxyW+evO9REc+DKMQ9hmHKOt+422VKzjwrwzVW/hpoKTpv5bmnsJIvkpUZahy +1szajoFpq5382DevfIlxsURMce8nKFG3Gea8hCANptHhN8YpkpFMaqQR3J30QwRP +U5OOG3rUdqfD8z1d+40hPlbl/jA06ycG2eZf+Hyn0cOg5lYzqkHuy8faR4C/gkII +U0PZbUOW7dSfVT1EToVjR04MclxZc3wg7yWDCSQSzWOUrHIzVbVbvK1lpW9AOVNV +mLQZSjrgQtY9Bu09diefXAK57ipsjIXmPXrUvjlbguukSuPIVYIXUNHxAac3x9ub +PR8DBO8tBwDxdqNSuXuf1nnXQMd53JtMa8Hoolp/wuhePDlPnchcba58hsywvdGu +FJZisBZYNxIzhyB9hpeGWIrIwpf3c8w7W0DSFaH7BnLnxiGRE5KVK4ORJ+Skj/p9 +K8R7yfBECHYkNTVDKWl1X3b8AmaY5lB+kADl7UC8o34VZZFL3Ff6Y4+WhB1gfluK +CbH2E7IaQYwchR7wH88Ljz79q7NKoItLxm6Vi5F73aEnhkzptOq64IFKJsC61Xca +z3f6HneTh2sNTTmAJBUpjZDurPcG/iujHoBZVHbsSJ9Pfm3MRG4Au+mske/R+t/T +N9fJZCeKSomYVnVZ+qyaGq4LwPjLFaliBb0C45RD/Eg3z081jwdhvNQr53ChgeX0 +FxJNEVYes0P2WxcGUPm613qCNY3q9LZR+eYtdCFVu4ZRcU789zMTE22h6UJPNyN/ +d6UcxVexuAFFR/vE16+1SvKlLvDnlMzydAoBSz+zyTopdvlvvWLTp5QUWMwpgvJn +VNDq0mpYedS23qFHfjXvX/1JWfYHQJWBkH37E56d3+dtIeDWiPv9r0/96Mx2ivxy +dlxKaCHgMiArbh86B8vFZGtoY/QCzSgeGIZhfUYP7Uq0JD+ohdaRjr1p4SHbEBlb +9MqzbPDl80S0ebQftssxUhcu85CY1u/c/pm5Cw/SEM/86cFjqB+nPuGet48EZv0S +Ck9QOfXvvmOX/EcR+mjCY0cCV+DMQFsQbO9F5aBNj23JNy3wMV8NNLdp7Gbp6Pw/ +qoUNWdK9cGH8myrSLyq+ckzJlSqIlu9GKA5FqhrQ1t84KC1F3KUhKEMsBSM5S6ay +XYZup7czit7dsIkJXjyFMyspufg3ECMJWItjCzDJ/N97itFCI6nrlrVMyrRYxxmx +Le0X4d2ie8IbVUp2YsJAsm2f88NV7N2lVkH88W6xbZamyYNuXom8IiPLScNqQahe +xMysKBAUF58ilB2p/3TCrLhkISF5xve9USYpTuNSKh9mvxGdAsyjEOrqPrqidQ4A +4fpJmAECggIBAM/raykBAvw0xn5NnMMuhX+F4eXOQtFlCEjyN/wCVh0K5W10ZFh8 +Rio/DNdJKE81TxdLs7Hp4tQ8yxV9fjTa7WooHWlQWeUOBZNCFyvlCG5f0C/netp/ +NFIqUCLurZ04Hmlh1QdS/CZ+s6Sh/qZoLZc1LnCfUu5zcpGNVnarlLtgr1ha2GdG +f8l9KRE9HTTrSYZmhxZFt5m+tgtcqd2BBh2tKcgH2cOngoqQEhynmu7ygM+CDX2I +4xAEuQh1cu/fptr3anS9PE5eG5H2rGPy3yQjePE1sqxtRUM9k0UVAlAyGdW1Zd9J +QKBZfrcRXGAJlDg1ZOu1XIQBZFc+p+0KESjvZbYE2vN1lLPpjtfae591RRnA2UjL +5zvZfJEliKVAopK3sAlZteJEfWkp9AyoNR3q9bNdCqT41APIAn5631AVSPPcKLwH +kgwBQWlJjfpM3A8dw2FPw30O4anxoNz32CRYRWJgLLfmHPXK0aCx1/D6MI2Qb89v +bm0qH0Q3fheJEVLG1OcK0JvMeiXwXJqpiV2L7zkl9fJeP1B06voffkXf+iOCwdzf +DR2fxCheL3K2plBb5lO3pzFsuPeftHIbtzOdUCpxwWSHXqGIldDTQOcID5ufGts6 +0pA2heeISoiAKloOXY+M8wESygRDfXYnvj9YRX9DPNiZ1D0DShlwzQOhAoICAQDJ +A6EEy2vVBnyjgvCnFH/JHYQRAQbrBy1nLzZQOWfpfw66Ja7T/QvWF5SbQfCVaCve +yoIvkTtI/f53Fma9p1cdQbyB15u9p0dEeI6wYFreVyHHyZrXhAeybRoDj6DGRidT +cta5IlAVs9Nk5Wb1w1bXxt4biWgwngpo3mbwrvxNVLH26Sm/3WbDXDgY+uJYmBN4 +XoLBgc+Dt7cyYYNr+Z3k6ntOZ9iMNXatPWT/dJiLK8msymFpmOB9rfTT/3lLeCM9 +J/93WuVlcvAIq26n1BqSXH+NL10wI1FiPZk+7YOX/QunKf9fJCD6qgtYIOZ7FmRi +B29KgxHtLrzJYpYQ6IG1WOruwhpaDOrGE6nihhInZ5EWaOIcbhGVh5qidgDhbTBm +uWqFxq6rcB715qFhLdrUkXcsxKQBWwMmkU1+GstItIjYQenKOW6oGhwNgq6jzUej +bwYfo/bIslO44GfktLFayBuS7vzBbkyaTUJZgdtNnecvUacO+xs5qU126nama5A8 +kRcGdZyAx3L0W2E9GiRvAA283mU8geYHw3JlYJBtJGmhD3TyNKr23jm9WY6R8CTg +CkZ83rVpwd2zaupUOrzv4RjUZTreQCFZbzxPpEcOAicjbXAVyBDlaiXlqASt3Zlx +J1AbZLKIh4QqmrMj97C+bW4w/m3oAviGhIskHnk8MQKCAgEAyRreqml1FraBKxcs +wkjUDRVU+u73CAvd6JiH9/PWkP7CDI1gpYmGYERdyjnTiFF6r4CkTTh5Emm+0Ily +MfNzYZNtZzi1ymw2jkmFmgpMjl2UQ1F1LbONys9sdW1Adeoa2DktUIk+pIk2fs3F +PfVT64Yf5gTktQjrTsdTUzMAiACreR1dZP72iM/LkgX3owDVO+8dSDikrkudTv4Q +utOaM8gSuoyFX8484IMbUaX3oJjkaFFVdQ+a+BppUjovsr4zaGWZDVMf6njx18us +0HvQwuagi0YyDL8gGDqNoGsCssjS3jc3UrJKlQ4bFzzuiWGagId8ltPzqSajhBNx +Xz+2e06apWSq1oLrEt2cMUH9Aq3t6UvznorCnMvuxYF1Wslateh/l3uzBijS2I4g +pMFppwdlIVij/A9FGmcxql50csQzrNNMfxofdAce2pSvg+MlkmVqXkxFPEfRk4vH +2RLMd9L9QXrepf0oE8FZ40FBKa8EmViUHSKdv27XkSbPijokjFkPAm4eeiNcHigP +mfTTjazU9QS3j/cC7HI5+TXO8A0Ep6ZIlrcTu4yVsanv4Nezo9RPwrfHOnH7sl9B +rIEMQRsut+8RbIfWyw0OQ06h3xSX7CEHW/bYRW7HM7xKwx6cWEC+1CMzw90Fkvwo +dMlaJXDev4osZyDa/SyaVmMZmSECggIBAJhqJAEarNyNWpwwgIBvTqUTuDucZ751 +ZrvCVJBntp6ZNHV4dSNPz1W583f1e5INtpXrPuMKX8VssTFizuwmoisQ2PoqnXAk +Eimcr7SUmtHTh02RU9LtzVhA2WSx1tn//3mKrb0ag1axTyxFtNfMEWDy7R48BcA3 +VPVHDQ6Z37xS582r5XgRTAX9OpvWPyGlzb2LC+Hlp47cEhAlWBza3BnioTRGES/e +qemZj6cSpUeBIB3gJhSHUlB5QhYss6/BnBaW6WF6jk1p5Q7tza17adpoQF6w9xu0 +69RtmHDabtkjiV5qvbNKFad6n7dm2tuhkuOxd3UsBL+unH6mPdr8ML1selYm3wxA +lxMxfbLArasrIBu50xhzbOnQNDPS/b/vpq99D4P3riFXlmIlSWACANcEpTRQtXpB +pBXuPq/LaS/rk4dGExq+iWT0xyiHWhvhXtxRJnd/P3PVox2fKaeESqXm7OFwTD3u +gC7PPevYRoyHme+LHfyB8Za7BH2SMfzluivyZ18CdnQ+xq75SrWlyNJRXBlFF8XV +SLHCRE8R9PCMl3sD2Ux9GtSsk2M7MJr/VzZ5FBFCXJOf55ZPDvZmwzOvncAOMaCr +R54kdbp9eVLp1vtJ057wX79TyQBlcYbTa7EceeULaUOUXWZgfkxbVqxNFSwY/wTY +m9CDV20/nfVBAoICAQDMfQKuLGK/d43i5twBsk2H+6jZah19ZA4ffYRjKcWfXbd6 +TxbNjGW23mfW49VD+/lNp8OdplL+ztqG+4kz+2k4npj+c0cVMFDbPpD0daMMFs+c +AKVTc2g03a18Q+Q+5IFEY7VvCUfbYlHeqOBBNXtVQphtgjc8ZCTAYGXuytHKkhMg +l5hYdicrimOK+7LZCe1vuUzxKTO1YTcrBlYerwbn95/JO7Rv3bWUbYXRGbGiQs9n ++MKsPY9qCSz2KihTNDotHgx1HENWK2HvlQOn65MU91LYcB3VGLibQaKUiXXV4BEA +WVOTr+XKEJYD24J3v6cH+Ol0JNT+gYHO1CX1dhFL9AkgGBTtwDf8KcQCKfNU5384 +cUyT05BrXg4oWTOxdYFTGTQU95G10cPcAVyltPvPmiMCE0D+njsNWl3fDaRGhlku +j4ogCD2UcnFQRbUtYhHffkbqohSpzRYYxlh0M0XhN6aPmOwm7RgjgCxch04HFgsE +SSoW2zQ61YdR6NXXnMq0eyxTPejH/ycZLfb3EstmXYhsMftJebwwM3Ni+L8qqfg+ +7aJMGqq6CP+tXCjN88oaweZJbkhl14SmFA3TumqHmYSO4wFDA2Hf9c06fmXMewon +lksq5bd72R9VfzBw44UyLoy3ae8MuQZTNoVkSKzedCxFtc/RBOm980Tnu/lp4Q== -----END RSA PRIVATE KEY----- diff --git a/tests/auto/network/ssl/qsslsocket/certs/qt-test-server-cacert.pem b/tests/auto/network/ssl/qsslsocket/certs/qt-test-server-cacert.pem index c5aea0d7c9..29fd755de7 100644 --- a/tests/auto/network/ssl/qsslsocket/certs/qt-test-server-cacert.pem +++ b/tests/auto/network/ssl/qsslsocket/certs/qt-test-server-cacert.pem @@ -1,17 +1,17 @@ -----BEGIN CERTIFICATE----- -MIICpzCCAhACCQCzAF1hyRVzAjANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UEBhMC -Tk8xDTALBgNVBAgTBE9zbG8xDTALBgNVBAcTBE9zbG8xDjAMBgNVBAoTBU5va2lh -MTUwMwYDVQQLFCxRdCBTb2Z0d2FyZS9lbWFpbEFkZHJlc3M9bm9ib2R5QG5vZG9t -YWluLm9yZzEjMCEGA1UEAxMacXQtdGVzdC1zZXJ2ZXIucXQtdGVzdC1uZXQwHhcN -MTkwNjI0MTI0OTIxWhcNMjIwNjIzMTI0OTIxWjCBlzELMAkGA1UEBhMCTk8xDTAL -BgNVBAgTBE9zbG8xDTALBgNVBAcTBE9zbG8xDjAMBgNVBAoTBU5va2lhMTUwMwYD -VQQLFCxRdCBTb2Z0d2FyZS9lbWFpbEFkZHJlc3M9bm9ib2R5QG5vZG9tYWluLm9y -ZzEjMCEGA1UEAxMacXQtdGVzdC1zZXJ2ZXIucXQtdGVzdC1uZXQwgZ8wDQYJKoZI -hvcNAQEBBQADgY0AMIGJAoGBAM2q22/WNMmn8cC+5EEYGeICySLmp9W6Ay6eKHr0 -Xxp3X3epETuPfvAuxp7rOtkS18EMUegkUj8jw0IMEcbyHKFC/rTCaYOt93CxGBXM -IChiMPAsFeYzGa/D6xzAkfcRaJRQ+Ek3CDLXPnXfo7xpABXezYcPXAJrgsgBfWrw -HdxzAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEASCKbqEX5ysC549mq90ydk4jyDW3m -PUyet01fKpcRqVs+OJxdExFBTra3gho6WzzpTSPsuX2ZKOLF5k6KkCvdCGvhC1Kv -HHPIExurfzvdlSRzj6HbKyPuSfxyOloH0bBp7/Gg5RIuBPKlbmfbnTLtwEjhhbMU -SoYI8HZd3HfY87c= +MIICyjCCAjMCFHPGDqJR+klHni4XbETMk6GLn/UEMA0GCSqGSIb3DQEBDQUAMIGj +MRcwFQYDVQQKEw5UaGUgUXQgQ29tcGFueTEUMBIGA1UECxMLUXQgU29mdHdhcmUx +IjAgBgkqhkiG9w0BCQEWE25vYm9keUBub2RvbWFpbi5vcmcxDTALBgNVBAcTBE9z +bG8xDTALBgNVBAgTBE9zbG8xCzAJBgNVBAYTAk5PMSMwIQYDVQQDExpxdC10ZXN0 +LXNlcnZlci5xdC10ZXN0LW5ldDAeFw0yMjA2MjQxMTU4NDlaFw0zMjA2MjExMTU4 +NDlaMIGjMRcwFQYDVQQKEw5UaGUgUXQgQ29tcGFueTEUMBIGA1UECxMLUXQgU29m +dHdhcmUxIjAgBgkqhkiG9w0BCQEWE25vYm9keUBub2RvbWFpbi5vcmcxDTALBgNV +BAcTBE9zbG8xDTALBgNVBAgTBE9zbG8xCzAJBgNVBAYTAk5PMSMwIQYDVQQDExpx +dC10ZXN0LXNlcnZlci5xdC10ZXN0LW5ldDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw +gYkCgYEAzarbb9Y0yafxwL7kQRgZ4gLJIuan1boDLp4oevRfGndfd6kRO49+8C7G +nus62RLXwQxR6CRSPyPDQgwRxvIcoUL+tMJpg633cLEYFcwgKGIw8CwV5jMZr8Pr +HMCR9xFolFD4STcIMtc+dd+jvGkAFd7Nhw9cAmuCyAF9avAd3HMCAwEAATANBgkq +hkiG9w0BAQ0FAAOBgQCZyRe25WqOjrNS6BKPs7ep7eyCON3NKdWnfABZrSjGJQ87 +PoFKl6+9YBSlSpl8qk7c29ic+wA4qFQzPJkrbYIXjwVMAr+cC1kVrlUVqcwmvnKo +5vj57/v8S0Uc4/GesIsxZR7QM+3diPDyk7Bsc3IkpINb31Dl0mlg25nztg8NxA== -----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qsslsocket/certs/qtiochain.crt b/tests/auto/network/ssl/qsslsocket/certs/qtiochain.crt new file mode 100644 index 0000000000..9634bcef68 --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket/certs/qtiochain.crt @@ -0,0 +1,50 @@ +-----BEGIN CERTIFICATE----- +MIIEjjCCBDOgAwIBAgIQCQsKtxCf9ik3vIVQ+PMa5TAKBggqhkjOPQQDAjBKMQsw +CQYDVQQGEwJVUzEZMBcGA1UEChMQQ2xvdWRmbGFyZSwgSW5jLjEgMB4GA1UEAxMX +Q2xvdWRmbGFyZSBJbmMgRUNDIENBLTMwHhcNMjAwODE2MDAwMDAwWhcNMjEwODE2 +MTIwMDAwWjBhMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDVNh +biBGcmFuY2lzY28xGTAXBgNVBAoTEENsb3VkZmxhcmUsIEluYy4xEjAQBgNVBAMT +CXd3dy5xdC5pbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABP/r0xH22wdU8fLk +RsXhxRj5fmUNUo7rxnUl3lyqYYp53cLvn3agQifXkegpE8Xv4pGmuyWZj85FtoeZ +UZh8iyCjggLiMIIC3jAfBgNVHSMEGDAWgBSlzjfq67B1DpRniLRF+tkkEIeWHzAd +BgNVHQ4EFgQU7qPYGi9VtC4/6MS+54LNEAXApBgwFAYDVR0RBA0wC4IJd3d3LnF0 +LmlvMA4GA1UdDwEB/wQEAwIHgDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH +AwIwewYDVR0fBHQwcjA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0Ns +b3VkZmxhcmVJbmNFQ0NDQS0zLmNybDA3oDWgM4YxaHR0cDovL2NybDQuZGlnaWNl +cnQuY29tL0Nsb3VkZmxhcmVJbmNFQ0NDQS0zLmNybDBMBgNVHSAERTBDMDcGCWCG +SAGG/WwBATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20v +Q1BTMAgGBmeBDAECAjB2BggrBgEFBQcBAQRqMGgwJAYIKwYBBQUHMAGGGGh0dHA6 +Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBABggrBgEFBQcwAoY0aHR0cDovL2NhY2VydHMu +ZGlnaWNlcnQuY29tL0Nsb3VkZmxhcmVJbmNFQ0NDQS0zLmNydDAMBgNVHRMBAf8E +AjAAMIIBBAYKKwYBBAHWeQIEAgSB9QSB8gDwAHYA9lyUL9F3MCIUVBgIMJRWjuNN +Exkzv98MLyALzE7xZOMAAAFz90PlSQAABAMARzBFAiAhrrtxdmuxpCy8HAJJ5Qkg +WNvlo8nZqfe6pqGUcz0dmwIhAOMqDtd5ZhcfRk96GAJxPm8bH4hDnmqDP/zJG2Mq +nFpMAHYAXNxDkv7mq0VEsV6a1FbmEDf71fpH3KFzlLJe5vbHDsoAAAFz90PlewAA +BAMARzBFAiB/EkdY10LDdaRcf6eSc/QxucxU+2PI+3pWjh/21A8ZUAIhAK2Qz9Kw +onlRNyHpV3E6qyVydkXihj3c3q5UclpURYcmMAoGCCqGSM49BAMCA0kAMEYCIQDz +K/lzLb2Rbeg1HErRLLm2HkJUmfOGU2+tbROSTGK8ugIhAKA+MKqaZ8VjPxQ+Ho4v +fuwccvZfkU/fg8tAHTOzX23v +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDzTCCArWgAwIBAgIQCjeHZF5ftIwiTv0b7RQMPDANBgkqhkiG9w0BAQsFADBa +MQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJl +clRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTIw +MDEyNzEyNDgwOFoXDTI0MTIzMTIzNTk1OVowSjELMAkGA1UEBhMCVVMxGTAXBgNV +BAoTEENsb3VkZmxhcmUsIEluYy4xIDAeBgNVBAMTF0Nsb3VkZmxhcmUgSW5jIEVD +QyBDQS0zMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEua1NZpkUC0bsH4HRKlAe +nQMVLzQSfS2WuIg4m4Vfj7+7Te9hRsTJc9QkT+DuHM5ss1FxL2ruTAUJd9NyYqSb +16OCAWgwggFkMB0GA1UdDgQWBBSlzjfq67B1DpRniLRF+tkkEIeWHzAfBgNVHSME +GDAWgBTlnVkwgkdYzKz6CFQ2hns6tQRN8DAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0l +BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYI +KwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j +b20wOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL09t +bmlyb290MjAyNS5jcmwwbQYDVR0gBGYwZDA3BglghkgBhv1sAQEwKjAoBggrBgEF +BQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzALBglghkgBhv1sAQIw +CAYGZ4EMAQIBMAgGBmeBDAECAjAIBgZngQwBAgMwDQYJKoZIhvcNAQELBQADggEB +AAUkHd0bsCrrmNaF4zlNXmtXnYJX/OvoMaJXkGUFvhZEOFp3ArnPEELG4ZKk40Un ++ABHLGioVplTVI+tnkDB0A+21w0LOEhsUCxJkAZbZB2LzEgwLt4I4ptJIsCSDBFe +lpKU1fwg3FZs5ZKTv3ocwDfjhUkV+ivhdDkYD7fa86JXWGBPzI6UAPxGezQxPk1H +goE6y/SJXQ7vTQ1unBuCJN0yJV0ReFEQPaA1IwQvZW+cwdFD19Ae8zFnWSfda9J1 +CZMRJCQUzym+5iPDuI9yP+kHyCREU3qzuWFloUwOxkgAyXVjBYdwRVKD05WdRerw +6DEdfgkfCv4+3ao8XnTSrLE= +-----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qsslsocket/certs/selfsigned-client.crt b/tests/auto/network/ssl/qsslsocket/certs/selfsigned-client.crt new file mode 100644 index 0000000000..88da2db920 --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket/certs/selfsigned-client.crt @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC6TCCAdECCC/r9KvmbWTKMA0GCSqGSIb3DQEBCwUAMDUxFDASBgNVBAMMC0F1 +c3dlaXNBcHAyMR0wGwYDVQQFExQxODIzNTE0MTY0NzI5NDg5NDM3MTAiGA8xOTcw +MDEwMTAwMDAwMFoYDzk5OTkxMjMxMjM1OTU5WjA1MRQwEgYDVQQDDAtBdXN3ZWlz +QXBwMjEdMBsGA1UEBRMUMTgyMzUxNDE2NDcyOTQ4OTQzNzEwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCahBpcZyr+PJBCpolzQeFVvDKABwlpdRKGZ8qq +jD4sq2L7VlBJslgJGv5vsB5oJbnX1FFEu4Uw2kYb/LhnFCEXEFtGKRpWOEZOOqWb +4l4q2MCa82ZCoIDt8yoAt0sSShbtR6pjW+l0lwAOEpfGvMaMVo5JUyspRxhl1dSu +sS2Wf65zliqF5VSM2r4xMfJ6LVytxDZsGfTe/HFT2OYYrF+UQZg0mNL39rYWOK4R +xoOz8eLl3K5hKuHNfn5zPt5QtMhaIvebijBg23xJpl+BeoS37WzaK1f+NyWZKPFb +rttvSnFxpkyRHqJJ5piNGH6pkQ1+zhd7uh7eOIwxktjYBOFzAgMBAAEwDQYJKoZI +hvcNAQELBQADggEBADw3MYPft+X78OK/2HAltzsKjfxv/D5qVizm9hcyG1GYe5pS +qgFn0trCyJopYdbRr+hP7CuHwMmv62CZiHSog3CBPoUh19JENUDGbHXxTEFleB0i +Fd8I2+WvRjbQ+ehaeTJPx88v5kkJnB2tZUNZuhEws8emCwr1G0TQv1tRYCR1Lp9i +8/I3FSFpL1zyk47WfM/THa279MPw9WtrFGA6oi36gH9mYxek7n/zQTVi54xDx9GT +KigBYqavjFdNXryjLTCCtJpMTDePgP66NAUnxn0D/amI2vSbIN++PSTsBm+n4Ti5 +QW/ShFQDNb4bDiwjtTKCeKwvAp2/6GSHVkYy28M= +-----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qsslsocket/certs/selfsigned-client.key b/tests/auto/network/ssl/qsslsocket/certs/selfsigned-client.key new file mode 100644 index 0000000000..9e59342963 --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket/certs/selfsigned-client.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAmoQaXGcq/jyQQqaJc0HhVbwygAcJaXUShmfKqow+LKti+1ZQ +SbJYCRr+b7AeaCW519RRRLuFMNpGG/y4ZxQhFxBbRikaVjhGTjqlm+JeKtjAmvNm +QqCA7fMqALdLEkoW7UeqY1vpdJcADhKXxrzGjFaOSVMrKUcYZdXUrrEtln+uc5Yq +heVUjNq+MTHyei1crcQ2bBn03vxxU9jmGKxflEGYNJjS9/a2FjiuEcaDs/Hi5dyu +YSrhzX5+cz7eULTIWiL3m4owYNt8SaZfgXqEt+1s2itX/jclmSjxW67bb0pxcaZM +kR6iSeaYjRh+qZENfs4Xe7oe3jiMMZLY2AThcwIDAQABAoIBAFjgvc0C5t8AdTZx +VsS+U2Aedang4lAPsE0xbIj3TFgjaTcLKfmKJUtvhIU39/WOJbz4+pofhvhXxVYZ +4vQfxvzeQrIzuFt52S7sWxA0gFgC/57hfKO8cQzt/u4UgJEPnupze5XVa47NwJFX +rof5U/erXgLdXQlMRMNm4QRvE7rp58E2MkSYNur0Xgy9L7cRcUQJ8iuMaxBpOzhS +fbNFi5zT7RCGcQSIDcb1JFlgs5tMUs6jzLoDSVD2+vvsN4i4LAAPkJSGTGed5vY1 +xn4G8KPR4HHrnBYEb0SGu4ZTznOnQ+JSKhQrbnvEzXM4RTfjqn0YvF8x70+pWSMi +Fb4mlBECgYEAzW82O79HAlMm8LD7J4byPfVc/1M5/JOnE9H+RR5Vt4jZQGyjCmJu +cj4UeZyVim0xg30sSYrJ2Urd27CtHp+sMgHkvJt3/ZgcfMZJbMKNGq/OUtV8s/cA +nkU++/LgeW8r7wpaDjT7bfnOdcf16mYoXrmk0rTJvRqGXCBvCxtt5bsCgYEAwIxu +vZjPV4Vu/VX6sH2d31D9EFZuZKjGhqukFVtRqLbeosqT9mA+LhQ/wP5qoR2gLQbe +EwxJLJwGFjUhyhbHNlo6oHv3fWkzmHIMPwDRRI3Ktwi/50SwNSnyERUQcLaiwqKx +BqaxPYNnspUt0nKE0LFZsSlrfEyxajqAlUEgm6kCgYAV+uQumFScpxDvh8AXhpS8 +lFgS6XC22YVy1XEDLC+3p2i3P+hh4A45IvNF378QRIabrvTiGXtnSF9cdhbPw/3E +i/dRRsEb3P6PSxfoDxjR1iWZL0Zcav0h8f6/LkleNMralJz2EC0moye36mEhZzTC +jdJYyQccuI3PpZi7839aqQKBgGezOnEiO4kHdB88jyc+gCglliWWZx4PR9x/1H8s +D26uDnneYJHwg4yNm0h1vTfInNujNzdLBp3f6edL9kbAvcmoDqsgGMqSPhd8VNwZ +tJsXQnYRYElN1RjM3nIUxiXuNvpcZLsQS6S1gMPNVEBjLOS4n3WquRjYtTRhDZ9U +1BsBAoGAUFrIatOLFhcgaqENHyUbMx5uSx0lIfF6Xd5KIAgi+btdmugHe+NK8Cd2 +Rc2bQLQ9K1SvKFX6nFuEsGxnXkKuyhL/j0Kgm8nZin4uAcrtFnNdFumvCL6YgYSc +IvvM+uVfGEdbqm4pTuiLBfzOXIIy3kVlLGo402QG1pBzOtmsRMs= +-----END RSA PRIVATE KEY----- diff --git a/tests/auto/network/ssl/qsslsocket/certs/selfsigned-server.crt b/tests/auto/network/ssl/qsslsocket/certs/selfsigned-server.crt new file mode 100644 index 0000000000..c97d27721c --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket/certs/selfsigned-server.crt @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC5TCCAc0CCAO22gNi0v20MA0GCSqGSIb3DQEBCwUAMDMxFDASBgNVBAMMC0F1 +c3dlaXNBcHAyMRswGQYDVQQFExIyNTIxMTE1NjY3NjM2MjExODgwIhgPMTk3MDAx +MDEwMDAwMDBaGA85OTk5MTIzMTIzNTk1OVowMzEUMBIGA1UEAwwLQXVzd2Vpc0Fw +cDIxGzAZBgNVBAUTEjI1MjExMTU2Njc2MzYyMTE4ODCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAL+Fl6v5dcU7qk7vbINclWOhvCe/uklKnXV2QU382x7g +qpbYxJiJvz24C6tgDMmE0pwEz6PiCbh1dkc8+9cdp37eBcFLCOXYQb27gqVVyVtu +xO0LLVXPCv48bGSwljOz0FRC3FolzWxzrZogM/i2b/lmehHJ3D4ejmINmIgtFJ9P +JNNCH4Oh5YEbaFFlNf2m7lCoSuQkOlLZcGeLoipK2XvhZJff6c1uxValh/Mx5dNB +5Mgd5cOZSSEhwf7mcE8C3SHVfjeNfZGIqlkwdY8lvAOjirAtj6Yl88sJOUID/Q/N +hU9D8IZy6+Bk2cJQwI/Gzr590VYvlSTI+6lXr//oBBECAwEAATANBgkqhkiG9w0B +AQsFAAOCAQEArSMO88AYT+9tPCl5lXtSRa0OycqKNlW58GujxIDuR8WX1eFmGSHQ +uijo5KPYUnqydZzAewGC8NvC9WcLwFltNZ9igXikUHiAHc1JLfW7+7SgKpwOUb02 +rJkUkpPA/SmwkLSKYiR1prt5wgSulU1HPBESep05DfR8MCU5+KHkLyXDqtrbudJ4 +lQd9dSKJFn+cSjUC5JNxCPHoIISe7hfGFMLkd0/tVfSIXLVOAZG4K6zExUdjyPi8 +qEuPq6QCRyIJbYQc5HfnARgwK6GXHqkyLWlqK946Yz8VOba7Nan5uQ6xCjUMHw8Z +z/673o/3DCaQ9N6dWahNQ09a9ZH8U1X4iA== +-----END CERTIFICATE----- diff --git a/tests/auto/network/ssl/qsslsocket/certs/selfsigned-server.key b/tests/auto/network/ssl/qsslsocket/certs/selfsigned-server.key new file mode 100644 index 0000000000..b7be118cb9 --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket/certs/selfsigned-server.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAv4WXq/l1xTuqTu9sg1yVY6G8J7+6SUqddXZBTfzbHuCqltjE +mIm/PbgLq2AMyYTSnATPo+IJuHV2Rzz71x2nft4FwUsI5dhBvbuCpVXJW27E7Qst +Vc8K/jxsZLCWM7PQVELcWiXNbHOtmiAz+LZv+WZ6EcncPh6OYg2YiC0Un08k00If +g6HlgRtoUWU1/abuUKhK5CQ6UtlwZ4uiKkrZe+Fkl9/pzW7FVqWH8zHl00HkyB3l +w5lJISHB/uZwTwLdIdV+N419kYiqWTB1jyW8A6OKsC2PpiXzywk5QgP9D82FT0Pw +hnLr4GTZwlDAj8bOvn3RVi+VJMj7qVev/+gEEQIDAQABAoIBADdoXsjSEtBMwqiz +e6FFV7LLR7P4M9ygSY2B+MKnNH1qYe/iJn4626jvZfDeiNSEKKoaejffXRCQaveR +HQrO+XYqpV+WZayZM+vAI7vRZb+d/DrX0PXSQEvtDy7SJ6Itk0fNUBKEfTmy/bZp +Op/pp9tvWkFrNNyD2o1jgY1j/WNY8g605m0oURJ9WQsMUu/Kzu+NMoaKTIoQGb3d +dP71F4KaTXHYxj3B0c+y0NedKbrvnBsP6XbEpgJBaXjtD9z+z/aMF6dmuvpkx7uY +qzwPMRw05QPyJ9x+1V/v4TytY5f596NgW2niVj77BunkZasTYIEX7bjByrlTeLdx +xvPRpAECgYEA5KkM/ORbhN1oaw9+tQxA48oG2DFqChBr+vc4NU4j5SNFn9ks5nHI +xdJNZ9k+bjVUkBP4m88Wd07SW9zXCL8Q5lczb+p5SWl/Pp7ltqaxpH17uzamsaIv +KIBkeJTOU5TuWdXiV5FY+ofK9ojyEaqX1tmylWnoVe4bIMRWXE5bMSkCgYEA1mvJ +snkNzPFG0RK7ikjsNxrhzE07+7RSnoM9WeW8y2lvQ9MjdR6eOgqnnlcdk2A7OVbf +culNgLc0qx/PxZ4BV+8yLLb1EBBGvuVG+x4a6H2mLHdFCJekByZHaQNs9ogVLvdv +3z8D59KknBUjtj9dCw90Z41yMM4kpWMG9yfSEKkCgYEAvuCvytwF2d/JrrV8nD3i +XUTkecymLEiRGysMbNMR+9F56XotlSEe7KQloa8kAnPaZ3uEaOxyYJ4X1D+B8fct +cFsSwTYGkVXTtr6GG/cDC8EEbL+uX1J382Nae54croEAh1WYYGkg0eJRd4PSLxUt +M1j/TuLd4/2j/7JmNR/j2CECgYBdB3MBHghgzKXe+/OmMbFazyz8SN4nfLsDzwkF +QenBj0MY+DhADkK0B/9lcYKBeJT5cbmMz7AykkolnK22nbETh9ILGG4GxCkNlchQ +F2WxTSKV1EF9Ut11xKPi6fuSksQuFmjRQTPelsOYfIt7/M3PiKsGapYKmsXHg8l3 +3i0D0QKBgQCi+HNOaYqduxwjrj8h4eUbiwjID8DCNJ+jXsuGVa6jcsfFpdpivx2c +ytYSXuTXLRq0I3c1ChUOGQQeztJ5GtCPnXjLHHMf3f6yr7Pk56AUmUsaIlR1Q2Zo +gqpFD8zYD5UFc2KM7Y38YTh4j82uDzDvHBBFpli7dEmSn2WpcmzFag== +-----END RSA PRIVATE KEY----- diff --git a/tests/auto/network/ssl/qsslsocket/qsslsocket.pro b/tests/auto/network/ssl/qsslsocket/qsslsocket.pro deleted file mode 100644 index 51fcff9a8d..0000000000 --- a/tests/auto/network/ssl/qsslsocket/qsslsocket.pro +++ /dev/null @@ -1,27 +0,0 @@ -CONFIG += testcase - -SOURCES += tst_qsslsocket.cpp -QT = core core-private network-private testlib - -TARGET = tst_qsslsocket - -win32 { - CONFIG(debug, debug|release) { - DESTDIR = debug -} else { - DESTDIR = release - } -} - -TESTDATA += certs - -DEFINES += SRCDIR=\\\"$$PWD/\\\" - -requires(qtConfig(private_tests)) - -# DOCKERTODO: it's 'linux' because it requires cyrus, which -# is linux-only for now ... -linux { - CONFIG += unsupported/testserver - QT_TEST_SERVER_LIST = squid danted cyrus apache2 echo -} diff --git a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp index 321eede9c9..b45d6b5d8f 100644 --- a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp +++ b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp @@ -1,36 +1,14 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// Copyright (C) 2014 Governikus GmbH & Co. KG. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QtNetwork/private/qtnetworkglobal_p.h> #include <QtCore/qglobal.h> #include <QtCore/qthread.h> #include <QtCore/qelapsedtimer.h> #include <QtCore/qrandom.h> +#include <QtCore/qscopeguard.h> #include <QtNetwork/qhostaddress.h> #include <QtNetwork/qhostinfo.h> #include <QtNetwork/qnetworkproxy.h> @@ -40,24 +18,48 @@ #include <QtNetwork/qsslsocket.h> #include <QtNetwork/qtcpserver.h> #include <QtNetwork/qsslpresharedkeyauthenticator.h> -#include <QtTest/QtTest> +#include <QtTest/private/qemulationdetector_p.h> + +#include <QTest> #include <QNetworkProxy> #include <QAuthenticator> +#include <QTestEventLoop> +#include <QSignalSpy> +#include <QSemaphore> #include "private/qhostinfo_p.h" #include "private/qiodevice_p.h" // for QIODEVICE_BUFFERSIZE #include "../../../network-settings.h" +#include "../shared/tlshelpers.h" -#ifndef QT_NO_SSL -#ifndef QT_NO_OPENSSL -#include "private/qsslsocket_openssl_p.h" -#include "private/qsslsocket_openssl_symbols_p.h" +#if QT_CONFIG(openssl) +#include "../shared/qopenssl_symbols.h" #endif + +#include "private/qtlsbackend_p.h" + #include "private/qsslsocket_p.h" #include "private/qsslconfiguration_p.h" +using namespace std::chrono_literals; + +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED +// make these enum values available without causing deprecation warnings: +namespace Test { +#define COPY(tag, v) \ + constexpr auto tag ## V ## v = QSsl:: tag ## V ## v ; \ + constexpr auto tag ## V ## v ## OrLater = QSsl:: tag ## V ## v ## OrLater ; \ + /* end */ +COPY(Tls, 1_0) +COPY(Dtls, 1_0) +COPY(Tls, 1_1) +#undef COPY +} // namespace Test +QT_WARNING_POP + Q_DECLARE_METATYPE(QSslSocket::SslMode) typedef QList<QSslError::SslError> SslErrorList; Q_DECLARE_METATYPE(SslErrorList) @@ -67,25 +69,6 @@ Q_DECLARE_METATYPE(QSsl::SslProtocol) Q_DECLARE_METATYPE(QSslSocket::PeerVerifyMode); typedef QSharedPointer<QSslSocket> QSslSocketPtr; -// Non-OpenSSL backends are not able to report a specific error code -// for self-signed certificates. -#ifndef QT_NO_OPENSSL -#define FLUKE_CERTIFICATE_ERROR QSslError::SelfSignedCertificate -#else -#define FLUKE_CERTIFICATE_ERROR QSslError::CertificateUntrusted -#endif -#endif // QT_NO_OPENSSL - -// Detect ALPN (Application-Layer Protocol Negotiation) support -#undef ALPN_SUPPORTED // Undef the variable first to be safe -#if defined(OPENSSL_VERSION_NUMBER) && !defined(OPENSSL_NO_TLSEXT) -#define ALPN_SUPPORTED 1 -#endif - -#if QT_CONFIG(schannel) && !defined(Q_CC_MINGW) -#define ALPN_SUPPORTED 1 -#endif - #if defined Q_OS_HPUX && defined Q_CC_GNU // This error is delivered every time we try to use the fluke CA // certificate. For now we work around this bug. Task 202317. @@ -95,19 +78,18 @@ typedef QSharedPointer<QSslSocket> QSslSocketPtr; // Use this cipher to force PSK key sharing. // Also, it's a cipher w/o auth, to check that we emit the signals warning // about the identity of the peer. -#ifndef QT_NO_OPENSSL +#if QT_CONFIG(openssl) static const QString PSK_CIPHER_WITHOUT_AUTH = QStringLiteral("PSK-AES256-CBC-SHA"); static const quint16 PSK_SERVER_PORT = 4433; static const QByteArray PSK_CLIENT_PRESHAREDKEY = QByteArrayLiteral("\x1a\x2b\x3c\x4d\x5e\x6f"); static const QByteArray PSK_SERVER_IDENTITY_HINT = QByteArrayLiteral("QtTestServerHint"); static const QByteArray PSK_CLIENT_IDENTITY = QByteArrayLiteral("Client_identity"); +#endif // QT_CONFIG(openssl) QT_BEGIN_NAMESPACE void qt_ForceTlsSecurityLevel(); QT_END_NAMESPACE -#endif // !QT_NO_OPENSSL - class tst_QSslSocket : public QObject { Q_OBJECT @@ -128,10 +110,10 @@ public: return QTestEventLoop::instance().timeout(); } -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) QSslSocketPtr newSocket(); -#ifndef QT_NO_OPENSSL +#if QT_CONFIG(openssl) enum PskConnectTestType { PskConnectDoNotHandlePsk, PskConnectEmptyCredentials, @@ -142,20 +124,22 @@ public: PskConnectRightCredentialsVerifyPeer, PskConnectRightCredentialsDoNotVerifyPeer, }; -#endif -#endif +#endif // QT_CONFIG(openssl) +#endif // QT_CONFIG(ssl) public slots: void initTestCase_data(); void initTestCase(); void init(); void cleanup(); -#ifndef QT_NO_NETWORKPROXY +#if QT_CONFIG(networkproxy) void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth); #endif -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) private slots: + void activeBackend(); + void backends(); void constructing(); void configNoOnDemandLoad(); void simpleConnect(); @@ -164,34 +148,30 @@ private slots: // API tests void sslErrors_data(); void sslErrors(); - void addCaCertificate(); - void addCaCertificates(); - void addCaCertificates2(); void ciphers(); +#if QT_CONFIG(securetransport) + void tls13Ciphers(); +#endif // QT_CONFIG(securetransport) void connectToHostEncrypted(); void connectToHostEncryptedWithVerificationPeerName(); void sessionCipher(); - void flush(); - void isEncrypted(); void localCertificate(); void mode(); void peerCertificate(); void peerCertificateChain(); void privateKey(); -#ifndef QT_NO_OPENSSL +#if QT_CONFIG(openssl) void privateKeyOpaque(); #endif void protocol(); void protocolServerSide_data(); void protocolServerSide(); -#ifndef QT_NO_OPENSSL void serverCipherPreferences(); -#endif // QT_NO_OPENSSL void setCaCertificates(); void setLocalCertificate(); void localCertificateChain(); void setLocalCertificateChain(); - void setPrivateKey(); + void tlsConfiguration(); void setSocketDescriptor(); void setSslConfiguration_data(); void setSslConfiguration(); @@ -218,9 +198,10 @@ private slots: void waitForMinusOne(); void verifyMode(); void verifyDepth(); + void verifyAndDefaultConfiguration(); void disconnectFromHostWhenConnecting(); void disconnectFromHostWhenConnected(); -#ifndef QT_NO_OPENSSL +#if QT_CONFIG(openssl) void closeWhileEmittingSocketError(); #endif void resetProxy(); @@ -233,19 +214,16 @@ private slots: void writeBigChunk(); void blacklistedCertificates(); void versionAccessors(); -#ifndef QT_NO_OPENSSL - void sslOptions(); -#endif void encryptWithoutConnecting(); void resume_data(); void resume(); void qtbug18498_peek(); void qtbug18498_peek2(); void dhServer(); -#ifndef QT_NO_OPENSSL +#if QT_CONFIG(openssl) void dhServerCustomParamsNull(); void dhServerCustomParams(); -#endif +#endif // QT_CONFIG(openssl) void ecdhServer(); void verifyClientCertificate_data(); void verifyClientCertificate(); @@ -253,7 +231,7 @@ private slots: void allowedProtocolNegotiation(); -#ifndef QT_NO_OPENSSL +#if QT_CONFIG(openssl) void simplePskConnect_data(); void simplePskConnect(); void ephemeralServerKey_data(); @@ -262,7 +240,7 @@ private slots: void forwardReadChannelFinished(); void signatureAlgorithm_data(); void signatureAlgorithm(); -#endif +#endif // QT_CONFIG(openssl) void unsupportedProtocols_data(); void unsupportedProtocols(); @@ -271,6 +249,10 @@ private slots: #if QT_CONFIG(openssl) void alertMissingCertificate(); void alertInvalidCertificate(); + void selfSignedCertificates_data(); + void selfSignedCertificates(); + void pskHandshake_data(); + void pskHandshake(); #endif // openssl void setEmptyDefaultConfiguration(); // this test should be last @@ -308,19 +290,48 @@ protected slots: private: QSslSocket *socket; QList<QSslError> storedExpectedSslErrors; -#endif // QT_NO_SSL + bool isTestingOpenSsl = false; + bool isSecurityLevel0Required = false; + bool opensslResolved = false; + bool isTestingSecureTransport = false; + bool isTestingSchannel = false; + QSslError::SslError flukeCertificateError = QSslError::CertificateUntrusted; + bool hasServerAlpn = false; +#endif // QT_CONFIG(ssl) private: static int loopLevel; public: static QString testDataDir; + + bool supportsTls13() const + { + if (isTestingOpenSsl) { +#ifdef TLS1_3_VERSION + return true; +#endif + } + if (isTestingSchannel) { + // Copied from qtls_schannel.cpp #supportsTls13() + static bool supported = []() { + const auto current = QOperatingSystemVersion::current(); + const auto minimum = + QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 20221); + return current >= minimum; + }(); + return supported; + } + + return false; + } + }; QString tst_QSslSocket::testDataDir; -#ifndef QT_NO_SSL -#ifndef QT_NO_OPENSSL +#if QT_CONFIG(ssl) +#if QT_CONFIG(openssl) Q_DECLARE_METATYPE(tst_QSslSocket::PskConnectTestType) -#endif -#endif +#endif // QT_CONFIG(openssl) +#endif // QT_CONFIG(ssl) int tst_QSslSocket::loopLevel = 0; @@ -341,17 +352,18 @@ QString httpServerCertChainPath() tst_QSslSocket::tst_QSslSocket() { -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) qRegisterMetaType<QList<QSslError> >("QList<QSslError>"); qRegisterMetaType<QSslError>("QSslError"); qRegisterMetaType<QAbstractSocket::SocketState>("QAbstractSocket::SocketState"); qRegisterMetaType<QAbstractSocket::SocketError>("QAbstractSocket::SocketError"); -#ifndef QT_NO_OPENSSL +#if QT_CONFIG(openssl) qRegisterMetaType<QSslPreSharedKeyAuthenticator *>(); qRegisterMetaType<tst_QSslSocket::PskConnectTestType>(); -#endif -#endif +#endif // QT_CONFIG(openssl) + +#endif // QT_CONFIG(ssl) } enum ProxyTests { @@ -388,7 +400,31 @@ void tst_QSslSocket::initTestCase() testDataDir = QCoreApplication::applicationDirPath(); if (!testDataDir.endsWith(QLatin1String("/"))) testDataDir += QLatin1String("/"); -#ifndef QT_NO_SSL + + hasServerAlpn = QSslSocket::supportedFeatures().contains(QSsl::SupportedFeature::ServerSideAlpn); + // Several plugins (TLS-backends) can co-exist. QSslSocket would implicitly + // select 'openssl' if available, and if not: 'securetransport' (Darwin) or + // 'schannel' (Windows). Check what we actually have: + const auto &tlsBackends = QSslSocket::availableBackends(); + if (tlsBackends.contains(QTlsBackend::builtinBackendNames[QTlsBackend::nameIndexOpenSSL])) { + isTestingOpenSsl = true; + flukeCertificateError = QSslError::SelfSignedCertificate; +#if QT_CONFIG(openssl) + opensslResolved = qt_auto_test_resolve_OpenSSL_symbols(); + // This is where OpenSSL moved several protocols under + // non-default (0) security level (the default is 1). + isSecurityLevel0Required = OPENSSL_VERSION_NUMBER >= 0x30100010; +#else + opensslResolved = false; // Not 'unused variable' anymore. +#endif + } else if (tlsBackends.contains(QTlsBackend::builtinBackendNames[QTlsBackend::nameIndexSchannel])) { + isTestingSchannel = true; + } else { + QVERIFY(tlsBackends.contains(QTlsBackend::builtinBackendNames[QTlsBackend::nameIndexSecureTransport])); + isTestingSecureTransport = true; + } + +#if QT_CONFIG(ssl) qDebug("Using SSL library %s (%ld)", qPrintable(QSslSocket::sslLibraryVersionString()), QSslSocket::sslLibraryVersionNumber()); @@ -405,14 +441,14 @@ void tst_QSslSocket::initTestCase() if (!QtNetworkSettings::verifyTestNetworkSettings()) QSKIP("No network test server available"); #endif // QT_TEST_SERVER -#endif // QT_NO_SSL +#endif // QT_CONFIG(ssl) } void tst_QSslSocket::init() { QFETCH_GLOBAL(bool, setProxy); if (setProxy) { -#ifndef QT_NO_NETWORKPROXY +#if QT_CONFIG(networkproxy) QFETCH_GLOBAL(int, proxyType); const QString socksProxyAddr = QtNetworkSettings::socksProxyServerIp().toString(); const QString httpProxyAddr = QtNetworkSettings::httpProxyServerIp().toString(); @@ -440,26 +476,24 @@ void tst_QSslSocket::init() break; } QNetworkProxy::setApplicationProxy(proxy); -#else // !QT_NO_NETWORKPROXY +#else QSKIP("No proxy support"); -#endif // QT_NO_NETWORKPROXY +#endif // QT_CONFIG(networkproxy) } -#ifndef QT_NO_OPENSSL QT_PREPEND_NAMESPACE(qt_ForceTlsSecurityLevel)(); -#endif // QT_NO_OPENSSL qt_qhostinfo_clear_cache(); } void tst_QSslSocket::cleanup() { -#ifndef QT_NO_NETWORKPROXY +#if QT_CONFIG(networkproxy) QNetworkProxy::setApplicationProxy(QNetworkProxy::DefaultProxy); #endif } -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) QSslSocketPtr tst_QSslSocket::newSocket() { const auto socket = QSslSocketPtr::create(); @@ -471,18 +505,184 @@ QSslSocketPtr tst_QSslSocket::newSocket() return socket; } -#endif +#endif // QT_CONFIG(ssl) -#ifndef QT_NO_NETWORKPROXY +#if QT_CONFIG(networkproxy) void tst_QSslSocket::proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth) { ++proxyAuthCalled; auth->setUser("qsockstest"); auth->setPassword("password"); } -#endif // !QT_NO_NETWORKPROXY +#endif // QT_CONFIG(networkproxy) + +#if QT_CONFIG(ssl) + +void tst_QSslSocket::activeBackend() +{ + QFETCH_GLOBAL(const bool, setProxy); + if (setProxy) // Not interesting for backend test. + return; + + // We cannot set non-existing as active: + const QString nonExistingBackend = QStringLiteral("TheQtTLS"); + QCOMPARE(QSslSocket::setActiveBackend(nonExistingBackend), false); + QCOMPARE(QSslSocket::supportedProtocols(nonExistingBackend).size(), 0); + QCOMPARE(QSslSocket::supportedFeatures(nonExistingBackend), QList<QSsl::SupportedFeature>()); + QCOMPARE(QSslSocket::implementedClasses(nonExistingBackend), QList<QSsl::ImplementedClass>()); + + const QString backendName = QSslSocket::activeBackend(); + // Implemented by all our existing backends: + const auto implemented = QSsl::ImplementedClass::Socket; + const auto supportedFt = QSsl::SupportedFeature::ClientSideAlpn; + + QVERIFY(QSslSocket::availableBackends().contains(backendName)); + QCOMPARE(QSslSocket::setActiveBackend(backendName), true); + QCOMPARE(QSslSocket::activeBackend(), backendName); + QCOMPARE(QSslSocket::setActiveBackend(backendName), true); // We can do it again. + QCOMPARE(QSslSocket::activeBackend(), backendName); + + const auto protocols = QSslSocket::supportedProtocols(); + QVERIFY(protocols.size() > 0); + // 'Any' and 'Secure', since they are always present: + QVERIFY(protocols.contains(QSsl::AnyProtocol)); + QVERIFY(protocols.contains(QSsl::SecureProtocols)); + + const auto protocolsForNamed = QSslSocket::supportedProtocols(backendName); + QCOMPARE(protocols, protocolsForNamed); + // Any and secure, new versions are coming, old + // go away, nothing more specific. + QVERIFY(protocolsForNamed.contains(QSsl::AnyProtocol)); + QVERIFY(protocolsForNamed.contains(QSsl::SecureProtocols)); + QCOMPARE(QSslSocket::isProtocolSupported(QSsl::SecureProtocols), true); + QCOMPARE(QSslSocket::isProtocolSupported(QSsl::SecureProtocols, backendName), true); + + const auto classes = QSslSocket::implementedClasses(); + QVERIFY(classes.contains(implemented)); + QVERIFY(QSslSocket::isClassImplemented(implemented)); + QVERIFY(QSslSocket::isClassImplemented(implemented, backendName)); + + const auto features = QSslSocket::supportedFeatures(); + QVERIFY(features.contains(QSsl::SupportedFeature(supportedFt))); + QVERIFY(QSslSocket::isFeatureSupported(QSsl::SupportedFeature(supportedFt))); + QVERIFY(QSslSocket::isFeatureSupported(QSsl::SupportedFeature(supportedFt), backendName)); +} + +namespace { +struct MockTlsBackend : QTlsBackend +{ + MockTlsBackend(const QString &mockName) : name(mockName) + { + } + QString backendName() const override + { + return name; + } + + QList<QSsl::SupportedFeature> supportedFeatures() const override + { + return features; + } + QList<QSsl::SslProtocol> supportedProtocols() const override + { + return protocols; + } + QList<QSsl::ImplementedClass> implementedClasses() const override + { + return classes; + } + + QString name; + QList<QSsl::ImplementedClass> classes; + QList<QSsl::SupportedFeature> features; + QList<QSsl::SslProtocol> protocols; +}; + +} // Unnamed backend. -#ifndef QT_NO_SSL +void tst_QSslSocket::backends() +{ + QFETCH_GLOBAL(const bool, setProxy); + if (setProxy) // Not interesting for backend test. + return; + + // We are here, protected by QT_CONFIG(ssl). Some backend must be pre-existing. + // Let's test the 'real' backend: + auto backendNames = QTlsBackend::availableBackendNames(); + const auto sizeBefore = backendNames.size(); + QVERIFY(sizeBefore > 0); + + const QString tlsBackend = QSslSocket::activeBackend(); + QVERIFY(tlsBackend == QTlsBackend::builtinBackendNames[QTlsBackend::nameIndexOpenSSL] + || tlsBackend == QTlsBackend::builtinBackendNames[QTlsBackend::nameIndexSchannel] + || tlsBackend == QTlsBackend::builtinBackendNames[QTlsBackend::nameIndexSecureTransport]); + + const auto builtinProtocols = QSslSocket::supportedProtocols(tlsBackend); + QVERIFY(builtinProtocols.contains(QSsl::SecureProtocols)); + // Socket and ALPN are supported by all our backends: + const auto builtinClasses = QSslSocket::implementedClasses(tlsBackend); + QVERIFY(builtinClasses.contains(QSsl::ImplementedClass::Socket)); + const auto builtinFeatures = QSslSocket::supportedFeatures(tlsBackend); + QVERIFY(builtinFeatures.contains(QSsl::SupportedFeature::ClientSideAlpn)); + + // Verify that non-dummy backend can be found: + auto *systemBackend = QTlsBackend::findBackend(tlsBackend); + QVERIFY(systemBackend); + + const auto protocols = QList<QSsl::SslProtocol>{QSsl::SecureProtocols}; + const auto classes = QList<QSsl::ImplementedClass>{QSsl::ImplementedClass::Socket}; + const auto features = QList<QSsl::SupportedFeature>{QSsl::SupportedFeature::CertificateVerification}; + + const QString nameA = QStringLiteral("backend A"); + const QString nameB = QStringLiteral("backend B"); + const QString nonExisting = QStringLiteral("non-existing backend"); + + QVERIFY(!backendNames.contains(nameA)); + QVERIFY(!backendNames.contains(nameB)); + QVERIFY(!backendNames.contains(nonExisting)); + { + MockTlsBackend factoryA(nameA); + backendNames = QTlsBackend::availableBackendNames(); + QVERIFY(backendNames.contains(nameA)); + QVERIFY(!backendNames.contains(nameB)); + QVERIFY(!backendNames.contains(nonExisting)); + + const auto *backendA = QTlsBackend::findBackend(nameA); + QVERIFY(backendA); + QCOMPARE(backendA->backendName(), nameA); + + QCOMPARE(factoryA.supportedFeatures().size(), 0); + QCOMPARE(factoryA.supportedProtocols().size(), 0); + QCOMPARE(factoryA.implementedClasses().size(), 0); + + factoryA.protocols = protocols; + factoryA.classes = classes; + factoryA.features = features; + + // It's an overrider in some re-implemented factory: + QCOMPARE(factoryA.supportedProtocols(), protocols); + QCOMPARE(factoryA.supportedFeatures(), features); + QCOMPARE(factoryA.implementedClasses(), classes); + + // That's a helper function (static member function): + QCOMPARE(QTlsBackend::supportedProtocols(nameA), protocols); + QCOMPARE(QTlsBackend::supportedFeatures(nameA), features); + QCOMPARE(QTlsBackend::implementedClasses(nameA), classes); + + MockTlsBackend factoryB(nameB); + QVERIFY(QTlsBackend::availableBackendNames().contains(nameA)); + QVERIFY(QTlsBackend::availableBackendNames().contains(nameB)); + QVERIFY(!QTlsBackend::availableBackendNames().contains(nonExisting)); + + const auto *nullBackend = QTlsBackend::findBackend(nonExisting); + QCOMPARE(nullBackend, nullptr); + } + backendNames = QTlsBackend::availableBackendNames(); + QCOMPARE(backendNames.size(), sizeBefore); + // Check we cleaned up our factories: + QVERIFY(!backendNames.contains(nameA)); + QVERIFY(!backendNames.contains(nameB)); +} void tst_QSslSocket::constructing() { @@ -514,7 +714,7 @@ void tst_QSslSocket::constructing() QVERIFY(!socket.isTextModeEnabled()); QVERIFY(!socket.isWritable()); QCOMPARE(socket.openMode(), QIODevice::NotOpen); - QTest::ignoreMessage(QtWarningMsg, readNotOpenMessage); + QTest::ignoreMessage(QtWarningMsg, "QIODevice::peek (QSslSocket): device not open"); QVERIFY(socket.peek(2).isEmpty()); QCOMPARE(socket.pos(), qint64(0)); QTest::ignoreMessage(QtWarningMsg, writeNotOpenMessage); @@ -525,8 +725,7 @@ void tst_QSslSocket::constructing() QCOMPARE(socket.read(0, 0), qint64(-1)); QTest::ignoreMessage(QtWarningMsg, readNotOpenMessage); QVERIFY(socket.readAll().isEmpty()); - QTest::ignoreMessage(QtWarningMsg, "QIODevice::readLine (QSslSocket): Called with maxSize < 2"); - QCOMPARE(socket.readLine(0, 0), qint64(-1)); + QTest::ignoreMessage(QtWarningMsg, "QIODevice::readLine (QSslSocket): device not open"); char buf[10]; QCOMPARE(socket.readLine(buf, sizeof(buf)), qint64(-1)); QTest::ignoreMessage(QtWarningMsg, "QIODevice::seek (QSslSocket): Cannot call seek on a sequential device"); @@ -548,7 +747,7 @@ void tst_QSslSocket::constructing() QCOMPARE(socket.peerAddress(), QHostAddress()); QVERIFY(socket.peerName().isEmpty()); QCOMPARE(socket.peerPort(), quint16(0)); -#ifndef QT_NO_NETWORKPROXY +#if QT_CONFIG(networkproxy) QCOMPARE(socket.proxy().type(), QNetworkProxy::DefaultProxy); #endif QCOMPARE(socket.readBufferSize(), qint64(0)); @@ -599,16 +798,32 @@ void tst_QSslSocket::configNoOnDemandLoad() QCOMPARE(customConfig, socket.sslConfiguration()); } +static void downgrade_TLS_QTQAINFRA_4499(QSslSocket &socket) +{ + // Set TLS 1.0 or above because the server doesn't support TLS 1.2 or above + // QTQAINFRA-4499 + QSslConfiguration config = socket.sslConfiguration(); + config.setProtocol(Test::TlsV1_0OrLater); + socket.setSslConfiguration(config); +} + void tst_QSslSocket::simpleConnect() { if (!QSslSocket::supportsSsl()) return; + // Starting from OpenSSL v 3.1.1 deprecated protocol versions (we want to use when connecting) are not available by default. + if (isSecurityLevel0Required) + QSKIP("Testing with OpenSSL backend, but security level 0 is required for TLS v1.1 or earlier"); + QFETCH_GLOBAL(bool, setProxy); if (setProxy) return; QSslSocket socket; + + downgrade_TLS_QTQAINFRA_4499(socket); + QSignalSpy connectedSpy(&socket, SIGNAL(connected())); QSignalSpy hostFoundSpy(&socket, SIGNAL(hostFound())); QSignalSpy disconnectedSpy(&socket, SIGNAL(disconnected())); @@ -629,30 +844,30 @@ void tst_QSslSocket::simpleConnect() // Entered connecting state QCOMPARE(socket.state(), QAbstractSocket::ConnectingState); - QCOMPARE(connectedSpy.count(), 0); - QCOMPARE(hostFoundSpy.count(), 1); - QCOMPARE(disconnectedSpy.count(), 0); + QCOMPARE(connectedSpy.size(), 0); + QCOMPARE(hostFoundSpy.size(), 1); + QCOMPARE(disconnectedSpy.size(), 0); enterLoop(10); // Entered connected state QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); QCOMPARE(socket.mode(), QSslSocket::UnencryptedMode); QVERIFY(!socket.isEncrypted()); - QCOMPARE(connectedSpy.count(), 1); - QCOMPARE(hostFoundSpy.count(), 1); - QCOMPARE(disconnectedSpy.count(), 0); + QCOMPARE(connectedSpy.size(), 1); + QCOMPARE(hostFoundSpy.size(), 1); + QCOMPARE(disconnectedSpy.size(), 0); // Enter encrypted mode socket.startClientEncryption(); QCOMPARE(socket.mode(), QSslSocket::SslClientMode); QVERIFY(!socket.isEncrypted()); - QCOMPARE(connectionEncryptedSpy.count(), 0); - QCOMPARE(sslErrorsSpy.count(), 0); + QCOMPARE(connectionEncryptedSpy.size(), 0); + QCOMPARE(sslErrorsSpy.size(), 0); // Starting handshake enterLoop(10); - QCOMPARE(sslErrorsSpy.count(), 1); - QCOMPARE(connectionEncryptedSpy.count(), 0); + QCOMPARE(sslErrorsSpy.size(), 1); + QCOMPARE(connectionEncryptedSpy.size(), 0); QVERIFY(!socket.isEncrypted()); QCOMPARE(socket.state(), QAbstractSocket::UnconnectedState); } @@ -662,6 +877,10 @@ void tst_QSslSocket::simpleConnectWithIgnore() if (!QSslSocket::supportsSsl()) return; + // Starting from OpenSSL v 3.1.1 deprecated protocol versions (we want to use when connecting) are not available by default. + if (isSecurityLevel0Required) + QSKIP("Testing with OpenSSL backend, but security level 0 is required for TLS v1.1 or earlier"); + QFETCH_GLOBAL(bool, setProxy); if (setProxy) return; @@ -671,6 +890,8 @@ void tst_QSslSocket::simpleConnectWithIgnore() QSignalSpy encryptedSpy(&socket, SIGNAL(encrypted())); QSignalSpy sslErrorsSpy(&socket, SIGNAL(sslErrors(QList<QSslError>))); + downgrade_TLS_QTQAINFRA_4499(socket); + connect(&socket, SIGNAL(readyRead()), this, SLOT(exitLoop())); connect(&socket, SIGNAL(encrypted()), this, SLOT(exitLoop())); connect(&socket, SIGNAL(connected()), this, SLOT(exitLoop())); @@ -688,10 +909,10 @@ void tst_QSslSocket::simpleConnectWithIgnore() enterLoop(10); // Done; encryption should be enabled. - QCOMPARE(sslErrorsSpy.count(), 1); + QCOMPARE(sslErrorsSpy.size(), 1); QVERIFY(socket.isEncrypted()); QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); - QCOMPARE(encryptedSpy.count(), 1); + QCOMPARE(encryptedSpy.size(), 1); // Wait for incoming data if (!socket.canReadLine()) @@ -704,6 +925,10 @@ void tst_QSslSocket::simpleConnectWithIgnore() void tst_QSslSocket::sslErrors_data() { + // Starting from OpenSSL v 3.1.1 deprecated protocol versions (we want to use in 'sslErrors' test) are not available by default. + if (isSecurityLevel0Required) + QSKIP("Testing with OpenSSL backend, but security level 0 is required for TLS v1.1 or earlier"); + QTest::addColumn<QString>("host"); QTest::addColumn<int>("port"); @@ -720,10 +945,10 @@ void tst_QSslSocket::sslErrors() QFETCH(int, port); QSslSocketPtr socket = newSocket(); -#if QT_CONFIG(schannel) - // Needs to be < 1.2 because of the old certificate and <= 1.0 because of the mail server - socket->setProtocol(QSsl::SslProtocol::TlsV1_0); -#endif + + QVERIFY(socket); + downgrade_TLS_QTQAINFRA_4499(*socket); + QSignalSpy sslErrorsSpy(socket.data(), SIGNAL(sslErrors(QList<QSslError>))); QSignalSpy peerVerifyErrorSpy(socket.data(), SIGNAL(peerVerifyError(QSslError))); @@ -753,12 +978,15 @@ void tst_QSslSocket::sslErrors() sslErrors << err.error(); std::sort(sslErrors.begin(), sslErrors.end()); QVERIFY(sslErrors.contains(QSslError::HostNameMismatch)); - QVERIFY(sslErrors.contains(FLUKE_CERTIFICATE_ERROR)); + + // Non-OpenSSL backends are not able to report a specific error code + // for self-signed certificates. + QVERIFY(sslErrors.contains(flukeCertificateError)); // check the same errors were emitted by sslErrors QVERIFY(!sslErrorsSpy.isEmpty()); SslErrorList emittedErrors; - const auto sslErrorsSpyErrors = qvariant_cast<QList<QSslError> >(qAsConst(sslErrorsSpy).first().first()); + const auto sslErrorsSpyErrors = qvariant_cast<QList<QSslError> >(std::as_const(sslErrorsSpy).first().first()); for (const QSslError &err : sslErrorsSpyErrors) emittedErrors << err.error(); std::sort(emittedErrors.begin(), emittedErrors.end()); @@ -774,28 +1002,17 @@ void tst_QSslSocket::sslErrors() QCOMPARE(sslErrors, peerErrors); } -void tst_QSslSocket::addCaCertificate() -{ - if (!QSslSocket::supportsSsl()) - return; -} - -void tst_QSslSocket::addCaCertificates() -{ - if (!QSslSocket::supportsSsl()) - return; -} - -void tst_QSslSocket::addCaCertificates2() +void tst_QSslSocket::ciphers() { if (!QSslSocket::supportsSsl()) return; -} -void tst_QSslSocket::ciphers() -{ - if (!QSslSocket::supportsSsl()) + QFETCH_GLOBAL(const bool, setProxy); + if (setProxy) { + // KISS(mart), we don't connect, no need to test the same thing + // many times! return; + } QSslSocket socket; QCOMPARE(socket.sslConfiguration().ciphers(), QSslConfiguration::defaultConfiguration().ciphers()); @@ -818,7 +1035,7 @@ void tst_QSslSocket::ciphers() QString ciphersAsString; const auto &supported = sslConfig.supportedCiphers(); for (const auto &cipher : supported) { - if (cipher.isNull() || !cipher.name().length()) + if (cipher.isNull() || !cipher.name().size()) continue; if (ciphers.size() > 0) ciphersAsString += QStringLiteral(":"); @@ -831,27 +1048,73 @@ void tst_QSslSocket::ciphers() if (!ciphers.size()) QSKIP("No proper ciphersuite was found to test 'setCiphers'"); -#if QT_CONFIG(schannel) - qWarning("Schannel doesn't support setting ciphers from a cipher-string."); -#else - sslConfig.setCiphers(ciphersAsString); - socket.setSslConfiguration(sslConfig); - QCOMPARE(ciphers, socket.sslConfiguration().ciphers()); -#endif + + if (isTestingSchannel) { + qWarning("Schannel doesn't support setting ciphers from a cipher-string."); + } else { + sslConfig.setCiphers(ciphersAsString); + socket.setSslConfiguration(sslConfig); + QCOMPARE(ciphers, socket.sslConfiguration().ciphers()); + } + sslConfig.setCiphers(ciphers); socket.setSslConfiguration(sslConfig); QCOMPARE(ciphers, socket.sslConfiguration().ciphers()); + + if (isTestingOpenSsl) { + for (const auto &cipher : ciphers) { + if (cipher.name().size() && cipher.protocol() != QSsl::UnknownProtocol) { + const QSslCipher aCopy(cipher.name(), cipher.protocol()); + QCOMPARE(aCopy, cipher); + break; + } + } + } } +#if QT_CONFIG(securetransport) +void tst_QSslSocket::tls13Ciphers() +{ + // SecureTransport introduced several new ciphers under + // "TLS 1.3 ciphersuites" section. Since Qt 6 we respect + // the ciphers from QSslConfiguration. In case of default + // configuration, these are the same we report and we + // were failing (for historical reasons) to report those + // TLS 1.3 suites when creating default QSslConfiguration. + // Check we now have them. + if (!isTestingSecureTransport) + QSKIP("The feature 'securetransport' was enabled, but active backend is not \"securetransport\""); + + QFETCH_GLOBAL(const bool, setProxy); + if (setProxy) + return; + + const auto suites = QSslConfiguration::defaultConfiguration().ciphers(); + QSslCipher ciph; + // Check the one of reported and previously missed: + for (const auto &suite : suites) { + if (suite.encryptionMethod() == QStringLiteral("CHACHA20")) { + // There are several ciphesuites using CHACHA20, the first one + // is sufficient for the purpose of this test: + ciph = suite; + break; + } + } + + QVERIFY(!ciph.isNull()); + QCOMPARE(ciph.encryptionMethod(), QStringLiteral("CHACHA20")); + QCOMPARE(ciph.supportedBits(), 256); + QCOMPARE(ciph.usedBits(), 256); +} +#endif // QT_CONFIG(securetransport) + void tst_QSslSocket::connectToHostEncrypted() { if (!QSslSocket::supportsSsl()) return; QSslSocketPtr socket = newSocket(); -#if QT_CONFIG(schannel) // old certificate not supported with TLS 1.2 - socket->setProtocol(QSsl::SslProtocol::TlsV1_1); -#endif + this->socket = socket.data(); auto config = socket->sslConfiguration(); QVERIFY(config.addCaCertificates(httpServerCertChainPath())); @@ -871,6 +1134,7 @@ void tst_QSslSocket::connectToHostEncrypted() socket->disconnectFromHost(); QVERIFY(socket->waitForDisconnected()); + QVERIFY(!socket->isEncrypted()); QCOMPARE(socket->mode(), QSslSocket::SslClientMode); @@ -887,9 +1151,7 @@ void tst_QSslSocket::connectToHostEncryptedWithVerificationPeerName() return; QSslSocketPtr socket = newSocket(); -#if QT_CONFIG(schannel) // old certificate not supported with TLS 1.2 - socket->setProtocol(QSsl::SslProtocol::TlsV1_1); -#endif + this->socket = socket.data(); auto config = socket->sslConfiguration(); @@ -944,14 +1206,6 @@ void tst_QSslSocket::sessionCipher() QVERIFY(socket->waitForDisconnected()); } -void tst_QSslSocket::flush() -{ -} - -void tst_QSslSocket::isEncrypted() -{ -} - void tst_QSslSocket::localCertificate() { if (!QSslSocket::supportsSsl()) @@ -995,7 +1249,7 @@ void tst_QSslSocket::peerCertificateChain() QSslSocketPtr socket = newSocket(); this->socket = socket.data(); QList<QSslCertificate> caCertificates = QSslCertificate::fromPath(httpServerCertChainPath()); - QCOMPARE(caCertificates.count(), 1); + QCOMPARE(caCertificates.size(), 1); auto config = socket->sslConfiguration(); config.addCaCertificates(caCertificates); socket->setSslConfiguration(config); @@ -1012,7 +1266,7 @@ void tst_QSslSocket::peerCertificateChain() QSKIP("Skipping flaky test - See QTBUG-29941"); QList<QSslCertificate> certChain = socket->peerCertificateChain(); - QVERIFY(certChain.count() > 0); + QVERIFY(certChain.size() > 0); QCOMPARE(certChain.first(), socket->peerCertificate()); socket->disconnectFromHost(); @@ -1053,11 +1307,15 @@ void tst_QSslSocket::privateKey() { } -#ifndef QT_NO_OPENSSL +#if QT_CONFIG(openssl) void tst_QSslSocket::privateKeyOpaque() { - if (!QSslSocket::supportsSsl()) - return; +#ifndef OPENSSL_NO_DEPRECATED_3_0 + if (!isTestingOpenSsl) + QSKIP("The active TLS backend does not support private opaque keys"); + + if (!opensslResolved) + QSKIP("Failed to resolve OpenSSL symbols, required by this test"); QFile file(testDataDir + "certs/fluke.key"); QVERIFY(file.open(QIODevice::ReadOnly)); @@ -1086,8 +1344,9 @@ void tst_QSslSocket::privateKeyOpaque() QFETCH_GLOBAL(bool, setProxy); if (setProxy && !socket->waitForEncrypted(10000)) QSKIP("Skipping flaky test - See QTBUG-29941"); +#endif // OPENSSL_NO_DEPRECATED_3_0 } -#endif +#endif // Feature 'openssl'. void tst_QSslSocket::protocol() { @@ -1111,38 +1370,38 @@ void tst_QSslSocket::protocol() QFETCH_GLOBAL(bool, setProxy); { // qt-test-server allows TLSV1. - socket->setProtocol(QSsl::TlsV1_0); - QCOMPARE(socket->protocol(), QSsl::TlsV1_0); + socket->setProtocol(Test::TlsV1_0); + QCOMPARE(socket->protocol(), Test::TlsV1_0); socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); if (setProxy && !socket->waitForEncrypted()) QSKIP("Skipping flaky test - See QTBUG-29941"); - QCOMPARE(socket->protocol(), QSsl::TlsV1_0); + QCOMPARE(socket->protocol(), Test::TlsV1_0); socket->abort(); - QCOMPARE(socket->protocol(), QSsl::TlsV1_0); + QCOMPARE(socket->protocol(), Test::TlsV1_0); socket->connectToHost(QtNetworkSettings::httpServerName(), 443); QVERIFY2(socket->waitForConnected(), qPrintable(socket->errorString())); socket->startClientEncryption(); if (setProxy && !socket->waitForEncrypted()) QSKIP("Skipping flaky test - See QTBUG-29941"); - QCOMPARE(socket->protocol(), QSsl::TlsV1_0); + QCOMPARE(socket->protocol(), Test::TlsV1_0); socket->abort(); } { // qt-test-server probably doesn't allow TLSV1.1 - socket->setProtocol(QSsl::TlsV1_1); - QCOMPARE(socket->protocol(), QSsl::TlsV1_1); + socket->setProtocol(Test::TlsV1_1); + QCOMPARE(socket->protocol(), Test::TlsV1_1); socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); if (setProxy && !socket->waitForEncrypted()) QSKIP("Skipping flaky test - See QTBUG-29941"); - QCOMPARE(socket->protocol(), QSsl::TlsV1_1); + QCOMPARE(socket->protocol(), Test::TlsV1_1); socket->abort(); - QCOMPARE(socket->protocol(), QSsl::TlsV1_1); + QCOMPARE(socket->protocol(), Test::TlsV1_1); socket->connectToHost(QtNetworkSettings::httpServerName(), 443); QVERIFY2(socket->waitForConnected(), qPrintable(socket->errorString())); socket->startClientEncryption(); if (setProxy && !socket->waitForEncrypted()) QSKIP("Skipping flaky test - See QTBUG-29941"); - QCOMPARE(socket->protocol(), QSsl::TlsV1_1); + QCOMPARE(socket->protocol(), Test::TlsV1_1); socket->abort(); } { @@ -1164,13 +1423,12 @@ void tst_QSslSocket::protocol() socket->abort(); } -#ifdef TLS1_3_VERSION - { + if (supportsTls13()) { // qt-test-server probably doesn't allow TLSV1.3 socket->setProtocol(QSsl::TlsV1_3); QCOMPARE(socket->protocol(), QSsl::TlsV1_3); socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); - if (setProxy && !socket->waitForEncrypted()) + if (!socket->waitForEncrypted(10'000)) QSKIP("TLS 1.3 is not supported by the test server or the test is flaky - see QTBUG-29941"); QCOMPARE(socket->protocol(), QSsl::TlsV1_3); socket->abort(); @@ -1178,12 +1436,11 @@ void tst_QSslSocket::protocol() socket->connectToHost(QtNetworkSettings::httpServerName(), 443); QVERIFY2(socket->waitForConnected(), qPrintable(socket->errorString())); socket->startClientEncryption(); - if (setProxy && !socket->waitForEncrypted()) + if (!socket->waitForEncrypted(10'000)) QSKIP("TLS 1.3 is not supported by the test server or the test is flaky - see QTBUG-29941"); QCOMPARE(socket->sessionProtocol(), QSsl::TlsV1_3); socket->abort(); } -#endif // TLS1_3_VERSION { // qt-test-server allows SSLV3, so it allows AnyProtocol. socket->setProtocol(QSsl::AnyProtocol); @@ -1215,7 +1472,7 @@ public: config(QSslConfiguration::defaultConfiguration()), ignoreSslErrors(true), peerVerifyMode(QSslSocket::AutoVerifyPeer), - protocol(QSsl::TlsV1_0), + protocol(QSsl::SecureProtocols), m_keyFile(keyFile), m_certFile(certFile), m_interFile(interFile) @@ -1232,9 +1489,12 @@ public: QList<QSslCipher> ciphers; signals: + void sslErrors(const QList<QSslError> &errors); void socketError(QAbstractSocket::SocketError); + void handshakeInterruptedOnError(const QSslError& rrror); void gotAlert(QSsl::AlertLevel level, QSsl::AlertType type, const QString &message); void alertSent(QSsl::AlertLevel level, QSsl::AlertType type, const QString &message); + void socketEncrypted(QSslSocket *); protected: void incomingConnection(qintptr socketDescriptor) override @@ -1245,9 +1505,14 @@ protected: configuration.setProtocol(protocol); if (ignoreSslErrors) connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot())); + else + connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SIGNAL(sslErrors(QList<QSslError>))); connect(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), this, SIGNAL(socketError(QAbstractSocket::SocketError))); + connect(socket, &QSslSocket::handshakeInterruptedOnError, this, &SslServer::handshakeInterruptedOnError); connect(socket, &QSslSocket::alertReceived, this, &SslServer::gotAlert); connect(socket, &QSslSocket::alertSent, this, &SslServer::alertSent); + connect(socket, &QSslSocket::preSharedKeyAuthenticationRequired, this, &SslServer::preSharedKeyAuthenticationRequired); + connect(socket, &QSslSocket::encrypted, this, [this](){ emit socketEncrypted(socket); }); QFile file(m_keyFile); QVERIFY(file.open(QIODevice::ReadOnly)); @@ -1295,6 +1560,11 @@ protected: } protected slots: + void preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator) + { + authenticator->setPreSharedKey("123456"); + } + void ignoreErrorSlot() { socket->ignoreSslErrors(); @@ -1307,45 +1577,34 @@ void tst_QSslSocket::protocolServerSide_data() QTest::addColumn<QSsl::SslProtocol>("clientProtocol"); QTest::addColumn<bool>("works"); - QTest::newRow("tls1.0-tls1.0") << QSsl::TlsV1_0 << QSsl::TlsV1_0 << true; QTest::newRow("any-any") << QSsl::AnyProtocol << QSsl::AnyProtocol << true; QTest::newRow("secure-secure") << QSsl::SecureProtocols << QSsl::SecureProtocols << true; - QTest::newRow("tls1.0-secure") << QSsl::TlsV1_0 << QSsl::SecureProtocols << true; - QTest::newRow("tls1.0-any") << QSsl::TlsV1_0 << QSsl::AnyProtocol << true; - - QTest::newRow("secure-tls1.0") << QSsl::SecureProtocols << QSsl::TlsV1_0 << true; + QTest::newRow("tls1.0-secure") << Test::TlsV1_0 << QSsl::SecureProtocols << false; + QTest::newRow("secure-tls1.0") << QSsl::SecureProtocols << Test::TlsV1_0 << false; QTest::newRow("secure-any") << QSsl::SecureProtocols << QSsl::AnyProtocol << true; - QTest::newRow("tls1.0orlater-tls1.0") << QSsl::TlsV1_0OrLater << QSsl::TlsV1_0 << true; - QTest::newRow("tls1.0orlater-tls1.1") << QSsl::TlsV1_0OrLater << QSsl::TlsV1_1 << true; - QTest::newRow("tls1.0orlater-tls1.2") << QSsl::TlsV1_0OrLater << QSsl::TlsV1_2 << true; -#ifdef TLS1_3_VERSION - QTest::newRow("tls1.0orlater-tls1.3") << QSsl::TlsV1_0OrLater << QSsl::TlsV1_3 << true; -#endif + QTest::newRow("tls1.0orlater-tls1.2") << Test::TlsV1_0OrLater << QSsl::TlsV1_2 << true; + if (supportsTls13()) + QTest::newRow("tls1.0orlater-tls1.3") << Test::TlsV1_0OrLater << QSsl::TlsV1_3 << true; - QTest::newRow("tls1.1orlater-tls1.0") << QSsl::TlsV1_1OrLater << QSsl::TlsV1_0 << false; - QTest::newRow("tls1.1orlater-tls1.1") << QSsl::TlsV1_1OrLater << QSsl::TlsV1_1 << true; - QTest::newRow("tls1.1orlater-tls1.2") << QSsl::TlsV1_1OrLater << QSsl::TlsV1_2 << true; + QTest::newRow("tls1.1orlater-tls1.0") << Test::TlsV1_1OrLater << Test::TlsV1_0 << false; + QTest::newRow("tls1.1orlater-tls1.2") << Test::TlsV1_1OrLater << QSsl::TlsV1_2 << true; -#ifdef TLS1_3_VERSION - QTest::newRow("tls1.1orlater-tls1.3") << QSsl::TlsV1_1OrLater << QSsl::TlsV1_3 << true; -#endif + if (supportsTls13()) + QTest::newRow("tls1.1orlater-tls1.3") << Test::TlsV1_1OrLater << QSsl::TlsV1_3 << true; - QTest::newRow("tls1.2orlater-tls1.0") << QSsl::TlsV1_2OrLater << QSsl::TlsV1_0 << false; - QTest::newRow("tls1.2orlater-tls1.1") << QSsl::TlsV1_2OrLater << QSsl::TlsV1_1 << false; + QTest::newRow("tls1.2orlater-tls1.0") << QSsl::TlsV1_2OrLater << Test::TlsV1_0 << false; + QTest::newRow("tls1.2orlater-tls1.1") << QSsl::TlsV1_2OrLater << Test::TlsV1_1 << false; QTest::newRow("tls1.2orlater-tls1.2") << QSsl::TlsV1_2OrLater << QSsl::TlsV1_2 << true; -#ifdef TLS1_3_VERSION - QTest::newRow("tls1.2orlater-tls1.3") << QSsl::TlsV1_2OrLater << QSsl::TlsV1_3 << true; -#endif -#ifdef TLS1_3_VERSION - QTest::newRow("tls1.3orlater-tls1.0") << QSsl::TlsV1_3OrLater << QSsl::TlsV1_0 << false; - QTest::newRow("tls1.3orlater-tls1.1") << QSsl::TlsV1_3OrLater << QSsl::TlsV1_1 << false; - QTest::newRow("tls1.3orlater-tls1.2") << QSsl::TlsV1_3OrLater << QSsl::TlsV1_2 << false; - QTest::newRow("tls1.3orlater-tls1.3") << QSsl::TlsV1_3OrLater << QSsl::TlsV1_3 << true; -#endif // TLS1_3_VERSION + if (supportsTls13()) { + QTest::newRow("tls1.2orlater-tls1.3") << QSsl::TlsV1_2OrLater << QSsl::TlsV1_3 << true; + QTest::newRow("tls1.3orlater-tls1.0") << QSsl::TlsV1_3OrLater << Test::TlsV1_0 << false; + QTest::newRow("tls1.3orlater-tls1.1") << QSsl::TlsV1_3OrLater << Test::TlsV1_1 << false; + QTest::newRow("tls1.3orlater-tls1.2") << QSsl::TlsV1_3OrLater << QSsl::TlsV1_2 << false; + QTest::newRow("tls1.3orlater-tls1.3") << QSsl::TlsV1_3OrLater << QSsl::TlsV1_3 << true; + } - QTest::newRow("any-tls1.0") << QSsl::AnyProtocol << QSsl::TlsV1_0 << true; QTest::newRow("any-secure") << QSsl::AnyProtocol << QSsl::SecureProtocols << true; } @@ -1402,23 +1661,37 @@ void tst_QSslSocket::protocolServerSide() QCOMPARE(client.isEncrypted(), works); } -#ifndef QT_NO_OPENSSL - void tst_QSslSocket::serverCipherPreferences() { - if (!QSslSocket::supportsSsl()) { - qWarning("SSL not supported, skipping test"); - return; - } + if (!isTestingOpenSsl) + QSKIP("The active TLS backend does not support server-side cipher preferences"); QFETCH_GLOBAL(bool, setProxy); if (setProxy) return; - // First using the default (server preference) + QSslCipher testedCiphers[2]; { + // First using the default (server preference) + const auto supportedCiphers = QSslConfiguration::supportedCiphers(); + int nSet = 0; + for (const auto &cipher : supportedCiphers) { + // Ciphersuites from TLS 1.2 and 1.3 are set separately, + // let's select 1.3 or above explicitly. + if (cipher.protocol() < QSsl::TlsV1_3) + continue; + + testedCiphers[nSet++] = cipher; + if (nSet == 2) + break; + } + + if (nSet != 2) + QSKIP("Failed to find two proper ciphersuites to test, bailing out."); + SslServer server; - server.ciphers = {QSslCipher("AES128-SHA"), QSslCipher("AES256-SHA")}; + server.protocol = QSsl::TlsV1_2OrLater; + server.ciphers = {testedCiphers[0], testedCiphers[1]}; QVERIFY(server.listen()); QEventLoop loop; @@ -1428,7 +1701,8 @@ void tst_QSslSocket::serverCipherPreferences() socket = &client; auto sslConfig = socket->sslConfiguration(); - sslConfig.setCiphers({QSslCipher("AES256-SHA"), QSslCipher("AES128-SHA")}); + sslConfig.setProtocol(QSsl::TlsV1_2OrLater); + sslConfig.setCiphers({testedCiphers[1], testedCiphers[0]}); socket->setSslConfiguration(sslConfig); // upon SSL wrong version error, errorOccurred will be triggered, not sslErrors @@ -1441,16 +1715,19 @@ void tst_QSslSocket::serverCipherPreferences() loop.exec(); QVERIFY(client.isEncrypted()); - QCOMPARE(client.sessionCipher().name(), QString("AES128-SHA")); + QCOMPARE(client.sessionCipher().name(), testedCiphers[0].name()); } { + if (QTestPrivate::isRunningArmOnX86()) + QSKIP("This test is known to crash on QEMU emulation for no good reason."); // Now using the client preferences SslServer server; QSslConfiguration config = QSslConfiguration::defaultConfiguration(); config.setSslOption(QSsl::SslOptionDisableServerCipherPreference, true); server.config = config; - server.ciphers = {QSslCipher("AES128-SHA"), QSslCipher("AES256-SHA")}; + server.protocol = QSsl::TlsV1_2OrLater; + server.ciphers = {testedCiphers[0], testedCiphers[1]}; QVERIFY(server.listen()); QEventLoop loop; @@ -1460,7 +1737,8 @@ void tst_QSslSocket::serverCipherPreferences() socket = &client; auto sslConfig = socket->sslConfiguration(); - sslConfig.setCiphers({QSslCipher("AES256-SHA"), QSslCipher("AES128-SHA")}); + sslConfig.setProtocol(QSsl::TlsV1_2OrLater); + sslConfig.setCiphers({testedCiphers[1], testedCiphers[0]}); socket->setSslConfiguration(sslConfig); // upon SSL wrong version error, errorOccurred will be triggered, not sslErrors @@ -1473,12 +1751,10 @@ void tst_QSslSocket::serverCipherPreferences() loop.exec(); QVERIFY(client.isEncrypted()); - QCOMPARE(client.sessionCipher().name(), QString("AES256-SHA")); + QCOMPARE(client.sessionCipher().name(), testedCiphers[1].name()); } } -#endif // QT_NO_OPENSSL - void tst_QSslSocket::setCaCertificates() { @@ -1548,18 +1824,46 @@ void tst_QSslSocket::setLocalCertificateChain() loop.exec(); QList<QSslCertificate> chain = socket->peerCertificateChain(); -#if QT_CONFIG(schannel) - QEXPECT_FAIL("", "Schannel cannot send intermediate certificates not " - "located in a system certificate store", - Abort); -#endif + if (isTestingSchannel) { + QEXPECT_FAIL("", "Schannel cannot send intermediate certificates not " + "located in a system certificate store", + Abort); + } + QCOMPARE(chain.size(), 2); - QCOMPARE(chain[0].serialNumber(), QByteArray("10:a0:ad:77:58:f6:6e:ae:46:93:a3:43:f9:59:8a:9e")); - QCOMPARE(chain[1].serialNumber(), QByteArray("3b:eb:99:c5:ea:d8:0b:5d:0b:97:5d:4f:06:75:4b:e1")); + QCOMPARE(chain[0].serialNumber(), + QByteArray("58:df:33:c1:9b:bc:c5:51:7a:00:86:64:43:94:41:e2:26:ef:3f:89")); + QCOMPARE(chain[1].serialNumber(), + QByteArray("11:72:34:bc:21:e6:ca:04:24:13:f8:35:48:84:a6:e9:de:96:22:15")); } -void tst_QSslSocket::setPrivateKey() +void tst_QSslSocket::tlsConfiguration() { + QFETCH_GLOBAL(const bool, setProxy); + if (setProxy) + return; + // Test some things not covered by any other auto-test. + QSslSocket socket; + auto tlsConfig = socket.sslConfiguration(); + QVERIFY(tlsConfig.sessionCipher().isNull()); + QCOMPARE(tlsConfig.addCaCertificates(QStringLiteral("nonexisting/chain.crt")), false); + QCOMPARE(tlsConfig.sessionProtocol(), QSsl::UnknownProtocol); + QSslConfiguration nullConfig; + QVERIFY(nullConfig.isNull()); +#if QT_CONFIG(openssl) + nullConfig.setEllipticCurves(tlsConfig.ellipticCurves()); + QCOMPARE(nullConfig.ellipticCurves(), tlsConfig.ellipticCurves()); +#endif + QMap<QByteArray, QVariant> backendConfig; + backendConfig["DTLSMTU"] = QVariant::fromValue(1024); + backendConfig["DTLSTIMEOUTMS"] = QVariant::fromValue(1000); + nullConfig.setBackendConfiguration(backendConfig); + QCOMPARE(nullConfig.backendConfiguration(), backendConfig); + QTest::ignoreMessage(QtWarningMsg, "QSslConfiguration::setPeerVerifyDepth: cannot set negative depth of -1000"); + nullConfig.setPeerVerifyDepth(-1000); + QVERIFY(nullConfig.peerVerifyDepth() != -1000); + nullConfig.setPeerVerifyDepth(100); + QCOMPARE(nullConfig.peerVerifyDepth(), 100); } void tst_QSslSocket::setSocketDescriptor() @@ -1602,11 +1906,16 @@ void tst_QSslSocket::setSslConfiguration_data() QTest::newRow("empty") << QSslConfiguration() << false; QSslConfiguration conf = QSslConfiguration::defaultConfiguration(); QTest::newRow("default") << conf << false; // does not contain test server cert - QList<QSslCertificate> testServerCert = QSslCertificate::fromPath(httpServerCertChainPath()); - conf.setCaCertificates(testServerCert); - QTest::newRow("set-root-cert") << conf << true; - conf.setProtocol(QSsl::SecureProtocols); - QTest::newRow("secure") << conf << true; + + if (!isTestingSecureTransport) { + QList<QSslCertificate> testServerCert = QSslCertificate::fromPath(httpServerCertChainPath()); + conf.setCaCertificates(testServerCert); + QTest::newRow("set-root-cert") << conf << true; + conf.setProtocol(QSsl::SecureProtocols); + QTest::newRow("secure") << conf << true; + } else { + qWarning("Skipping the cases with certificate, SecureTransport does not like old certificate on the test server"); + } } void tst_QSslSocket::setSslConfiguration() @@ -1617,9 +1926,7 @@ void tst_QSslSocket::setSslConfiguration() QSslSocketPtr socket = newSocket(); QFETCH(QSslConfiguration, configuration); socket->setSslConfiguration(configuration); -#if QT_CONFIG(schannel) // old certificate not supported with TLS 1.2 - socket->setProtocol(QSsl::SslProtocol::TlsV1_1); -#endif + this->socket = socket.data(); socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); QFETCH(bool, works); @@ -1672,9 +1979,19 @@ void tst_QSslSocket::waitForConnectedEncryptedReadyRead() if (!QSslSocket::supportsSsl()) return; + // Starting from OpenSSL v 3.1.1 deprecated protocol versions (we want to use here) are not available by default. + if (isSecurityLevel0Required) + QSKIP("Testing with OpenSSL backend, but security level 0 is required for TLS v1.1 or earlier"); + QSslSocketPtr socket = newSocket(); this->socket = socket.data(); + // Set TLS 1.0 or above because the server doesn't support TLS 1.2 or above + // QTQAINFRA-4499 + QSslConfiguration config = socket->sslConfiguration(); + config.setProtocol(Test::TlsV1_0OrLater); + socket->setSslConfiguration(config); + connect(this->socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot())); socket->connectToHostEncrypted(QtNetworkSettings::imapServerName(), 993); @@ -1953,8 +2270,17 @@ void tst_QSslSocket::spontaneousWrite() receiver->startClientEncryption(); // SSL handshake: - connect(receiver, SIGNAL(encrypted()), SLOT(exitLoop())); + // Need to wait for both sides to emit encrypted as the ordering of which + // ones emits encrypted() changes depending on whether we use TLS 1.2 or 1.3 + int waitFor = 2; + auto earlyQuitter = [&waitFor]() { + if (!--waitFor) + exitLoop(); + }; + connect(receiver, &QSslSocket::encrypted, this, earlyQuitter); + connect(sender, &QSslSocket::encrypted, this, earlyQuitter); enterLoop(1); + QVERIFY(!timeout()); QVERIFY(sender->isEncrypted()); QVERIFY(receiver->isEncrypted()); @@ -1997,9 +2323,21 @@ void tst_QSslSocket::setReadBufferSize() receiver->ignoreSslErrors(); receiver->startClientEncryption(); - // SSL handshake: - connect(receiver, SIGNAL(encrypted()), SLOT(exitLoop())); + // Need to wait for both sides to emit encrypted as the ordering of which + // ones emits encrypted() changes depending on whether we use TLS 1.2 or 1.3 + int waitFor = 2; + auto earlyQuitter = [&waitFor]() { + if (!--waitFor) + exitLoop(); + }; + connect(receiver, &QSslSocket::encrypted, this, earlyQuitter); + connect(sender, &QSslSocket::encrypted, this, earlyQuitter); + enterLoop(1); + if (!sender->isEncrypted()) { + connect(sender, &QSslSocket::encrypted, this, &tst_QSslSocket::exitLoop); + enterLoop(1); + } QVERIFY(!timeout()); QVERIFY(sender->isEncrypted()); QVERIFY(receiver->isEncrypted()); @@ -2319,9 +2657,7 @@ void tst_QSslSocket::verifyMode() return; QSslSocket socket; -#if QT_CONFIG(schannel) // old certificate not supported with TLS 1.2 - socket.setProtocol(QSsl::SslProtocol::TlsV1_1); -#endif + QCOMPARE(socket.peerVerifyMode(), QSslSocket::AutoVerifyPeer); socket.setPeerVerifyMode(QSslSocket::VerifyNone); QCOMPARE(socket.peerVerifyMode(), QSslSocket::VerifyNone); @@ -2334,7 +2670,7 @@ void tst_QSslSocket::verifyMode() QSKIP("Skipping flaky test - See QTBUG-29941"); QList<QSslError> expectedErrors = QList<QSslError>() - << QSslError(FLUKE_CERTIFICATE_ERROR, socket.peerCertificate()); + << QSslError(flukeCertificateError, socket.peerCertificate()); QCOMPARE(socket.sslHandshakeErrors(), expectedErrors); socket.abort(); @@ -2365,6 +2701,43 @@ void tst_QSslSocket::verifyDepth() QCOMPARE(socket.peerVerifyDepth(), 1); } +void tst_QSslSocket::verifyAndDefaultConfiguration() +{ + QFETCH_GLOBAL(const bool, setProxy); + if (setProxy) + return; + if (!QSslSocket::supportedFeatures().contains(QSsl::SupportedFeature::CertificateVerification)) + QSKIP("This backend doesn't support manual certificate verification"); + const auto defaultCACertificates = QSslConfiguration::defaultConfiguration().caCertificates(); + const auto chainGuard = qScopeGuard([&defaultCACertificates]{ + auto conf = QSslConfiguration::defaultConfiguration(); + conf.setCaCertificates(defaultCACertificates); + QSslConfiguration::setDefaultConfiguration(conf); + }); + + auto chain = QSslCertificate::fromPath(testDataDir + QStringLiteral("certs/qtiochain.crt"), QSsl::Pem); + QCOMPARE(chain.size(), 2); + QVERIFY(!chain.at(0).isNull()); + QVERIFY(!chain.at(1).isNull()); + auto errors = QSslCertificate::verify(chain); + // At least, test that 'verify' did not alter the default configuration: + QCOMPARE(defaultCACertificates, QSslConfiguration::defaultConfiguration().caCertificates()); + if (!errors.isEmpty()) + QSKIP("The certificate for qt.io could not be trusted, skipping the rest of the test"); +#ifdef Q_OS_WINDOWS + const auto fakeCaChain = QSslCertificate::fromPath(testDataDir + QStringLiteral("certs/fluke.cert")); + QCOMPARE(fakeCaChain.size(), 1); + const auto caCert = fakeCaChain.at(0); + QVERIFY(!caCert.isNull()); + auto conf = QSslConfiguration::defaultConfiguration(); + conf.setCaCertificates({caCert}); + QSslConfiguration::setDefaultConfiguration(conf); + errors = QSslCertificate::verify(chain); + QVERIFY(errors.size() > 0); + QCOMPARE(QSslConfiguration::defaultConfiguration().caCertificates(), QList{caCert}); +#endif +} + void tst_QSslSocket::disconnectFromHostWhenConnecting() { QSslSocketPtr socket = newSocket(); @@ -2409,7 +2782,7 @@ void tst_QSslSocket::disconnectFromHostWhenConnected() QCOMPARE(socket->bytesToWrite(), qint64(0)); } -#ifndef QT_NO_OPENSSL +#if QT_CONFIG(openssl) class BrokenPskHandshake : public QTcpServer { @@ -2440,6 +2813,9 @@ private: void tst_QSslSocket::closeWhileEmittingSocketError() { + if (!isTestingOpenSsl) + QSKIP("The active TLS backend does not support this test"); + QFETCH_GLOBAL(bool, setProxy); if (setProxy) return; @@ -2460,17 +2836,17 @@ void tst_QSslSocket::closeWhileEmittingSocketError() // Make sure we have some data buffered so that close will try to flush: clientSocket.write(QByteArray(1000000, Qt::Uninitialized)); - QTestEventLoop::instance().enterLoopMSecs(1000); + QTestEventLoop::instance().enterLoop(1s); QVERIFY(!QTestEventLoop::instance().timeout()); - QCOMPARE(socketErrorSpy.count(), 1); + QCOMPARE(socketErrorSpy.size(), 1); } -#endif // QT_NO_OPENSSL +#endif // Feature 'openssl'. void tst_QSslSocket::resetProxy() { -#ifndef QT_NO_NETWORKPROXY +#if QT_CONFIG(networkproxy) QFETCH_GLOBAL(bool, setProxy); if (setProxy) return; @@ -2514,7 +2890,7 @@ void tst_QSslSocket::resetProxy() socket2.setProxy(goodProxy); socket2.connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); QVERIFY2(socket2.waitForConnected(10000), qPrintable(socket.errorString())); -#endif // QT_NO_NETWORKPROXY +#endif // QT_CONFIG(networkproxy) } void tst_QSslSocket::ignoreSslErrorsList_data() @@ -2526,8 +2902,8 @@ void tst_QSslSocket::ignoreSslErrorsList_data() QList<QSslError> expectedSslErrors; // fromPath gives us a list of certs, but it actually only contains one QList<QSslCertificate> certs = QSslCertificate::fromPath(httpServerCertChainPath()); - QSslError rightError(FLUKE_CERTIFICATE_ERROR, certs.at(0)); - QSslError wrongError(FLUKE_CERTIFICATE_ERROR); + QSslError rightError(flukeCertificateError, certs.at(0)); + QSslError wrongError(flukeCertificateError); QTest::newRow("SSL-failure-empty-list") << expectedSslErrors << 1; @@ -2560,7 +2936,7 @@ void tst_QSslSocket::ignoreSslErrorsList() bool expectEncryptionSuccess = (expectedSslErrorSignalCount == 0); if (socket.waitForEncrypted(10000) != expectEncryptionSuccess) QSKIP("Skipping flaky test - See QTBUG-29941"); - QCOMPARE(sslErrorsSpy.count(), expectedSslErrorSignalCount); + QCOMPARE(sslErrorsSpy.size(), expectedSslErrorSignalCount); } void tst_QSslSocket::ignoreSslErrorsListWithSlot_data() @@ -2621,9 +2997,7 @@ void tst_QSslSocket::abortOnSslErrors() void tst_QSslSocket::readFromClosedSocket() { QSslSocketPtr socket = newSocket(); -#if QT_CONFIG(schannel) // old certificate not supported with TLS 1.2 - socket->setProtocol(QSsl::SslProtocol::TlsV1_1); -#endif + socket->ignoreSslErrors(); socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); socket->ignoreSslErrors(); @@ -2720,9 +3094,16 @@ void tst_QSslSocket::blacklistedCertificates() connect(receiver, SIGNAL(encrypted()), SLOT(exitLoop())); enterLoop(1); QList<QSslError> sslErrors = receiver->sslHandshakeErrors(); - QVERIFY(sslErrors.count() > 0); + QVERIFY(sslErrors.size() > 0); // there are more errors (self signed cert and hostname mismatch), but we only care about the blacklist error - QCOMPARE(sslErrors.at(0).error(), QSslError::CertificateBlacklisted); + std::optional<QSslError> blacklistedError; + for (const QSslError &error : sslErrors) { + if (error.error() == QSslError::CertificateBlacklisted) { + blacklistedError = error; + break; + } + } + QVERIFY2(blacklistedError, "CertificateBlacklisted error not found!"); } void tst_QSslSocket::versionAccessors() @@ -2734,60 +3115,6 @@ void tst_QSslSocket::versionAccessors() qDebug() << QString::number(QSslSocket::sslLibraryVersionNumber(), 16); } -#ifndef QT_NO_OPENSSL -void tst_QSslSocket::sslOptions() -{ - if (!QSslSocket::supportsSsl()) - return; - -#ifdef SSL_OP_NO_COMPRESSION - QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols, - QSslConfigurationPrivate::defaultSslOptions), - long(SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_COMPRESSION|SSL_OP_CIPHER_SERVER_PREFERENCE)); -#else - QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols, - QSslConfigurationPrivate::defaultSslOptions), - long(SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_CIPHER_SERVER_PREFERENCE)); -#endif - - QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols, - QSsl::SslOptionDisableEmptyFragments - |QSsl::SslOptionDisableLegacyRenegotiation), - long(SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_CIPHER_SERVER_PREFERENCE)); - -#ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION - QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols, - QSsl::SslOptionDisableEmptyFragments), - long((SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION|SSL_OP_CIPHER_SERVER_PREFERENCE))); -#endif - -#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS - QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols, - QSsl::SslOptionDisableLegacyRenegotiation), - long((SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_CIPHER_SERVER_PREFERENCE) & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)); -#endif - -#ifdef SSL_OP_NO_TICKET - QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols, - QSsl::SslOptionDisableEmptyFragments - |QSsl::SslOptionDisableLegacyRenegotiation - |QSsl::SslOptionDisableSessionTickets), - long((SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TICKET|SSL_OP_CIPHER_SERVER_PREFERENCE))); -#endif - -#ifdef SSL_OP_NO_TICKET -#ifdef SSL_OP_NO_COMPRESSION - QCOMPARE(QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SecureProtocols, - QSsl::SslOptionDisableEmptyFragments - |QSsl::SslOptionDisableLegacyRenegotiation - |QSsl::SslOptionDisableSessionTickets - |QSsl::SslOptionDisableCompression), - long((SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TICKET|SSL_OP_NO_COMPRESSION|SSL_OP_CIPHER_SERVER_PREFERENCE))); -#endif -#endif -} -#endif - void tst_QSslSocket::encryptWithoutConnecting() { if (!QSslSocket::supportsSsl()) @@ -2802,6 +3129,10 @@ void tst_QSslSocket::encryptWithoutConnecting() void tst_QSslSocket::resume_data() { + // Starting from OpenSSL v 3.1.1 deprecated protocol versions (we want to use in 'resume' test) are not available by default. + if (isSecurityLevel0Required) + QSKIP("Testing with OpenSSL backend, but security level 0 is required for TLS v1.1 or earlier"); + QTest::addColumn<bool>("ignoreErrorsAfterPause"); QTest::addColumn<QList<QSslError> >("errorsToIgnore"); QTest::addColumn<bool>("expectSuccess"); @@ -2813,8 +3144,8 @@ void tst_QSslSocket::resume_data() // Note, httpServerCertChainPath() it's ... because we use the same certificate on // different services. We'll be actually connecting to IMAP server. QList<QSslCertificate> certs = QSslCertificate::fromPath(httpServerCertChainPath()); - QSslError rightError(FLUKE_CERTIFICATE_ERROR, certs.at(0)); - QSslError wrongError(FLUKE_CERTIFICATE_ERROR); + QSslError rightError(flukeCertificateError, certs.at(0)); + QSslError wrongError(flukeCertificateError); errorsList.append(wrongError); QTest::newRow("ignoreSpecificErrors-Wrong") << true << errorsList << false; errorsList.clear(); @@ -2837,6 +3168,12 @@ void tst_QSslSocket::resume() QSslSocket socket; socket.setPauseMode(QAbstractSocket::PauseOnSslErrors); + // Set TLS 1.0 or above because the server doesn't support TLS 1.2 or above + // QTQAINFRA-4499 + QSslConfiguration config = socket.sslConfiguration(); + config.setProtocol(Test::TlsV1_0OrLater); + socket.setSslConfiguration(config); + QSignalSpy sslErrorSpy(&socket, SIGNAL(sslErrors(QList<QSslError>))); QSignalSpy encryptedSpy(&socket, SIGNAL(encrypted())); QSignalSpy errorSpy(&socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError))); @@ -2852,9 +3189,9 @@ void tst_QSslSocket::resume() QFETCH_GLOBAL(bool, setProxy); if (setProxy && QTestEventLoop::instance().timeout()) QSKIP("Skipping flaky test - See QTBUG-29941"); - QCOMPARE(sslErrorSpy.count(), 1); - QCOMPARE(errorSpy.count(), 0); - QCOMPARE(encryptedSpy.count(), 0); + QCOMPARE(sslErrorSpy.size(), 1); + QCOMPARE(errorSpy.size(), 0); + QCOMPARE(encryptedSpy.size(), 0); QVERIFY(!socket.isEncrypted()); if (ignoreErrorsAfterPause) { if (errorsToIgnore.empty()) @@ -2866,15 +3203,15 @@ void tst_QSslSocket::resume() QTestEventLoop::instance().enterLoop(10); QVERIFY(!QTestEventLoop::instance().timeout()); // quit by encrypted() or error() signal if (expectSuccess) { - QCOMPARE(encryptedSpy.count(), 1); + QCOMPARE(encryptedSpy.size(), 1); QVERIFY(socket.isEncrypted()); - QCOMPARE(errorSpy.count(), 0); + QCOMPARE(errorSpy.size(), 0); socket.disconnectFromHost(); QVERIFY(socket.waitForDisconnected(10000)); } else { - QCOMPARE(encryptedSpy.count(), 0); + QCOMPARE(encryptedSpy.size(), 0); QVERIFY(!socket.isEncrypted()); - QCOMPARE(errorSpy.count(), 1); + QCOMPARE(errorSpy.size(), 1); QCOMPARE(socket.error(), QAbstractSocket::SslHandshakeFailedError); } } @@ -3061,17 +3398,17 @@ void tst_QSslSocket::qtbug18498_peek2() bigblock.fill('#', QIODEVICE_BUFFERSIZE + 1024); QVERIFY(client->write(QByteArray("head"))); QVERIFY(client->write(bigblock)); - QTRY_COMPARE(server->bytesAvailable(), bigblock.length() + 4); + QTRY_COMPARE(server->bytesAvailable(), bigblock.size() + 4); QCOMPARE(server->read(4), QByteArray("head")); - QCOMPARE(server->peek(bigblock.length()), bigblock); - b.reserve(bigblock.length()); - b.resize(server->peek(b.data(), bigblock.length())); + QCOMPARE(server->peek(bigblock.size()), bigblock); + b.reserve(bigblock.size()); + b.resize(server->peek(b.data(), bigblock.size())); QCOMPARE(b, bigblock); //check oversized peek - QCOMPARE(server->peek(bigblock.length() * 3), bigblock); - b.reserve(bigblock.length() * 3); - b.resize(server->peek(b.data(), bigblock.length() * 3)); + QCOMPARE(server->peek(bigblock.size() * 3), bigblock); + b.reserve(bigblock.size() * 3); + b.resize(server->peek(b.data(), bigblock.size() * 3)); QCOMPARE(b, bigblock); QCOMPARE(server->readAll(), bigblock); @@ -3139,7 +3476,13 @@ void tst_QSslSocket::dhServer() return; SslServer server; - server.ciphers = {QSslCipher("DHE-RSA-AES256-SHA"), QSslCipher("DHE-DSS-AES256-SHA")}; + QSslCipher rsaCipher("DHE-RSA-AES256-SHA"); + QSslCipher dssCipher("DHE-DSS-AES256-SHA"); + if (rsaCipher.isNull()) + QSKIP("The current backend doesn't support DHE-RSA-AES256-SHA"); + if (dssCipher.isNull()) + QSKIP("The current backend doesn't support DHE-DSS-AES256-SHA"); + server.ciphers = { rsaCipher, dssCipher }; QVERIFY(server.listen()); QEventLoop loop; @@ -3157,18 +3500,20 @@ void tst_QSslSocket::dhServer() QCOMPARE(client.state(), QAbstractSocket::ConnectedState); } -#ifndef QT_NO_OPENSSL +#if QT_CONFIG(openssl) void tst_QSslSocket::dhServerCustomParamsNull() { - if (!QSslSocket::supportsSsl()) - QSKIP("No SSL support"); + if (!isTestingOpenSsl) + QSKIP("This test requires OpenSSL as the active TLS backend"); QFETCH_GLOBAL(bool, setProxy); if (setProxy) return; + const QSslCipher cipherWithDH("DHE-RSA-AES256-SHA256"); SslServer server; - server.ciphers = {QSslCipher("DHE-RSA-AES256-SHA"), QSslCipher("DHE-DSS-AES256-SHA")}; + server.ciphers = {cipherWithDH}; + server.protocol = QSsl::TlsV1_2; QSslConfiguration cfg = server.config; cfg.setDiffieHellmanParameters(QSslDiffieHellmanParameters()); @@ -3180,6 +3525,8 @@ void tst_QSslSocket::dhServerCustomParamsNull() QTimer::singleShot(5000, &loop, SLOT(quit())); QSslSocket client; + QSslConfiguration config = client.sslConfiguration(); + client.setSslConfiguration(config); socket = &client; connect(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), &loop, SLOT(quit())); connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot())); @@ -3189,22 +3536,25 @@ void tst_QSslSocket::dhServerCustomParamsNull() loop.exec(); - QVERIFY(client.state() != QAbstractSocket::ConnectedState); + QCOMPARE(client.state(), QAbstractSocket::ConnectedState); + QCOMPARE(client.sessionCipher(), cipherWithDH); } -#endif // QT_NO_OPENSSL -#ifndef QT_NO_OPENSSL void tst_QSslSocket::dhServerCustomParams() { if (!QSslSocket::supportsSsl()) QSKIP("No SSL support"); + if (!QSslSocket::isClassImplemented(QSsl::ImplementedClass::DiffieHellman)) + QSKIP("The current backend doesn't support diffie hellman parameters"); QFETCH_GLOBAL(bool, setProxy); if (setProxy) return; SslServer server; - server.ciphers = {QSslCipher("DHE-RSA-AES256-SHA"), QSslCipher("DHE-DSS-AES256-SHA")}; + const QSslCipher cipherWithDH("DHE-RSA-AES256-SHA256"); + server.ciphers = {cipherWithDH}; + server.protocol = QSsl::TlsV1_2; QSslConfiguration cfg = server.config; @@ -3234,9 +3584,10 @@ void tst_QSslSocket::dhServerCustomParams() loop.exec(); - QVERIFY(client.state() == QAbstractSocket::ConnectedState); + QCOMPARE(client.state(), QAbstractSocket::ConnectedState); + QCOMPARE(client.sessionCipher(), cipherWithDH); } -#endif // QT_NO_OPENSSL +#endif // QT_CONFIG(openssl) void tst_QSslSocket::ecdhServer() { @@ -3250,7 +3601,10 @@ void tst_QSslSocket::ecdhServer() return; SslServer server; - server.ciphers = {QSslCipher("ECDHE-RSA-AES128-SHA")}; + QSslCipher cipher("ECDHE-RSA-AES128-SHA"); + if (cipher.isNull()) + QSKIP("The current backend doesn't support ECDHE-RSA-AES128-SHA"); + server.ciphers = {cipher}; QVERIFY(server.listen()); QEventLoop loop; @@ -3338,14 +3692,15 @@ void tst_QSslSocket::verifyClientCertificate_data() void tst_QSslSocket::verifyClientCertificate() { -#if QT_CONFIG(securetransport) - // We run both client and server on the same machine, - // this means, client can update keychain with client's certificates, - // and server later will use the same certificates from the same - // keychain thus making tests fail (wrong number of certificates, - // success instead of failure etc.). - QSKIP("This test can not work with Secure Transport"); -#endif // QT_CONFIG(securetransport) + if (isTestingSecureTransport) { + // We run both client and server on the same machine, + // this means, client can update keychain with client's certificates, + // and server later will use the same certificates from the same + // keychain thus making tests fail (wrong number of certificates, + // success instead of failure etc.). + QSKIP("This test can not work with Secure Transport"); + } + if (!QSslSocket::supportsSsl()) { qWarning("SSL not supported, skipping test"); return; @@ -3356,12 +3711,13 @@ void tst_QSslSocket::verifyClientCertificate() return; QFETCH(QSslSocket::PeerVerifyMode, peerVerifyMode); -#if QT_CONFIG(schannel) - if (peerVerifyMode == QSslSocket::QueryPeer || peerVerifyMode == QSslSocket::AutoVerifyPeer) - QSKIP("Schannel doesn't tackle requesting a certificate and not receiving one."); -#endif + if (isTestingSchannel) { + if (peerVerifyMode == QSslSocket::QueryPeer || peerVerifyMode == QSslSocket::AutoVerifyPeer) + QSKIP("Schannel doesn't tackle requesting a certificate and not receiving one."); + } SslServer server; + server.protocol = QSsl::TlsV1_2; server.addCaCertificates = testDataDir + "certs/bogus-ca.crt"; server.ignoreSslErrors = false; server.peerVerifyMode = peerVerifyMode; @@ -3375,6 +3731,9 @@ void tst_QSslSocket::verifyClientCertificate() QSslSocket client; client.setLocalCertificateChain(clientCerts); client.setPrivateKey(clientKey); + QSslConfiguration config = client.sslConfiguration(); + config.setProtocol(Test::TlsV1_0OrLater); + client.setSslConfiguration(config); socket = &client; connect(socket, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(ignoreErrorSlot())); @@ -3399,13 +3758,13 @@ void tst_QSslSocket::verifyClientCertificate() QVERIFY(server.socket->peerCertificateChain().isEmpty()); } else { QCOMPARE(server.socket->peerCertificate(), clientCerts.first()); -#if QT_CONFIG(schannel) - if (clientCerts.count() == 1 && server.socket->peerCertificateChain().count() == 2) { - QEXPECT_FAIL("", - "Schannel includes the entire chain, not just the leaf and intermediates", - Continue); + if (isTestingSchannel) { + if (clientCerts.size() == 1 && server.socket->peerCertificateChain().size() == 2) { + QEXPECT_FAIL("", + "Schannel includes the entire chain, not just the leaf and intermediates", + Continue); + } } -#endif QCOMPARE(server.socket->peerCertificateChain(), clientCerts); } @@ -3416,7 +3775,18 @@ void tst_QSslSocket::verifyClientCertificate() void tst_QSslSocket::readBufferMaxSize() { -#if QT_CONFIG(securetransport) || QT_CONFIG(schannel) + // QTBUG-94186: originally, only SecureTransport was + // running this test (since it was a bug in that backend, + // see comment below), after TLS plugins were introduced, + // we enabled this test on all backends, as a part of + // the clean up. This revealed the fact that this test + // is flaky, and it started to fail on Windows. + // TODO: this is a temporary solution, to be removed + // as soon as 94186 fixed for good. + if (!isTestingSecureTransport) + QSKIP("This test is flaky with TLS backend other than SecureTransport"); + + // QTBUG-55170: // SecureTransport back-end was ignoring read-buffer // size limit, resulting (potentially) in a constantly @@ -3441,11 +3811,19 @@ void tst_QSslSocket::readBufferMaxSize() socket = client.data(); connect(socket, SIGNAL(errorOccurred(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()); + int waitFor = 2; + auto earlyQuitter = [&loop, &waitFor]() { + if (!--waitFor) + loop.exit(); + }; + + connect(socket, &QSslSocket::encrypted, &loop, earlyQuitter); + connect(&server, &SslServer::socketEncrypted, &loop, earlyQuitter); + // Wait for 'encrypted' first: QTimer::singleShot(5000, &loop, SLOT(quit())); loop.exec(); @@ -3471,9 +3849,6 @@ void tst_QSslSocket::readBufferMaxSize() loop.exec(); QCOMPARE(client->bytesAvailable() + readSoFar, message.size()); -#else - // Not needed, QSslSocket works correctly with other back-ends. -#endif // QT_CONFIG(securetransport) || QT_CONFIG(schannel) } void tst_QSslSocket::setEmptyDefaultConfiguration() // this test should be last, as it has some side effects @@ -3498,20 +3873,13 @@ void tst_QSslSocket::setEmptyDefaultConfiguration() // this test should be last, void tst_QSslSocket::allowedProtocolNegotiation() { -#ifndef ALPN_SUPPORTED - QSKIP("ALPN is unsupported, skipping test"); -#endif - -#if QT_CONFIG(schannel) - if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8_1) - QSKIP("ALPN is not supported on this version of Windows using Schannel."); -#endif + if (!hasServerAlpn) + QSKIP("Server-side ALPN is unsupported, skipping test"); QFETCH_GLOBAL(bool, setProxy); if (setProxy) return; - const QByteArray expectedNegotiated("cool-protocol"); QList<QByteArray> serverProtos; serverProtos << expectedNegotiated << "not-so-cool-protocol"; @@ -3533,15 +3901,25 @@ void tst_QSslSocket::allowedProtocolNegotiation() QEventLoop loop; QTimer::singleShot(5000, &loop, SLOT(quit())); - connect(&clientSocket, SIGNAL(encrypted()), &loop, SLOT(quit())); + + // Need to wait for both sides to emit encrypted as the ordering of which + // ones emits encrypted() changes depending on whether we use TLS 1.2 or 1.3 + int waitFor = 2; + auto earlyQuitter = [&loop, &waitFor]() { + if (!--waitFor) + loop.exit(); + }; + connect(&clientSocket, &QSslSocket::encrypted, &loop, earlyQuitter); + connect(&server, &SslServer::socketEncrypted, &loop, earlyQuitter); + loop.exec(); - QVERIFY(server.socket->sslConfiguration().nextNegotiatedProtocol() == - clientSocket.sslConfiguration().nextNegotiatedProtocol()); - QVERIFY(server.socket->sslConfiguration().nextNegotiatedProtocol() == expectedNegotiated); + QCOMPARE(server.socket->sslConfiguration().nextNegotiatedProtocol(), + clientSocket.sslConfiguration().nextNegotiatedProtocol()); + QCOMPARE(server.socket->sslConfiguration().nextNegotiatedProtocol(), expectedNegotiated); } -#ifndef QT_NO_OPENSSL +#if QT_CONFIG(openssl) class PskProvider : public QObject { Q_OBJECT @@ -3551,7 +3929,7 @@ public: QByteArray m_identity; QByteArray m_psk; - explicit PskProvider(QObject *parent = 0) + explicit PskProvider(QObject *parent = nullptr) : QObject(parent), m_server(false) { } @@ -3599,7 +3977,7 @@ public: config(QSslConfiguration::defaultConfiguration()), ignoreSslErrors(true), peerVerifyMode(QSslSocket::AutoVerifyPeer), - protocol(QSsl::TlsV1_0), + protocol(QSsl::TlsV1_2), m_pskProvider() { m_pskProvider.m_server = true; @@ -3645,8 +4023,12 @@ protected slots: socket->ignoreSslErrors(); } }; + void tst_QSslSocket::simplePskConnect_data() { + if (!isTestingOpenSsl) + QSKIP("The active TLS backend does support PSK"); + QTest::addColumn<PskConnectTestType>("pskTestType"); QTest::newRow("PskConnectDoNotHandlePsk") << PskConnectDoNotHandlePsk; QTest::newRow("PskConnectEmptyCredentials") << PskConnectEmptyCredentials; @@ -3737,14 +4119,14 @@ void tst_QSslSocket::simplePskConnect() case PskConnectWrongCredentials: // provide totally wrong credentials - provider.setIdentity(PSK_CLIENT_IDENTITY.left(PSK_CLIENT_IDENTITY.length() - 1)); - provider.setPreSharedKey(PSK_CLIENT_PRESHAREDKEY.left(PSK_CLIENT_PRESHAREDKEY.length() - 1)); + provider.setIdentity(PSK_CLIENT_IDENTITY.left(PSK_CLIENT_IDENTITY.size() - 1)); + provider.setPreSharedKey(PSK_CLIENT_PRESHAREDKEY.left(PSK_CLIENT_PRESHAREDKEY.size() - 1)); connect(&socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), &provider, SLOT(providePsk(QSslPreSharedKeyAuthenticator*))); break; case PskConnectWrongIdentity: // right PSK, wrong identity - provider.setIdentity(PSK_CLIENT_IDENTITY.left(PSK_CLIENT_IDENTITY.length() - 1)); + provider.setIdentity(PSK_CLIENT_IDENTITY.left(PSK_CLIENT_IDENTITY.size() - 1)); provider.setPreSharedKey(PSK_CLIENT_PRESHAREDKEY); connect(&socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), &provider, SLOT(providePsk(QSslPreSharedKeyAuthenticator*))); break; @@ -3752,7 +4134,7 @@ void tst_QSslSocket::simplePskConnect() case PskConnectWrongPreSharedKey: // right identity, wrong PSK provider.setIdentity(PSK_CLIENT_IDENTITY); - provider.setPreSharedKey(PSK_CLIENT_PRESHAREDKEY.left(PSK_CLIENT_PRESHAREDKEY.length() - 1)); + provider.setPreSharedKey(PSK_CLIENT_PRESHAREDKEY.left(PSK_CLIENT_PRESHAREDKEY.size() - 1)); connect(&socket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)), &provider, SLOT(providePsk(QSslPreSharedKeyAuthenticator*))); break; @@ -3804,32 +4186,32 @@ void tst_QSslSocket::simplePskConnect() // Entered connecting state QCOMPARE(socket.state(), QAbstractSocket::ConnectingState); - QCOMPARE(connectedSpy.count(), 0); - QCOMPARE(hostFoundSpy.count(), 1); - QCOMPARE(disconnectedSpy.count(), 0); + QCOMPARE(connectedSpy.size(), 0); + QCOMPARE(hostFoundSpy.size(), 1); + QCOMPARE(disconnectedSpy.size(), 0); enterLoop(10); // Entered connected state QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); QCOMPARE(socket.mode(), QSslSocket::UnencryptedMode); QVERIFY(!socket.isEncrypted()); - QCOMPARE(connectedSpy.count(), 1); - QCOMPARE(hostFoundSpy.count(), 1); - QCOMPARE(disconnectedSpy.count(), 0); + QCOMPARE(connectedSpy.size(), 1); + QCOMPARE(hostFoundSpy.size(), 1); + QCOMPARE(disconnectedSpy.size(), 0); // Enter encrypted mode socket.startClientEncryption(); QCOMPARE(socket.mode(), QSslSocket::SslClientMode); QVERIFY(!socket.isEncrypted()); - QCOMPARE(connectionEncryptedSpy.count(), 0); - QCOMPARE(sslErrorsSpy.count(), 0); - QCOMPARE(peerVerifyErrorSpy.count(), 0); + QCOMPARE(connectionEncryptedSpy.size(), 0); + QCOMPARE(sslErrorsSpy.size(), 0); + QCOMPARE(peerVerifyErrorSpy.size(), 0); // Start handshake. enterLoop(10); // We must get the PSK signal in all cases - QCOMPARE(pskAuthenticationRequiredSpy.count(), 1); + QCOMPARE(pskAuthenticationRequiredSpy.size(), 1); switch (pskTestType) { case PskConnectDoNotHandlePsk: @@ -3838,40 +4220,40 @@ void tst_QSslSocket::simplePskConnect() case PskConnectWrongIdentity: case PskConnectWrongPreSharedKey: // Handshake failure - QCOMPARE(socketErrorsSpy.count(), 1); + QCOMPARE(socketErrorsSpy.size(), 1); QCOMPARE(qvariant_cast<QAbstractSocket::SocketError>(socketErrorsSpy.at(0).at(0)), QAbstractSocket::SslHandshakeFailedError); - QCOMPARE(sslErrorsSpy.count(), 0); - QCOMPARE(peerVerifyErrorSpy.count(), 0); - QCOMPARE(connectionEncryptedSpy.count(), 0); + QCOMPARE(sslErrorsSpy.size(), 0); + QCOMPARE(peerVerifyErrorSpy.size(), 0); + QCOMPARE(connectionEncryptedSpy.size(), 0); QVERIFY(!socket.isEncrypted()); break; case PskConnectRightCredentialsPeerVerifyFailure: // Peer verification failure - QCOMPARE(socketErrorsSpy.count(), 1); + QCOMPARE(socketErrorsSpy.size(), 1); QCOMPARE(qvariant_cast<QAbstractSocket::SocketError>(socketErrorsSpy.at(0).at(0)), QAbstractSocket::SslHandshakeFailedError); - QCOMPARE(sslErrorsSpy.count(), 1); - QCOMPARE(peerVerifyErrorSpy.count(), 1); - QCOMPARE(connectionEncryptedSpy.count(), 0); + QCOMPARE(sslErrorsSpy.size(), 1); + QCOMPARE(peerVerifyErrorSpy.size(), 1); + QCOMPARE(connectionEncryptedSpy.size(), 0); QVERIFY(!socket.isEncrypted()); break; case PskConnectRightCredentialsVerifyPeer: // Peer verification failure, but ignore it and keep connecting - QCOMPARE(socketErrorsSpy.count(), 0); - QCOMPARE(sslErrorsSpy.count(), 1); - QCOMPARE(peerVerifyErrorSpy.count(), 1); - QCOMPARE(connectionEncryptedSpy.count(), 1); + QCOMPARE(socketErrorsSpy.size(), 0); + QCOMPARE(sslErrorsSpy.size(), 1); + QCOMPARE(peerVerifyErrorSpy.size(), 1); + QCOMPARE(connectionEncryptedSpy.size(), 1); QVERIFY(socket.isEncrypted()); QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); break; case PskConnectRightCredentialsDoNotVerifyPeer: // No peer verification => no failure - QCOMPARE(socketErrorsSpy.count(), 0); - QCOMPARE(sslErrorsSpy.count(), 0); - QCOMPARE(peerVerifyErrorSpy.count(), 0); - QCOMPARE(connectionEncryptedSpy.count(), 1); + QCOMPARE(socketErrorsSpy.size(), 0); + QCOMPARE(sslErrorsSpy.size(), 0); + QCOMPARE(peerVerifyErrorSpy.size(), 0); + QCOMPARE(connectionEncryptedSpy.size(), 1); QVERIFY(socket.isEncrypted()); QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); break; @@ -3912,11 +4294,14 @@ void tst_QSslSocket::simplePskConnect() } QCOMPARE(socket.state(), QAbstractSocket::UnconnectedState); - QCOMPARE(disconnectedSpy.count(), 1); + QCOMPARE(disconnectedSpy.size(), 1); } void tst_QSslSocket::ephemeralServerKey_data() { + if (!isTestingOpenSsl) + QSKIP("The active TLS backend does not support ephemeral keys"); + QTest::addColumn<QString>("cipher"); QTest::addColumn<bool>("emptyKey"); @@ -3942,16 +4327,16 @@ void tst_QSslSocket::ephemeralServerKey() client->connectToHostEncrypted(QHostAddress(QHostAddress::LocalHost).toString(), server.serverPort()); spy.wait(); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QVERIFY(server.config.ephemeralServerKey().isNull()); QCOMPARE(client->sslConfiguration().ephemeralServerKey().isNull(), emptyKey); } void tst_QSslSocket::pskServer() { -#if QT_CONFIG(schannel) - QSKIP("Schannel does not have PSK support implemented."); -#endif + if (!isTestingOpenSsl) + QSKIP("The active TLS-backend does not have PSK support implemented."); + QFETCH_GLOBAL(bool, setProxy); if (!QSslSocket::supportsSsl() || setProxy) return; @@ -4005,22 +4390,22 @@ void tst_QSslSocket::pskServer() QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); QCOMPARE(socket.mode(), QSslSocket::UnencryptedMode); QVERIFY(!socket.isEncrypted()); - QCOMPARE(connectedSpy.count(), 1); - QCOMPARE(disconnectedSpy.count(), 0); + QCOMPARE(connectedSpy.size(), 1); + QCOMPARE(disconnectedSpy.size(), 0); // Enter encrypted mode socket.startClientEncryption(); QCOMPARE(socket.mode(), QSslSocket::SslClientMode); QVERIFY(!socket.isEncrypted()); - QCOMPARE(connectionEncryptedSpy.count(), 0); + QCOMPARE(connectionEncryptedSpy.size(), 0); // Start handshake. enterLoop(10); // We must get the PSK signal in all cases - QCOMPARE(pskAuthenticationRequiredSpy.count(), 1); + QCOMPARE(pskAuthenticationRequiredSpy.size(), 1); - QCOMPARE(connectionEncryptedSpy.count(), 1); + QCOMPARE(connectionEncryptedSpy.size(), 1); QVERIFY(socket.isEncrypted()); QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); @@ -4033,13 +4418,13 @@ void tst_QSslSocket::pskServer() enterLoop(10); QCOMPARE(socket.state(), QAbstractSocket::UnconnectedState); - QCOMPARE(disconnectedSpy.count(), 1); + QCOMPARE(disconnectedSpy.size(), 1); } void tst_QSslSocket::signatureAlgorithm_data() { - if (!QSslSocket::supportsSsl()) - QSKIP("Signature algorithms cannot be tested without SSL support"); + if (!isTestingOpenSsl) + QSKIP("Signature algorithms cannot be tested with a non-OpenSSL TLS backend"); if (QSslSocket::sslLibraryVersionNumber() >= 0x10101000L) { // FIXME: investigate if this test makes any sense with TLS 1.3. @@ -4105,7 +4490,7 @@ void tst_QSslSocket::signatureAlgorithm_data() // signature algorithms do not match, but are ignored because the tls version is not v1.2 QTest::newRow("client_ignore_TlsV1_1") << QByteArrayList({rsaSha256}) - << QSsl::TlsV1_1 + << Test::TlsV1_1 << QByteArrayList({rsaSha512}) << QSsl::AnyProtocol << QAbstractSocket::ConnectedState; @@ -4113,11 +4498,11 @@ void tst_QSslSocket::signatureAlgorithm_data() << QByteArrayList({rsaSha256}) << QSsl::AnyProtocol << QByteArrayList({rsaSha512}) - << QSsl::TlsV1_1 + << Test::TlsV1_1 << QAbstractSocket::ConnectedState; QTest::newRow("client_ignore_TlsV1_0") << QByteArrayList({rsaSha256}) - << QSsl::TlsV1_0 + << Test::TlsV1_0 << QByteArrayList({rsaSha512}) << QSsl::AnyProtocol << QAbstractSocket::ConnectedState; @@ -4125,7 +4510,7 @@ void tst_QSslSocket::signatureAlgorithm_data() << QByteArrayList({rsaSha256}) << QSsl::AnyProtocol << QByteArrayList({rsaSha512}) - << QSsl::TlsV1_0 + << Test::TlsV1_0 << QAbstractSocket::ConnectedState; } @@ -4168,8 +4553,9 @@ void tst_QSslSocket::signatureAlgorithm() void tst_QSslSocket::forwardReadChannelFinished() { - if (!QSslSocket::supportsSsl()) - QSKIP("Needs SSL"); + if (!isTestingOpenSsl) + QSKIP("This test requires the OpenSSL backend"); + QFETCH_GLOBAL(bool, setProxy); if (setProxy) QSKIP("This test doesn't work via a proxy"); @@ -4185,17 +4571,17 @@ void tst_QSslSocket::forwardReadChannelFinished() &QTestEventLoop::instance(), &QTestEventLoop::exitLoop); socket.connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443); enterLoop(10); - QVERIFY(readChannelFinishedSpy.count()); + QVERIFY(readChannelFinishedSpy.size()); } -#endif // QT_NO_OPENSSL +#endif // QT_CONFIG(openssl) void tst_QSslSocket::unsupportedProtocols_data() { QTest::addColumn<QSsl::SslProtocol>("unsupportedProtocol"); - QTest::newRow("DtlsV1_0") << QSsl::DtlsV1_0; + QTest::newRow("DtlsV1_0") << Test::DtlsV1_0; QTest::newRow("DtlsV1_2") << QSsl::DtlsV1_2; - QTest::newRow("DtlsV1_0OrLater") << QSsl::DtlsV1_0OrLater; + QTest::newRow("DtlsV1_0OrLater") << Test::DtlsV1_0OrLater; QTest::newRow("DtlsV1_2OrLater") << QSsl::DtlsV1_2OrLater; QTest::newRow("UnknownProtocol") << QSsl::UnknownProtocol; } @@ -4207,7 +4593,7 @@ void tst_QSslSocket::unsupportedProtocols() return; QFETCH(const QSsl::SslProtocol, unsupportedProtocol); - const int timeoutMS = 500; + constexpr auto timeout = 500ms; // Test a client socket. { // 0. connectToHostEncrypted: client-side, non-blocking API, error is discovered @@ -4229,7 +4615,7 @@ void tst_QSslSocket::unsupportedProtocols() QCOMPARE(socket.error(), QAbstractSocket::UnknownSocketError); socket.connectToHost(QHostAddress::LocalHost, server.serverPort()); - QVERIFY(socket.waitForConnected(timeoutMS)); + QVERIFY(socket.waitForConnected(int(timeout.count()))); socket.setProtocol(unsupportedProtocol); socket.startClientEncryption(); @@ -4254,7 +4640,7 @@ void tst_QSslSocket::unsupportedProtocols() QTcpSocket client; client.connectToHost(QHostAddress::LocalHost, server.serverPort()); - loop.enterLoopMSecs(timeoutMS); + loop.enterLoop(timeout); QVERIFY(!loop.timeout()); QVERIFY(server.socket); QCOMPARE(server.socket->error(), QAbstractSocket::SslInvalidUserDataError); @@ -4267,13 +4653,15 @@ void tst_QSslSocket::oldErrorsOnSocketReuse() if (setProxy) return; // not relevant SslServer server; - server.protocol = QSsl::TlsV1_1; + if (!isTestingOpenSsl) + server.protocol = Test::TlsV1_1; server.m_certFile = testDataDir + "certs/fluke.cert"; server.m_keyFile = testDataDir + "certs/fluke.key"; QVERIFY(server.listen(QHostAddress::SpecialAddress::LocalHost)); QSslSocket socket; - socket.setProtocol(QSsl::TlsV1_1); + if (!isTestingOpenSsl) + socket.setProtocol(Test::TlsV1_1); QList<QSslError> errorList; auto connection = connect(&socket, QOverload<const QList<QSslError> &>::of(&QSslSocket::sslErrors), [&socket, &errorList](const QList<QSslError> &errors) { @@ -4308,8 +4696,6 @@ void tst_QSslSocket::oldErrorsOnSocketReuse() } } -#endif // QT_NO_SSL - #if QT_CONFIG(openssl) void tst_QSslSocket::alertMissingCertificate() @@ -4317,6 +4703,8 @@ void tst_QSslSocket::alertMissingCertificate() // In this test we want a server to abort the connection due to the failing // client authentication. The server expected to send an alert before closing // the connection, and the client expected to receive this alert and report it. + if (!isTestingOpenSsl) + QSKIP("This test requires the OpenSSL backend"); QFETCH_GLOBAL(const bool, setProxy); if (setProxy) // Not what we test here, bail out. @@ -4334,7 +4722,6 @@ void tst_QSslSocket::alertMissingCertificate() QSslSocket clientSocket; connect(&clientSocket, &QSslSocket::sslErrors, [&clientSocket](const QList<QSslError> &errors){ - qDebug() << "ERR"; clientSocket.ignoreSslErrors(errors); }); @@ -4344,7 +4731,8 @@ void tst_QSslSocket::alertMissingCertificate() clientSocket.connectToHostEncrypted(server.serverAddress().toString(), server.serverPort()); QTestEventLoop runner; - QTimer::singleShot(500, [&runner](){ + auto *context = &runner; + QTimer::singleShot(500, context, [&runner](){ runner.exitLoop(); }); @@ -4359,10 +4747,19 @@ void tst_QSslSocket::alertMissingCertificate() connect(&clientSocket, &QAbstractSocket::errorOccurred, earlyQuitter); connect(&server, &SslServer::socketError, earlyQuitter); - runner.enterLoopMSecs(1000); + runner.enterLoop(1s); - QVERIFY(serverSpy.count() > 0); - QVERIFY(clientSpy.count() > 0); + if (clientSocket.isEncrypted()) { + // When using TLS 1.3 the client side thinks it is connected very + // quickly, before the server has finished processing. So wait for the + // inevitable disconnect. + QCOMPARE(clientSocket.sessionProtocol(), QSsl::TlsV1_3); + connect(&clientSocket, &QSslSocket::disconnected, &runner, &QTestEventLoop::exitLoop); + runner.enterLoop(10s); + } + + QVERIFY(serverSpy.size() > 0); + QVERIFY(clientSpy.size() > 0); QVERIFY(server.socket && !server.socket->isEncrypted()); QVERIFY(!clientSocket.isEncrypted()); } @@ -4373,6 +4770,9 @@ void tst_QSslSocket::alertInvalidCertificate() // it also will do 'early' checks, meaning the reported and // not ignored _during_ the hanshake, not after. This ensures // OpenSSL sends an alert. + if (!isTestingOpenSsl) + QSKIP("This test requires the OpenSSL backend"); + QFETCH_GLOBAL(const bool, setProxy); if (setProxy) // Not what we test here, bail out. return; @@ -4394,7 +4794,8 @@ void tst_QSslSocket::alertInvalidCertificate() clientSocket.connectToHostEncrypted(server.serverAddress().toString(), server.serverPort()); QTestEventLoop runner; - QTimer::singleShot(500, [&runner](){ + auto *context = &runner; + QTimer::singleShot(500, context, [&runner](){ runner.exitLoop(); }); @@ -4409,16 +4810,294 @@ void tst_QSslSocket::alertInvalidCertificate() connect(&clientSocket, &QAbstractSocket::errorOccurred, earlyQuitter); connect(&server, &SslServer::socketError, earlyQuitter); - runner.enterLoopMSecs(1000); + runner.enterLoop(1s); - QVERIFY(serverSpy.count() > 0); - QVERIFY(clientSpy.count() > 0); - QVERIFY(interruptedSpy.count() > 0); + QVERIFY(serverSpy.size() > 0); + QVERIFY(clientSpy.size() > 0); + QVERIFY(interruptedSpy.size() > 0); QVERIFY(server.socket && !server.socket->isEncrypted()); QVERIFY(!clientSocket.isEncrypted()); } -#endif // openssl +void tst_QSslSocket::selfSignedCertificates_data() +{ + if (!isTestingOpenSsl) + QSKIP("The active TLS backend does not detect the required error"); + + QTest::addColumn<bool>("clientKnown"); + + QTest::newRow("Client known") << true; + QTest::newRow("Client unknown") << false; +} + +void tst_QSslSocket::selfSignedCertificates() +{ + // In this test we want to check the behavior of the client/server when + // self-signed certificates are used and the client is un/known to the server. + QFETCH(bool, clientKnown); + + QFETCH_GLOBAL(const bool, setProxy); + if (setProxy) // Not what we test here, bail out. + return; + + SslServer server(testDataDir + "certs/selfsigned-server.key", + testDataDir + "certs/selfsigned-server.crt"); + server.protocol = QSsl::TlsV1_2; + server.ignoreSslErrors = false; + server.peerVerifyMode = QSslSocket::VerifyPeer; + + if (!server.listen(QHostAddress::LocalHost)) + QSKIP("SslServer::listen() returned false"); + + QFile clientFile(testDataDir + "certs/selfsigned-client.key"); + QVERIFY(clientFile.open(QIODevice::ReadOnly)); + QSslKey clientKey(clientFile.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey); + QSslCertificate clientCert + = QSslCertificate::fromPath(testDataDir + "certs/selfsigned-client.crt").first(); + + server.config.setCiphers({QSslCipher("DHE-RSA-AES256-SHA256")}); + server.config.setHandshakeMustInterruptOnError(true); + server.config.setMissingCertificateIsFatal(true); + if (clientKnown) + server.config.setCaCertificates({clientCert}); + + connect(&server, &SslServer::sslErrors, + [](const QList<QSslError> &errors) { + QCOMPARE(errors.size(), 1); + QVERIFY(errors.first().error() == QSslError::SelfSignedCertificate); + } + ); + connect(&server, &SslServer::socketError, + [](QAbstractSocket::SocketError socketError) { + QVERIFY(socketError == QAbstractSocket::SslHandshakeFailedError); + } + ); + connect(&server, &SslServer::handshakeInterruptedOnError, + [&server](const QSslError& error) { + QVERIFY(error.error() == QSslError::SelfSignedCertificate); + server.socket->continueInterruptedHandshake(); + } + ); + + QSslSocket clientSocket; + auto configuration = QSslConfiguration::defaultConfiguration(); + configuration.setProtocol(QSsl::TlsV1_2); + configuration.setCiphers({QSslCipher("DHE-RSA-AES256-SHA256")}); + configuration.setPrivateKey(clientKey); + configuration.setLocalCertificate(clientCert); + configuration.setPeerVerifyMode(QSslSocket::VerifyPeer); + configuration.setHandshakeMustInterruptOnError(true); + configuration.setMissingCertificateIsFatal(true); + clientSocket.setSslConfiguration(configuration); + + connect(&clientSocket, &QSslSocket::sslErrors, + [&clientSocket](const QList<QSslError> &errors) { + for (const auto &error : errors) { + if (error.error() == QSslError::HostNameMismatch) { + QVERIFY(errors.size() == 2); + clientSocket.ignoreSslErrors(errors); + } else { + QVERIFY(error.error() == QSslError::SelfSignedCertificate); + } + } + } + ); + connect(&clientSocket, &QAbstractSocket::errorOccurred, + [](QAbstractSocket::SocketError socketError) { + QVERIFY(socketError == QAbstractSocket::RemoteHostClosedError); + } + ); + connect(&clientSocket, &QSslSocket::handshakeInterruptedOnError, + [&clientSocket](const QSslError& error) { + QVERIFY(error.error() == QSslError::SelfSignedCertificate); + clientSocket.continueInterruptedHandshake(); + } + ); + + QSignalSpy serverSpy(&server, &SslServer::alertSent); + QSignalSpy clientSpy(&clientSocket, &QSslSocket::alertReceived); + + clientSocket.connectToHostEncrypted(server.serverAddress().toString(), server.serverPort()); + + QTestEventLoop runner; + auto *context = &runner; + QTimer::singleShot(500, context, + [&runner]() { + runner.exitLoop(); + } + ); + + int waitFor = 2; + auto earlyQuitter = [&runner, &waitFor](QAbstractSocket::SocketError) { + if (!--waitFor) + runner.exitLoop(); + }; + + // Presumably, RemoteHostClosedError for the client and SslHandshakeError + // for the server: + connect(&clientSocket, &QAbstractSocket::errorOccurred, earlyQuitter); + connect(&server, &SslServer::socketError, earlyQuitter); + + runner.enterLoop(1s); + + if (clientKnown) { + QCOMPARE(serverSpy.size(), 0); + QCOMPARE(clientSpy.size(), 0); + QVERIFY(server.socket && server.socket->isEncrypted()); + QVERIFY(clientSocket.isEncrypted()); + } else { + QVERIFY(serverSpy.size() > 0); + QEXPECT_FAIL("", "Failing to trigger signal, QTBUG-81661", Continue); + QVERIFY(clientSpy.size() > 0); + QVERIFY(server.socket && !server.socket->isEncrypted()); + QVERIFY(!clientSocket.isEncrypted()); + } +} + +void tst_QSslSocket::pskHandshake_data() +{ + if (!isTestingOpenSsl) + QSKIP("The active TLS backend does not support PSK"); + + QTest::addColumn<bool>("pskRight"); + + QTest::newRow("Psk right") << true; + QTest::newRow("Psk wrong") << false; +} + +void tst_QSslSocket::pskHandshake() +{ + // In this test we want to check the behavior of the + // client/server when a preshared key (right/wrong) is used. + QFETCH(bool, pskRight); + + QFETCH_GLOBAL(const bool, setProxy); + if (setProxy) // Not what we test here, bail out. + return; + + SslServer server(testDataDir + "certs/selfsigned-server.key", + testDataDir + "certs/selfsigned-server.crt"); + server.protocol = QSsl::TlsV1_2; + server.ignoreSslErrors = false; + server.peerVerifyMode = QSslSocket::VerifyPeer; + + if (!server.listen(QHostAddress::LocalHost)) + QSKIP("SslServer::listen() returned false"); + + QFile clientFile(testDataDir + "certs/selfsigned-client.key"); + QVERIFY(clientFile.open(QIODevice::ReadOnly)); + QSslKey clientKey(clientFile.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey); + QSslCertificate clientCert + = QSslCertificate::fromPath(testDataDir + "certs/selfsigned-client.crt").first(); + + server.config.setCiphers({QSslCipher("RSA-PSK-AES128-CBC-SHA256")}); + server.config.setHandshakeMustInterruptOnError(true); + server.config.setMissingCertificateIsFatal(true); + + connect(&server, &SslServer::sslErrors, + [&server](const QList<QSslError> &errors) { + QCOMPARE(errors.size(), 1); + QVERIFY(errors.first().error() == QSslError::SelfSignedCertificate); + server.socket->ignoreSslErrors(errors); + } + ); + connect(&server, &SslServer::socketError, + [](QAbstractSocket::SocketError socketError) { + QVERIFY(socketError == QAbstractSocket::SslHandshakeFailedError); + } + ); + connect(&server, &SslServer::handshakeInterruptedOnError, + [&server](const QSslError& error) { + QVERIFY(error.error() == QSslError::SelfSignedCertificate); + server.socket->continueInterruptedHandshake(); + } + ); + + QSslSocket clientSocket; + auto configuration = QSslConfiguration::defaultConfiguration(); + configuration.setProtocol(QSsl::TlsV1_2); + configuration.setCiphers({QSslCipher("RSA-PSK-AES128-CBC-SHA256")}); + configuration.setPrivateKey(clientKey); + configuration.setLocalCertificate(clientCert); + configuration.setPeerVerifyMode(QSslSocket::VerifyPeer); + configuration.setHandshakeMustInterruptOnError(true); + configuration.setMissingCertificateIsFatal(true); + clientSocket.setSslConfiguration(configuration); + + connect(&clientSocket, &QSslSocket::preSharedKeyAuthenticationRequired, + [pskRight](QSslPreSharedKeyAuthenticator *authenticator) { + authenticator->setPreSharedKey(pskRight ? "123456": "654321"); + } + ); + + connect(&clientSocket, &QSslSocket::sslErrors, + [&clientSocket](const QList<QSslError> &errors) { + for (const auto &error : errors) { + if (error.error() == QSslError::HostNameMismatch) { + QVERIFY(errors.size() == 2); + clientSocket.ignoreSslErrors(errors); + } else { + QVERIFY(error.error() == QSslError::SelfSignedCertificate); + } + } + } + ); + connect(&clientSocket, &QAbstractSocket::errorOccurred, + [](QAbstractSocket::SocketError socketError) { + QVERIFY(socketError == QAbstractSocket::SslHandshakeFailedError); + } + ); + connect(&clientSocket, &QSslSocket::handshakeInterruptedOnError, + [&clientSocket](const QSslError& error) { + QVERIFY(error.error() == QSslError::SelfSignedCertificate); + clientSocket.continueInterruptedHandshake(); + } + ); + + QSignalSpy serverSpy(&server, &SslServer::alertSent); + QSignalSpy clientSpy(&clientSocket, &QSslSocket::alertReceived); + + clientSocket.connectToHostEncrypted(server.serverAddress().toString(), server.serverPort()); + + QTestEventLoop runner; + auto *context = &runner; + QTimer::singleShot(500, context, [&runner]() { + runner.exitLoop(); + }); + + int waitFor = 2; + auto earlyQuitter = [&runner, &waitFor](QAbstractSocket::SocketError) { + if (!--waitFor) + runner.exitLoop(); + }; + + // Presumably, RemoteHostClosedError for the client and SslHandshakeError + // for the server: + connect(&clientSocket, &QAbstractSocket::errorOccurred, earlyQuitter); + connect(&server, &SslServer::socketError, earlyQuitter); + + runner.enterLoop(1s); + + if (pskRight) { + QCOMPARE(serverSpy.size(), 0); + QCOMPARE(clientSpy.size(), 0); + QVERIFY(server.socket && server.socket->isEncrypted()); + QVERIFY(clientSocket.isEncrypted()); + } else { + QVERIFY(serverSpy.size() > 0); + QCOMPARE(serverSpy.first().at(0).toInt(), static_cast<int>(QSsl::AlertLevel::Fatal)); + QCOMPARE(serverSpy.first().at(1).toInt(), static_cast<int>(QSsl::AlertType::BadRecordMac)); + QVERIFY(clientSpy.size() > 0); + QCOMPARE(clientSpy.first().at(0).toInt(), static_cast<int>(QSsl::AlertLevel::Fatal)); + QCOMPARE(clientSpy.first().at(1).toInt(), static_cast<int>(QSsl::AlertType::BadRecordMac)); + QVERIFY(server.socket && !server.socket->isEncrypted()); + QVERIFY(!clientSocket.isEncrypted()); + } +} + +#endif // QT_CONFIG(openssl) +#endif // QT_CONFIG(ssl) + QTEST_MAIN(tst_QSslSocket) diff --git a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/BLACKLIST b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/BLACKLIST new file mode 100644 index 0000000000..96d94bd935 --- /dev/null +++ b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/BLACKLIST @@ -0,0 +1,7 @@ +# QTBUG-101274 +# [onDemandRootCertLoadingMemberMethods:WithoutProxy] +# qnx ci + +# QTBUG-63481 +[onDemandRootCertLoadingMemberMethods] +* diff --git a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/CMakeLists.txt b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/CMakeLists.txt index 0d6b8a4c4a..34e026cb8b 100644 --- a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/CMakeLists.txt +++ b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/CMakeLists.txt @@ -1,4 +1,11 @@ -# Generated from qsslsocket_onDemandCertificates_member.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qsslsocket_onDemandCertificates_member LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() if(NOT QT_FEATURE_private_tests) return() @@ -8,29 +15,12 @@ endif() ## tst_qsslsocket_onDemandCertificates_member Test: ##################################################################### -qt_add_test(tst_qsslsocket_onDemandCertificates_member +qt_internal_add_test(tst_qsslsocket_onDemandCertificates_member SOURCES tst_qsslsocket_onDemandCertificates_member.cpp - DEFINES - SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/\\\" - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::NetworkPrivate - QT_TEST_SERVER_LIST "squid" "danted" # special case + QT_TEST_SERVER_LIST "squid" "danted" + BUNDLE_ANDROID_OPENSSL_LIBS ) - -#### Keys ignored in scope 1:.:.:qsslsocket_onDemandCertificates_member.pro:<TRUE>: -# _REQUIREMENTS = "qtConfig(private_tests)" -# testcase.timeout = "300" - -## Scopes: -##################################################################### - -#### Keys ignored in scope 3:.:.:qsslsocket_onDemandCertificates_member.pro:(CMAKE_BUILD_TYPE STREQUAL Debug): -# DESTDIR = "debug" - -#### Keys ignored in scope 4:.:.:qsslsocket_onDemandCertificates_member.pro:else: -# DESTDIR = "release" - -#### Keys ignored in scope 5:.:.:qsslsocket_onDemandCertificates_member.pro:LINUX: -# QT_TEST_SERVER_LIST = "squid" "danted" 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 deleted file mode 100644 index 8585a3c861..0000000000 --- a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/qsslsocket_onDemandCertificates_member.pro +++ /dev/null @@ -1,25 +0,0 @@ -CONFIG += testcase -testcase.timeout = 300 # this test is slow - -SOURCES += tst_qsslsocket_onDemandCertificates_member.cpp -QT = core core-private network-private testlib - -TARGET = tst_qsslsocket_onDemandCertificates_member - -win32 { - CONFIG(debug, debug|release) { - DESTDIR = debug -} else { - DESTDIR = release - } -} - -DEFINES += SRCDIR=\\\"$$PWD/\\\" - -requires(qtConfig(private_tests)) - -# DOCKERTODO: linux, docker is disabled on macOS/Windows. -linux { - CONFIG += unsupported/testserver - QT_TEST_SERVER_LIST = squid danted -} diff --git a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/tst_qsslsocket_onDemandCertificates_member.cpp b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/tst_qsslsocket_onDemandCertificates_member.cpp index 000f2f4da9..119891c916 100644 --- a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/tst_qsslsocket_onDemandCertificates_member.cpp +++ b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_member/tst_qsslsocket_onDemandCertificates_member.cpp @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtNetwork> -#include <QtTest/QtTest> +#include <QTest> #include <QNetworkProxy> #include <QAuthenticator> @@ -219,6 +194,7 @@ static bool waitForEncrypted(QSslSocket *socket) void tst_QSslSocket_onDemandCertificates_member::onDemandRootCertLoadingMemberMethods() { +#define ERR(socket) socket->errorString().toLatin1() const QString host("www.qt.io"); // not using any root certs -> should not work @@ -228,13 +204,13 @@ void tst_QSslSocket_onDemandCertificates_member::onDemandRootCertLoadingMemberMe sslConfig.setCaCertificates(QList<QSslCertificate>()); socket2->setSslConfiguration(sslConfig); socket2->connectToHostEncrypted(host, 443); - QVERIFY(!waitForEncrypted(socket2.data())); + QVERIFY2(!waitForEncrypted(socket2.data()), ERR(socket2)); // default: using on demand loading -> should work QSslSocketPtr socket = newSocket(); this->socket = socket.data(); socket->connectToHostEncrypted(host, 443); - QVERIFY2(waitForEncrypted(socket.data()), qPrintable(socket->errorString())); + QVERIFY2(waitForEncrypted(socket.data()), ERR(socket)); // not using any root certs again -> should not work QSslSocketPtr socket3 = newSocket(); @@ -243,7 +219,7 @@ void tst_QSslSocket_onDemandCertificates_member::onDemandRootCertLoadingMemberMe sslConfig.setCaCertificates(QList<QSslCertificate>()); socket3->setSslConfiguration(sslConfig); socket3->connectToHostEncrypted(host, 443); - QVERIFY(!waitForEncrypted(socket3.data())); + QVERIFY2(!waitForEncrypted(socket3.data()), ERR(socket3)); // setting empty SSL configuration explicitly -> depends on on-demand loading QSslSocketPtr socket4 = newSocket(); @@ -254,16 +230,20 @@ void tst_QSslSocket_onDemandCertificates_member::onDemandRootCertLoadingMemberMe #ifdef QT_BUILD_INTERNAL const bool works = QSslSocketPrivate::rootCertOnDemandLoadingSupported(); #if defined(Q_OS_LINUX) || defined(Q_OS_WIN) - QCOMPARE(works, true); + QVERIFY2(works, ERR(socket4)); #elif defined(Q_OS_MAC) - QCOMPARE(works, false); + QVERIFY2(!works, ERR(socket4)); #endif // other platforms: undecided. // When we *allow* on-demand loading, we enable it by default; so, on Unix, // it will work without setting any certificates. Otherwise, the configuration // contains an empty set of certificates, so on-demand loading shall fail. - QCOMPARE(waitForEncrypted(socket4.data()), works); + const bool result = waitForEncrypted(socket4.data()); + if (result != works) + qDebug() << socket4->errorString(); + QCOMPARE(waitForEncrypted(socket4.data()), works); #endif // QT_BUILD_INTERNAL } +#undef ERR #endif // QT_NO_OPENSSL diff --git a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_static/BLACKLIST b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_static/BLACKLIST deleted file mode 100644 index 52bd2bc86d..0000000000 --- a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_static/BLACKLIST +++ /dev/null @@ -1,2 +0,0 @@ -[onDemandRootCertLoadingStaticMethods:WithSocks5ProxyAuth] -windows diff --git a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_static/CMakeLists.txt b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_static/CMakeLists.txt index b17da05d86..696eec98ee 100644 --- a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_static/CMakeLists.txt +++ b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_static/CMakeLists.txt @@ -1,4 +1,11 @@ -# Generated from qsslsocket_onDemandCertificates_static.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qsslsocket_onDemandCertificates_static LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() if(NOT QT_FEATURE_private_tests) return() @@ -8,28 +15,12 @@ endif() ## tst_qsslsocket_onDemandCertificates_static Test: ##################################################################### -qt_add_test(tst_qsslsocket_onDemandCertificates_static +qt_internal_add_test(tst_qsslsocket_onDemandCertificates_static SOURCES tst_qsslsocket_onDemandCertificates_static.cpp - DEFINES - SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/\\\" - PUBLIC_LIBRARIES + LIBRARIES Qt::CorePrivate Qt::NetworkPrivate - QT_TEST_SERVER_LIST "squid" "danted" # special case + QT_TEST_SERVER_LIST "squid" "danted" + BUNDLE_ANDROID_OPENSSL_LIBS ) - -#### Keys ignored in scope 1:.:.:qsslsocket_onDemandCertificates_static.pro:<TRUE>: -# _REQUIREMENTS = "qtConfig(private_tests)" - -## Scopes: -##################################################################### - -#### Keys ignored in scope 3:.:.:qsslsocket_onDemandCertificates_static.pro:(CMAKE_BUILD_TYPE STREQUAL Debug): -# DESTDIR = "debug" - -#### Keys ignored in scope 4:.:.:qsslsocket_onDemandCertificates_static.pro:else: -# DESTDIR = "release" - -#### Keys ignored in scope 5:.:.:qsslsocket_onDemandCertificates_static.pro:LINUX: -# QT_TEST_SERVER_LIST = "squid" "danted" 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 deleted file mode 100644 index 158ecbee37..0000000000 --- a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_static/qsslsocket_onDemandCertificates_static.pro +++ /dev/null @@ -1,24 +0,0 @@ -CONFIG += testcase - -SOURCES += tst_qsslsocket_onDemandCertificates_static.cpp -QT = core core-private network-private testlib - -TARGET = tst_qsslsocket_onDemandCertificates_static - -win32 { - CONFIG(debug, debug|release) { - DESTDIR = debug -} else { - DESTDIR = release - } -} - -DEFINES += SRCDIR=\\\"$$PWD/\\\" - -requires(qtConfig(private_tests)) - -#DOCKERTODO Linux, docker is disabled on macOS and Windows. -linux { - CONFIG += unsupported/testserver - QT_TEST_SERVER_LIST = squid danted -} diff --git a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_static/tst_qsslsocket_onDemandCertificates_static.cpp b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_static/tst_qsslsocket_onDemandCertificates_static.cpp index b71f7cc27b..c5475da581 100644 --- a/tests/auto/network/ssl/qsslsocket_onDemandCertificates_static/tst_qsslsocket_onDemandCertificates_static.cpp +++ b/tests/auto/network/ssl/qsslsocket_onDemandCertificates_static/tst_qsslsocket_onDemandCertificates_static.cpp @@ -1,34 +1,9 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtNetwork> -#include <QtTest/QtTest> +#include <QTest> #include <QNetworkProxy> #include <QAuthenticator> diff --git a/tests/auto/network/ssl/shared/qopenssl_symbols.h b/tests/auto/network/ssl/shared/qopenssl_symbols.h new file mode 100644 index 0000000000..c98e90d424 --- /dev/null +++ b/tests/auto/network/ssl/shared/qopenssl_symbols.h @@ -0,0 +1,787 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// Copyright (C) 2014 BlackBerry Limited. All rights reserved. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +/**************************************************************************** +** +** In addition, as a special exception, the copyright holders listed above give +** permission to link the code of its release of Qt with the OpenSSL project's +** "OpenSSL" library (or modified versions of the "OpenSSL" library that use the +** same license as the original version), and distribute the linked executables. +** +** You must comply with the GNU General Public License version 2 in all +** respects for all of the code used other than the "OpenSSL" code. If you +** modify this file, you may extend this exception to your version of the file, +** but you are not obligated to do so. If you do not wish to do so, delete +** this exception statement from your version of this file. +** +****************************************************************************/ + +#ifndef QOPENSSL_SYMBOLS_H +#define QOPENSSL_SYMBOLS_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +// This file is what was known as qsslsocket_openssl_symbols_p.h, +// reduced to the needs of our auto-tests, that have to mess with +// OpenSSL calls directly. + +#include <QtCore/qset.h> +#include <QtNetwork/private/qtnetworkglobal_p.h> + +QT_REQUIRE_CONFIG(openssl); + +#ifdef Q_OS_WIN +#include <QtCore/private/qsystemlibrary_p.h> +#elif QT_CONFIG(library) +#include <QtCore/qlibrary.h> +#endif // Q_OS_WIN + +#include <QtCore/qloggingcategory.h> +#include <QtCore/qstringview.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qdatetime.h> +#include <QtCore/qstring.h> +#include <QtCore/qglobal.h> + +#if defined(Q_OS_UNIX) +#include <QtCore/qdir.h> +#endif + +#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) +#include <link.h> +#endif + +#ifdef Q_OS_DARWIN +#include <QtCore/private/qcore_mac_p.h> +#endif + +#include <algorithm> +#include <memory> + +#ifdef Q_OS_WIN +#include <qt_windows.h> +// wincrypt has those as macros, which may conflict with +// typedef names in OpenSSL. +#if defined(OCSP_RESPONSE) +#undef OCSP_RESPONSE +#endif +#if defined(X509_NAME) +#undef X509_NAME +#endif +#endif // Q_OS_WIN + +#include <openssl/stack.h> +#include <openssl/x509.h> +#include <openssl/asn1.h> +#include <openssl/bio.h> +#include <openssl/ssl.h> +#include <openssl/evp.h> +#include <openssl/dsa.h> +#include <openssl/rsa.h> +#include <openssl/dh.h> +#if QT_CONFIG(ocsp) +#include <openssl/ocsp.h> +#endif // ocsp + +QT_BEGIN_NAMESPACE + +namespace { + +// BIO-related functions, that auto-tests use: +BIO *q_BIO_new(const BIO_METHOD *a); +int q_BIO_free(BIO *a); +int q_BIO_write(BIO *a, const void *b, int c); +const BIO_METHOD *q_BIO_s_mem(); + +// EVP_PKEY-related functions, that auto-tests use: +EVP_PKEY *q_EVP_PKEY_new(); +void q_EVP_PKEY_free(EVP_PKEY *a); +int q_EVP_PKEY_up_ref(EVP_PKEY *a); +EVP_PKEY *q_PEM_read_bio_PrivateKey(BIO *a, EVP_PKEY **b, pem_password_cb *c, void *d); +EVP_PKEY *q_PEM_read_bio_PUBKEY(BIO *a, EVP_PKEY **b, pem_password_cb *c, void *d); +const EVP_MD *q_EVP_sha1(); +int q_EVP_PKEY_set1_RSA(EVP_PKEY *a, RSA *b); +int q_EVP_PKEY_set1_DSA(EVP_PKEY *a, DSA *b); +int q_EVP_PKEY_set1_DH(EVP_PKEY *a, DH *b); +#ifndef OPENSSL_NO_EC +int q_EVP_PKEY_set1_EC_KEY(EVP_PKEY *a, EC_KEY *b); +#endif // !OPENSSL_NO_EC +int q_EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b); + +// Stack-management functions, that auto-tests use: +int q_OPENSSL_sk_num(OPENSSL_STACK *a); +void q_OPENSSL_sk_pop_free(OPENSSL_STACK *a, void (*b)(void *)); +OPENSSL_STACK *q_OPENSSL_sk_new_null(); +void q_OPENSSL_sk_push(OPENSSL_STACK *st, void *data); +void q_OPENSSL_sk_free(OPENSSL_STACK *a); +void *q_OPENSSL_sk_value(OPENSSL_STACK *a, int b); + +// X509-related functions: +void q_X509_up_ref(X509 *a); +void q_X509_free(X509 *a); + +// ASN1_TIME-related functions: +ASN1_TIME *q_X509_gmtime_adj(ASN1_TIME *s, long adj); +void q_ASN1_TIME_free(ASN1_TIME *t); + +#if QT_CONFIG(ocsp) +// OCSP auto-test: +int q_i2d_OCSP_RESPONSE(OCSP_RESPONSE *r, unsigned char **ppout); +OCSP_RESPONSE *q_OCSP_response_create(int status, OCSP_BASICRESP *bs); +void q_OCSP_RESPONSE_free(OCSP_RESPONSE *rs); +OCSP_SINGLERESP *q_OCSP_basic_add1_status(OCSP_BASICRESP *rsp, OCSP_CERTID *cid, + int status, int reason, ASN1_TIME *revtime, + ASN1_TIME *thisupd, ASN1_TIME *nextupd); +int q_OCSP_basic_sign(OCSP_BASICRESP *brsp, X509 *signer, EVP_PKEY *key, const EVP_MD *dgst, + STACK_OF(X509) *certs, unsigned long flags); +OCSP_BASICRESP *q_OCSP_BASICRESP_new(); +void q_OCSP_BASICRESP_free(OCSP_BASICRESP *bs); +OCSP_CERTID *q_OCSP_cert_to_id(const EVP_MD *dgst, X509 *subject, X509 *issuer); +void q_OCSP_CERTID_free(OCSP_CERTID *cid); + +#endif // QT_CONFIG(ocsp) + +#ifndef QT_LINKED_OPENSSL + +Q_LOGGING_CATEGORY(lcOsslSymbols, "qt.openssl.symbols"); + +void qsslSocketUnresolvedSymbolWarning(const char *functionName) +{ + qCWarning(lcOsslSymbols, "QSslSocket: cannot call unresolved function %s", functionName); +} + +#if QT_CONFIG(library) +void qsslSocketCannotResolveSymbolWarning(const char *functionName) +{ + qCWarning(lcOsslSymbols, "QSslSocket: cannot resolve %s", functionName); +} +#endif // QT_CONFIG(library) + +#endif // QT_LINKED_OPENSS + +#define DUMMYARG + +#if defined(QT_LINKED_OPENSSL) +// **************** Static declarations ****************** + +// ret func(arg) +# define DEFINEFUNC(ret, func, arg, a, err, funcret) \ + [[maybe_unused]] ret q_##func(arg) { funcret func(a); } + +// ret func(arg1, arg2) +# define DEFINEFUNC2(ret, func, arg1, a, arg2, b, err, funcret) \ + [[maybe_unused]] ret q_##func(arg1, arg2) { funcret func(a, b); } + +// ret func(arg1, arg2, arg3) +# define DEFINEFUNC3(ret, func, arg1, a, arg2, b, arg3, c, err, funcret) \ + [[maybe_unused]] ret q_##func(arg1, arg2, arg3) { funcret func(a, b, c); } + +// ret func(arg1, arg2, arg3, arg4) +# define DEFINEFUNC4(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, err, funcret) \ + [[maybe_unused]] ret q_##func(arg1, arg2, arg3, arg4) { funcret func(a, b, c, d); } + +// ret func(arg1, arg2, arg3, arg4, arg5) +# define DEFINEFUNC5(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, err, funcret) \ + [[maybe_unused]] ret q_##func(arg1, arg2, arg3, arg4, arg5) { funcret func(a, b, c, d, e); } + +// ret func(arg1, arg2, arg3, arg4, arg6) +# define DEFINEFUNC6(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, arg6, f, err, funcret) \ + [[maybe_unused]] ret q_##func(arg1, arg2, arg3, arg4, arg5, arg6) { funcret func(a, b, c, d, e, f); } + +// ret func(arg1, arg2, arg3, arg4, arg6, arg7) +# define DEFINEFUNC7(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, arg6, f, arg7, g, err, funcret) \ + [[maybe_unused]] ret q_##func(arg1, arg2, arg3, arg4, arg5, arg6, arg7) { funcret func(a, b, c, d, e, f, g); } + +// ret func(arg1, arg2, arg3, arg4, arg6, arg7, arg8, arg9) +# define DEFINEFUNC9(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, arg6, f, arg7, g, arg8, h, arg9, i, err, funcret) \ + [[maybe_unused]] ret q_##func(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) { funcret func(a, b, c, d, e, f, g, h, i); } + +// **************** Static declarations ****************** + +#else + +// **************** Shared declarations ****************** +// ret func(arg) + +# define DEFINEFUNC(ret, func, arg, a, err, funcret) \ + typedef ret (*_q_PTR_##func)(arg); \ + static _q_PTR_##func _q_##func = 0; \ + [[maybe_unused]] ret q_##func(arg) { \ + if (Q_UNLIKELY(!_q_##func)) { \ + qsslSocketUnresolvedSymbolWarning(#func); \ + err; \ + } \ + funcret _q_##func(a); \ + } + +// ret func(arg1, arg2) +# define DEFINEFUNC2(ret, func, arg1, a, arg2, b, err, funcret) \ + typedef ret (*_q_PTR_##func)(arg1, arg2); \ + static _q_PTR_##func _q_##func = 0; \ + [[maybe_unused]] ret q_##func(arg1, arg2) { \ + if (Q_UNLIKELY(!_q_##func)) { \ + qsslSocketUnresolvedSymbolWarning(#func);\ + err; \ + } \ + funcret _q_##func(a, b); \ + } + +// ret func(arg1, arg2, arg3) +# define DEFINEFUNC3(ret, func, arg1, a, arg2, b, arg3, c, err, funcret) \ + typedef ret (*_q_PTR_##func)(arg1, arg2, arg3); \ + static _q_PTR_##func _q_##func = 0; \ + [[maybe_unused]] ret q_##func(arg1, arg2, arg3) { \ + if (Q_UNLIKELY(!_q_##func)) { \ + qsslSocketUnresolvedSymbolWarning(#func); \ + err; \ + } \ + funcret _q_##func(a, b, c); \ + } + +// ret func(arg1, arg2, arg3, arg4) +# define DEFINEFUNC4(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, err, funcret) \ + typedef ret (*_q_PTR_##func)(arg1, arg2, arg3, arg4); \ + static _q_PTR_##func _q_##func = 0; \ + [[maybe_unused]] ret q_##func(arg1, arg2, arg3, arg4) { \ + if (Q_UNLIKELY(!_q_##func)) { \ + qsslSocketUnresolvedSymbolWarning(#func); \ + err; \ + } \ + funcret _q_##func(a, b, c, d); \ + } + +// ret func(arg1, arg2, arg3, arg4, arg5) +# define DEFINEFUNC5(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, err, funcret) \ + typedef ret (*_q_PTR_##func)(arg1, arg2, arg3, arg4, arg5); \ + static _q_PTR_##func _q_##func = 0; \ + [[maybe_unused]] ret q_##func(arg1, arg2, arg3, arg4, arg5) { \ + if (Q_UNLIKELY(!_q_##func)) { \ + qsslSocketUnresolvedSymbolWarning(#func); \ + err; \ + } \ + funcret _q_##func(a, b, c, d, e); \ + } + +// ret func(arg1, arg2, arg3, arg4, arg6) +# define DEFINEFUNC6(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, arg6, f, err, funcret) \ + typedef ret (*_q_PTR_##func)(arg1, arg2, arg3, arg4, arg5, arg6); \ + static _q_PTR_##func _q_##func = 0; \ + [[maybe_unused]] ret q_##func(arg1, arg2, arg3, arg4, arg5, arg6) { \ + if (Q_UNLIKELY(!_q_##func)) { \ + qsslSocketUnresolvedSymbolWarning(#func); \ + err; \ + } \ + funcret _q_##func(a, b, c, d, e, f); \ + } + +// ret func(arg1, arg2, arg3, arg4, arg6, arg7) +# define DEFINEFUNC7(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, arg6, f, arg7, g, err, funcret) \ + typedef ret (*_q_PTR_##func)(arg1, arg2, arg3, arg4, arg5, arg6, arg7); \ + static _q_PTR_##func _q_##func = 0; \ + [[maybe_unused]] ret q_##func(arg1, arg2, arg3, arg4, arg5, arg6, arg7) { \ + if (Q_UNLIKELY(!_q_##func)) { \ + qsslSocketUnresolvedSymbolWarning(#func); \ + err; \ + } \ + funcret _q_##func(a, b, c, d, e, f, g); \ + } + +// ret func(arg1, arg2, arg3, arg4, arg6, arg7, arg8, arg9) +# define DEFINEFUNC9(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, arg6, f, arg7, g, arg8, h, arg9, i, err, funcret) \ + typedef ret (*_q_PTR_##func)(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); \ + static _q_PTR_##func _q_##func = 0; \ + [[maybe_unused]] ret q_##func(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) { \ + if (Q_UNLIKELY(!_q_##func)) { \ + qsslSocketUnresolvedSymbolWarning(#func); \ + err; \ + } \ + funcret _q_##func(a, b, c, d, e, f, g, h, i); \ + } +// **************** Shared declarations ****************** + +#endif // QT_LINKED_OPENSSL + +// BIO: +DEFINEFUNC(BIO *, BIO_new, const BIO_METHOD *a, a, return nullptr, return) +DEFINEFUNC(int, BIO_free, BIO *a, a, return 0, return) +DEFINEFUNC3(int, BIO_write, BIO *a, a, const void *b, b, int c, c, return -1, return) +DEFINEFUNC(const BIO_METHOD *, BIO_s_mem, void, DUMMYARG, return nullptr, return) + +// EVP: +DEFINEFUNC(EVP_PKEY *, EVP_PKEY_new, DUMMYARG, DUMMYARG, return nullptr, return) +DEFINEFUNC(void, EVP_PKEY_free, EVP_PKEY *a, a, return, DUMMYARG) +DEFINEFUNC(int, EVP_PKEY_up_ref, EVP_PKEY *a, a, return 0, return) +DEFINEFUNC4(EVP_PKEY *, PEM_read_bio_PrivateKey, BIO *a, a, EVP_PKEY **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return) +DEFINEFUNC4(EVP_PKEY *, PEM_read_bio_PUBKEY, BIO *a, a, EVP_PKEY **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return) +DEFINEFUNC(const EVP_MD *, EVP_sha1, DUMMYARG, DUMMYARG, return nullptr, return) +DEFINEFUNC2(int, EVP_PKEY_set1_RSA, EVP_PKEY *a, a, RSA *b, b, return -1, return) +DEFINEFUNC2(int, EVP_PKEY_set1_DSA, EVP_PKEY *a, a, DSA *b, b, return -1, return) +DEFINEFUNC2(int, EVP_PKEY_set1_DH, EVP_PKEY *a, a, DH *b, b, return -1, return) +#ifndef OPENSSL_NO_EC +DEFINEFUNC2(int, EVP_PKEY_set1_EC_KEY, EVP_PKEY *a, a, EC_KEY *b, b, return -1, return) +#endif +DEFINEFUNC2(int, EVP_PKEY_cmp, const EVP_PKEY *a, a, const EVP_PKEY *b, b, return -1, return) + +// Stack: +DEFINEFUNC(int, OPENSSL_sk_num, OPENSSL_STACK *a, a, return -1, return) +DEFINEFUNC2(void, OPENSSL_sk_pop_free, OPENSSL_STACK *a, a, void (*b)(void*), b, return, DUMMYARG) +DEFINEFUNC(OPENSSL_STACK *, OPENSSL_sk_new_null, DUMMYARG, DUMMYARG, return nullptr, return) +DEFINEFUNC2(void, OPENSSL_sk_push, OPENSSL_STACK *a, a, void *b, b, return, DUMMYARG) +DEFINEFUNC(void, OPENSSL_sk_free, OPENSSL_STACK *a, a, return, DUMMYARG) +DEFINEFUNC2(void *, OPENSSL_sk_value, OPENSSL_STACK *a, a, int b, b, return nullptr, return) + +// X509: +DEFINEFUNC(void, X509_up_ref, X509 *a, a, return, DUMMYARG) +DEFINEFUNC(void, X509_free, X509 *a, a, return, DUMMYARG) + +// ASN1_TIME: +DEFINEFUNC2(ASN1_TIME *, X509_gmtime_adj, ASN1_TIME *s, s, long adj, adj, return nullptr, return) +DEFINEFUNC(void, ASN1_TIME_free, ASN1_TIME *t, t, return, DUMMYARG) + +#if QT_CONFIG(ocsp) + +DEFINEFUNC2(int, i2d_OCSP_RESPONSE, OCSP_RESPONSE *r, r, unsigned char **ppout, ppout, return 0, return) +DEFINEFUNC2(OCSP_RESPONSE *, OCSP_response_create, int status, status, OCSP_BASICRESP *bs, bs, return nullptr, return) +DEFINEFUNC(void, OCSP_RESPONSE_free, OCSP_RESPONSE *rs, rs, return, DUMMYARG) +DEFINEFUNC7(OCSP_SINGLERESP *, OCSP_basic_add1_status, OCSP_BASICRESP *r, r, OCSP_CERTID *c, c, int s, s, + int re, re, ASN1_TIME *rt, rt, ASN1_TIME *t, t, ASN1_TIME *n, n, return nullptr, return) +DEFINEFUNC6(int, OCSP_basic_sign, OCSP_BASICRESP *br, br, X509 *signer, signer, EVP_PKEY *key, key, + const EVP_MD *dg, dg, STACK_OF(X509) *cs, cs, unsigned long flags, flags, return 0, return) +DEFINEFUNC(OCSP_BASICRESP *, OCSP_BASICRESP_new, DUMMYARG, DUMMYARG, return nullptr, return) +DEFINEFUNC(void, OCSP_BASICRESP_free, OCSP_BASICRESP *bs, bs, return, DUMMYARG) +DEFINEFUNC3(OCSP_CERTID *, OCSP_cert_to_id, const EVP_MD *dgst, dgst, X509 *subject, subject, X509 *issuer, issuer, return nullptr, return) +DEFINEFUNC(void, OCSP_CERTID_free, OCSP_CERTID *cid, cid, return, DUMMYARG) + +#endif // QT_CONFIG(ocsp) + +#ifndef QT_LINKED_OPENSSL + +#if !QT_CONFIG(library) +bool qt_auto_test_resolve_OpenSSL_symbols() +{ + qCWarning(lcOsslSymbols, "QSslSocket: unable to resolve symbols. Qt is configured without the " + "'library' feature, which means runtime resolving of libraries won't work."); + qCWarning(lcOsslSymbols, "Either compile Qt statically or with support for runtime resolving " + "of libraries."); + return false; +} + +#else + +#ifdef Q_OS_UNIX + +struct NumericallyLess +{ + bool operator()(QStringView lhs, QStringView rhs) const + { + bool ok = false; + int b = 0; + int a = lhs.toInt(&ok); + if (ok) + b = rhs.toInt(&ok); + if (ok) { + // both toInt succeeded + return a < b; + } else { + // compare as strings; + return lhs < rhs; + } + } +}; + +struct LibGreaterThan +{ + bool operator()(QStringView lhs, QStringView rhs) const + { + const auto lhsparts = lhs.split(QLatin1Char('.')); + const auto rhsparts = rhs.split(QLatin1Char('.')); + Q_ASSERT(lhsparts.size() > 1 && rhsparts.size() > 1); + + // note: checking rhs < lhs, the same as lhs > rhs + return std::lexicographical_compare(rhsparts.begin() + 1, rhsparts.end(), + lhsparts.begin() + 1, lhsparts.end(), + NumericallyLess()); + } +}; + +#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) + +int dlIterateCallback(struct dl_phdr_info *info, size_t size, void *data) +{ + if (size < sizeof (info->dlpi_addr) + sizeof (info->dlpi_name)) + return 1; + QSet<QString> *paths = (QSet<QString> *)data; + QString path = QString::fromLocal8Bit(info->dlpi_name); + if (!path.isEmpty()) { + QFileInfo fi(path); + path = fi.absolutePath(); + if (!path.isEmpty()) + paths->insert(path); + } + return 0; +} + +#endif // defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) + +QStringList libraryPathList() +{ + QStringList paths; + +#ifdef Q_OS_DARWIN + paths = QString::fromLatin1(qgetenv("DYLD_LIBRARY_PATH")) + .split(QLatin1Char(':'), Qt::SkipEmptyParts); + + // search in .app/Contents/Frameworks + UInt32 packageType; + CFBundleGetPackageInfo(CFBundleGetMainBundle(), &packageType, nullptr); + if (packageType == FOUR_CHAR_CODE('APPL')) { + QUrl bundleUrl = QUrl::fromCFURL(QCFType<CFURLRef>(CFBundleCopyBundleURL(CFBundleGetMainBundle()))); + QUrl frameworksUrl = QUrl::fromCFURL(QCFType<CFURLRef>(CFBundleCopyPrivateFrameworksURL(CFBundleGetMainBundle()))); + paths << bundleUrl.resolved(frameworksUrl).path(); + } +#else // Q_OS_DARWIN + paths = QString::fromLatin1(qgetenv("LD_LIBRARY_PATH")).split(QLatin1Char(':'), Qt::SkipEmptyParts); +#endif // Q_OS_DARWIN + + paths << QLatin1String("/lib") << QLatin1String("/usr/lib") << QLatin1String("/usr/local/lib"); + paths << QLatin1String("/lib64") << QLatin1String("/usr/lib64") << QLatin1String("/usr/local/lib64"); + paths << QLatin1String("/lib32") << QLatin1String("/usr/lib32") << QLatin1String("/usr/local/lib32"); + +#if defined(Q_OS_ANDROID) + paths << QLatin1String("/system/lib"); +#elif defined(Q_OS_LINUX) + // discover paths of already loaded libraries + QSet<QString> loadedPaths; + dl_iterate_phdr(dlIterateCallback, &loadedPaths); + paths.append(loadedPaths.values()); +#endif // Q_OS_ANDROID + + return paths; +} + +Q_NEVER_INLINE +QStringList findAllLibs(QLatin1String filter) +{ + const QStringList paths = libraryPathList(); + QStringList found; + const QStringList filters((QString(filter))); + + for (const QString &path : paths) { + QDir dir(path); + QStringList entryList = dir.entryList(filters, QDir::Files); + + std::sort(entryList.begin(), entryList.end(), LibGreaterThan()); + for (const QString &entry : std::as_const(entryList)) + found << path + QLatin1Char('/') + entry; + } + + return found; +} + +QStringList findAllLibSsl() +{ + return findAllLibs(QLatin1String("libssl.*")); +} + +QStringList findAllLibCrypto() +{ + return findAllLibs(QLatin1String("libcrypto.*")); +} + +#endif // Q_OS_UNIX + +#ifdef Q_OS_WIN + +#if (OPENSSL_VERSION_NUMBER >> 28) < 3 +#define QT_OPENSSL_VERSION "1_1" +#elif OPENSSL_VERSION_MAJOR == 3 // Starting with 3.0 this define is available +#define QT_OPENSSL_VERSION "3" +#endif // > 3 intentionally left undefined + +struct LoadedOpenSsl { + std::unique_ptr<QSystemLibrary> ssl, crypto; +}; + +bool tryToLoadOpenSslWin32Library(QLatin1String ssleay32LibName, QLatin1String libeay32LibName, LoadedOpenSsl &result) +{ + auto ssleay32 = std::make_unique<QSystemLibrary>(ssleay32LibName); + if (!ssleay32->load(false)) { + return FALSE; + } + + auto libeay32 = std::make_unique<QSystemLibrary>(libeay32LibName); + if (!libeay32->load(false)) { + return FALSE; + } + + result.ssl = std::move(ssleay32); + result.crypto = std::move(libeay32); + return TRUE; +} + +static LoadedOpenSsl loadOpenSsl() +{ + LoadedOpenSsl result; + + // With OpenSSL 1.1 the names have changed to libssl-1_1 and libcrypto-1_1 for builds using + // MSVC and GCC, with architecture suffixes for non-x86 builds. + +#if defined(Q_PROCESSOR_X86_64) +#define QT_SSL_SUFFIX "-x64" +#elif defined(Q_PROCESSOR_ARM_64) +#define QT_SSL_SUFFIX "-arm64" +#elif defined(Q_PROCESSOR_ARM_32) +#define QT_SSL_SUFFIX "-arm" +#else +#define QT_SSL_SUFFIX +#endif + + tryToLoadOpenSslWin32Library(QLatin1String("libssl-" QT_OPENSSL_VERSION QT_SSL_SUFFIX), + QLatin1String("libcrypto-" QT_OPENSSL_VERSION QT_SSL_SUFFIX), + result); + +#undef QT_SSL_SUFFIX + return result; +} + +#else // Q_OS_WIN + +struct LoadedOpenSsl { + std::unique_ptr<QLibrary> ssl, crypto; +}; + +LoadedOpenSsl loadOpenSsl() +{ + LoadedOpenSsl result = { std::make_unique<QLibrary>(), std::make_unique<QLibrary>() }; + +# if defined(Q_OS_UNIX) + QLibrary * const libssl = result.ssl.get(); + QLibrary * const libcrypto = result.crypto.get(); + + // Try to find the libssl library on the system. + // + // Up until Qt 4.3, this only searched for the "ssl" library at version -1, that + // is, libssl.so on most Unix systems. However, the .so file isn't present in + // user installations because it's considered a development file. + // + // The right thing to do is to load the library at the major version we know how + // to work with: the SHLIB_VERSION_NUMBER version (macro defined in opensslv.h) + // + // However, OpenSSL is a well-known case of binary-compatibility breakage. To + // avoid such problems, many system integrators and Linux distributions change + // the soname of the binary, letting the full version number be the soname. So + // we'll find libssl.so.0.9.7, libssl.so.0.9.8, etc. in the system. For that + // reason, we will search a few common paths (see findAllLibSsl() above) in hopes + // we find one that works. + // + // If that fails, for OpenSSL 1.0 we also try some fallbacks -- look up + // libssl.so with a hardcoded soname. The reason is QTBUG-68156: the binary + // builds of Qt happen (at the time of this writing) on RHEL machines, + // which change SHLIB_VERSION_NUMBER to a non-portable string. When running + // those binaries on the target systems, this code won't pick up + // libssl.so.MODIFIED_SHLIB_VERSION_NUMBER because it doesn't exist there. + // Given that the only 1.0 supported release (at the time of this writing) + // is 1.0.2, with soname "1.0.0", give that a try too. Note that we mandate + // OpenSSL >= 1.0.0 with a configure-time check, and OpenSSL has kept binary + // compatibility between 1.0.0 and 1.0.2. + // + // It is important, however, to try the canonical name and the unversioned name + // without going through the loop. By not specifying a path, we let the system + // dlopen(3) function determine it for us. This will include any DT_RUNPATH or + // DT_RPATH tags on our library header as well as other system-specific search + // paths. See the man page for dlopen(3) on your system for more information. + +#ifdef Q_OS_OPENBSD + libcrypto->setLoadHints(QLibrary::ExportExternalSymbolsHint); +#endif + +#if defined(SHLIB_VERSION_NUMBER) && !defined(Q_OS_QNX) // on QNX, the libs are always libssl.so and libcrypto.so + // first attempt: the canonical name is libssl.so.<SHLIB_VERSION_NUMBER> + libssl->setFileNameAndVersion(QLatin1String("ssl"), QLatin1String(SHLIB_VERSION_NUMBER)); + libcrypto->setFileNameAndVersion(QLatin1String("crypto"), QLatin1String(SHLIB_VERSION_NUMBER)); + if (libcrypto->load() && libssl->load()) { + // libssl.so.<SHLIB_VERSION_NUMBER> and libcrypto.so.<SHLIB_VERSION_NUMBER> found + return result; + } else { + libssl->unload(); + libcrypto->unload(); + } +#endif // defined(SHLIB_VERSION_NUMBER) && !defined(Q_OS_QNX) + +#ifndef Q_OS_DARWIN + // second attempt: find the development files libssl.so and libcrypto.so + // + // disabled on macOS/iOS: + // macOS's /usr/lib/libssl.dylib, /usr/lib/libcrypto.dylib will be picked up in the third + // attempt, _after_ <bundle>/Contents/Frameworks has been searched. + // iOS does not ship a system libssl.dylib, libcrypto.dylib in the first place. +#if defined(Q_OS_ANDROID) + // OpenSSL 1.1.x must be suffixed otherwise it will use the system libcrypto.so libssl.so which on API-21 are OpenSSL 1.0 not 1.1 + auto openSSLSuffix = [](const QByteArray &defaultSuffix = {}) { + auto suffix = qgetenv("ANDROID_OPENSSL_SUFFIX"); + if (suffix.isEmpty()) + return defaultSuffix; + return suffix; + }; + + static QString suffix = QString::fromLatin1(openSSLSuffix("_1_1")); + + libssl->setFileNameAndVersion(QLatin1String("ssl") + suffix, -1); + libcrypto->setFileNameAndVersion(QLatin1String("crypto") + suffix, -1); +#else // Q_OS_ANDROID + libssl->setFileNameAndVersion(QLatin1String("ssl"), -1); + libcrypto->setFileNameAndVersion(QLatin1String("crypto"), -1); +#endif // Q_OS_ANDROID + + if (libcrypto->load() && libssl->load()) { + // libssl.so.0 and libcrypto.so.0 found + return result; + } else { + libssl->unload(); + libcrypto->unload(); + } +#endif // !Q_OS_DARWIN + + // third attempt: loop on the most common library paths and find libssl + const QStringList sslList = findAllLibSsl(); + const QStringList cryptoList = findAllLibCrypto(); + + for (const QString &crypto : cryptoList) { +#ifdef Q_OS_DARWIN + // Clients should not load the unversioned libcrypto dylib as it does not have a stable ABI + if (crypto.endsWith("libcrypto.dylib")) + continue; +#endif + libcrypto->setFileNameAndVersion(crypto, -1); + if (libcrypto->load()) { + QFileInfo fi(crypto); + QString version = fi.completeSuffix(); + + for (const QString &ssl : sslList) { + if (!ssl.endsWith(version)) + continue; + + libssl->setFileNameAndVersion(ssl, -1); + + if (libssl->load()) { + // libssl.so.x and libcrypto.so.x found + return result; + } else { + libssl->unload(); + } + } + } + libcrypto->unload(); + } + + // failed to load anything + result = {}; + return result; + +# else + // not implemented for this platform yet + return result; +# endif // Q_OS_UNIX +} + +#endif // Q_OS_WIN + +bool qt_auto_test_resolve_OpenSSL_symbols() +{ +#define RESOLVEFUNC(func) \ + if (!(_q_##func = _q_PTR_##func(libs.ssl->resolve(#func))) \ + && !(_q_##func = _q_PTR_##func(libs.crypto->resolve(#func)))) {\ + qsslSocketCannotResolveSymbolWarning(#func); \ + return false; \ + } + + LoadedOpenSsl libs = loadOpenSsl(); + if (!libs.ssl || !libs.crypto) { + qCWarning(lcOsslSymbols, "Failed to load libcrypto/libssl"); + return false; + } + + // BIO: + RESOLVEFUNC(BIO_new) + RESOLVEFUNC(BIO_free) + RESOLVEFUNC(BIO_write) + RESOLVEFUNC(BIO_s_mem) + + // EVP: + RESOLVEFUNC(EVP_PKEY_new) + RESOLVEFUNC(EVP_PKEY_free) + RESOLVEFUNC(EVP_PKEY_up_ref) + RESOLVEFUNC(PEM_read_bio_PrivateKey) + RESOLVEFUNC(PEM_read_bio_PUBKEY) + RESOLVEFUNC(EVP_sha1) + RESOLVEFUNC(EVP_PKEY_set1_RSA) + RESOLVEFUNC(EVP_PKEY_set1_DSA) + RESOLVEFUNC(EVP_PKEY_set1_DH) +#ifndef OPENSSL_NO_EC + RESOLVEFUNC(EVP_PKEY_set1_EC_KEY) +#endif + RESOLVEFUNC(EVP_PKEY_cmp) + + // Stack: + RESOLVEFUNC(OPENSSL_sk_num) + RESOLVEFUNC(OPENSSL_sk_pop_free) + RESOLVEFUNC(OPENSSL_sk_new_null) + RESOLVEFUNC(OPENSSL_sk_push) + RESOLVEFUNC(OPENSSL_sk_free) + RESOLVEFUNC(OPENSSL_sk_value) + + // X509: + RESOLVEFUNC(X509_up_ref) + RESOLVEFUNC(X509_free) + + // ASN1_TIME: + RESOLVEFUNC(X509_gmtime_adj) + RESOLVEFUNC(ASN1_TIME_free) + +#if QT_CONFIG(ocsp) + + RESOLVEFUNC(i2d_OCSP_RESPONSE) + RESOLVEFUNC(OCSP_response_create) + RESOLVEFUNC(OCSP_RESPONSE_free) + RESOLVEFUNC(OCSP_basic_add1_status) + RESOLVEFUNC(OCSP_basic_sign) + RESOLVEFUNC(OCSP_BASICRESP_new) + RESOLVEFUNC(OCSP_BASICRESP_free) + RESOLVEFUNC(OCSP_cert_to_id) + RESOLVEFUNC(OCSP_CERTID_free) + +#endif // QT_CONFIG(ocsp) + + return true; +} + +#endif // QT_CONFIG(library) + +#else // !defined QT_LINKED_OPENSSL + +bool qt_auto_test_resolve_OpenSSL_symbols() +{ +#ifdef QT_NO_OPENSSL + return false; +#endif + return true; +} + +#endif // !defined QT_LINKED_OPENSSL + +} // Unnamed namespace + +QT_END_NAMESPACE + +#endif // QOPENSSL_SYMBOLS_H + diff --git a/tests/auto/network/ssl/shared/tlshelpers.h b/tests/auto/network/ssl/shared/tlshelpers.h new file mode 100644 index 0000000000..de3c2ea51a --- /dev/null +++ b/tests/auto/network/ssl/shared/tlshelpers.h @@ -0,0 +1,31 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QtNetwork/qtnetworkglobal.h> + +#if QT_CONFIG(ssl) + +#include <QtNetwork/qsslsocket.h> + +#endif // QT_CONFIG(ssl) + +#include <QtCore/qstring.h> +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +namespace TlsAux { + +inline bool classImplemented(QSsl::ImplementedClass cl) +{ +#if QT_CONFIG(ssl) + return QSslSocket::implementedClasses().contains(cl); +#endif + return cl == QSsl::ImplementedClass::Certificate; // This is the only thing our 'cert-only' supports. +} + +} // namespace TlsAux + + + +QT_END_NAMESPACE diff --git a/tests/auto/network/ssl/ssl.pro b/tests/auto/network/ssl/ssl.pro deleted file mode 100644 index 014ff34064..0000000000 --- a/tests/auto/network/ssl/ssl.pro +++ /dev/null @@ -1,34 +0,0 @@ -TEMPLATE=subdirs -QT_FOR_CONFIG += network-private - -SUBDIRS=\ - qpassworddigestor \ - qsslcertificate \ - qsslcipher \ - qsslellipticcurve \ - qsslerror \ - qsslkey \ - -qtConfig(ssl) { - qtConfig(private_tests) { - SUBDIRS += \ - qsslsocket \ - qsslsocket_onDemandCertificates_member \ - qsslsocket_onDemandCertificates_static - - qtConfig(dtls) { - SUBDIRS += \ - qdtlscookie \ - qdtls - } - - qtConfig(ocsp): SUBDIRS += qocsp - } -} - -qtConfig(ssl) { - qtConfig(private_tests) { - SUBDIRS += qasn1element \ - qssldiffiehellmanparameters - } -} |